裝置 ID

Android 10 變更了裝置 ID 的權限,現在所有裝置 ID 都受到 READ_PRIVILEGED_PHONE_STATE 權限保護。在 Android 10 之前,永久裝置 ID (IMEI/MEID、IMSI、SIM 卡和建構序號) 是受到 READ_PHONE_STATE 執行階段權限保護。READ_PRIVILEGED_PHONE_STATE 權限僅授予使用平台金鑰簽署的應用程式,以及具有特殊權限的系統應用程式。

如要進一步瞭解新的權限規定,請參閱 TelephonyManager.java 和 Build.java 的 Javadoc 頁面。

這項異動會影響下列 API:

  • TelephonyManager#getDeviceId
  • TelephonyManager#getImei
  • TelephonyManager#getMeid
  • TelephonyManager#getSimSerialNumber
  • TelephonyManager#getSubscriberId
  • Build#getSerial

沒有 READ_PRIVILEGED_PHONE_STATE 權限的電信業者應用程式存取權

不符合 READ_PRIVILEGED_PHONE_STATE 權限資格的預先載入電信業者應用程式,可以實作下表中的其中一個選項。

選項 說明 限制
UICC 貨運公司權限 Android 平台會載入儲存在 UICC 上的憑證,並授予由這些憑證簽署的應用程式權限,以便呼叫特殊方法。 傳統電信業者擁有大量已建立的 SIM 卡族群,但這些 SIM 卡不容易更新。此外,如果電信業者沒有新 SIM 卡的授權權利 (例如,MVNO 的 SIM 卡是由 MNO 核發),就無法在 SIM 卡上新增或更新憑證。
OEM 許可清單 原始設備製造商 (OEM) 可以使用 OP_READ_DEVICE_IDENTIFIER,為許可清單中的電信業者應用程式提供裝置 ID。 這項解決方案無法擴大適用於所有電信業者。
類型分配代碼 (TAC) 使用 Android 10 導入的 getTypeAllocationCode 方法,公開傳回製造商和型號資訊的 TAC。 TAC 中的資訊不足以識別特定裝置。
MSISDN 電信業者可以使用 TelephonyManager 權限群組中 PHONE 下方的電話號碼 (MSISDN),在後端系統中查詢 IMEI。 這需要電信業者投入大量資金。如果電信業者使用 IMSI 對應網路金鑰,則需要大量技術資源才能改用 MSISDN。

所有電信業者應用程式都可以存取裝置 ID,方法是使用電信業者應用程式的簽署憑證雜湊更新 CarrierConfig.xml 檔案。當電信業者應用程式呼叫方法來讀取具備存取權的資訊時,平台會在 CarrierConfig.xml 檔案中尋找相符的應用程式簽署憑證雜湊 (憑證的 SHA-1 或 SHA-256 簽章)。如果找到相符項目,系統就會傳回要求的資訊。如果找不到相符項目,系統會傳回安全性例外狀況。

如要實作這項解決方案,電信業者「必須」按照下列步驟操作:

  1. 更新 CarrierConfig.xml,加入電信業者應用程式的簽署憑證雜湊,然後提交修補程式。
  2. 請要求原始設備製造商 (OEM) 使用 QPR-1 以上版本 (建議) 或這些必要平台修補程式,以及包含上述步驟 1 中更新 CarrierConfig.xml 檔案的修補程式,更新建構版本。

導入作業

更新特殊權限許可清單,將 READ_PRIVILEGED_PHONE_STATE 權限授予需要存取裝置 ID 的特殊權限應用程式。

如要進一步瞭解許可清單,請參閱「特殊權限許可清單」。

如要叫用受影響的 API,應用程式必須符合下列其中一項規定:

  • 如果應用程式是預先載入的具備特殊權限應用程式,則需要 AndroidManifest.xml 中宣告的 READ_PRIVILEGED_PHONE_STATE 權限。應用程式也需要將這項特殊權限加入許可清單。
  • 透過 Google Play 提供的應用程式必須具備電信業者權限。 如要進一步瞭解如何授予電信業者權限,請參閱「UICC 電信業者權限」頁面。
  • 已獲授 READ_PHONE_STATE 權限的裝置或設定檔擁有者應用程式。

