Android 11 unbundles the product
partition, making it independent of the system
and vendor
partitions. As part of these changes, you can now control the product
partition's access to native and Java interfaces (which is similar to how interface enforcement works for vendor
partitions).
Enforce native interfaces
To enable the native interface enforcement, set PRODUCT_PRODUCT_VNDK_VERSION
to current
. (The version is automatically set to current
when the shipping API level for the target is greater than 29.) Enforcement allows:
- Native modules in the
product
partition to link:- Statically or dynamically to other modules in the
product
partition that include static, shared, or header libraries. - Dynamically to VNDK libraries in the
system
partition.
- Statically or dynamically to other modules in the
- JNI libraries in unbundled APKs in the
product
partition to link to libraries in/product/lib
or/product/lib64
(this is in addition to the NDK libraries).
Enforcement doesn't allow other links to partitions other than the product
partition.
Build time enforcement (Android.bp)
In Android 11, system modules can create a product image variant in addition to core and vendor image variants. When native interface enforcement is enabled (PRODUCT_PRODUCT_VNDK_VERSION
is set to current
):
Native modules in the
product
partition are in the product variant instead of the core variant.Modules with
product_available: true
in theirAndroid.bp
files are available to the product variant.Libraries or binaries that specify
product_specific: true
can link to other libraries that specifyproduct_specific: true
orproduct_available: true
in theirAndroid.bp
files.VNDK libraries must have
product_available: true
in theirAndroid.bp
files soproduct
binaries can link to VNDK libs.
The following table summarizes the Android.bp
properties used to create image variants.
Properties in Android.bp | Variants created | |
---|---|---|
Before enforcement | After enforcement | |
default (none) | core (includes /system , /system_ext and /product ) | core (includes /system and /system_ext but not /product ) |
system_ext_specific: true | core | core |
product_specific: true | core | product |
vendor: true | vendor | vendor |
vendor_available: true | core, vendor | core, vendor |
product_available: true | N/A | core, product |
vendor_available: true AND product_available: true | N/A | core, product, vendor |
system_ext_specific: true AND vendor_available: true | core, vendor | core, vendor |
product_specific: true AND vendor_available: true | core, vendor | product, vendor |
Build time enforcement (Android.mk)
When native interface enforcement is enabled, native modules installed to the product
partition have a native:product
link type that can link only to other native:product
or native:vndk
modules. Attempting to link to any modules other than these causes the build system to generate a link type check error.
Runtime enforcement
When native interface enforcement is enabled, the linker configuration for the bionic linker doesn't allow system processes to use product
libraries, creating a product
section for the product
processes that can't link to libraries outside the product
partition (however, such processes can link to VNDK libraries). Attempts to violate the runtime link configuration cause the process to fail and generate a CANNOT LINK EXECUTABLE
error message.
Enforce Java interfaces
To enable the Java interface enforcement, set PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
to true
. (The value is automatically set to true
when the shipping API level for the target is greater than 29.) When enabled, enforcement allows or disallows the following access:
API | /system | /system_ext | /product | /vendor | /data |
---|---|---|---|---|---|
Public API | |||||
@SystemApi | |||||
@hide API |
As in the vendor
partition, an app or a Java library in the product
partition is allowed to use only public and system APIs; linking to a library that uses hidden APIs isn't allowed. This restriction includes linking at build time and reflection in runtime.
Build time enforcement
At build time, Make and Soong verify that Java modules in the product
partition don't use hidden APIs by checking the platform_apis
and sdk_version
fields. The sdk_version
of apps in the product
partition must be filled with current
, system_current
, or numeric version of the API, and the platform_apis
field must be empty.
Runtime enforcement
The Android runtime verifies that apps in the product
partition don't use hidden APIs, including reflection. For details, refer to Restrictions on non-SDK interfaces.
Enable product interface enforcement
Use the steps in this section to enable product interface enforcement.
Step | Task | Required |
---|---|---|
1 | Define your own system makefile that specifies the packages for the system partition, then set the artifacts path requirement check in the device.mk (to prevent nonsystem modules from installing to the system partition). | N |
2 | Clean up the allowed list. | N |
3 | Enforce native interfaces and identify runtime link failures (can run in parallel with Java enforcement). | Y |
4 | Enforce Java interfaces and verify runtime behavior (can run in parallel with native enforcement). | Y |
5 | Check runtime behaviors. | Y |
6 | Update device.mk with product interface enforcement. | Y |
Step 1: Create makefile and enable artifact path check
In this step, you define the system
makefile.
Create a makefile that defines the packages for the
system
partition. For example, create anoem_system.mk
file with the following:$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk) $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk) # Applications PRODUCT_PACKAGES += \ CommonSystemApp1 \ CommonSystemApp2 \ CommonSystemApp3 \ # Binaries PRODUCT_PACKAGES += \ CommonSystemBin1 \ CommonSystemBin2 \ CommonSystemBin3 \ # Libraries PRODUCT_PACKAGES += \ CommonSystemLib1 \ CommonSystemLib2 \ CommonSystemLib3 \ PRODUCT_SYSTEM_NAME := oem_system PRODUCT_SYSTEM_BRAND := Android PRODUCT_SYSTEM_MANUFACTURER := Android PRODUCT_SYSTEM_MODEL := oem_system PRODUCT_SYSTEM_DEVICE := generic # For system-as-root devices, system.img should be mounted at /, so we # include ROOT here. _my_paths := \ $(TARGET_COPY_OUT_ROOT)/ \ $(TARGET_COPY_OUT_SYSTEM)/ \ $(call require-artifacts-in-path, $(_my_paths),)
In the
device.mk
file, inherit the common makefile for thesystem
partition and enable the artifact path requirements check. For example:$(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk) # Enable artifact path requirements checking PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
About the artifact path requirements
When PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
is set to true
or strict
, the build system prevents packages defined in other makefiles from installing to the paths defined in require-artifacts-in-path
and prevents packages defined in the current makefile from installing artifacts outside the paths defined in require-artifacts-in-path
.
In the example above, with PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
set to strict
, makefiles outside oem_system.mk
can't include modules installed to the root
or system
partition. To include these modules, you must either define them in the oem_system.mk
file itself or in an included makefile. Attempts to install modules to disallowed paths cause build breaks. To fix breaks, do one of the following:
Option 1: Include the system module in the makefiles included in
oem_system.mk
. This makes it so the artifact path requirement is met (as the modules now exist in an included makefile) and thus allows installation to the set of paths in `require-artifacts-in-path.Option 2: Install modules to the
system_ext
orproduct
partition (and don't install modules to thesystem
partition).Option 3: Add modules to the
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
. This lists allowed modules to be installed.
Step 2: Empty the allowed list
In this step, you make the PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
empty so all devices sharing oem_system.mk
can also share a single system
image. To empty the allowed list, move any modules in the list to the system_ext
or product
partition or add them to system
make files. This step is optional because defining a common system
image isn't required to enable product interface enforcement. However, emptying the allowed list is helpful for defining the system
boundary with system_ext
.
Step 3: Enforce native interfaces
In this step, you set PRODUCT_PRODUCT_VNDK_VERSION := current
, then look for build and runtime errors and resolve them. To check the device boot and logs and find and fix runtime link failures:
Set
PRODUCT_PRODUCT_VNDK_VERSION := current
.Build the device and look for build errors. You're likely to see a few build breaks for missing product variants or core variants. Common breaks include:
- Any
hidl_interface
module that hasproduct_specific: true
won't be available for system modules. To fix, replaceproduct_specific: true
withsystem_ext_specific: true
. - Modules might be missing the product variant required for product modules. To fix, make that module available to the
product
partition by settingproduct_available: true
or move the module to theproduct
partition by settingproduct_specific: true
.
- Any
Resolve build errors and ensure that the device builds successfully.
Flash the image and look for runtime errors in the device boot and logs.
- If the
linker
tag from a test case log shows aCANNOT LINK EXECUTABLE
message, the make file is missing a dependency (and wasn't captured at build time). - To check it from the build system, add the required library to the
shared_libs:
orrequired:
field.
- If the
Resolve the missing dependencies using the guidance given above.
Step 4: Enforce Java interfaces
In this step, you set PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
, then find and fix resultant build errors. Look for two specific types of errors:
Link type errors. This error indicates that an app links to Java modules that have a broader
sdk_version
. To fix, you can broaden the app'ssdk_version
or restrict the library'ssdk_version
. Example error:error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
Symbol errors. This error indicates that a symbol can't be found because it's in a hidden API. To fix, use a visible (non-hidden) API or find an alternative. Example error:
frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( ^ symbol: class ProxyAuthenticate location: class SipSessionGroup.SipSessionImpl
Step 5: Check runtime behaviors
In this step, you verify runtime behaviors are as expected. For apps that are debuggable, you can monitor hidden API usage by log using StrictMode.detectNonSdkApiUsage
(which generates a log when the app uses a hidden API). Alternatively, you can use the veridex static analysis tool to get the type of usage (linking or reflection), restriction level, and call stack.
Veridex syntax:
./art/tools/veridex/appcompat.sh --dex-file={apk file}
Example veridex result:
#1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s): Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s): Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
For details on veridex usage, refer to Test using the veridex tool.
Step 6: Update device.mk
After fixing all build and runtime failures, and verifying that runtime behaviors are as expected, set the following in device.mk
:
PRODUCT_PRODUCT_VNDK_VERSION := current
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true