Identificadores de dispositivos

Android 10 cambia los permisos para los identificadores de dispositivos, de modo que todos los identificadores de dispositivos ahora están protegidos por el permiso READ_PRIVILEGED_PHONE_STATE. Antes de Android 10, los identificadores de dispositivos persistentes (IMEI/MEID, IMSI, SIM y número de serie de la compilación) estaban protegidos por el permiso de tiempo de ejecución READ_PHONE_STATE. El permiso READ_PRIVILEGED_PHONE_STATE solo se otorga a las apps firmadas con la clave de plataforma y a las apps del sistema con privilegios.

Puedes encontrar más información sobre los nuevos requisitos de permisos en las páginas de Javadoc de TelephonyManager.java y Build.java.

Este cambio afecta a las siguientes APIs:

  • TelephonyManager#getDeviceId
  • TelephonyManager#getImei
  • TelephonyManager#getMeid
  • TelephonyManager#getSimSerialNumber
  • TelephonyManager#getSubscriberId
  • Build#getSerial

Acceso para apps de operadores sin el permiso READ_PRIVILEGED_PHONE_STATE

Las apps de operador precargadas que no cumplen con los requisitos para el permiso READ_PRIVILEGED_PHONE_STATE pueden implementar una de las opciones de la siguiente tabla.

Opción Descripción Limitaciones
Privilegios de operador de UICC La plataforma de Android carga los certificados almacenados en la UICC y otorga permiso a las apps firmadas con estos certificados para realizar llamadas a métodos especiales. Los operadores heredados tienen una gran cantidad de SIM establecidas, que no se pueden actualizar fácilmente. Además, los operadores que no tienen derechos de autoría para las SIMs nuevas (por ejemplo, los MVNO que tienen SIMs emitidas por MNO) no pueden agregar ni actualizar certificados en las SIMs.
Inclusión en la lista de entidades permitidas del OEM Los OEM pueden usar OP_READ_DEVICE_IDENTIFIER para proporcionar identificadores de dispositivos a las apps de operadores incluidas en la lista de entidades permitidas. Esta solución no es escalable para todos los operadores.
Código de asignación de tipo (TAC) Usa el método getTypeAllocationCode, que se introdujo en Android 10, para exponer el TAC que devuelve la información del fabricante y el modelo. La información del TAC no es suficiente para identificar un dispositivo específico.
MSISDN Los operadores pueden usar el número de teléfono (MSISDN), disponible en TelephonyManager con el grupo de permisos PHONE, para buscar el IMEI en sus sistemas de backend. Esto requiere una inversión significativa para los operadores. Los operadores que asignan sus claves de red con IMSI requieren recursos técnicos significativos para cambiar a MSISDN.

Todas las apps de proveedores pueden acceder a los identificadores de dispositivos actualizando el archivo CarrierConfig.xml con el hash del certificado de firma de la app del proveedor. Cuando la app del proveedor llama a un método para leer información privilegiada, la plataforma busca una coincidencia del hash del certificado de firma de la app (firma SHA-1 o SHA-256 del certificado) en el archivo CarrierConfig.xml. Si se encuentra una coincidencia, se devuelve la información solicitada. Si no se encuentra ninguna coincidencia, se devuelve una excepción de seguridad.

Para implementar esta solución, las empresas de telefonía celular DEBEN seguir estos pasos:

  1. Actualiza CarrierConfig.xml con el hash del certificado de firma de la app del operador y envía un parche.
  2. Solicita a los OEM que actualicen su compilación con QPR-1 o una versión posterior (recomendado) O bien con estos parches de plataforma obligatorios y el parche que contiene el archivo CarrierConfig.xml actualizado del paso 1 anterior.

Implementación

Actualiza tu lista de entidades permitidas de permisos con privilegios para otorgar el permiso READ_PRIVILEGED_PHONE_STATE a las apps con privilegios que requieran acceso a los identificadores de dispositivos.

