更新环境

有问题就查看,命令一直在更新,谷歌官网

1
2
3
4
#更新系统环境
sudo apt update
#安装所需软件
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig

下载源码

  1. 创建aosp目录(例aosp11),进入目录下载repo,不需要设置环境变量。参考镜像下载

  2. 额外添加-b 可以指定分支 -b可以指定下载路径

  3. 在aosp下创建android目录,下载源码,详细步骤查看清华镜像,提供了两种方式

  • 每月更新的初始化包
  • 传统初始化方法,例如使用指定版本android-12.1.0_r27,版本号可以去谷歌官网查看
  1. 执行repo sync -c -j4同步代码

编译

1
2
3
4
5
6
7
8
#加载aosp环境
source build/envsetup.sh
#启动编译Product
lunch sdk_phone_x86_64
#开始编译
make -j22
#模拟器运行系统
emulator

其中sdk_phone_x86_64(64位),sdk_phone_x86(32位)为模拟器Product,其他可以使用lunch命令查看
模拟器文档

编译失败

out/soong/make_vars-lunch:No such file问题,多试几次

1
2
3
4
5
6
#加载aosp环境
source build/envsetup.sh
#lunch一定要带参数,不要只执行lunch
lunch sdk_phone_x86_64
#开始编译
make -j16

其他常用编译命令

1
2
3
4
5
6
7
8
9
10
11
#删除整个 out/ 目录
make clean
#用于清除编译缓存
make clobber

#删除大部分生成的文件但是保留配置文件和足够的构建外部模块的构建支持
make clean
#删除所有生成的文件,配置和各种各样备份的文件
make mrproper
#相当于执行一次make mrproper,然后再删除编辑器备份和补丁文件
make distclean

新增product

官网文档
举个栗子:小米公司创建正在开发米13的手机

  1. 在aosp下新建device/<company-name>/<device-name>目录,例如device/xiaomi/mi13
  2. 创建一个产品定义 Makefile文件,mi13.mk
    该文件中PRODUCT_DEVICE字段对应的就是所代表的device
  3. 创建一个指向产品的 Makefile 的 AndroidProducts.mk 文件
    1
    2
    3
    4
    5
    6
    7
    8
    #产品mk文件
    PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/mi13.mk \

    #启动类型
    COMMON_LUNCH_CHOICES := \
    mi13-userdebug \
    mi13-eng \
  4. 创建一个包含主板特定配置的 BoardConfig.mk Makefile

相关文件可以在aosp/build/target目录下找到模板文件进行修改

build/target: aosp 提供的product配置一般保存在该目录

device:芯片以及方案厂商放置的目录

源码方式预置apk

假设需要添加一个名为MyFirstSystemApp的预置apk,步骤如下

在我们的product目录下创建MyFirstSystemApp目录,并创建res目录和src目录,接着将app源码中的res目录和java目录下内容分别复制到res和src目录即可。

将AndroidManifest.xml文件拷贝到MyFirstSystemApp目录中。(需要注意的AndroidManifest需要为合并处理后的没有gradle构建为我们自动添加packageName等属性)

最后在MyFirstSystemApp目录下创建Android.bp文件(aosp中没有gradle,通过bp和mk文件去描述构建),内容大致如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
android_app {
name: "MyFirstSystemApp",
manifest: "AndroidManifest.xml",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
sdk_version:"current",
//apk签名类型
certificate: "platform",

//引用的库文件,这些库被定义在prebuilts,如果没有则需要自己添加
static_libs: [
"androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx.core_core-ktx",
"androidx-constraintlayout_constraintlayout",
],
}

然后我们需要修改product的mk文件,我这里对应 device/xiaomi/mi13/mi13.mk,添加

1
PRODUCT_PACKAGES += MyFirstSystemApp

执行编译

1
2
3
4
source build/envsetup.sh
lunch mi13-eng
make -j22
emulator

添加依赖

添加已有依赖

1
2
3
4
5
6
static_libs: [
"androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx.core_core-ktx",
"androidx-constraintlayout_constraintlayout",
]

在 AOSP 中,很多常用的库均以预编译模块的方式添加到系统源码中。
比如常用的 AndroidX 库定义在prebuilts/sdk/current/androidx 目录下,这些库通过 prebuilts/sdk/current/androidx/Android.bp 引入,而prebuilts/tools/common/m2目录下引入了大量的三方库

自定义lib

与创建app工程方式一样,创建lib工程。

aar包形式引入

假设 需要引入 lottie 这个动画库,首先我们这里下载好 lottie 库的 aar 打包文件。
在 device/xiaomi/mi13 目录下创建如下的目录结构:
liblottie/
├── Android.bp
└── lottie-5.2.0.aar
其中 Android.bp 的内容如下

1
2
3
4
5
android_library_import {
name: "lib-lottie",
aars: ["lottie-5.2.0.aar"],
sdk_version: "current",
}

然后我们修改 FirstSystemApp 中的 Android.bp 引入这个库:

1
2
3
4
5
static_libs: ["androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout",
"lib",
"lib-lottie"],

