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 卡的著作權 (例如,MVNO 有由 MNO 核發的 SIM 卡),就無法在 SIM 卡上新增或更新憑證。 |
原始設備製造商 (OEM) 許可清單 | 原始設備製造商 (OEM) 可以使用 OP_READ_DEVICE_IDENTIFIER ,為已核准的電信業者應用程式提供裝置 ID。 |
這項解決方案無法適用於所有電信業者。 |
類型分配碼 (TAC) | 使用 Android 10 中推出的 getTypeAllocationCode 方法,公開可傳回製造商和型號資訊的 TAC。 |
TAC 中的資訊不足以識別特定裝置。 |
MSISDN | 電信業者可以使用 TelephonyManager 下方具有 PHONE 權限群組的電話號碼 (MSISDN),在後端系統中查詢 IMEI。 |
這需要電信業者投入大量資金。使用 IMSI 對應網路金鑰的電信業者,需要大量技術資源才能改用 MSISDN。 |
所有電信業者應用程式都可以透過更新 CarrierConfig.xml
檔案,並使用電信業者應用程式的簽署憑證雜湊值,存取裝置 ID。當電信業者應用程式呼叫方法來讀取特權資訊時,平台會在 CarrierConfig.xml
檔案中尋找應用程式的簽署憑證雜湊值 (憑證的 SHA-1 或 SHA-256 簽名) 是否相符。如果找到相符項目,系統會傳回要求的資訊。如果找不到相符項目,系統會傳回安全性例外狀況。
如要實作此解決方案,運營商必須按照下列步驟操作:
- 使用電信業者應用程式的簽署憑證雜湊更新
CarrierConfig.xml
,並提交修補程式。 - 請 OEM 廠商使用 QPR1+ (建議) 或以下必要的平台修補程式更新其版本,以及包含上述步驟 1 中更新
CarrierConfig.xml
檔案的修補程式。
實作
更新特權權限許可清單,將 READ_PRIVILEGED_PHONE_STATE
權限授予需要存取裝置 ID 的特權應用程式。
如要進一步瞭解許可清單,請參閱「特權權限許可清單」。
如要叫用受影響的 API,應用程式必須符合下列任一規定:
- 如果應用程式是預先載入的特權應用程式,就需要在 AndroidManifest.xml 中宣告
READ_PRIVILEGED_PHONE_STATE
權限。應用程式也需要將這項特權權限加入許可清單。 - 透過 Google Play 提供的應用程式需要電信業者特殊權限。 如要進一步瞭解如何授予電信業者權限,請參閱「UICC 電信業者權限」頁面。
- 已授予
READ_PHONE_STATE
權限的裝置或設定檔擁有者應用程式。
不符合任何規定的應用程式會出現以下行為:
- 如果應用程式指定的目標版本為 Q 以下版本,且未獲得
READ_PHONE_STATE
權限,系統就會觸發SecurityException
。這是目前 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
常見問題
在特定 (MCC、MNC) 中,CarrierConfig.xml
可加入許可清單的應用程式數量為何?
陣列中包含的憑證雜湊數量沒有限制。
如要將應用程式加入許可清單,我需要使用 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
。也就是說,如果電信業者 X 的應用程式在插入電信業者 Y 的 SIM 卡時嘗試取得存取權限,裝置就不會找到相符的雜湊值,並傳回安全性例外狀況。
在多 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>