Android Studio开发系统应用

编译 framework 模块

系统应用可以调用隐藏的API,开发时需要包含隐藏 API 的 jar 包。
源码下编译 Framework 模块来得到这个 jar 包:

source 
lunch afra55-eng
# Android10 及以前
make framework
# Android11 及以后
#make framework-minus-apex

编译完成后,我们在 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates 目录下找到
classes.jar 文件,为方便识别,我们将该文件拷贝到其他地方,并将文件名修改为
framework.jar 。

Android Studio 下载

Android Studio 版本需要接近源码的发布日期最好。比如针对Android10源码,版本选择 3.6.3。
https://developer.android.google.cn/studio/archive?hl=zh-cn

SDK工具相关下载

https://androidsdkmanager.azurewebsites.net/
比如下载 29.0.3 版本的 build tools: https://dl.google.com/android/repository/build-tools_r29.0.3-linux.zip
解压缩重命名为 29.0.3 并放到 /home/{用户名}/Android/Sdk/build-tools 目录下。

创建项目

gradle 镜像国内配置:
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-5.6.4-all.zip

AndroidManifest.xml 中添加系统应用标识

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserId="android.uid.system">

android:sharedUserId="android.uid.system"
在Android应用的AndroidManifest.xml文件中,android:sharedUserId是一个属性,它允许你指定一个共享的用户ID,以便多个应用可以共享相同的Linux用户ID和相应的文件系统权限。
在Android系统中,每个应用都有一个唯一的用户ID(UID),这个UID决定了应用可以访问哪些系统资源和文件。
通过设置android:sharedUserId,你可以让多个应用共享同一个UID,这意味着这些应用在文件系统级别被视为同一个用户,可以共享数据、访问彼此的私有文件和组件(在合适权限设置下)。
数据共享: 允许不同应用访问和共享相同的数据存储,例如SharedPreferences、数据库文件等。
权限共享: 应用之间可以更方便地共享权限,例如如果一个应用获得了某个特权,其他共享同一UID的应用也可以利用这些权限。
组件访问: 在某些情况下,可以让一个应用直接启动或交互另一个应用的组件(Activity、Service等),而不需要通过Intent进行跨应用调用。

修改 build.gradle 中的 buildToolsVersion

compliteSdkVersion 29
buildToolsVersion "29.0.3"
minSdkVersion 29
targetSdkVersion 29

添加包含隐藏API的jar包

将上文的 framework.jar 拷贝到项目的 app/libs 文件夹中, 修改根 build.gradle :
Android studio 4.2 及以后:

allprojects{
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            Set<File> fileSet = options.bootstrapClasspath.getFiles()
            List<File> newFileList = new ArrayList<>();
            newFileList.add(new File("./app/libs/framework.jar"))
            newFileList.addAll(fileSet)
            options.bootstrapClasspath = files(
                    newFileList.toArray()
            )
        }
    }
}

Android Studio 4.2 前包括Android Studio 3.x:

allprojects {
gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            //相对位置,根据存放的位置修改路径
            options.compilerArgs.add('-Xbootclasspath/p:app/libs/framework.jar')
        }
    }
}

并在应用级build.gradle添加依赖:

dependencies {
    compileOnly files('libs/framework.jar')
    //.......
}

制作系统签名文件

https://github.com/getfatday/keytool-importkeypair 签名工具 clone 到本地,并将其中的 keytool-importkeypair 文件添加到 PATH 路径。
接着进入系统源码下的 build/target/product/security 路径,接着执行:

keytool-importkeypair -k ./platform.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform

k 表示要生成的签名文件的名字,这里命名为 platform.keystore -p 表示要生成的 keystore 的密码,这里是 android -pk8 表示要导入的 platform.pk8 文件 -cert 表示要导入的platform.x509.pem -alias 表示给生成的 platform.keystore 取一个别名,这是命名为 platform。

接着,把生成的签名文件 platform.keystore 拷贝到 Android Studio 项目的 app 目录下,然后在 app/build.gradle 中添加签名的配置信息:

