Google is committed to advancing racial equity for Black communities. See how.
本頁面由 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 ,然後查找構建和運行時錯誤並解決。要檢查設備啟動和日誌並查找並修復運行時鏈接故障:

  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