非 SDK 介面的相關限制

Stay organized with collections Save and categorize content based on your preferences.

自 Android 9 (API 級別 28) 起,這個平台會限制應用程式可使用的非 SDK 介面。每當應用程式參照非 SDK 介面,或嘗試透過反映或 JNI 取得其控點時,就適用這些限制。這些限制旨在改善使用者和開發人員的體驗,降低使用者遭遇當機的風險,並降低開發人員為此緊急發布更新的風險。若要進一步瞭解這項決策,請參閱「減少使用非 SDK 介面以改善穩定性」。

區分 SDK 和非 SDK 介面

一般而言,公用 SDK 介面是指記錄在 Android 架構套件索引中的介面。處理非 SDK 介面是 API 抽離的實作細節,因此這些介面如有變更,恕不另行通知。

為避免當機和非預期的行為,應用程式只能使用 SDK 中正式記錄的類別。這也意味著當您透過反映等機制與類別互動時,不應存取 SDK 中未列出的方法或欄位。

非 SDK API 清單

每個 Android 版本都會有額外的非 SDK 介面受到限制。我們瞭解這些限制可能會影響發布作業流程,我們希望確保您擁有適合的工具,可偵測非 SDK 介面的使用情形、有機會提供意見回饋,並且有時間規劃及適應新政策。

為盡量減少非 SDK 限制對開發工作流程的影響,非 SDK 介面會分成多個清單,根據鎖定的 API 級別,定義其使用受限的嚴格程度。下表逐一說明這些清單:

清單 說明
封鎖清單 (blacklist) 無論應用程式的目標 API 級別為何,都無法使用的非 SDK 介面。如果應用程式嘗試存取這類介面,系統就會擲回錯誤
有條件封鎖 (greylist-max-x)

自 Android 9 (API 級別 28) 起,如果應用程式鎖定該 API 級別,則每個 API 級別都有受到限制的非 SDK 介面。

在應用程式再也不能存取該清單中的非 SDK 介面之前,這些清單會以應用程式可鎖定的最高 API 級別 (max-target-x) 進行標示。例如,過去未在 Android Pie 中遭到封鎖的非 SDK 介面,現已在 Android 10 中遭到封鎖,其包含在 max-target-p (greylist-max-p) 清單中,其中「p」代表 Pie 或 Android 9 (API 級別 28)。

如果應用程式嘗試存取因目標 API 級別而受到限制的介面,系統會以該 API 為封鎖清單的一部分的形式運作

不支援 (greylist) 目前未受限且應用程式可使用的非 SDK 介面。不過請注意,這些介面不在支援範圍內,如有變更,恕不另行通知。預期這些介面會在 max-target-x 清單中的日後 Android 版本中遭到有條件封鎖。
SDK (whitelist) 可自由使用且現已做為正式記錄的 Android 架構套件索引的一部分而獲得支援的介面。

儘管您目前可使用某些非 SDK 介面 (視應用程式的目標 API 級別而定),但使用任何非 SDK 方法或欄位時,應用程式停止運作的風險極高。如果應用程式仰賴非 SDK 介面,則應開始規劃遷移至 SDK 介面或其他替代方案。如果您除了為應用程式中的某個功能使用非 SDK 介面外,已別無他法,則應要求新的公用 API

判定介面所屬的清單

這個平台已提供內建的非 SDK 介面清單。請參閱以下各節,瞭解各個 Android 版本的相關資訊。

Android 13

對於 Android 13 (API 級別 33),您可下載以下檔案,其中說明所有非 SDK 介面及其對應清單:

檔案:hiddenapi-flags.csv

SHA-256 總和檢查碼:233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3

若要進一步瞭解 Android 13 中的非 SDK API 清單變更情形,包括 Android 13 內遭到有條件封鎖的 API 的建議公用 API 替代方案,請參閱「Android 13 的非 SDK 介面限制更新內容」。

Android 12

對於 Android 12 (API 級別 31),您可下載下列檔案,其中說明所有非 SDK 介面及其對應清單:

檔案:hiddenapi-flags.csv

SHA-256 總和檢查碼:40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761

