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: true
或vendor_available: true
庫。VNDK庫在其
Android.bp
文件中必須具有vendor_available: true
,以便product
二進製文件可以鏈接到VNDK庫。
下表總結了用於創建圖像變體的Android.bp
屬性。
Android.bp中的屬性 | 創建的變體 | |
---|---|---|
執法前 | 執行後 | |
默認(無) | 核心 (包括 | 核心 (包括 |
system_ext_specific: true | 核心 | 核心 |
product_specific: true | 核心 | 產品 |
vendor: true | 供應商 | 供應商 |
vendor_available: true | 核心,供應商 | 核心,產品,供應商 |
system_ext_specific: true 和vendor_available: true | 核心,供應商 | 核心,產品,供應商 |
product_specific: true 和vendor_available: true | 核心,供應商 | 產品,供應商 |
建立時間執行(Android.mk)
啟用本機接口強制後,安裝到product
分區的native:product
機模塊具有native:product
鏈接類型,該鏈接類型只能鏈接到其他native:product
或native: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_apis
和sdk_version
字段來驗證product
分區中的Java模塊未使用隱藏的API。 product
分區中應用程序的sdk_version
必須用API的current
, system_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。
創建一個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),)
在
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
設置為true
或strict
,構建系統將阻止將其他makefile中定義的軟件包安裝到require-artifacts-in-path
定義require-artifacts-in-path
並防止當前makefile中定義的軟件包將require-artifacts-in-path
定義的路徑之外的工件安裝到- require-artifacts-in-path
。
在以上示例中,將PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
設置為strict
, oem_system.mk
之外的makefile不能包含安裝到root
分區或system
分區的模塊。要包括這些模塊,您必須在oem_system.mk
文件本身中或在包含的makefile中定義它們。嘗試將模塊安裝到不允許的路徑會導致構建中斷。要修復中斷,請執行以下任一操作:
選項1:將系統模塊包含在
oem_system.mk
包含的makefile中。這樣就可以滿足工件路徑的要求(因為模塊現在包含在包含的makefile中),因此可以安裝到“ require-artifacts-in-path”中的路徑集。選項2:將模塊安裝到
system_ext
或product
分區(不要將模塊安裝到system
分區)。選項3:將模塊添加到
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
。這列出了允許安裝的模塊。
步驟2:清空允許的列表
在此步驟中,將PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
空,以便所有共享oem_system.mk
設備也可以共享一個system
映像。要清空允許的列表,請將列表中的所有模塊移至system_ext
或product
分區,或將其添加到system
製造文件中。此步驟是可選的,因為無需啟用通用system
映像即可啟用產品接口。但是,清空允許列表有助於使用system_ext
定義system
邊界。
步驟3:強制執行本機界面
在此步驟中,您設置PRODUCT_PRODUCT_VNDK_VERSION := current
,然後查找構建和運行時錯誤並解決。要檢查設備啟動和日誌並查找並修復運行時鏈接故障:
設置
PRODUCT_PRODUCT_VNDK_VERSION := current
。編譯設備並查找編譯錯誤。您可能會因缺少產品變體或核心變體而遇到一些構建中斷。常見的休息時間包括:
- 任何具有
product_specific: true
hidl_interface
模塊將不適用於系統模塊。要修復,請將product_specific: true
替換為system_ext_specfic: true
。 - 模塊可能缺少產品模塊所需的產品變型。要修復,請通過設置
vendor_available: true
使該模塊對product
分區可用,或者通過設置product_specific: true
將模塊移至product
分區。
- 任何具有
解決構建錯誤,並確保設備成功構建。
刷新映像,並在設備啟動和日誌中查找運行時錯誤。
- 如果測試用例日誌中的
linker
標記顯示CANNOT LINK EXECUTABLE
消息,則說明make文件缺少依賴項(並且在構建時未捕獲)。 - 要從構建系統檢查它,請將所需的庫添加到
shared_libs:
或required:
字段。
- 如果測試用例日誌中的
使用上面給出的指南解決缺少的依賴關係。
步驟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