設備標識符

Android 10更改了設備標識符的權限,因此所有設備標識符現在都受到READ_PRIVILEGED_PHONE_STATE權限的保護。在Android 10之前的版本中,持久性設備標識符(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卡創作權限的運營商(例如,具有從MNO發行的SIM卡的MVNO)不能在SIM卡上添加或更新證書。
OEM白名單OEM可以使用OP_READ_DEVICE_IDENTIFIER向列入白名單的運營商應用程序提供設備標識符。此解決方案並非適用於所有運營商。
類型分配代碼(TAC)使用Android 10中引入的getTypeAllocationCode方法來公開返回製造商和型號信息的TAC。 TAC中的信息不足以標識特定設備。
MSISDN運營商可以使用TelephonyManager帶有PHONE權限組的電話號碼(MSISDN)在其後端系統上查找IMEI。這需要對運營商進行大量投資。使用IMSI映射其網絡密鑰的運營商需要大量技術資源才能切換到MSISDN

通過使用運營商應用程序的簽名證書哈希更新CarrierConfig.xml文件,所有運營商應用程序都可以訪問設備標識符。當運營商應用程序調用一種方法來讀取特權信息時,平台將在CarrierConfig.xml文件中查找該應用程序的簽名證書哈希(證書的SHA-1或SHA-256簽名)的匹配項。如果找到匹配項,則返回所請求的信息。如果未找到匹配項,則返回安全異常。

要實施此解決方案,運營商必須遵循以下步驟:

  1. 使用運營商應用程序的簽名證書哈希更新CarrierConfig.xml提交補丁
  2. 要求OEM使用QPR1 +(推薦)或這些必需的平台補丁以及包含上述步驟1中更新的CarrierConfig.xml文件的補丁來更新其內部版本。

執行

更新您的特權許可白名單,以將READ_PRIVILEGED_PHONE_STATE許可授予需要訪問設備標識符的那些特權應用。

要了解有關白名單的更多信息,請參閱特權權限白名單

要調用受影響的API,應用程序必須滿足以下要求之一:

  • 如果該應用程序是預加載的特權應用程序,則需要在AndroidManifest.xml中聲明的READ_PRIVILEGED_PHONE_STATE權限。該應用還需要將該特權許可列入白名單。
  • 通過Google Play交付的應用需要運營商特權。在UICC運營商特權頁面上了解有關授予運營商特權的更多信息。
  • 已被授予READ_PHONE_STATE權限的設備或個人資料所有者應用。

不滿足任何這些要求的應用程序具有以下行為:

  • 如果應用的目標是pre-Q,並且沒有授予READ_PHONE_STATE權限,則會觸發SecurityException 。這是當前的pre-Q行為,因為調用這些API需要此權限。
  • 如果該應用程序以Pre-Q為目標並且確實具有READ_PHONE_STATE權限,則它會為所有TelephonyManager API和Build#getSerial方法的Build.UNKNOWN接收一個空值。
  • 如果該應用程序定位於Android 10或更高版本,並且不滿足任何新要求,則它將收到SecurityException。

驗證與測試

兼容性測試套件(CTS)包含測試,以驗證具有運營商特權,設備和配置文件所有者的應用程序以及預期無法訪問設備標識符的應用程序的預期設備標識符訪問行為。

以下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是否必須在設備中才能訪問設備標識符?

根據當前插入的SIM卡確定所使用的CarrierConfig.xml 。這意味著,如果運營商X的應用在插入運營商Y的SIM卡時嘗試獲取訪問權限,則該設備將找不到哈希的匹配項並返回安全異常。

在多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>