裝置 ID

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

如要進一步瞭解新的權限規定,請參閱 TelephonyManager.javaBuild.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 電信業者可以使用手機號碼 (MSISDN,在 PHONE 權限群組下提供) 在後端系統中查詢 IMEI。TelephonyManager 這需要電信業者投入大量資金。如果電信業者使用 IMSI 對應網路金鑰,則需要大量技術資源才能改用 MSISDN

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

如要實作此解決方案,貨運公司「必須」按照下列步驟操作:

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

實作

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

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

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

  • 如果應用程式是預先載入的具備特殊權限應用程式,則需要 AndroidManifest.xml 中宣告的 READ_PRIVILEGED_PHONE_STATE 權限。應用程式也必須將這項特殊權限加入許可清單。
  • 透過 Google Play 提供的應用程式需要電信業者權限。 如要進一步瞭解如何授予電信業者權限,請參閱「UICC Carrier Privileges」(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。

驗證和測試

相容性測試套件 (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>

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

系統會根據目前插入的 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 的陣列,且值為 1234554321,請將下列項目新增至電信業者設定檔。

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