Google 致力于为黑人社区推动种族平等。查看具体举措
此页面由 Cloud Translation API 翻译。
Switch to English

实施产品分区接口

Android 11取消捆绑product分区,使其独立于system分区和vendor分区。作为这些更改的一部分,您现在可以控制product分区对本机和Java接口的访问(这类似于对vendor分区实施接口实施的方式)。

实施本机接口

要启用本机接口强制实施,请将PRODUCT_PRODUCT_VNDK_VERSION设置为current 。 (当目标的发布API级别大于29时,该版本会自动设置为current版本。)强制执行允许:

  • product分区中要链接的本机模块:
    • product分区中包含静态,共享或标头库的其他模块,以静态或动态方式进行。
    • 动态到system分区中的VNDK库。
  • product分区中非捆绑式APK中的JNI库可链接到/product/lib/product/lib64 (这是NDK库的补充)。

强制执行不允许除product分区以外的其他链接指向其他分区。

建立时间执行(Android.bp)

在Android 11中,除了核心和供应商映像变体之外,系统模块还可以创建产品映像变体。启用本机界面强制( PRODUCT_PRODUCT_VNDK_VERSION设置为current )时:

  • product分区中的本机模块位于产品变型中,而不是核心变型中。

  • Android.bp文件中具有vendor_available: true模块可用于产品变体和供应商变体。

  • 指定product_specific: true库或二进制文件可以链接到其他在其Android.bp文件中指定product_specific: truevendor_available: true库。

  • VNDK库在其Android.bp文件中必须具有vendor_available: true ,以便product二进制文件可以链接到VNDK库。

下表总结了用于创建图像变体的Android.bp属性。

Android.bp中的属性创建的变体
执法前执行后
默认(无)核心