Para obtener más información sobre las listas de entidades permitidas, consulta Lista de entidades permitidas con permisos privilegiados.

Para invocar las APIs afectadas, una app debe cumplir con uno de los siguientes requisitos:

  • Si la app es una app privilegiada cargada previamente, necesita la declaración de permisos READ_PRIVILEGED_PHONE_STATE declarada en AndroidManifest.xml. La app también debe incluir este permiso privilegiado en la lista de entidades permitidas.
  • Las apps que se entregan a través de Google Play necesitan privilegios de operador. Obtén más información para otorgar privilegios de operador en la página UICC Carrier Privileges.
  • Una app de propietario de dispositivo o perfil a la que se le otorgó el permiso READ_PHONE_STATE

Una app que no cumple con ninguno de estos requisitos tiene el siguiente comportamiento:

  • Si la app segmenta versiones anteriores a Android Q y no tiene el permiso READ_PHONE_STATE otorgado, se activa SecurityException. Este es el comportamiento actual de las versiones anteriores a Android Q, ya que se requiere este permiso para invocar estas APIs.
  • Si la app se orienta a una versión anterior a Q y tiene otorgado el permiso READ_PHONE_STATE, recibe un valor nulo para todas las APIs de TelephonyManager y Build.UNKNOWN para el método Build#getSerial.
  • Si la app se orienta a Android 10 o versiones posteriores y no cumple con ninguno de los nuevos requisitos, recibirá una SecurityException.

Validación y prueba

El conjunto de pruebas de compatibilidad (CTS) incluye pruebas para verificar el comportamiento esperado de acceso a los identificadores de dispositivos para las apps con privilegios de operador, los propietarios de dispositivos y perfiles, y las apps que se espera que no tengan acceso a los identificadores de dispositivos.

Las siguientes pruebas del CTS son específicas de esta función.

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

Preguntas frecuentes

¿Cuántas apps se pueden incluir en la lista de entidades permitidas en CarrierConfig.xml para un par (MCC, MNC) determinado?

No hay límite para la cantidad de hashes de certificados incluidos en el array.

¿Qué parámetros de CarrierConfig en CarrierConfig.xml debo usar para que una app se incluya en la lista de entidades permitidas?

Usa el siguiente elemento de configuración de nivel superior dentro del CarrierConfig.xml específico de las opciones de AOSP que estás configurando:

<string-array name="carrier_certificate_string_array" num="2">
    <item value="BF02262E5EF59FDD53E57059082F1A7914F284B"/>
    <item value="9F3868A3E1DD19A5311D511A60CF94D975A344B"/>
</string-array>

¿Hay una plantilla base de CarrierConfig que pueda usar?

Usa la siguiente plantilla. Esto se debe agregar al recurso pertinente.

<?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>

¿La tarjeta SIM del operador debe estar en el dispositivo para acceder a los identificadores del dispositivo?

El CarrierConfig.xml que se usa se determina según la SIM que está insertada. Esto significa que, si la app del operador X intenta obtener privilegios de acceso mientras se inserta la SIM del operador Y, el dispositivo no encontrará una coincidencia para el hash y devolverá una excepción de seguridad.

En los dispositivos con varias SIM, el operador 1 solo tiene privilegios de acceso para la SIM 1 y viceversa.

¿Cómo convierten los operadores el certificado de firma de una app en un hash?

Para convertir los certificados de firma en un hash antes de agregarlos a CarrierConfig.xml, haz lo siguiente:

  1. Convierte la firma del certificado de firma en un array de bytes con toByteArray.
  2. Usa MessageDigest para convertir el array de bytes en un hash de tipo byte[].
  3. Convierte el hash de byte[] en un formato de cadena hexadecimal. Para ver un ejemplo, consulta 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. Si certHashes es un array de tamaño 2 con un valor de 12345 y 54321, agrega lo siguiente al archivo de configuración del operador.

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