В Android 10 изменены разрешения для идентификаторов устройств. Теперь все идентификаторы устройств защищены разрешением READ_PRIVILEGED_PHONE_STATE. До Android 10 постоянные идентификаторы устройств (IMEI/MEID, IMSI, SIM и серийный номер сборки) были защищены динамическим разрешением READ_PHONE_STATE.
Разрешение READ_PRIVILEGED_PHONE_STATE предоставляется только приложениям, подписанным ключом платформы, и привилегированным системным приложениям.
Дополнительную информацию о новых требованиях к разрешениям можно найти на страницах Javadoc для TelephonyManager.java и Build.java.
Это изменение затрагивает следующие 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-карты, выпущенные операторами мобильной связи), не могут добавлять или обновлять сертификаты на SIM-картах. |
| Добавление OEM в белый список | Производители оригинального оборудования могут использовать OP_READ_DEVICE_IDENTIFIER, чтобы предоставлять идентификаторы устройств приложениям операторов из белого списка. |
Это решение не подходит для всех операторов. |
| Код распределения типов (TAC) | Используйте метод getTypeAllocationCode, представленный в Android 10, чтобы получить TAC, который возвращает информацию о производителе и модели. |
Информация в TAC недостаточна для идентификации определенного устройства. |
| MSISDN | Операторы могут использовать номер телефона (MSISDN), доступный в разделе TelephonyManager с группой разрешений PHONE, чтобы найти IMEI в своих внутренних системах. |
Это требует значительных инвестиций со стороны операторов. Операторам, которые сопоставляют ключи сети с помощью IMSI, требуются значительные технические ресурсы, чтобы перейти на MSISDN. |
Все приложения операторов могут получить доступ к идентификаторам устройств, обновив файл CarrierConfig.xml с помощью хеша сертификата для подписи приложения оператора. Когда приложение оператора вызывает метод для чтения привилегированной информации, платформа ищет совпадение хеша сертификата для подписи приложения (подпись SHA-1 или SHA-256 сертификата) в файле CarrierConfig.xml. Если совпадение найдено, возвращается запрошенная информация. Если совпадение не найдено, возвращается исключение безопасности.
Чтобы реализовать это решение, операторы связи должны выполнить следующие действия:
- Обновите элемент
CarrierConfig.xml, указав хеш сертификата подписи приложения оператора, и отправьте исправление. - Попросите OEM-производителей обновить сборку до QPR-1 или более поздней версии (рекомендуется) ИЛИ установить необходимые исправления платформы и исправление, содержащее обновленный файл
CarrierConfig.xmlиз шага 1.
Реализация
Обновите белый список разрешений с повышенными привилегиями, чтобы предоставить разрешение READ_PRIVILEGED_PHONE_STATE приложениям с повышенными привилегиями, которым требуется доступ к идентификаторам устройств.
Чтобы узнать больше о белых списках, ознакомьтесь со статьей Белые списки разрешений с повышенными привилегиями.
Чтобы вызвать затронутые API, приложение должно соответствовать одному из следующих требований:
- Если приложение является предустановленным привилегированным приложением, в файле AndroidManifest.xml должна быть объявлена декларация разрешения
READ_PRIVILEGED_PHONE_STATE. Приложение также должно добавить это привилегированное разрешение в белый список. - Приложениям, распространяемым через Google Play, требуются права оператора. Подробнее о том, как предоставить оператору связи права на UICC…
- Приложение владельца устройства или профиля, которому предоставлено разрешение
READ_PHONE_STATE.
Если приложение не соответствует ни одному из этих требований, оно будет работать следующим образом:
- Если приложение предназначено для версий ОС до Q и у него нет разрешения
READ_PHONE_STATE, то вызываетсяSecurityException. Это поведение характерно для версий ОС до Q, поскольку для вызова этих API требуется указанное разрешение. - Если приложение предназначено для версий до Q и имеет разрешение
READ_PHONE_STATE, оно получает нулевое значение для всех API TelephonyManager иBuild.UNKNOWNдля методаBuild#getSerial. - Если приложение предназначено для Android 10 или более поздней версии и не соответствует хотя бы одному из новых требований, оно получит исключение SecurityException.
Проверка и тестирование
Набор тестов на совместимость (CTS) включает тесты, которые позволяют проверить, как приложения с привилегиями оператора, владельца устройства и профиля, а также приложения, которые не должны иметь доступ к идентификаторам устройства, получают доступ к идентификаторам устройства.
Для этой функции предусмотрены следующие тесты 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 в CarrierConfig.xml нужно использовать, чтобы приложение попало в белый список?
Используйте следующий элемент конфигурации верхнего уровня в определенном файле CarrierConfig.xml из вариантов AOSP, которые вы настраиваете:
<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-карту оператора в устройство, чтобы получить доступ к его идентификаторам?
Используемая CarrierConfig.xml определяется в зависимости от того, какая SIM-карта вставлена в устройство. Это означает, что если приложение оператора X попытается получить права доступа, когда в устройство вставлена SIM-карта оператора Y, устройство не найдет совпадения для хеша и вернет исключение безопасности.
На устройствах с несколькими SIM-картами оператор 1 имеет доступ только к SIM-карте 1, и наоборот.
Как операторы связи преобразуют сертификат подписи приложения в хеш?
Чтобы преобразовать сертификаты подписи в хеш перед добавлением в CarrierConfig.xml, выполните следующие действия:
- Преобразуйте подпись сертификата в массив байтов, используя
toByteArray. - Используйте
MessageDigest, чтобы преобразовать массив байтов в хеш типа 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>