(包括/system/system_ext/product

核心

(包括/system/system_ext但不包括/product

system_ext_specific: true核心核心
product_specific: true核心产品
vendor: true供应商供应商
vendor_available: true核心,供应商核心,产品,供应商
system_ext_specific: truevendor_available: true核心,供应商核心,产品,供应商
product_specific: truevendor_available: true核心,供应商产品,供应商

建立时间执行(Android.mk)

启用本机接口强制后,安装到product分区的native:product机模块具有native:product链接类型,该链接类型只能链接到其他native:productnative:vndk模块。尝试链接到除这些模块之外的任何模块都会导致生成系统生成链接类型检查错误。

运行时执行

当启用本机接口的执行,用于仿生接头接头配置不允许系统进程使用product库,创建product的部分product不能外部链接到的库过程product分区(然而,这样的过程可以链接到VNDK库)。尝试违反运行时链接配置会导致该过程失败并生成CANNOT LINK EXECUTABLE错误消息。

实施Java接口

要启用Java接口强制实施,请将PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE设置为true 。 (当目标的发布API级别大于29时,该值将自动设置为true 。)启用后,强制实施将允许/禁止以下访问。

API /系统/ system_ext /产品/供应商/数据
公开API
@SystemApi
@hide API

vendor分区中一样, product分区中的应用程序或Java库仅允许使用公共和系统API。不允许链接到使用隐藏API的库。此限制包括在构建时链接和在运行时反射。

建立时间执行

在构建时,Make和Soong通过检查platform_apissdk_version字段来验证product分区中的Java模块未使用隐藏的API。 product分区中应用程序的sdk_version必须用API的currentsystem_current或数字版本填充,并且platform_apis字段必须为空。

运行时执行

Android运行时会验证product分区中的应用程序没有使用隐藏的API,包括反射。有关详细信息,请参阅非SDK接口的限制

启用产品界面实施

使用本节中的步骤启用产品界面强制实施。

任务需要
1个定义您自己的系统makefile,该文件指定system分区的软件包,然后在device.mk设置工件路径需求检查(以防止非系统模块安装到system分区)。 ñ
2清理允许的列表。 ñ
3强制本机接口并识别运行时链接故障(可以与Java强制并行运行)。 ÿ
4强制执行Java接口并验证运行时行为(可以与本机强制执行并行运行)。 ÿ
5检查运行时行为。 ÿ
6通过产品界面强制更新device.mk ÿ

步骤1:创建makefile并启用工件路径检查

在此步骤中,您将定义system makefile。

  1. 创建一个makefile,该文件定义system分区的软件包。例如,使用以下命令创建oem_system.mk文件:

    $(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),)
    
  2. device.mk文件中,继承system分区的通用makefile并启用工件路径需求检查。例如:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

关于工件路径要求

PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS设置为truestrict ,构建系统将阻止将其他makefile中定义的软件包安装到require-artifacts-in-path定义require-artifacts-in-path防止当前makefile中定义的软件包将require-artifacts-in-path定义的路径之外的工件安装到- require-artifacts-in-path

在上面的示例中,将PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS设置为strictoem_system.mk之外的makefile不能包含安装到root分区或system分区的模块。要包括这些模块,您必须在oem_system.mk文件本身中或在包含的makefile中定义它们。尝试将模块安装到不允许的路径会导致构建中断。要修复中断,请执行以下任一操作:

  • 选项1:将系统模块包含在oem_system.mk包含的makefile中。这样就可以满足工件路径的要求(因为模块现在包含在包含的makefile中),因此可以安装到“ require-artifacts-in-path”中的路径集。

  • 选项2:将模块安装到system_extproduct分区(不要将模块安装到system分区)。

  • 选项3:将模块添加到PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST 。这列出了允许安装的模块。

步骤2:清空允许的列表

在此步骤中,您将PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST空,以便所有共享oem_system.mk设备也可以共享一个system映像。要清空允许的列表,请将列表中的所有模块移至system_extproduct分区,或将其添加到system制造文件中。此步骤是可选的,因为无需启用通用system映像即可启用产品接口。但是,清空允许列表有助于使用system_ext定义system边界。

步骤3:强制执行本机界面

在此步骤中,您将PRODUCT_PRODUCT_VNDK_VERSION := current设置为PRODUCT_PRODUCT_VNDK_VERSION := current ,然后查找构建和运行时错误并解决它们。要检查设备启动和日志并查找并修复运行时链接故障:

  1. 设置PRODUCT_PRODUCT_VNDK_VERSION := current

  2. 编译设备并查找编译错误。您可能会因缺少产品变体或核心变体而遇到一些构建中断。常见的休息时间包括:

    • 任何具有product_specific: true hidl_interface模块将不适用于系统模块。要修复,请将product_specific: true替换为system_ext_specfic: true
    • 模块可能缺少产品模块所需的产品变型。要进行修复,请通过设置vendor_available: true使该模块可用于product分区,或者通过设置product_specific: true将模块移至product分区。
  3. 解决构建错误,并确保设备成功构建。

  4. 刷新映像,并在设备启动和日志中查找运行时错误。

    • 如果测试用例日志中的linker标记显示CANNOT LINK EXECUTABLE消息,则说明make文件缺少依赖项(并且在构建时未捕获)。
    • 要从构建系统检查它,请将所需的库添加到shared_libs:required:字段。
  5. 使用上面给出的指南解决缺少的依赖关系。

步骤4:实施Java接口

在此步骤中,您设置PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true ,然后查找并修复生成的构建错误。查找两种特定类型的错误:

  • 链接类型错误。此错误表明一个应用程序链接到sdk_version较宽的Java模块。要解决此问题,您可以扩大应用程序的sdk_version或限制库的sdk_version 。错误示例:

    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.
    
  • 符号错误。此错误表明找不到符号,因为它在隐藏的API中。要解决此问题,请使用可见的(非隐藏)API或查找替代方法。错误示例:

    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
    

步骤5:检查运行时行为

在此步骤中,验证运行时行为是否符合预期。对于可调试的应用程序,您可以使用StrictMode.detectNonSdkApiUsage (在应用程序使用隐藏的API时生成日志)通过日志监视隐藏的API使用情况。另外,您可以使用veridex静态分析工具获取用法类型(链接或反射),限制级别和调用堆栈。

  • Veridex语法:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
    
  • veridex结果示例:

    #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;
    

有关veridex使用的详细信息,请参阅使用veridex工具进行测试

步骤6:更新device.mk

修复所有构建和运行时故障之后,并验证运行时行为是否符合预期,请在device.mk设置以下内容:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true