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