從Android 9(API級別28)開始,Android平臺對應(yīng)用能使用的非SDK接口實施了限制。只要應(yīng)用引用非SDK接口或嘗試使用反射或JNI來獲取其句柄,這些限制就適用。這些限制旨在幫助提升用戶體驗和開發(fā)者體驗,為用戶降低應(yīng)用發(fā)生崩潰的風險,同時為開發(fā)者降低緊急發(fā)布的風險。
區(qū)分SDK接口和非SDK接口
一般而言,公共SDK接口是在Android框架軟件包索引中記錄的那些接口。非SDK接口的處理是API抽象出來的實現(xiàn)細節(jié),因此這些接口可能會在不另行通知的情況下隨時發(fā)生更改。
為了避免發(fā)生崩潰和意外行為,應(yīng)用應(yīng)僅使用SDK中經(jīng)過正式記錄的類。這也意味著當您的應(yīng)用通過反射等機制與類互動時,不應(yīng)訪問SDK中未列出的方法或字段。
非SDK API名單
隨著每個Android版本的發(fā)布,會有更多非SDK接口受到限制。我們知道這些限制會影響您的發(fā)布工作流,同時我們希望確保您擁有相關(guān)工具來檢測非SDK接口的使用情況、有機會向我們提供反饋,并且有時間根據(jù)相應(yīng)新政策做出規(guī)劃和調(diào)整。
為最大程度地降低非SDK使用限制對開發(fā)工作流的影響,我們將非SDK接口分成了幾個名單,這些名單界定了非SDK接口使用限制的嚴格程度(取決于應(yīng)用的目標API級別)。下表介紹了這些名單:
盡管您目前仍可以使用某些非SDK接口(取決于應(yīng)用的目標API級別),但只要您使用任何非SDK方法或字段,終歸存在導致應(yīng)用出問題的顯著風險。如果您的應(yīng)用依賴于非SDK接口,建議您開始計劃遷移到SDK接口或其他替代方案。如果您無法為應(yīng)用中的功能找到無需使用非SDK接口的替代方案,我們建議您請求添加新的公共API。
確定接口屬于哪個名單
非SDK接口的名單會構(gòu)建為Android平臺的一部分。如需了解每個Android版本的相關(guān)信息,請參閱以下部分。
Android 11
以下文件針對Android 11(API級別30)介紹了所有非SDK接口及其對應(yīng)的名單:hiddenapi-flags.csv。
如需詳細了解Android 11中的非SDK API名單更改,包括針對在Android 11中有條件屏蔽的API建議的公共API替代選項,請參閱Android 11的名單更改。
Android 10
以下文件針對Android 10(API級別29)介紹了所有非SDK接口及其對應(yīng)的名單:hiddenapi-flags.csv。
如需詳細了解Android 10中的非SDK API名單更改,包括針對在Android 10中有條件屏蔽的API建議的公共API替代選項,請參閱Android 10的名單更改。
Android 9
以下文本文件針對Android 9(API級別28)列出了不受限制(已列入灰名單)的非SDK API:hiddenapi-light-greylist.txt。
屏蔽名單(blacklist)和有條件屏蔽的API名單(深灰名單)是在構(gòu)建時派生的。
通過AOSP生成名單
處理AOSP時,您可以生成一個hiddenapi-flags.csv文件,其中包含所有非SDK接口及其對應(yīng)的名單。為此,請下載AOSP源代碼,然后運行以下命令:
m out/soong/hiddenapi/hiddenapi-flags.csv
然后,您便可以在以下位置找到該文件:
out/soong/hiddenapi/hiddenapi-flags.csv
訪問受限的非SDK接口時可能會出現(xiàn)的預(yù)期行為
下表說明了當您的應(yīng)用嘗試訪問屏蔽名單中的非SDK接口時可能會出現(xiàn)的預(yù)期行為。
測試您的應(yīng)用是否使用非SDK接口
您可以通過多種方法來測試您的應(yīng)用是否使用非SDK接口。
使用可調(diào)試的應(yīng)用進行測試
您可以通過在搭載Android 9(API級別28)或更高版本的設(shè)備或模擬器上構(gòu)建和運行可調(diào)試應(yīng)用來測試該應(yīng)用是否使用非SDK接口。請確保您使用的設(shè)備或模擬器與應(yīng)用的目標API級別相匹配。
在您的應(yīng)用上運行測試時,如果該應(yīng)用訪問了某些非SDK接口,系統(tǒng)就會輸出一條日志消息。您可以檢查應(yīng)用的日志消息,查找以下詳細信息:
聲明的類、名稱和類型(采用Android運行時所使用的格式)。
訪問方式:鏈接、反射或JNI
所訪問的非SDK接口屬于哪個名單。
您可以使用adb logcat來查看這些日志消息,這些消息顯示在所運行應(yīng)用的PID下。舉例而言,日志中可能包含如下條目:
Accessing hidden field Landroid/os/Message;->flags:I(light greylist,JNI)
使用StrictMode API進行測試
您還可以利用StrictMode API來測試您的應(yīng)用是否使用非SDK接口。請使用detectNonSdkApiUsage方法來啟用此API。啟用StrictMode API后,您可以使用penaltyListener來接收每次使用非SDK接口時觸發(fā)的回調(diào),并且您可以在其中實現(xiàn)自定義處理?;卣{(diào)中提供的Violation對象派生自Throwable,并且封閉式堆棧軌跡會提供相應(yīng)使用行為的具體情境。
使用veridex工具進行測試
您還可以在APK上運行靜態(tài)分析工具veridex。veridex工具會掃描APK的整個代碼庫(包括所有第三方庫),并報告發(fā)現(xiàn)的所有使用非SDK接口的行為。
veridex工具存在以下局限性:
·它無法檢測到通過JNI實現(xiàn)的調(diào)用。
·它只能檢測到一部分通過反射實現(xiàn)的調(diào)用。
·它對非活動代碼路徑的分析僅限于API級別的檢查。
·它只能在支持SSE4.2和POPCNT指令的機器上運行。
Windows
雖然不提供本機Windows二進制文件,但您可以使用適用于Linux的Windows子系統(tǒng)(WSL)來執(zhí)行Linux二進制文件,從而在Windows上運行veridex工具。在執(zhí)行本節(jié)中的步驟之前,請安裝WSL,然后選擇Ubuntu作為您的Linux發(fā)行版本。
安裝Ubuntu后,啟動Ubuntu終端,然后按以下步驟操作:
1.從Android運行時預(yù)建代碼庫下載veridex工具。
2.解壓縮appcompat.tar.gz文件的內(nèi)容。
3.在解壓縮的文件夾中,找到veridex-linux.zip文件并將其解壓縮。
4.轉(zhuǎn)到解壓縮的文件夾,然后運行以下命令,其中your-app.apk是您要測試的APK:
./appcompat.sh--dex-file=your-app.apk
macOS
如需在macOS上運行veridex工具,請按以下步驟操作:
1.從Android運行時預(yù)建代碼庫下載veridex工具。
2.解壓縮appcompat.tar.gz文件的內(nèi)容。
3.在解壓縮的文件夾中,找到veridex-mac.zip文件并將其解壓縮。
4.轉(zhuǎn)到解壓縮的文件夾,然后運行以下命令,其中/path-from-root/your-app.apk是您要測試的APK的路徑,從系統(tǒng)的根目錄開始:
./appcompat.sh--dex-file=/path-from-root/your-app.apk
Linux
如需在Linux上運行veridex工具,請按以下步驟操作:
1.從Android運行時預(yù)建代碼庫下載veridex工具。
2.解壓縮appcompat.tar.gz文件的內(nèi)容。
3.在解壓縮的文件夾中,找到veridex-linux.zip文件并將其解壓縮。
4.轉(zhuǎn)到解壓縮的文件夾,然后運行以下命令,其中your-app.apk是您要測試的APK:
./appcompat.sh--dex-file=your-app.apk
使用Android Studio lint工具進行測試
每當您在Android Studio中構(gòu)建應(yīng)用時,lint工具都會檢查您的代碼中是否存在潛在問題。如果您的應(yīng)用使用非SDK接口,則可能會看到構(gòu)建錯誤或警告,具體取決于這些接口所屬的名單。
您也可以通過命令行運行l(wèi)int工具,或者在特定項目、文件夾或文件中手動運行檢查。
使用Play管理中心進行測試
當您將應(yīng)用上傳到Play管理中心的測試軌道時,系統(tǒng)會自動測試應(yīng)用以找出是否存在潛在問題,并生成發(fā)布前測試報告。如果您的應(yīng)用使用非SDK接口,發(fā)布前測試報告中會顯示錯誤或警告,具體取決于這些接口所屬的名單。
如需了解詳細信息,請參閱使用發(fā)布前測試報告找出問題中的“Android兼容性”部分。
請求新的公共API
如果您無法為應(yīng)用中的功能找到無需使用非SDK接口的替代方案,則可以在問題跟蹤器中通過創(chuàng)建功能請求來請求新的公共API。
創(chuàng)建功能請求時,請?zhí)峁┮韵路矫娴男畔ⅲ?/span>
您目前使用的是灰名單中的哪些API,包括Accessing hidden...logcat消息中顯示的完整描述符。
為什么需要使用這些API,包括與需要使用這些API的高級功能相關(guān)的詳情,而不僅是關(guān)于相應(yīng)低級功能的詳情。
為什么所有相關(guān)的公共SDK API都不足以滿足您的需要。
您嘗試過的其他替代方案,以及這些方案都無效的原因。
如果您在功能請求中提供這些詳細信息,我們批準添加新公共API的可能性就會更高。
其他問題
本部分針對開發(fā)者經(jīng)常會提出的其他一些問題給出了解答:
常見問題
Google如何確保通過問題跟蹤器捕獲所有應(yīng)用的需求?
我們對應(yīng)用進行靜態(tài)分析,并以下面的方法作為補充,從而針對Android 9(API級別28)創(chuàng)建了初始列表:
·對熱門的Play應(yīng)用和非Play應(yīng)用進行手動測試
·查看內(nèi)部報告
·自動在內(nèi)部用戶中收集數(shù)據(jù)
·查看開發(fā)者預(yù)覽報告
·執(zhí)行額外的靜態(tài)分析,以基于謹慎原則包含更多假正例
在我們評估針對每個新版本的列表時,我們會考慮API使用情況以及開發(fā)者通過問題跟蹤器提供的反饋。
如何允許訪問非SDK接口?
您可以使用adb命令來更改API強制執(zhí)行策略,從而允許在開發(fā)設(shè)備上訪問非SDK接口:您使用的命令因API級別而異。這些命令無需設(shè)備取得root權(quán)限即可執(zhí)行。
Android 10(API級別29)
如需允許訪問非SDK接口,請使用以下adb命令:
adb shell settings put global hidden_api_policy 1
如需將API強制執(zhí)行策略重置為默認設(shè)置,請使用以下命令:
adb shell settings delete global hidden_api_policy
Android 9(API級別28)
如需允許訪問非SDK接口,請使用以下adb命令:
adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1
如需將API強制執(zhí)行策略重置為默認設(shè)置,請使用以下命令:
adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps
您可以將API強制執(zhí)行策略中的整數(shù)設(shè)置為以下值之一:
0:停用所有非SDK接口檢測。如果您使用此設(shè)置,系統(tǒng)會停止輸出針對非SDK接口使用行為的所有日志消息,并阻止您使用StrictMode API測試應(yīng)用。建議不要使用此設(shè)置。
1:允許訪問所有非SDK接口,但同時輸出日志消息,并且在其中顯示針對所有非SDK接口使用情況的警告。如果使用此設(shè)置,您仍可以使用StrictMode API來測試應(yīng)用。
2:禁止使用列于屏蔽名單中的非SDK接口,或針對您的目標API級別被有條件屏蔽的非SDK接口。
有關(guān)非SDK接口名單的問題
在系統(tǒng)映像中的什么位置可以找到非SDK API名單?
它們是在平臺dex文件中的字段和方法訪問標記位中編碼的。系統(tǒng)鏡像中沒有單獨的文件包含這些名單。
搭載同一Android版本的不同OEM設(shè)備上的非SDK API名單是否相同?
原始設(shè)備制造商(OEM)可以將自己的接口添加到屏蔽名單(黑名單)中,但是無法從AOSP非SDK API名單中移除接口。CDD會阻止此類更改,并且CTS測試會確保Android運行時強制執(zhí)行相應(yīng)名單。
有關(guān)相關(guān)應(yīng)用兼容性的問題
對原生代碼中的非NDK接口是否有任何限制?
Android SDK包含Java接口。Android平臺從Android 7(API級別26)開始限制訪問原生C/C++代碼中的非NDK接口。如需了解詳情,請參閱通過在Android N中限制私有C/C++符號提升穩(wěn)定性。
Google是否計劃限制對dex2oat或DEX文件的操作?
我們沒有現(xiàn)有計劃要限制對dex2oat二進制文件的訪問,但并不打算讓DEX成為一種固定的文件格式,并且除了在Dalvik可執(zhí)行文件格式中公開指定的部分之外,我們也不打算讓它成為一個公共接口。我們保留隨時修改或清除dex2oat和DEX格式的未指定部分的權(quán)利。另請注意,由dex2oat生成的派生文件都屬于未指定的格式,例如ODEX(也稱為OAT)、VDEX和CDEX。
如果某個重要的第三方SDK(例如混淆器)無法避免使用非SDK接口,但確實承諾維持對未來Android版本的兼容性,該怎么辦?在這種情況下,Android可以免除其兼容性要求嗎?
我們不打算針對單個SDK免除兼容性要求。如果SDK開發(fā)者目前只能依賴于灰名單中的接口來維持兼容性,那么他們應(yīng)該著手計劃遷移到SDK接口或其他替代方案;倘若找不到無需使用非SDK接口的替代方案,可請求新的公共API。
針對非SDK接口的限制是否適用于包括系統(tǒng)應(yīng)用和第一方應(yīng)用在內(nèi)的所有應(yīng)用,而不僅是第三方應(yīng)用?
是,但我們對使用平臺密鑰進行簽名的應(yīng)用和某些系統(tǒng)映像應(yīng)用免除這項限制。請注意,免除限制的情況僅適用于系統(tǒng)映像應(yīng)用(或更新后的系統(tǒng)映像應(yīng)用)。軟件包白名單僅適用于針對私有平臺API(而不是SDK API)構(gòu)建的應(yīng)用(其中LOCAL_PRIVATE_PLATFORM_APIS:=true)。