android {
    signingConfigs {
        sign {
            storeFile file('platform.keystore')
            storePassword 'android'
            keyAlias = 'platform'
            keyPassword 'android'
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.sign
        }

        debug {
            minifyEnabled false
            signingConfig signingConfigs.sign
        }
    }
}

编译运行系统APP

在开发过程中,直接点击 Android Stuido 中的运行按钮来运行我们的配置好的 App。当我们的 App 开发完成,我们需要将其预制到系统中:
在系统源码下的 device/Victor/Afra55 目录下,创建如下的文件与文件夹:

Victor/
└── Afra55
    ├── Afra55.mk
    ├── AndroidProducts.mk
    ├── BoardConfig.mk
    └── AsSystemApp
        ├── Android.mk
        └── app.apk

其中 app.apk 是我们用 Android Studio 打包好的 apk 安装包。Android.mk 的内容如下(Android10 下,Android.bp 还不支持引入 apk, Android13 是没问题的):

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := AsSystemApp
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := app.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_PRODUCT_MODULE := true
include $(BUILD_PREBUILT)

修改 Afra55.mk:

PRODUCT_PACKAGES += \
    AsSystemApp

然后编译系统,启动虚拟机,就可以看到 App 了。

source build/envsetup.sh
lunch Afra55-eng
make -j16
emulator 

Product配置文件简述(对标 x86_64 模拟器 aosp_x86_64-eng)

BoardConfig.mk 用于定义和硬件相关的底层特性和变量,比如当前源码支持的 cpu 位数(64/32位),bootloader 和 kernel, 是否支持摄像头,GPS导航等一些板级特性。其中还通过 include 包含了 BoardConfigGsiCommon.mk 和 BoardConfigEmuCommon.mk 两个配置文件,前者用于通用系统映像的配置,后者用于模拟器的配置。主要和硬件相关,有一个基本的了解即可。一般很少改动。

# x86_64 emulator specific definitions
TARGET_CPU_ABI := x86_64
TARGET_ARCH := x86_64
TARGET_ARCH_VARIANT := x86_64

TARGET_2ND_CPU_ABI := x86
TARGET_2ND_ARCH := x86
TARGET_2ND_ARCH_VARIANT := x86_64

TARGET_PRELINK_MODULE := false
include build/make/target/board/BoardConfigGsiCommon.mk
include build/make/target/board/BoardConfigEmuCommon.mk

BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800

BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86

# Wifi.
BOARD_WLAN_DEVICE           := emulator
BOARD_HOSTAPD_DRIVER        := NL80211
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
WPA_SUPPLICANT_VERSION      := VER_0_8_X
WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
WIFI_DRIVER_FW_PATH_AP      := "/dev/null"

AndroidProducts.mk 定义我们执行 lunch 命令时,打印的列表以及每个选项对应的配置文件

PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/Afra55.mk

COMMON_LUNCH_CHOICES := \
    Afra55-eng \
    Afra55-userdebug \
    Afra55-user

afra55.mk:产品配置

# 表示这个产品构建将使用动态分区。动态分区是 Android 10 引入的一种新特性,允许系统在运行时动态地管理分区,比如更新系统应用而不需要重新启动设备。
PRODUCT_USE_DYNAMIC_PARTITIONS := true

# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled

# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.

# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)

# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)

# Enable mainline checking for excat this product name
#ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
#endif

PRODUCT_PACKAGES += AsSystemApp

PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
    root/init.zygote32_64.rc \
    root/init.zygote64_32.rc \

# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
#   1. 64-bit primary, 32-bit secondary OR
#   2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
    system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc

# Overrides, 定义了产品的品牌、名称、设备标识符和模型描述
PRODUCT_BRAND := Victor
PRODUCT_NAME := Afra55
PRODUCT_DEVICE := Afra55
PRODUCT_MODEL := Android SDK built for x86_64 Afra55
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容