如果應用程式不符合上述任一規定,就會出現下列情況:

  • 如果應用程式是以 Android Q 之前的版本為目標,且未獲准 READ_PHONE_STATE 權限,就會觸發 SecurityException。這是 Android Q 之前的現行行為,因為必須具備這項權限才能叫用這些 API。
  • 如果應用程式是以 Android Q 之前的版本為目標,且已取得 READ_PHONE_STATE 權限,則所有 TelephonyManager API 都會收到空值,而 Build#getSerial 方法則會收到 Build.UNKNOWN。
  • 如果應用程式指定 Android 10 以上版本,且不符合任何一項新規定,就會收到 SecurityException。

驗證和測試

Compatibility Test Suite (CTS) 包含測試,可驗證具有電信業者權限、裝置和設定檔擁有者的應用程式,以及預期無法存取裝置 ID 的應用程式,是否具有預期的裝置 ID 存取行為。

下列 CTS 測試專用於這項功能。

cts-tradefed run cts -m CtsCarrierApiTestCases -t
    android.carrierapi.cts.CarrierApiTest

cts-tradefed run cts -m CtsTelephonyTestCases -t
    android.telephony.cts.TelephonyManagerTest

cts-tradefed run cts -m CtsTelephony3TestCases

cts-tradefed run cts -m CtsPermissionTestCases -t
    android.permission.cts.TelephonyManagerPermissionTest

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCanGetDeviceIdentifiers

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCannotGetDeviceIdentifiersWithoutPermission

cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t
    com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCannotGetDeviceIdentifiersWithoutPermission

常見問題

在 CarrierConfig.xml 中,特定 (MCC、MNC) 可將多少應用程式加入許可清單?

陣列中包含的憑證雜湊數量沒有限制。

如要將應用程式加入許可清單,我需要使用 CarrierConfig.xml 中的哪些 CarrierConfig 參數?

在您要設定的 AOSP 選項 CarrierConfig.xml中,使用下列頂層設定項目:

<string-array name="carrier_certificate_string_array" num="2">
    <item value="BF02262E5EF59FDD53E57059082F1A7914F284B"/>
    <item value="9F3868A3E1DD19A5311D511A60CF94D975A344B"/>
</string-array>

是否有可用的 CarrierConfig 基礎範本?

請使用下列範本。請務必將這項資訊新增至 相關素材資源。

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<carrier_config>
    <string-array name="carrier_certificate_string_array"
num="1">
        <item value="CERTIFICATE_HASH_HERE"/>
    </string-array>
</carrier_config>

裝置是否必須插入電信業者 SIM 卡,才能存取裝置 ID?

系統會根據目前插入的 SIM 卡決定使用哪個 CarrierConfig.xml。也就是說,如果插入電信業者 Y 的 SIM 卡,電信業者 X 的應用程式嘗試取得存取權限時,裝置找不到相符的雜湊值,就會傳回安全性例外狀況。

在多 SIM 卡裝置上,電信業者 #1 僅具有 SIM 卡 #1 的存取權限,反之亦然。

電信業者如何將應用程式的簽署憑證轉換為雜湊?

如要先將簽署憑證轉換為雜湊,再新增至 CarrierConfig.xml,請按照下列步驟操作:

  1. 使用 toByteArray,將簽署憑證的簽章轉換為位元組陣列。
  2. 使用 MessageDigest 將位元組陣列轉換為 byte[] 類型的雜湊。
  3. 將雜湊從 byte[] 轉換為十六進位字串格式。如需範例,請參閱 IccUtils.java。

    List<String> certHashes = new ArrayList<>();
    PackageInfo pInfo; // Carrier app PackageInfo
    MessageDigest md =
    MessageDigest.getInstance("SHA-256");
    for (Signature signature : pInfo.signatures) {
        certHashes.add(bytesToHexString(md.digest(signature.toByteArray()));
    }
  4. 如果 certHashes 是大小為 2 的陣列,且值為 12345 和 54321,請將下列內容新增至電信業者設定檔。

    <string-array name="carrier_certificate_string_array" num="2">
        <item value="12345"/>
        <item value="54321"/>
    </string-array>