Android 10 changes the permissions for
device identifiers so that all device identifiers are now protected by
the READ_PRIVILEGED_PHONE_STATE
permission. Prior to
Android 10, persistent device identifiers
(IMEI/MEID, IMSI, SIM, and build serial) were protected behind the
READ_PHONE_STATE
runtime permission.
The READ_PRIVILEGED_PHONE_STATE
permission is only
granted to apps signed with the platform key and privileged system apps.
More information for the new permission requirements can be found in the Javadoc pages for TelephonyManager.java and Build.java.
This change affects the following APIs:
- TelephonyManager#getDeviceId
- TelephonyManager#getImei
- TelephonyManager#getMeid
- TelephonyManager#getSimSerialNumber
- TelephonyManager#getSubscriberId
- Build#getSerial
Access for carrier apps without READ_PRIVILEGED_PHONE_STATE permission
Preloaded carrier apps that don't qualify for the
READ_PRIVILEGED_PHONE_STATE
permission can implement one of the options in the table below.
Option | Description | Limitations |
---|---|---|
UICC carrier privileges | The Android platform loads certificates stored on the UICC and grants permission to apps signed by these certificates to make calls to special methods. | Legacy carriers have a large, established SIM population, which isn’t easily updatable. Also, carriers that don't have authoring rights to new SIMs (for example, MVNOs that have SIMs issued from MNOs) can't add or update certificates on the SIMs. |
OEM allowlisting | OEMs can use OP_READ_DEVICE_IDENTIFIER to provide device
identifiers to allowlisted carrier apps. |
This solution isn't scalable for all carriers. |
Type allocation code (TAC) | Use the
getTypeAllocationCode
method, introduced in
Android 10, to expose the TAC that returns the manufacturer and model
info. |
The information in the TAC is inadequate to identify a specific device. |
MSISDN | Carriers can use the phone number (MSISDN), available under
TelephonyManager with the PHONE permission
group, to look up the IMEI on their backend systems. |
This requires significant investment for carriers. Carriers that map their network keys using IMSI require significant technical resources to switch to MSISDN. |
All carrier apps can access device identifiers by updating
the CarrierConfig.xml
file with the signing certificate hash of
the carrier app. When the carrier app calls a method to read privileged
information, the platform looks for a match of the app's signing certificate
hash (SHA-1 or SHA-256 signature of the certificate) in the
CarrierConfig.xml
file. If a match is found, the requested
information is returned. If no match is found, a security exception is
returned.
To implement this solution, carriers MUST follow these steps:
- Update
CarrierConfig.xml
with the signing certificate hash of the carrier app and submit a patch. - Request OEMs to update their build with QPR1+ (recommended) OR these
required platform patches and the patch containing
updated
CarrierConfig.xml
file from step 1 above.
Implementation
Update your privileged permission allowlist to grant the
READ_PRIVILEGED_PHONE_STATE
permission to those privileged
apps that require access to device identifiers.
To learn more about allowlisting, refer to Privileged Permission Allowlisting.
To invoke the affected APIs, an app must meet one of the following requirements:
- If the app is a preloaded privileged app, it needs the
READ_PRIVILEGED_PHONE_STATE
permission declared in AndroidManifest.xml. The app also needs to allowlist this privileged permission. - Apps delivered through Google Play need carrier privileges. Learn more about granting carrier privileges on the UICC Carrier Privileges page.
- A device or profile owner app that has been granted the
READ_PHONE_STATE
permission.
An app that doesn't meet any of these requirements has the following behavior:
- If the app is targeting pre-Q and doesn't have the
READ_PHONE_STATE
permission granted,SecurityException
is triggered. this is the current pre-Q behavior as this permission is required to invoke these APIs. - If the app is targeting pre-Q and does have the
READ_PHONE_STATE
permission granted, it receives a null value for all of the TelephonyManager APIs andBuild.UNKNOWN
for theBuild#getSerial
method. - If the app is targeting Android 10 or higher and doesn't meet any one of the new requirements then it receives a SecurityException.
Validation and testing
The Compatibility Test Suite (CTS) includes tests to verify the expected device identifier access behavior for apps with carrier privileges, device and profile owners, and those apps that are expected to not have access to device identifiers.
The following CTS tests are specific to this feature.
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
FAQs
How many apps can be allowlisted in CarrierConfig.xml
for a given (MCC, MNC)?
There is no limit to the number of certificate hashes included in the array.
Which CarrierConfig parameters in CarrierConfig.xml
do I need to use for an app to be allowlisted?
Use the following top-level configuration item within the specific
CarrierConfig.xml
from the AOSP options you're configuring:
<string-array name="carrier_certificate_string_array" num="2"> <item value="BF02262E5EF59FDD53E57059082F1A7914F284B"/> <item value="9F3868A3E1DD19A5311D511A60CF94D975A344B"/> </string-array>
Is there a base CarrierConfig template I can use?
Use the following template. This should be added to the relevant asset.
<?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>
Does the carrier SIM have to be in the device to access device identifiers?
The CarrierConfig.xml
that is used is determined based on the
SIM that is currently inserted. This means that if carrier X's app tries to
get access privileges while carrier Y's SIM is inserted, the device won't find
a match for the hash and returns a security exception.
On multi-SIM devices, carrier #1 only has access privileges for SIM #1 and vice versa.
How do carriers convert an app's signing certificate to a hash?
To convert signing certificates to a hash before adding them to
CarrierConfig.xml
, do the following:
- Convert the signing certificate's signature to a byte array using
toByteArray
. - Use
MessageDigest
to convert the byte array into a hash in byte[] type. -
Convert the hash from byte[] into a hex string format. For an example, see
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())); }
If
certHashes
is an array of size2
with a value of12345
and54321
, add the following to the carrier config file.<string-array name="carrier_certificate_string_array" num="2"> <item value="12345"/> <item value="54321"/> </string-array>