Идентификаторы устройства

В 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. Если совпадение найдено, возвращается запрошенная информация. Если совпадение не найдено, возвращается исключение безопасности.

Чтобы реализовать это решение, операторы связи должны выполнить следующие действия:

  1. Обновите элемент CarrierConfig.xml, указав хеш сертификата подписи приложения оператора, и отправьте исправление.
  2. Попросите 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.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

Часто задаваемые вопросы

Сколько приложений можно добавить в белый список в 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, выполните следующие действия:

  1. Преобразуйте подпись сертификата в массив байтов, используя toByteArray.
  2. Используйте MessageDigest, чтобы преобразовать массив байтов в хеш типа byte[].
  3. Преобразуйте хеш из массива байтов в шестнадцатеричную строку. Пример: 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 со значениями 12345 и 54321, добавьте в файл конфигурации оператора следующий код:

    <string-array name="carrier_certificate_string_array" num="2">
        <item value="12345"/>
        <item value="54321"/>
    </string-array>