This page presents several mechanisms that Android device OEMs can use to have their own shared system image (SSI) across product lines. It also proposes a procedure for basing an OEM-owned SSI on an AOSP-built generic system image (GSI).
Background
With Project Treble, monolithic Android was split into two parts: the hardware-specific part (the vendor implementation) and the generic OS part (the Android OS framework). The software for each is installed in a separate partition: the vendor partition for the hardware-specific software, and the system partition for the generic OS software. A versioned interface, called the vendor interface (VINTF), is defined and enforced across the two partitions. By using this partitioning system, you can modify the system partition without modifying the vendor partition, and vice versa.
Motivation
The framework code released in AOSP has been compliant with the Treble architecture and has maintained backward compatibility with older vendor implementations. For example, a generic system image built from Android 10 AOSP sources can run on any Treble-compliant device that’s running on Android 8 or higher. The version of Android that’s shipped on consumer devices is modified by SoC vendors and OEMs. (See Life of an Android Release.) These changes and extensions that were made to the framework weren't written for maintaining backward compatibility, which translated to increased complexity and higher cost in an OS upgrade. Device-specific changes and modifications add to the cost and complexity of upgrading an Android OS version.
Before Android 11 there was no clear architecture that enabled partners to build modular extensions to the Android OS framework. This document describes the steps that SoC vendors and OEMs can take to create an SSI. This means one image, built from the Android OS framework sources for reuse across multiple devices, for maintaining backward compatibility with vendor implementations, and for providing a significant reduction in the complexity and cost of Android OS upgrades. For the specific steps you need to create an SSI, see the Suggested steps for GSI-based SSI section, and note that you don't have to use all four steps. Which steps you choose (only Step 1, for example) depends on your implementation.
SSI overview
With SSI, product-specific software components and OEM extensions are placed in
a new /product
partition. The components in the /product
partition use a
well-defined, stable interface to interact with components in the /system
partition. OEMs can either choose to build one SSI, or to have a small number of
SSIs for use across multiple device SKUs. When a new version of the Android OS
is released, OEMs invest only once in updating their SSIs to the latest
Android release. They can reuse the SSIs to update multiple devices without
updating the /product
partition.
Note that OEMs and SoC vendors build SSIs that include all the custom features and modifications that an OEM needs. The mechanisms and best practices provided on this page are intended for OEMs to use to reach these key goals:
- Reuse the SSI across multiple device SKUs.
- Update the Android system with the modular extensions to make OS upgrades easier.
The core idea of separating product-specific components into the product partition is similar to the Treble idea of separating SoC-specific components into the vendor partition. A product interface (similar to VINTF) allows communication between SSI and the product partition. Note that with respect to SSI, the term “components” describes all the resources, binaries, texts, libraries, and so on that are installed to images, which essentially become partitions.
Partitions around SSI
Figure 1 shows partitions around SSI, and the versioned interfaces across the partitions and policies on the interfaces. This section explains each of the partitions and interfaces in detail.
Figure 1. Partitions and interfaces around SSI
Images and partitions
The information in this section distinguishes between the terms image and partition.
- An image is a conceptual piece of software that can be updated independently.
- A partition is a physical storage location that can be updated independently.
The sections in Figure 1 are defined as follows:
SSI: The SSI is the image that’s common to an OEM, and can exist across multiple devices. It doesn't have any hardware-specific or product-specific components. Everything in a given SSI is, by definition, shared among all devices using that SSI. The SSI is composed of either a single
/system
image, or a/system
and the/system_ext
partitions, as seen in Figure 1.The
/system
partition contains AOSP-based components, while/system_ext
, when implemented, contains OEM and SoC vendor extensions and components that are tightly coupled with AOSP components. For example, an OEM Java framework library that provides custom APIs for the OEM’s own apps fits better in the/system_ext
than in the/system
partition. Content for both the/system
and/system_ext
partitions is built from OEM-modified Android sources.The
/system_ext
partition is optional, but it’s beneficial to use it for any custom features and extensions that are tightly coupled with AOSP- based components. This distinction helps you identify changes you need to make, to move such components from the/system_ext
partition to the/product
partition over a period of time.
Product: A collection of product- or device-specific components that represent OEM customizations and extensions to the Android OS. Put SoC-specific components in the
/vendor
partition. SoC vendors can also use the/product
partition for appropriate components, such as SoC-independent ones. For example, if an SoC vendor provides an SoC-independent component to their OEM customers (that’s optional to ship with the product), the SoC vendor can place that component in the product image. The location of a component isn’t determined by its ownership, it’s dictated by its purpose.Vendor: A collection of SoC-specific components.
ODM: A collection of board-specific components that aren’t provided by the SoC. Typically the SoC vendor owns the vendor image, while the device maker owns the ODM image. When there is no separate
/odm
partition, both the SoC vendor and ODM images are merged together in the/vendor
partition.
Interfaces between images
Two main interfaces for vendor and product images exist around SSI:
Vendor Interface (VINTF): VINTF is the interface to the components that reside in the vendor and the ODM images. Components in the product and system images can only interact with the vendor and ODM images through this interface. For example, a vendor image can’t depend on a private part of the system image, and vice versa. This is originally defined in Project Treble, which split the images into system and vendor partitions. The interface is described using the following mechanisms:
- HIDL (Passthrough HAL is only available for
system
andsystem_ext
modules) - Stable AIDL
- Configurations
- System properties API
- Config file schema API
- VNDK
- Android SDK APIs
- Java SDK library
- HIDL (Passthrough HAL is only available for
Product interfaces: The product interface is the interface between SSI and the product image. Defining a stable interface decouples the product components from the system components in an SSI. The product Interface requires the same stable interfaces as VINTF. However, only the VNDK and Android SDK APIs are enforced for devices launching with Android 11 (and higher).
Enable SSI in Android 11
This section explains how to use the new features in place to support SSI in Android 11.
The /system_ext partition
The /system_ext
partition was introduced in Android 11 as an optional
partition. (It’s the place for non-AOSP components that have tight coupling with
the AOSP-defined components in the /system
partition.) The /system_ext
partition is assumed to be the OEM-specific extension to the /system
partition, without an interface defined across the two partitions. Components in
the /system_ext
partition can make private API calls into the /system
partition, and components in the /system
partition can make private API calls
into the /system_ext
partition.
Because the two partitions are tightly coupled, both partitions are upgraded
together when a new Android version is released. A /system_ext
partition
created for the previous release of Android doesn’t need to be compatible with
the /system
partition in the next Android release.
To install a module to the /system_ext
partition, add system_ext_specific:
true
to the Android.bp
file. For devices that don't have a /system_ext
partition, install such modules to the ./system_ext
subdirectory in the
/system
partition.
History
Here is some history about the /system_ext
partition. The design goal was to
place all OEM-specific components, regardless of whether they're common, in the
/product
partition. However, moving them all at once wasn’t feasible,
especially when some components had a tight coupling with the /system
partition. To move a tightly coupled component to the /product
partition, the
product interface must be extended. This often required the component itself to
be extensively refactored, which consumes a lot of time and effort. The
/system_ext
partition started as a place to temporarily host those components
that aren’t ready to be moved to the /product
partition. The goal of the SSI
was to eventually eliminate the /system_ext
partition.
However, the /system_ext
partition is useful for keeping the /system
partition as close to AOSP as possible. With SSI, most of the upgrade effort is
spent on the components in the /system
and the /system_ext
partitions.
When the system image is built from sources that are as similar as possible to
those in AOSP, you can focus the upgrade effort on the system_ext
image.
Unbundle components from /system and /system_ext partitions into the /product partition
Android 9 introduced a /product
partition
that’s coupled with the /system
partition. The modules in the
/product
partition use the system resources without any restriction, and vice
versa. To make SSI possible in Android 10, the product components are split into
the /system_ext
and /product
partitions. The /system_ext
partition doesn’t
have to adhere to the restrictions on using system components that the
/product
partition did in Android 9. Starting in Android 10, the /product
partition must be unbundled from the /system
partition and must use stable
interfaces from the /system
and /system_ext
partitions.
The /system_ext
partition's primary purpose is to extend system features,
rather than to install bundled product modules, as described in the
/system_ext partition
section. To do this, unbundle
the product-specific modules and move them into the /product
partition.
Unbundling the product-specific modules makes /system_ext
common to the
devices. (For more detail, see Making the /system_ext partition common.)
To unbundle the /product
partition from the system components, the /product
partition must have the same enforcement policy as the /vendor
partition that
was already unbundled with Project Treble.
Starting in Android 11, native and Java interfaces for the /product
partition
are enforced as described below. For more information, see
Enforcing Product Partition Interfaces.
- Native interfaces: The native modules in the
/product
partition must be unbundled from the other partitions. The only allowed dependencies from the product modules are some VNDK libraries (including LLNDK) from the/system
partition. JNI libraries that the product apps depend on must be NDK libraries. - Java interfaces: The Java (app) modules in the
/product
partition can’t use hidden APIs, because they're unstable. These modules must only use public APIs and system APIs from the/system
partition, and Java SDK libraries in the/system
or/system_ext
partition. You can define Java SDK libraries for custom APIs.
Suggested steps for GSI-based SSI
Figure 2. Suggested partitions for GSI-based SSI
A generic system image (GSI) is the system image that’s built directly from AOSP. It’s used for the Treble compliance tests (for example, CTS-on-GSI) and as a reference platform that app developers can use to test the compatibility of their apps when they don’t have a real device running the required version of Android.
OEMs can also use GSI to make their SSI. As explained in Images and
partitions,
SSI consists of the system image for the AOSP-defined components
and the system_ext
image for the OEM-defined components. When GSI is used as
the system
image, the OEM can focus on the system_ext
image for the upgrade.
This section provides a guide to OEMs who want to modularize their
customizations into the /system_ext
and /product
partitions while using an
AOSP or near-AOSP system image. If OEMs build the system image from AOSP
sources, then they can substitute the system image that they build with the GSI
provided by AOSP. However, OEMs don’t need to reach the final step (using GSI as
it is) all at once.
Step 1. Inherit generic_system.mk for OEM’s system image (OEM GSI)
By inheriting
generic_system.mk
(which was named mainline_system.mk
in Android 11, and renamed to
generic_system.mk
in
AOSP), the system image (OEM GSI) includes all the files that the AOSP GSI has.
These files can be modified by OEMs, so that the OEM GSI can contain the OEM
proprietary files in addition to the AOSP GSI files. However, OEMs aren't
allowed to modify the generic_system.mk
file itself.
Figure 3. Inheriting generic_system.mk for OEM’s system image
Step 2. Make the OEM GSI have the same list of files with the AOSP GSI
The OEM GSI can’t have additional files at this stage. The OEM’s proprietary
files must be moved out to the system_ext
or product
partitions.
Figure 4. Moving added files out of the OEM GSI
Step 3. Define an allowlist to limit the modified files in the OEM GSI
To check the modified files, OEMs can use the
compare_images
tool, and compare the AOSP GSI with the OEM GSI. Obtain the AOSP GSI from the
AOSP lunch target generic_system_*
.
By running the compare_images
tool periodically with the allowlist
parameter, you can monitor the differences outside the allowed list. This prevents
needing additional modifications to the OEM GSI.
Figure 5. Define an allowlist to reduce the modified files list in the OEM GSI
Step 4. Make the OEM GSI have the same binaries as the AOSP GSI
Cleaning up the allowlist allows OEMs to use the AOSP GSI as the system image for their own products. To clean up the allowlist, OEMs can either abandon their changes in the OEM GSI, or upstream their changes to AOSP so that the AOSP GSI includes their changes.
Figure 6. Making the OEM GSI have the same binaries as the AOSP GSI
Define SSI for OEMs
Protect the /system partition at build time
To avoid any product-specific changes in the /system
partition and define the
OEM GSI, OEMs can use a makefile macro called
require-artifacts-in-path
to prevent any declaration of system modules after the macro is called. See
the Create makefile and enable artifact path check
example.
OEMs can define a list to allow product-specific modules to be installed in the
/system
partition temporarily. However, the list must be empty to make the OEM
GSI common to all of the OEM’s products. This process is for defining the OEM
GSI and can be independent from the steps for the AOSP
GSI.
Enforce product interfaces
To guarantee that the /product
partition is unbundled, OEMs can ensure their
devices enforce the product interfaces by setting
PRODUCT_PRODUCT_VNDK_VERSION:= current
for native modules, and PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE:= true
for Java modules. These variables are automatically set if the
PRODUCT_SHIPPING_API_LEVEL
of the device is greater than or equal to 30
. For
detailed information, see Enforcing Product Partition
Interfaces.
Make the /system_ext partition common
The /system_ext
partition might differ between devices, because it can have
device-specific, system-bundled modules. Because the SSI consists of /system
and /system_ext
partitions, the differences in the /system_ext
partition
hinder OEMs from defining an SSI. OEMs can have their own SSI and can share that
SSI among multiple devices by removing any differences and making the
/system_ext
partition common.
This section gives recommendations for making the /system_ext
partition common.
Expose hidden APIs in the system partition
Many product-specific apps can’t be installed in the product partition because they use hidden APIs, which are prohibited in the product partition. To move device-specific apps to the product partition, remove the use of hidden APIs.
The preferred way to remove hidden APIs from the apps is to find the alternative public or system APIs to replace them. If there are no APIs to replace the hidden APIs, OEMs can contribute to AOSP to define the new system APIs for their devices.
Alternatively, OEMs can define custom APIs by creating their own Java SDK
library
in the /system_ext
partition. It can use hidden APIs in the system partition,
and can provide the APIs to the apps in the product or vendor partition.
OEMs must freeze the product-facing
APIs
for backward compatibility.
Include the superset of all APKs and skip some packages installs for each device
Certain packages that are bundled with the system aren’t common across devices.
Unbundling these APK modules to move them to the product or the vendor partition
can be difficult. As an interim solution, OEMs can make the SSI include all the
modules, then filter unwanted ones out by using a SKU property
(ro.boot.hardware.sku
). To use the filter, OEMs overlay the framework
resources config_disableApkUnlessMatchedSku_skus_list
and
config_disableApksUnlessMatchedSku_apk_list
.
For more precise settings, declare a broadcast receiver that disables
unnecessary packages. The broadcast receiver calls
setApplicationEnabledSetting
to disable the package when it receives the
ACTION_BOOT_COMPLETED
message.
Define RRO instead of using static resource overlay
A static resource overlay manipulates the overlaid packages. However, it can impede defining an SSI, so ensure that properties for RRO are turned on and set properly. By setting the properties as follows, OEMs can have all auto-generated overlays as RROs.
PRODUCT_ENFORCE_RRO_TARGETS := *
PRODUCT_ENFORCE_RRO_EXCLUDED_OVERLAYS := # leave it empty
If a detailed configuration is required, define an RRO manually instead of
relying on an auto-generated one. For detailed information, see Runtime
Resource Overlays (RROs).
OEMs also can define conditional RROs that depend on the system properties by
using the android:requiredSystemPropertyName
and
android:requiredSystemPropertyValue
attributes.
Frequently asked questions (FAQ)
Can I define multiple SSIs?
It depends on the commonality and characteristics of devices (or device group).
OEMs can try to make the system_ext
partition common, as described in
Making the system_ext partition common. If a device
group has many differences, then it’s better to define multiple SSIs.
Can I modify generic_system.mk (mainline_system.mk) for an OEM GSI?
No. But OEMs can define a new makefile for an OEM GSI that inherits the
generic_system.mk
file and use the new makefile instead. For an example, see
Enforcing Product Partition
Interfaces.
Can I remove modules from generic_system.mk that conflict with my implementation?
No. GSI has a minimum set of bootable and testable modules. If you think a
module isn't essential, please file a bug to update the generic_system.mk
file
in AOSP.