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
productpartition to link:- Statically or dynamically to other modules in the
productpartition that include static, shared, or header libraries. - Dynamically to VNDK libraries in the
systempartition.
- Statically or dynamically to other modules in the
- JNI libraries in unbundled APKs in the
productpartition to link to libraries in/product/libor/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
productpartition are in the product variant instead of the core variant.Modules with
product_available: truein theirAndroid.bpfiles are available to the product variant.Libraries or binaries that specify
product_specific: truecan link to other libraries that specifyproduct_specific: trueorproduct_available: truein theirAndroid.bpfiles.VNDK libraries must have
product_available: truein theirAndroid.bpfiles soproductbinaries 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
systempartition. For example, create anoem_system.mkfile 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.mkfile, inherit the common makefile for thesystempartition 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_extorproductpartition (and don't install modules to thesystempartition).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_interfacemodule that hasproduct_specific: truewon't be available for system modules. To fix, replaceproduct_specific: truewithsystem_ext_specific: true. - Modules might be missing the product variant required for product
modules. To fix, make that module available to the
productpartition by settingproduct_available: trueor move the module to theproductpartition 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
linkertag from a test case log shows aCANNOT LINK EXECUTABLEmessage, 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_versionor 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 := currentPRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true