Shared system image

This page presents several mechanisms that Android OEMs can use to have a 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

The Android Open Source Project (AOSP) framework complies with Mainline architecture to maintain backward compatibility with older vendor implementations. For example, a Generic System Image (GSI) built from Android 10 AOSP sources can run on any Treble-compliant device running Android 8 or higher.

Mainline achieves this by splitting Android into two distinct parts: the hardware-specific vendor implementation and the generic Android OS framework. Each component is installed in a separate partition—the vendor partition for hardware-specific software and the system partition for the generic OS. A versioned interface, called the vendor interface (VINTF), is enforced between them. This partitioning system lets OEMs modify the system partition without touching the vendor partition, and the other way around.

Historically, SoC vendors and OEMs heavily modified the Android framework version shipped on consumer devices (for details, see Life of an Android Release). Because these framework extensions were rarely designed with backward compatibility in mind, device-specific modifications dramatically increased the complexity and financial cost of subsequent OS upgrades. In Android 10 (API level 29) and lower, the ecosystem lacked a clear, standardized architecture that lets partners build modular extensions to the Android framework.

This page outlines how SoC vendors and OEMs can build a shared system image (SSI). An SSI is a unified framework image built from Android OS sources that can be reused across multiple devices. By maintaining clean backward compatibility with vendor implementations through this partitioned architecture, an SSI significantly lowers the cost and complexity of Android OS upgrades.

For implementation details, see Suggested steps for GSI-based SSI. The steps are modular; depending on your architecture, you can choose to implement specific stages (such as Step 1: Inherit generic_system.mk for OEM system image (OEM GSI)) rather than all stages.

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.

OEMs and SoC vendors can build SSIs that include custom features and modifications. 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 more straightforward.

The core idea of separating product-specific components into the product partition is similar to Mainline separating SoC-specific components into the vendor partition. A product interface (similar to VINTF) allows communication between SSI and the product partition. With respect to SSI, the term components describes all the resources, binaries, texts, and libraries that are installed to images, which 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: An image that's common to an OEM, and which 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.

  • Product image: 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 is determined by its purpose and not its ownership.

  • Vendor image: A collection of SoC-specific components.

  • ODM image: 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.

The /system_ext partition

The /system_ext partition is optional. Use this partition for any custom features and extensions that are tightly coupled with AOSP-based components. This 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. On devices that don't have a /system_ext partition, install such modules to the ./system_ext subdirectory in the /system partition.

History: The original design goal of the /system_ext partition 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.

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 the other way around. This is defined in the Treble architecture (now part of the broader Mainline architecture), which splits the images into system and vendor partitions. The interface is described using the following mechanisms:

    • HIDL (Passthrough HAL is available only 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.

Enable SSI

This section explains how to support SSI in Android 11 and higher.

Unbundle components

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 Mainline.

  • Built-in interfaces: The built-in 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 use only 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.

Enforce product interfaces

To make sure that the /product partition is unbundled, OEMs can have their devices enforce the product interfaces by setting PRODUCT_PRODUCT_VNDK_VERSION:= current for built-in 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 Enforce product partition interfaces.

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 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 guidance 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 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.

Inheriting `generic_system.mk` for OEM system image

Figure 3. Inherit 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, so move OEM-proprietary files to the system_ext or product partitions.

Moving added files out of the OEM GSI

Figure 4. Move 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 additional modifications to the OEM GSI.

Define an allowlist to reduce the list of modified files in OEM GSI

Figure 5. Define 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. Make the OEM GSI have the same binaries as the AOSP GSI.

Define SSI

OEMs can use the following guidance to define their SSI.

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 example in Step 1: Create makefile and enable artifact path check.

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.

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. This library 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.

Replace SKU-specific app disabling

Android 16 deprecated and removed the legacy mechanism for selectively disabling APKs based on hardware SKU using framework resource overlays (config_disableApksUnlessMatchedSku_apk_list and config_disableApkUnlessMatchedSku_skus_list). For details, see aosp/3444399.

The recommended replacement is to use the install-in-user-type system configuration within SKU-specific directories. This approach prevents the package from being installed for any user on a specific SKU, rather than just disabling it post-installation.

  1. Include all APKs (the superset of all potential apps for all SKUs in your system image) in the image, typically in the /product partition.

  2. Ensure the device SKU is set correctly in the ro.boot.hardware.sku system property (used by the system to identify the device SKU at boot time).

  3. Create SKU-specific sysconfig subdirectories under /product/etc/sysconfig/ using the naming convention sku_<SKU_NAME>. The system automatically loads configurations from the directory that matches the ro.boot.hardware.sku property. Example path: /product/etc/sysconfig/sku_basic_model/.

  4. Configure app installation prevention. Inside the SKU-specific directory, create an XML configuration file (for example, disabled_apps.xml) and use the <do-not-install-in> tag to exclude specific packages.

XML example (/product/etc/sysconfig/sku_basic_model/disabled_apps.xml):

<?xml version="1.0" encoding="utf-8"?>
<config>
    <!-- Prevents this package from being installed for ANY user on this SKU -->
    <install-in-user-type package="com.example.premium.feature.app" >
        <do-not-install-in user-type="FULL" />
        <do-not-install-in user-type="SYSTEM" />
    </install-in-user-type>
</config>

Here's a comparison of the two methods:

Feature Android 15 and lower Android 16 and higher
Configuration method Framework resource overlays SystemConfig XML files
Logic location config.xml (resource overlay) /product/etc/sysconfig/sku_<name>/
Outcome Disables app using PackageManager Prevents app installation for the user
Robustness Can be re-enabled by system services Package is never installed for the user

For cases requiring more granular control (that is, disabling an app that is normally installed by default across all SKUs), Android also supports disabled-in-sku and enabled-in-sku-override tags in sysconfig:

  • <disabled-in-sku package="com.example.app" /> disables the app globally.

  • <enabled-in-sku-override package="com.example.app" /> re-enables the app for a specific SKU when placed in the corresponding sku_<name> directory.

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 Change the value of an app's resources at runtime. 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)

The following are frequently asked questions about SSI.

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 Make the system_ext partition common. If a device group has many differences, then it's better to define multiple SSIs.

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, file a bug to update the generic_system.mk file.