若要進一步瞭解 Android 12 中非 SDK API 清單的變動情形,包括在 Android 12 中遭到有條件封鎖的 API 的建議公用 API 替代方案,請參閱「Android 12 的清單變動情形」。

Android 11

對於 Android 11 (API 級別 30),您可下載下列檔案,其中說明所有非 SDK 介面及其對應清單:

檔案:hiddenapi-flags.csv

SHA-256 總和檢查碼:a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56

若要進一步瞭解 Android 11 中非 SDK API 清單的變動情形,包括在 Android 11 中遭到有條件封鎖的 API 的建議公用 API 替代方案,請參閱「Android 11 的清單變動情形」。

Android 10

對於 Android 10 (API 級別 29),您可下載下列檔案,其中說明所有非 SDK 介面及其對應清單:

檔案:hiddenapi-flags.csv

SHA-256 總和檢查碼:f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb

若要進一步瞭解 Android 10 中非 SDK API 清單的變動情形,包括在 Android 10 中遭到有條件封鎖的 API 的建議公用 API 替代方案,請參閱「Android 10 的清單變動情形」。

Android 9

對於 Android 9 (API 級別 28),以下文字檔包含未受限制的非 SDK API 清單 (列入可疑項目清單):hiddenapi-light-greylist.txt

封鎖清單 (blacklist) 和有條件封鎖的 API 清單 (深灰色清單) 會在建構期間產生。

透過 Android 開放原始碼計畫產生清單

處理 Android 開放原始碼計畫時,您可以產生 hiddenapi-flags.csv 檔案,內含所有非 SDK 介面及其對應的清單。為此,請下載 Android 開放原始碼計畫來源,然後執行下列指令:

m out/soong/hiddenapi/hiddenapi-flags.csv

隨即您可在下列位置找到檔案:

out/soong/hiddenapi/hiddenapi-flags.csv

存取受限制的非 SDK 介面的預期行為

下表說明應用程式嘗試存取已加入封鎖清單的非 SDK 介面時的可預期行為。

存取方式 結果
參照欄位的 Davik 指示 已擲回 NoSuchFieldError
參考方法的 Davik 指示 已擲回 NoSuchMethodError
透過 Class.getDeclaredField()Class.getField() 的反映 已擲回 NoSuchFieldException
透過 Class.getDeclaredMethod()Class.getMethod() 的反映 已擲回 NoSuchMethodException
透過 Class.getDeclaredFields()Class.getFields() 的反映 非 SDK 成員不在結果中
透過 Class.getDeclaredMethods()Class.getMethods() 的反映 非 SDK 成員不在結果中
透過 env->GetFieldID() 的 JNI 已回傳 NULL,已擲回 NoSuchFieldError
透過 env->GetMethodID() 的 JNI 已回傳 NULL,已擲回 NoSuchMethodError

測試應用程式的非 SDK 介面

有多種方法可用來測試應用程式中的非 SDK 介面。

使用可進行偵錯的應用程式進行測試

您可在搭載 Android 9 (API 級別 28) 以上版本的裝置或模擬器上,建構並執行可進行偵錯的應用程式,藉此測試非 SDK 介面。請確認您使用的裝置或模擬器與應用程式的目標 API 級別相符。

在應用程式上執行測試時,如果應用程式存取特定非 SDK 介面,系統會列印記錄訊息。您可以檢查應用程式的記錄訊息,查看下列詳細資料:

  • 宣告類別、名稱和類型 (採用 Android 執行階段使用的格式)。
  • 存取方式:透過連結、反映或 JNI。
  • 非 SDK 介面所屬的清單。

您可以使用 adb logcat 存取這些記錄訊息,這些訊息會顯示在執行中應用程式的 PID 下方。例如,記錄中的項目可能如下:

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)

使用 StrictMode API 進行測試

您也可以使用 StrictMode API 測試非 SDK 介面。請使用 detectNonSdkApiUsage 方法啟用這項功能。啟用 StrictMode API 後,您就可以使用 penaltyListener (可供您實作自訂使用方式) 接收每次使用非 SDK 介面時的回呼。回呼中提供的 Violation 物件衍生自 Throwable,而封閉式堆疊追蹤可提供使用情形的內容。

使用 veridex 工具進行測試

