強制執行產品分區介面

Android 11 將 product 分區取消組合,使其遭到捨棄 不受 systemvendor 分區影響本次異動中 您現在可以控管 product 分區對原生和 Java 的存取權 介面 (與 vendor 強制執行介面的方式類似) 分區)。

強制執行原生介面

如要啟用原生介面的強制執行功能,請設定 PRODUCT_PRODUCT_VNDK_VERSIONcurrent。(版本在運送時會自動設為 current 目標的 API 級別大於 29)。強制執行的好處如下:

  • 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 檔案中有 product_available: true 的模組為 可用的產品子類

  • 指定 product_specific: true 的程式庫或二進位檔可連結至其他 指定 product_specific: trueproduct_available: true 的程式庫 該檔案位於其 Android.bp 檔案中。

  • VNDK 程式庫的 Android.bp 檔案中必須包含 product_available: true 因此 product 二進位檔可以連結至 VNDK 程式庫。

下表摘要說明用來建立圖片的 Android.bp 屬性 子類

Android.bp 中的屬性 已建立變化版本
強制執行前 違規處置後
預設 (無) 核心肌群
(包括/system/system_ext和 。/product
核心肌群
(包含 /system/system_ext,但不包含 。/product
system_ext_specific: true Core Core
product_specific: true Core 產品
vendor: true 販賣機 販賣機
vendor_available: true 核心、供應商 核心、供應商
product_available: true 核心, 產品
vendor_available: true」和「product_available: true 核心、產品、供應商
system_ext_specific: true」和「vendor_available: true 核心、供應商 核心、供應商
product_specific: true」和「vendor_available: true 核心、供應商 產品、供應商

建構時間強制執行機制 (Android.mk)

啟用原生介面強制執行功能後,系統會將原生模組安裝到 有 product 個分區的 native:product 連結類型只能連結至 其他 native:productnative:vndk 模組。嘗試連結到任何 以外的模組會導致建構系統產生連結類型檢查 錯誤。

執行階段強制執行

原生介面強制執行設定後, 生物連結器不允許系統程序使用 product 程式庫 為無法連結的 product 程序建立 product 區段 product 分區外的程式庫 (但這類程序可連結至 VNDK 程式庫)。如果嘗試違反執行階段連結設定,就會導致 並產生 CANNOT LINK EXECUTABLE 錯誤訊息

強制執行 Java 介面

如要啟用強制執行 Java 介面,請設定 PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACEtrue。(值為 當目標的運送 API 級別為 true 時,會自動設為 true 大於 29)。啟用時,強制執行允許或禁止下列行為: 存取:

API /system /system_ext /product /vendor /data
公用 API
@SystemApi
@隱藏 API

vendor 分區相同,product 中的應用程式或 Java 程式庫 分區只能使用公用和系統 API。連結到圖書館 而不得使用隱藏的 API。這項限制包括在建構期間連結 執行偵錯。

建構時間強制執行機制

在建構期間,Make 和 Soong 驗證 product 中的 Java 模組 分區不會透過檢查 platform_apissdk_version 欄位。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. 建立定義 system 分區套件的 makefile。適用對象 例如,請使用下列指令建立 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 以及啟用 Artifact 路徑需求條件檢查功能。例如:

    $(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 中定義的路徑「並」防止套件 根據目前 makefile 的定義,安裝路徑外的構件 定義於 require-artifacts-in-path

在上述範例中,PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS 設定為 strictoem_system.mk 以外的 makefile 無法包含安裝於 rootsystem 分區。如要加入這些模組,您必須 在 oem_system.mk 檔案本身或隨附的 makefile 中定義程序。 如果嘗試將模組安裝到不允許的路徑,會導致建構中斷。修正方法 中斷時,請執行下列其中一項動作:

  • 選項 1:在內含的 makefiles 中加入系統模組 oem_system.mk。如此一來,就能符合構件路徑要求 (因為 模組現已存在於隨附的 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_specific: true
    • 模組可能缺少產品所需的產品子類 模組。如要修正問題,請透過下列方式為 product 分區提供該模組: 設定 product_available: true 或將模組移至 product 數量。product_specific: true
  3. 解決建構錯誤,並確保裝置建構成功。

  4. 刷新映像檔,並在裝置開機和記錄中尋找執行階段錯誤。

    • 如果測試案例記錄中的 linker 標記顯示 CANNOT LINK EXECUTABLE 訊息,就表示 make 檔案缺少依附元件 (無法在 建構時間)。
    • 如要從建構系統檢查,請將必要的程式庫新增至 shared_libs:required: 欄位。
  5. 按照上述指南解決缺少的依附元件。

步驟 4:強制執行 Java 介面

在這個步驟中,您將設定 PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true 找出並修正導致的建構錯誤。尋找以下兩種特定錯誤:

  • 連結類型錯誤。這個錯誤表示應用程式連結至 Java 模組 sdk_version 的靜態元素如要修正這個問題,您可以擴大應用程式的 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:檢查執行階段行為

在這個步驟中,您將驗證執行階段行為是否符合預期。對於以下類型的應用程式: 進行偵錯時,您可以透過記錄監控隱藏的 API 用量 StrictMode.detectNonSdkApiUsage (應用程式使用 隱藏的 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