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