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 簽章)。如果找到相符項目,系統就會傳回要求的資訊。如果找不到相符項目,系統會傳回安全性例外狀況。
如要實作這項解決方案,電信業者「必須」按照下列步驟操作:
- 更新
CarrierConfig.xml,加入電信業者應用程式的簽署憑證雜湊,然後提交修補程式。 - 請要求原始設備製造商 (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.CarrierApiTestcts-tradefed run cts -m CtsTelephonyTestCases -t android.telephony.cts.TelephonyManagerTestcts-tradefed run cts -m CtsTelephony3TestCasescts-tradefed run cts -m CtsPermissionTestCases -t android.permission.cts.TelephonyManagerPermissionTestcts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifierscts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCanGetDeviceIdentifierscts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testProfileOwnerCannotGetDeviceIdentifiersWithoutPermissioncts-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,請按照下列步驟操作:
- 使用
toByteArray,將簽署憑證的簽章轉換為位元組陣列。 - 使用
MessageDigest將位元組陣列轉換為 byte[] 類型的雜湊。 -
將雜湊從 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())); } 如果
certHashes是大小為2的陣列,且值為12345和54321,請將下列內容新增至電信業者設定檔。<string-array name="carrier_certificate_string_array" num="2"> <item value="12345"/> <item value="54321"/> </string-array>