您也可以在 APK 上執行 veridex 靜態分析工具。veridex 工具會掃描 APK 的整個程式碼集 (包括任何第三方程式庫),並回報偵測到的任何非 SDK 介面使用情形。

veridex 工具的限制包括:

  • 無法透過 JNI 偵測叫用。
  • 只能透過反映偵測叫用子集。
  • 其對閒置程式碼路徑的分析僅限於 API 級別檢查。
  • 只能在支援 SSE4.2 和 POPCNT 指示的機器上執行。

Windows

不提供原生 Windows 二進位檔,但您可透過執行使用 Windows Subsystem for Linux (WSL) 的 Linux 二進位檔,在 Windows 上執行 veridex 工具。在依本節中的步驟操作之前,請先安裝 WSL,並選擇 Ubuntu 做為 Linux 發行版本。

安裝 Ubuntu 後,請啟動 Ubuntu 終端機,然後依下列步驟操作:

  1. 從 Android 執行階段預建存放區下載 veridex 工具
  2. 擷取 appcompat.tar.gz 檔案的內容。
  3. 在擷取的資料夾中,找到 veridex-linux.zip 檔案並將其解壓縮。
  4. 前往解壓縮後的資料夾,然後執行下列指令,其中 your-app.apk 是您要測試的 APK:

    ./appcompat.sh --dex-file=your-app.apk
    

macOS

若要在 macOS 上執行 veridex 工具,請依下列步驟操作:

  1. 從 Android 執行階段預建存放區下載 veridex 工具
  2. 擷取 appcompat.tar.gz 檔案的內容。
  3. 在擷取的資料夾中,找到 veridex-mac.zip 檔案並將其解壓縮。
  4. 前往解壓縮後的資料夾,然後執行下列指令,其中 /path-from-root/your-app.apk 是您要測試的 APK 路徑 (從系統根目錄開始)。

    ./appcompat.sh --dex-file=/path-from-root/your-app.apk
    

Linux

若要在 Linux 上執行 veridex 工具,請依下列步驟操作:

  1. 從 Android 執行階段預建存放區下載 veridex 工具
  2. 擷取 appcompat.tar.gz 檔案的內容。
  3. 在擷取的資料夾中,找到 veridex-linux.zip 檔案並將其解壓縮。
  4. 前往解壓縮後的資料夾,然後執行下列指令,其中 your-app.apk 是您要測試的 APK:

    ./appcompat.sh --dex-file=your-app.apk
    

使用 Android Studio Lint 工具進行測試

當您在 Android Studio 中建構應用程式時,Lint 工具會檢查程式碼是否有潛在問題。如果應用程式使用非 SDK 介面,則根據這些介面所屬的清單而定,您可能會看到建構錯誤或警告。

您也可以透過指令列執行 Lint 工具,或是針對特定專案、資料夾或檔案手動執行檢查

使用 Play 管理中心進行測試

將應用程式上傳至 Play 管理中心的測試群組時,系統會自動測試應用程式是否有潛在問題,並產生正式發布前測試報告。如果應用程式使用非 SDK 介面,則根據這些介面所屬的清單而定,正式發布前測試報告可能會顯示錯誤或警告。

詳情請參閱運用正式發布前測試報告找出問題中的「Android 相容性」一節。

要求新的公用 API

如果您除了為應用程式中的某個功能使用非 SDK 介面外,已別無他法,則可在 Issue Tracker 中建立功能要求,藉此要求新的公用 API。

建立功能要求時,請提供下列資訊:

  • 您目前使用可疑項目清單中的哪些 API,包括 Accessing hidden ... Logcat 訊息中的完整描述元。
  • 需要使用這類 API 的原因,包括需要使用該 API 的高階功能詳細資料,而非只有低階詳細資料。
  • 任何相關公用 SDK API 不敷使用的原因。
  • 您過去試過的其他替代方案,以及失敗的原因。

在功能要求中提供這些詳細資料,就能提高取得新公用 API 的可能性。

其他問題

本節另外解答一些開發人員常見問題:

一般問題

Google 如何確保透過 Issue Tracker 掌握所有應用程式的需求?

