You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# How To APEX
[go/android-apex-howto](http://go/android-apex-howto) (internal link)
This doc reflects the current implementation status, and thus is expected to
change regularly.
## Reference
To understand the design rationale, visit this
[public doc](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/docs/README.md#alternatives-considered-when-developing-apex)
and [go/android-apex](http://go/android-apex) (internal).
## Building an APEX
A cheat sheet:
```
apex {
name: "com.android.my.apex",
manifest: "apex_manifest.json",
// optional. if unspecified, a default one is auto-generated
androidManifest: "AndroidManifest.xml",
// libc.so and libcutils.so are included in the apex
native_shared_libs: ["libc", "libcutils"],
binaries: ["vold"],
java_libs: ["core-all"],
apps: ["myapk"],
prebuilts: ["my_prebuilt"],
compile_multilib: "both",
key: "com.android.my.apex.key",
certificate: ":com.android.my.apex.certificate",
}
```
`apex_manifest.json` should look like:
```
{
"name": "com.android.my.apex",
"version": 1
}
```
The file contexts files should be created at
`/system/sepolicy/apex/com.android.my.apex-file_contexts`:
```
(/.*)? u:object_r:system_file:s0
/sub(/.*)? u:object_r:sub_file:s0
/sub/file3 u:object_r:file3_file:s0
```
The file should describe the contents of your apex. Note that the file is
amended by the build system so that the `apexd` can access the root directory of
your apex and the `apex_manifest.pb` file. (Technically, they are labeled as
`system_file`.) So if you're
[building the apex without Soong](#building-apex-without-soong), please be sure
that `apexd` can access the root directory and the `apex_manifest.pb` file. (In
the example above, the first line does that.)
#### A script to create a skeleton of APEX
For convenience, you might want to use a
[script](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/tools/create_apex_skeleton.sh)
that creates a skeleton (`Android.bp`, keys, etc.) of an APEX for you. You only
need to adjust the `APEX_NAME` variable to be your actual APEX name.
#### File types and places where they are installed in apex
file type | place in apex
-------------- | ----------------------------------------------------------
shared libs | `/lib` and `/lib64` (`/lib/arm` for translated arm in x86)
executables | `/bin`
java libraries | `/javalib`
android apps | `/app` or `/priv-app`
prebuilts | `/etc`
### Transitive dependencies
Transitive dependencies of a native shared lib or an executable are
automatically included in the APEX. For example, if `libFoo` depends on
`libBar`, then the two libs are included even when only `libFoo` is listed in
`native_shared_libs` property.
However, if a transitive dependency has a stable ABI, it is not included
transitively. It can be included in an APEX only by directly being referenced.
Currently (2019/08/05), the only module type that can provide stable ABI is
`cc_library`. To do so, add `stubs.*` property as shown below:
```
cc_library {
name: "foo",
srcs: [...],
stubs: {
symbol_file: "foo.map.txt",
versions: ["29", "30"],
},
}
```
Use this when a lib has to be accessed across the APEX boundary, e.g. between
APEXes or between an APEX and the platform.
### apex_available
Any module that is “included” (not just referenced) in an APEX either via the
direct dependency or the transitive dependency has to correctly set the
`apex_available` property in its `Android.bp` file. The property can have one or
more of the following values:
* `<name_of_an_apex>`: Like `com.android.adbd`. By specifying the APEX names
explicitly, the module is guaranteed to be included in those APEXes. This is
useful when a module has to be kept as an implementation detail of an APEX
and therefore shouldnt be used from outside.
* `//apex_available:anyapex`: This means that the module can be included in
any APEX. This is useful for general-purpose utility libraries like
`libbase`, `libcutils`, etc.
* `//apex_available:platform`: The module can be installed to the platform,
outside of APEXes. This is the default value. However, `if apex_available`
is set to either of `<name_of_an_apex` or `//apex_available:anyapex`, the
default is removed. If a module has to be included in both APEX and the
platform, `//apex_available:platform` and`//apex_available:anyapex` should
be specified together.
The act of adding an APEX name to the `apex_available` property of a module has
to be done or be reviewed by the author(s) of the module. Being included in an
APEX means that the module will be portable, i.e., running on multiple versions
of the current and previous platforms, whereas it usually was expected to run on
the current (the up-to-date) platform. Therefore, the module might have to be
prepared to not have version-specific dependencies to the platform, like the
existence of a dev node, a system call, etc.
### Handling multiple ABIs
`compile_multilib`: specifies the ABI(s) that this APEX will compile native
modules for. Can be either of `both`, `first`, `32`, `64`, `prefer32`. For most
of the cases, this should be `both`.
`native_shared_libs`: installed for **_both_** primary and secondary ABIs of the
device. Of course, if the APEX is built for a target having single ABI (i.e.
32-bit only or 64-bit only), only libraries with the corresponding ABI are
installed.
`binaries`: installed only for the **_primary_** ABI of the device. In other
words,
* If the device is 32-bit only, only the 32-bit variant of the binary is
installed.
* If the device supports both 32/64 ABIs, but with
`TARGET_PREFER_32_BIT_EXECUTABLES=true`, then only the 32-bit variant of the
binary is installed.
* If the device is 64-bit only, then only the 64-bit variant of the binary is
installed.
* If the device supports both 32/64 ABIs, but without
`TARGET_PREFER_32_BIT_EXECUTABLES=true`, then only the 64-bit variant of the
binary is installed.
In order to fine control the ABIs of the native libraries and binaries to be
installed, use
`multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]`
properties.
* `first`: matches with the primary ABI of the device. This is the default for
`binaries`.
* `lib32`: matches with the 32-bit ABI of the device, if supported
* `lib64`: matches with the 64-bit ABI of the device, it supported
* `prefer32`: matches with the 32-bit ABI of the device, if support. If 32-bit
ABI is not supported, it is matched with the 64-bit ABI.
* `both`: matches with the both ABIs. This is the default for
`native_shared_libraries`.
* `java libraries` and `prebuilts`: ABI-agnostic
Example: (lets assume that the device supports 32/64 and does not prefer32)
```
apex {
// other properties are omitted
compile_multilib: "both",
native_shared_libs: ["libFoo"], // installed for 32 and 64
binaries: ["exec1"], // installed for 64, but not for 32
multilib: {
first: {
native_shared_libs: ["libBar"], // installed for 64, but not for 32
binaries: ["exec2"], // same as binaries without multilib.first
},
both: {
native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
binaries: ["exec3"], // installed for 32 and 64
},
prefer32: {
native_shared_libs: ["libX"], // installed for 32, but not for 64
},
lib64: {
native_shared_libs: ["libY"], // installed for 64, but not for 32
},
},
}
```
### APEX image signing
**Note**: the APEX skeleton creation
[script](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/tools/create_apex_skeleton.sh)
automates this step.
Each APEX must be signed with different keys. There is no concept of the
platform key. `apexd` in the future might reject if multiple APEXes are signed
with the same key. When a new key is needed, create a public-private key pair
and make an `apex_key` module. Use `key` property to sign an APEX using the key.
The public key is included in the zip container of the APEX as a file entry
`apex_pubkey`.
How to generate the key pair:
```
# create an rsa key pair
$ openssl genrsa -out com.android.my.apex.pem 4096
# extract the public key from the key pair
$ avbtool extract_public_key --key com.android.my.apex.pem \
--output com.android.my.apex.avbpubkey
# in Android.bp
apex_key {
name: "com.android.my.apex.key",
public_key: "com.android.my.apex.avbpubkey",
private_key: "com.android.my.apex.pem",
}
```
Important: In the above example, the name of the public key (that is
`com.android.my.apex`) becomes the ID of the key. The ID of the key used to sign
an APEX is recorded in the APEX. At runtime, a public key with the same ID in
the device is used to verify the APEX.
### APK (APEX container) signing
**Note**: the APEX skeleton creation
[script](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/tools/create_apex_skeleton.sh)
automates this step.
An APEX should also be signed just like APKs. So, an APEX is signed twice; once
for the mini file system (`apex_payload.img` file) and once for the entire file.
Just like APK, the file-level signing is done via the `certificate` property. It
can be set in three ways.
* not set: if unset, the APEX is signed with the certificate located at
`PRODUCT_DEFAULT_DEV_CERTIFICATE`. If the flag is also unset, it defaults to
`build/target/product/security/testkey`
* `<name>`: the APEX is signed with the certificate named `<name>` in the same
directory as `PRODUCT_DEFAULT_DEV_CERTIFICATE`
* `<name>`: the APEX signed with the certificate which is defined by a
Soong module named `<name>`. The certificate module can be defined as
follows.
```
android_app_certificate {
name: "com.android.my.apex.certificate",
// This will use com.android.my.apex.x509.pem (the cert) and
// com.android.my.apex.pk8 (the private key)
certificate: "com.android.my.apex",
}
```
How to generate the certificate/private key pair:
```
# Create certificate and private in PEM form
$ openssl req -x509 -newkey rsa:4096 -nodes -days 999999 -keyout key.pem -out com.android.my.apex.x509.pem
# Enter following info via the interactive prompts
# Country Name: US
# State: California
# Locality Name: Mountain View
# Organization Name: Android
# Organization Unit Name: Android
# Common Name: <your-apk-name>
# Email address: android@android.com
# Convert the private to pkcs8 format
$ openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -out com.android.my.apex.pk8 -nocrypt
```
### Signing APEXs with release keys
The procedures described in the [APEX image signing](#apex-image-signing) and
[APK (APEX container) signing](#apk-apex-container_signing) sections require the
private keys to be present in the tree. This is not suitable for public release.
Please refer to the
[APEX signing key replacement](https://source.android.com/devices/tech/ota/sign_builds#apex-signing-key-replacement)
documentation to prepare the APEX packages for release.
For the Google-specific procedure for release keys, the documentation is
available at
[go/android-apex-howto-internal](http://go/android-apex-howto-internal)
(internal only).
### Linker namespaces for native libraries and binaries
The linker needs to be set up with separate namespaces for each APEX, for
isolation. It is done through `ld.config.txt` files, which are autogenerated by
`linkerconfig`. Normally you only need to ensure that the APEX manifest
correctly lists the native libraries it requires (from platform or other APEXes)
and provides, which by default is taken from the build system.
Refer to the [design doc](go/linker-config-apex) for more information about
linkerconfig and apex.
## Installing an APEX
Use
```
adb install --staged <path_to_apex> && adb reboot
```
The `adb install --staged` command triggers a verification for the staged APEX
which might fail when the APEX is signed incorrectly.
Note that on Q devices when the `adb install --staged` command completes you
still will have to wait until the verification for the staged APEX is finished
before issuing `adb reboot`.
On R devices we added the `--wait` option to `adb install` to wait until the
verification is completed before returning. On S devices the `--wait` option is
implicit.
## Hot swapping an APEX (development only)
Use
```
adb sync && adb shell cmd -w apexservice remountPackages
```
Note that for this command to remount your APEX, you must ensure that all
processes that have reference to your APEX are killed. E.g. if you are
developing an APEX that contributes to system\_server, you can use the
following:
```
adb root
adb remount
adb shell stop
adb sync
adb shell cmd -w apexservice remountPackages
adb shell start
```
## Using an APEX
After the reboot, the apex will be mounted at `/apex/<apex_name>@<version>`
directory. Multiple versions of the same APEX can be mounted at the same time. A
mount point that always points to the latest version of an APEX is provided:
`/apex/<apex_name>`.
Clients can use the latter path to read or execute something from APEX.
So, typical usage of APEX is as follows.
1. an APEX is pre-loaded under `/system/apex`when the device is shipped.
2. Files in it are accessed via the `/apex/<apex_name>/`path.
3. When an updated version of the APEX is installed in `/data/apex/active`, the
path will point to the new APEX after the reboot.
## Updating service with APEX
Using APEX, you can update a service. To do so, you need …
1) Mark the service in system partition as updatable. Add the new option
updatable to the service definition.
```
/system/etc/init/myservice.rc:
service myservice /system/bin/myservice
class core
user system
updatable
```
2) Create a new `.rc` file for the updated service. Use `override` option to
redefine the existing service.
```
/apex/my.apex/etc/init.rc:
service myservice /apex/my.apex/bin/myservice
class core
user system
override
```
Note that you can only have service definitions in the rc file in APEX. You
cannot have action triggers in APEXes.
Also note that if a service marked as updatable is started before APEXes are
activated, the start is delayed until the activation of APEXes is finished.
## Configuring system to support APEX updates
Set the following system property to true to support APEX file updates.
```
<device.mk>:
PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true
BoardConfig.mk:
TARGET_FLATTEN_APEX := false
or just
<device.mk>:
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
```
## Flattened APEX
For legacy devices, it is sometimes impossible or infeasible to update the old
kernel to fully support APEX. For example, the kernel might have been built
without `CONFIG_BLK_DEV_LOOP=Y`, which is crucial for mounting the file system
image inside an APEX.
Flattened APEX is a specially built APEX that can be activated on devices with a
legacy kernel. Files in a flattened APEX are directly installed to a directory
under the built-in partition. For example, `lib/libFoo.so` in a flattened APEX
my.apex is installed to `/system/apex/my.apex/lib/libFoo.so`.
Activating a flattened APEX doesn't involve the loop device. The entire
directory `/system/apex/my.apex` is directly bind-mounted to `/apex/name@ver`.
Flattened APEXs cant be updated by downloading updated versions of the APEXs
from network because the downloaded APEXs cant be flattened. Flattened APEXs
can be updated only via a regular OTA.
Note that flattened APEX is the default configuration for now (2019/Aug). This
means all APEXes are by default flattened unless you explicitly configure your
device to support updatable APEX (explained above).
Also note that, mixing flattened and non-flattened APEXes in a device is NOT
supported. It should be either all non-flattened or all flattened. This is
especially important when shipping pre-signed APEX prebuilts for the projects
like Mainline. APEXes that are not pre-signed (i.e. built from the source)
should also be non-flattened and signed with proper keys in that case. The
device should inherit from `updatable_apex.mk` as explained above.
## Building APEX without Soong
An APEX can be built without relying on the build commands generated by Soong.
1) Prepare following files:
- APEX manifest file (in JSON)
- AndroidManifest file (in XML, optional)
- AVB private key
- APK certificate (`*.x509.pem`)
- APK private key (`*.pk8`)
- `file_contexts` file
- files to be packaged into the APEX
2) Create `canned_fs_config` file
It is a file that specifies access bits and uid/gid of each file in the APEX.
```
/ 1000 1000 0755
/apex_manifest.json 1000 1000 0644
/apex_manifest.pb 1000 1000 0644
/file1 1000 1000 0644
/file2 1000 1000 0644
/dir 0 2000 0755
/dir/file3 1000 1000 0644
...
```
Note that ALL files AND directories must be specified. And dont forget to have
a line for `/`and `/apex_manifest.pb`. (`/apex_manifest.json` line is for
Q-targeting modules)
3) Invoke `apexer`
```
$ apexer \
--manifest <apex_manifest_file> \
--file_contexts <file_contexts_file> \
--canned_fs_config <canned_fs_config_file> \
--key <avb_private_key_file> \
--payload_type image \
--android_manifest <android_manifest_file> \
--override_apk_package_name com.google.foo \
<input_directory> \
<output_apex_file>
```
`--android_manifest` and -`-override_apk_package` are optional arguments and
thus can be omitted if not needed.
Note: The `<apex_manifest_file>` shouldnt be under `<input_directory>`.
4) Sign it
`apexer` signs the `apex_payload.img` file only. The entire apex (which is a zip
file) has to be signed with `Signapk`.
```
$ java \
-Djava.library.path=$(dirname out/soong/host/linux-x86/lib64/libconscrypt_openjdk_jni.so)\
-jar out/soong/host/linux-x86/framework/signapk.jar \
-a 4096 \
<apk_certificate_file> \
<apk_private_key_file> \
<unsigned_input_file> \
<signed_output_file>
```
This will sign the input file with the cert/privkey pairs to produce the output
file.
## Re-packaging an existing APEX
If an APEX has been build by passing `--include_build_info` to `apexer` (this is
the default when building via Soong), it will then include a file named
`apex_build_info.pb` which will store as much information as possible about how
the apex was built (see the `ApexBuildInfo` proto
[definition](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/proto/apex_build_info.proto)
for more info) with the exception of the signing keys.
We also provide a tool named `deapexer` to extract the payload content of an
APEX in a local directory.
By using these tools, you can then adapt the procedure described in the
[building the apex without Soong](#building-apex-without-soong) section and pass
the `--build_info apex_build_info.pb` file where `apex_build_info.pb` contains
all the build parameters that you would otherwise pass via flag to `apexer`.
We do this programmatically in some unit test code to generate "unusual" APEX
files, see for example
[here](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/apexer/apexer_test.py)
and
[here](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/tests/testdata/sharedlibs/build/shared_libs_repack.py).