AOSP-预置APP历险记

Android 系统预置 APP 是做 Framework 应用开发经常经常会遇到的工作,预置 APP 分为两种,一种是直接预置 APK,一种是预置带有源码的 APP。

源码形式内置

我这边编译时,lunch选择的版本是sdk_car的版本,所以下面以内置android_car app的形式进行讲解。

image

car目录内就是android_car源码内置app的目录。其余目录为手机版内置app的源码包。

第一步:创建APP源码根目录

进入/aosp/packages/app/car下创建DemoApp目录

image

第二步:APP根目录下创建Android.bp配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
android_app {
//应用名
name: "DemoApp",
manifest: "AndroidManifest.xml",
//源码目录
srcs: [
"src/**/*.java",
],
//res目录
resource_dirs: [
"res",
],
//静态库
static_libs: [
"androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout",
],

//签名类型
// certificate 用于指定APK的签名方式。如果不指定,默认使用testkey签名
// testkey:普通APK,默认使用该签名。
// platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试
// shared:该APK需要和home/contacts进程共享数据。
// media:该APK是media/download系统中的一环。
certificate: "platform",

// 设定apk安装路径为priv-app
privileged: true,

sdk_version: "system_current",
min_sdk_version: "28",
target_sdk_version: "28",

optimize: {
enabled: false,
},

dex_preopt: {
enabled: false,
},

}

第三部:根据上面的配置拷贝并放置对应目录及文件

image

注意

AndroidManifest.xml根节点要加上package属性标明包名称,要不然编译会报错。

第四部:配置Product

这个配置决定了应用是否能够正常显示到launcher里。

aosp下找到该路径下/aosp/build/target/product/handheld_product.mk文件

PRODUCT_PACKAGES下增加 DemoApp\,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# This makefile contains the product partition contents for
# a generic phone or tablet device. Only add something here if
# it definitely doesn't belong on other types of devices (if it
# does, use base_product.mk).
$(call inherit-product, $(SRC_TARGET_DIR)/product/media_product.mk)

# /product packages
PRODUCT_PACKAGES += \
Browser2 \
Calendar \
Camera2 \
Contacts \
DeskClock \
Gallery2 \
LatinIME \
Music \
OneTimeInitializer \
preinstalled-packages-platform-handheld-product.xml \
QuickSearchBox \
SettingsIntelligence \
DemoApp\
frameworks-base-overlays

PRODUCT_PACKAGES_DEBUG += \
frameworks-base-overlays-debug

第五步:编译

在aosp主目录下初始化环境

1
source build/envsetup.sh

然后进入自定义的app目录下/packages/app/Car/DemoApp执行模块编译

1
mm

编译完成后,回到aosp主目录,执行

1
lunch sdk_car_x86_64-userdebug

然后整体编译

1
make -j4

编译完成后,启动模拟器

1
emulator

即可看到新增的app

image

APK预置

第一步:创建APK放置的目录

进入/aosp/packages/app/car下,创建TestApk.apk放置的目录TestApp,将apk放置于该目录下,并创建Android.bp配置文件。

image

第二步:配置Android.bp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
android_app_import {
name: "TestApk",
//使用原签名
presigned: true,
//安装到system/pri-app下
privileged: true,
//指定apk文件
apk:"TestApk.apk",

dex_preopt: {
enabled: false,
},

}

第三步:配置product

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This makefile contains the product partition contents for
# a generic phone or tablet device. Only add something here if
# it definitely doesn't belong on other types of devices (if it
# does, use base_product.mk).
$(call inherit-product, $(SRC_TARGET_DIR)/product/media_product.mk)

# /product packages
PRODUCT_PACKAGES += \
Browser2 \
Calendar \
Camera2 \
Contacts \
DeskClock \
Gallery2 \
LatinIME \
Music \
OneTimeInitializer \
preinstalled-packages-platform-handheld-product.xml \
QuickSearchBox \
SettingsIntelligence \
DemoApp\
TestApk\
frameworks-base-overlays

PRODUCT_PACKAGES_DEBUG += \
frameworks-base-overlays-debug

第四步:编译

在aosp主目录下初始化环境

1
source build/envsetup.sh

然后进入自定义的app目录下/packages/app/Car/TestApk执行模块编译

1
mm

编译完成后,回到aosp主目录,执行

1
lunch sdk_car_x86_64-userdebug

然后整体编译

1
make -j4

编译完成后,启动模拟器

1
emulator

即可看到新增的app

遇到的错误

在Android 12 S上预制apk时候发现有编译不过情况,报artifact_path_requirements相关错误

1
2
3
4
5
6
build/make/core/artifact_path_requirements.mk:26: warning:  build/make/target/product/sdk_car_x86_64.mk produces files inside build/make/target/product/generic_system.mks artifact path requirement. 
Offending entries:
system/pri-app/TestApk/TestApk.apk
In file included from build/make/core/main.mk:1383:
build/make/core/artifact_path_requirements.mk:26: error: Build failed.
00:42:13 ckati failed with: exit status 1

因为新版本artifact_path_requirements有对预装相关东西进行了规则检测,发现system/pri-app/TestApk/TestApk.apk这种预制到system/pri-app的情况属于违规了。
那么具体怎么解决呢?

通过在github寻找到了一些第三方rom维护者也有遇到类似问题,参考他们解决方案,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ......
# and in with the new
local prebuiltdir=$(getprebuilt)
local gccprebuiltdir=$(get_abs_build_var ANDROID_GCC_PREBUILTS)

# defined in core/config.mk
local targetgccversion=$(get_build_var TARGET_GCC_VERSION)
local targetgccversion2=$(get_build_var 2ND_TARGET_GCC_VERSION)
export TARGET_GCC_VERSION=$targetgccversion

# 此处增加配置
export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"

# The gcc toolchain does not exists for windows/cygwin. In this case, do not reference it.
export ANDROID_TOOLCHAIN=
export ANDROID_TOOLCHAIN_2ND_ARCH=
local ARCH=$(get_build_var TARGET_ARCH)
local toolchaindir toolchaindir2=
# ......

build/envsetup.sh 加上export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"就可以顺利编译通过不再报artifact_path_requirements错误,这里其实就相当于把新版本编译系统中artifact_path_requirements检测关闭就可以

关于预置配置

签名

自签名

1
2
3
4
5
6
7
8
9
android_app_import {
name: "SogouInput",
system_ext_specific: true,
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}

系统签名

1
2
3
4
5
6
7
# system signal
android_app_import {
name: "SogouInput",
system_ext_specific: true,
certificate: "platform",
apk: "SogouInput_android_oem_baoneng.apk",
}

集成位置

system/app

1
2
3
4
5
6
7
8
android_app_import {
name: "SogouInput",
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}

system_ext/app

1
2
3
4
5
6
7
8
9
android_app_import {
name: "SogouInput",
system_ext_specific: true,
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}

system/pri-app

必须声明在permission白名单内。
aosp路径:frameworks/base/data/etc/privapp-permissions-platform.xml
手机路径:system/etc/permission/privapp-permission-platform.xml

1
2
3
4
5
6
7
8
9
android_app_import {
name: "SogouInput",
privileged: true,
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}

product/app

1
2
3
4
5
6
7
8
9
android_app_import {
name: "SogouInput",
product_specific: true,
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}

vendor/app

1
2
3
4
5
6
7
8
9
android_app_import {
name: "SogouInput",
proprietary: true,
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "SogouInput_android_oem_baoneng.apk",
}