这样就可以在 App 中使用 lottie 库了

注意事项

这种方式和app开发使用gradle插件开发方式差别很大,gradle插件内部做了很多事情,比如AndroidManifest合并处理,xml一些属性的添加以及第三方库的引用,这些都需要我们自己完成

编译错误

可能会遇到artifact_path_requirements Offending entries Build failed相关的错误

  1. 这是因为对预置apk做了检测,我们在编译前关闭这个检查即可,在make命令之前执行
1
export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"
  1. 解决方式二就是将预置apk预置到product分区即可,在android.bp文件中添加分区描述,推荐方式
    1
    2
    3
    4
    5
    6
    android_app {
    name: "MyFirstSystemApp",
    //指定分区product/app
    product_specific: true
    //...
    }

sdk版本

1
2
platform_apis: true,
sdk_version: "",

当 platform_apis 为 true 时,sdk_version 必须为空。这种情况下我们的 app 会使用平台 API 进行编译而不是 SDK,这样我们的 App 就能访问到非 SDK API 了。关于 SDK API 和非 SDK API 的内容可以参考官方文档

系统 App 的签名

AOSP 内置了 APK 签名文件,我们可以在 Android.bp 中通过 certificate 配置系统 app 的签名文件,certificate 的值主要有一下几个选项:

  • testkey:普通 APK,默认情况下使用
  • platform:该 APK 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的 APK 所在进程的 UID 为system
  • shared:该 APK 需要和 home/contacts 进程共享数据
  • media:该 APK 是 media/download 系统中的一环
  • presigned:表示 这个 apk 已经签过名了,系统不需要再次签名;

系统 App 能使用更多的权限

当 Android.bp 中的 privileged 被配置为 true 时,我们的系统 App 在添加特许权限许可名单后,能使用 signature 和 signatureOrSystem 级别的权限,而普通 App 是不能使用这些权限的。

参考资料

https://mp.weixin.qq.com/s/HHhycjkjMlIsZYgQoYi6PA

通过apk方式集成app

在product目录下创建一个app目录,假设我们需要集成myTest.apk,创建device/<company-name>/<device-name>/myTest目录,product目录见新增product部分。

然后将apk文件复制到myTest目录下,并创建android.bp文件,文件内容如下

1
2
3
4
5
6
7
8
9
10
11
android_app_import {
name: "myTest",
//存储app在system_ext/app位置
system_ext_specific: true,
//使用apk自签名,不用重签名
presigned: true,
dex_preopt: {
enabled: false,
},
apk: "myTest.apk",
}

最后我们需要修改product的mk文件,我这里对应 device/<company-name>/<device-name>/your.mk,添加

1
PRODUCT_PACKAGES += myTest \

集成完毕,编译验证

1
2
3
4
source build/envsetup.sh
lunch mi13-eng
make -j22
emulator

签名配置

在上面的签名配置中我们还可以使用

1
2
3
4
5
6
7
8
9
10
11
android_app_import {
name: "myTest",
//存储app在system镜像中位置
system_ext_specific: true,
//使用系统签名
certificate: "platform"
dex_preopt: {
enabled: false,
},
apk: "myTest.apk",
}

certificate其他选项如下

  • testkey:普通 APK,默认情况下使用
  • platform:该 APK 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的 APK 所在进程的 UID 为system
  • shared:该 APK 需要和 home/contacts 进程共享数据
  • media:该 APK 是 media/download 系统中的一环
  • presigned:表示 这个 apk 已经签过名了,系统不需要再次签名;

集成位置

  1. system/app,不指定时默认在该目录下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    android_app_import {
    name: "myTest",
    //使用apk自签名,不用重签名
    presigned: true,
    dex_preopt: {
    enabled: false,
    },
    apk: "myTest.apk",
    }
  2. system_ext/app
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    android_app_import {
    name: "myTest",
    //存储app在system镜像中位置
    system_ext_specific: true,
    //使用apk自签名,不用重签名
    presigned: true,
    dex_preopt: {
    enabled: false,
    },
    apk: "myTest.apk",
    }
  3. system/pri-app
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    android_app_import {
    name: "myTest",
    //系统权限
    privileged: true,
    //使用apk自签名,不用重签名
    presigned: true,
    dex_preopt: {
    enabled: false,
    },
    apk: "myTest.apk",
    }
  4. product/app
    1
    2
    3
    4
    android_app_import {
    //product/app
    product_specific: true
    }
  5. vendor/app
    1
    2
    3
    4
    android_app_import {
    //proprietary: true,
    proprietary: true,
    }

system/pri-app

该目录下的app具有系统权限,其他目录下跟该目录下app签名一致的app也具有系统权限。

所以我们在集成第三方应用时,三方应用没有系统签名,却又需要使用system级别权限时,我们可以把第三方应用集成到system/pri-app目录即可;反过来,如果预装第三方应用,却不想让其拥有system级别权限时,可以将其集成到system/app目录下即可。

权限机制

https://www.404bugs.com/index.php/details/1101289176044457984