APEX
简介
Android Pony EXpress (APEX) 是 Android 10 中引入的一种容器格式,用于较低级别系统模块的安装流程中。此格式可帮助更新不适用于标准 Android 应用模型的系统组件。一些示例组件包括原生服务和原生库、硬件抽象层 (HAL))、运行时 (ART) 以及类库。
架构
目前官网的模块化列表:
| 模块名称 | 软件包名称 | 类型 | 推出的版本 |
|---|---|---|---|
| adbd | com.android.adbd | APEX | Android 11 |
| ART | com.android.art | APEX | Android 12 |
| 强制门户登录 | com.android.captiveportallogin | APK | Android 10 |
| CellBroadcast | com.android.cellbroadcast | APEX | Android 11 |
| Conscrypt | com.android.conscrypt | APEX | Android 10 |
| 设备调度 | com.android.scheduling | APEX | Android 12 |
| DNS 解析器 | com.android.resolv | APEX | Android 10 |
| DocumentsUI | com.android.documentsui | APK | Android 10 |
| ExtServices | com.android.ext.services | APK (Android 10)APEX (Android 11) | Android 10 |
| IPsec/IKEv2 库 | com.android.ipsec | APEX | Android 11 |
| 媒体编解码器 | com.android.media.swcodec | APEX | Android 10 |
| 媒体 | com.android.media | APEX | Android 10(提取器、MediaSession API)Android 11 (MediaParser API) |
| MediaProvider | com.android.mediaprovider | APEX | Android 11 |
| ModuleMetadata | com.android.modulemetadata | APK | Android 10 |
| 网络堆栈权限配置 | com.android.networkstack.permissionconfig | APK | Android 10 |
| 网络组件 | com.android.networkstack | APK | Android 10 |
| NNAPI 运行时 | com.android.neuralnetworks | APK | Android 11 |
| PermissionController | com.android.permissioncontroller | APK | Android 10 |
| SDK 扩展 | com.android.sdkext | APEX | Android 11 |
| Statsd | com.android.os.statsd | APEX | Android 11 |
| 网络共享 | com.android.tethering | APK | Android 11 |
| 时区数据 | com.android.tzdata | APEX | Android 10 |
| Wi-Fi | com.android.wifi.apex | APEX | Android 11 |
APEX 格式
APEX 文件
系统编译后 apex 文件通常放在 /system/apex/ 目录下,下面以 wifi 模块的 apex 为例:
-
META-INF
这个跟 APK 一样存放文件签名信息。
-
AndroidManifest.xml
含包名称和版本信息,可以使用 aapt 工具查看。
-
apex_payload.img
由 dm-verity 支持的 ext2 文件系统映像,ubuntu 上双击即可打开。
apex 支持的文件类型:
- 本机共享库
- 本机可执行文件
- JAR文件
- 数据文件
- 配置文件
-
apex_pubkey
是用于对文件系统映像进行签名的公钥。在运行时,此密钥可确保下载的 APEX 使用在内置分区中签署相同 APEX 的同一实体进行签名。
APEX 签名
使用两种方式为 APEX 文件签名。第一种方式是使用密钥为 apex_payload.img文件签名。第二种方式是使用 APK 签名方案 v3 为整个 APEX 签名。在此过程中使用两个不同的密钥。
内置APEX
APEX文件可以位于内置分区中,例如 /system 分区;分区已经通过 dm-verity 校验,因此APEX文件直接安装在 loop 设备上。
如果内置分区中存在 APEX,可以通过提供具有相同软件包名称和更高或相同版本代码的 APEX 软件包来更新 APEX。新的 APEX 存储在 /data中,与 APK 类似,新安装的版本会替换内置分区中已存在的版本。但与 APK 不同的是,新安装的 APEX 版本仅在重新启动后才会激活。
如何构建 APEX
-
工程创建
apex 工程通常都命名为 apex ,工程一般包含以下内容:Android.bp,AndroidManifest.xml,apex_manifest.json, .avbpubkey, .pem,framework/。
-
创建 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <!-- * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * <http://www.apache.org/licenses/LICENSE-2.0> * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. --> <manifest xmlns:android="<http://schemas.android.com/apk/res/android>" package="com.haley.demo"> <!-- APEX does not have classes.dex --> <application android:hasCode="false" /> <!-- Setting maxSdk to lock the module to R. minSdk is auto-set by build system --> </manifest> -
创建 apex_manifest.json
{ "name": "com.haley.demo", "version": 1 } -
创建 Android.bp
apex_defaults { name: "com.haley.demo-defaults", //设置AndroidManifest.xml androidManifest: "AndroidManifest.xml", //设置vbmeta签名 key: "com.haley.demo.key", //设置zip签名,这里使用系统自带的签名,也可以自定义 certificate: "platform", } apex_key { name: "com.haley.demo.key", public_key: "com.haley.demo.avbpubkey", private_key: "com.haley.demo.pem" } apex { // 设置apex name name: "com.haley.demo", // 设置 apex_manifest.json manifest: "apex_manifest.json", defaults:["com.haley.demo-defaults"], } -
生成签名,下面以
com.haley.demo为例:openssl genrsa -out com.haley.demo.pem 4096 avbtool extract_public_key --key com.haley.demo.pem --output com.haley.demo.avbpubkey- 签名注意 apex_key 的 name 要和 .key、*.avbpubkey 命名要一致。
-
添加 file_context
需要为 apex 添加一个 file_context,文件位于
/system/sepolicy/apex/com.haley.demo-file_contexts。(/.*)? u:object_r:system_file:s0 -
编译 apex
直接使用 mmm 编译 apex 模块即可。
-
产物
编译 apex 模块时,会在
out/soong/.intermediates/device/generic/haley/apex/test生成 apex 的临时文件。编译成功后拷贝到out/target/product/generic_x86_64/system/apex目录下。
安装 APEX
apex 可以使用adb 直接安装:
adb install apex_file_name
adb reboot
安装成功之后,系统会提示你重启生效。
设备重启之后就可以在系统的 /apex 目录下找到我们安装的apex。
APEX 应用
添加一个app
修改 Android.bp 在 apex {} 中设置apps 字段,如下所示:
apex {
//... 省略部分代码
apps: ["JniDemo",],
}
添加一个jar
首先创建要添加的 jar 模块,如下所示:
修改 Android.bp 在 apex {} 中设置java_libs 字段,如下所示:
apex {
//... 省略部分代码
java_libs: ["JarDemo", "com.haley.demoapi"],
}
- 注意: 要在 jar 模块的 Android.bp 中需要添加
apex_available字段,否则会包"com.haley.demo" requires "JarDemo" that is not available for the APEX异常。
添加一个so
首先创建要添加的 so 模块,如下所示:
修改 Android.bp 在 apex {} 中设置native_shared_libs 字段,如下所示:
apex {
//... 省略部分代码
native_shared_libs: ["libdbus"],
}
- 跟添加 jar 模块一样,需要设置
apex_available字段。
apex 版本升级
如果 apex 版本需要升级,只需要修改 apex_manifest.json 中的 version 版本号即可:
{
"name": "com.haley.demo",
"version": 3
}
修改之后重新打包,使用 adb install 命令安装覆盖,设备重启生效。