我們透過使用下列方法實作的應用程式靜態分析,建立 Android 9 (API 級別 28) 的初始清單:

  • 手動測試熱門 Google Play 和非 Google Play 應用程式
  • 內部報告
  • 自動收集內部使用者的資料
  • 開發人員預覽報告
  • 旨在保守地納入更多偽陽性的其他靜態分析

在評估每個新版本的清單時,我們會透過 Issue Tracker 將帳戶 API 使用情形和開發人員意見回饋納入考量。

如何啟用非 SDK 介面的存取權?

您可以使用 adb 指令變更 API 強制執行政策,藉此在開發裝置上啟用非 SDK 介面的存取權。您使用的指令會因 API 級別而有所不同。這些指令不需要使用已解鎖裝置。

Android 10 (API 級別 29) 以上版本

若要啟用存取權,請使用下列 adb 指令:

adb shell settings put global hidden_api_policy  1

若要將 API 強制執行政策重設為預設設定,請使用下列指令:

adb shell settings delete global hidden_api_policy
Android 9 (API 等級 28)

若要啟用存取權,請使用下列 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 強制執行政策重設為預設設定,請使用下列指令:

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

您可將 API 強制執行政策中的整數設為下列其中一個值:

  • 0:停用所有非 SDK 介面的偵測作業。使用這項設定會停用所有非 SDK 介面使用情形的記錄訊息,並使您無法使用 StrictMode API 測試應用程式。不建議採用這項設定。
  • 1:啟用所有非 SDK 介面的存取權,但使用非 SDK 介面時,將會列印記錄訊息並附上警告。使用這項設定也可讓您使用 StrictMode API 測試應用程式。
  • 2:禁止使用封鎖清單中的非 SDK 介面,或視目標 API 級別進行有條件的封鎖。

非 SDK 介面清單相關問題

哪裡可以找到系統映像檔中的非 SDK API 清單?

這些清單編碼在平台 dex 檔案內的欄位和方法存取旗標位元中。包含這些清單的系統映像檔中沒有獨立的檔案。

Android 版本相同的不同原始設備製造商 (OEM) 裝置上的非 SDK API 清單是否相同?

原始設備製造商 (OEM) 可將自己的介面新增至封鎖清單 (黑名單),但無法從 Android 開放原始碼計畫的非 SDK API 清單中移除介面。CDD 不允許這類變更,且 CTS 測試可確保 Android 執行階段強制執行清單。

原生程式碼中的非 NDK 介面是否有任何相關限制?

Android SDK 包含 Java 介面。平台已開始限制 Android 7 (API 級別 26) 中對使用原生 C/C++ 程式碼的非 NDK 介面的存取。詳情請參閱「在 Android N 中使用私人 C/C++ 符號限制改善穩定性」。

有辦法限制 dex2oat 或 DEX 檔案操控嗎?

我們目前並未計劃限制 dex2oat 二進位檔的存取權,但我們無意讓 DEX 檔案格式保持穩定,或提供在 Dalvik 可執行的格式中公開指定的部分以外的公用介面。我們保留隨時修改或移除 dex2oat 和 DEX 格式未指定部分的權利。另請注意,dex2oat 產生的衍生檔案,例如 ODEX (也稱為 OAT)、VDEX 和 CDEX,都是未指定的格式。

如果重要的第三方 SDK (例如模糊處理工具) 無法避免使用非 SDK 介面,但會保證與日後的 Android 版本的相容性,此時該怎麼辦?在此情況下,Android 可以放棄其相容性需求嗎?

我們並未計劃以 SDK 為基礎免除相容性需求。如果 SDK 開發人員目前只能仰賴不支援的 (先前呈灰色) 清單中的介面維持相容性,則應開始規劃遷移至 SDK 介面,或是在遭遇除了使用非 SDK 介面外已別無他法的情況,要求新的公用 API

非 SDK 介面限制是否適用於所有應用程式,包括系統和第一方應用程式,而非僅限於第三方應用程式?

是,但使用平台金鑰簽署的應用程式及部分系統映像檔應用程式不在此限。請注意,這些豁免權僅適用於屬於系統映像檔的應用程式 (或更新後的系統映像檔應用程式)。此清單僅適用於以私人平台 API 建構的應用程式,而非 SDK API (其中 LOCAL_PRIVATE_PLATFORM_APIS := true)。