Android shared system image

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.

Partitions and interfaces around SSI block diagram

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 and system_ext modules)
    • Stable AIDL
    • Configurations
      • System properties API
      • Config file schema API
    • VNDK
    • Android SDK APIs
    • Java SDK library
  • 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 /systempartition 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: trueto 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

Suggested partitions 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.

Inheriting `generic_system.mk` for OEM system image

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.

Moving added files out of the OEM GSI

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.

Define an allowlist to reduce the list of modified files in 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.

Make OEM GSI have the same binaries as AOSP GSI

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.