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 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 la 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 operadores precargadas que no cumplen con los requisitos para obtener el permiso de READ_PRIVILEGED_PHONE_STATE pueden implementar una de las opciones que se indican en 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 por 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 OMV que tienen SIMs emitidas por OMR) no pueden agregar ni actualizar certificados en las SIMs.
Lista de anunciantes permitidos de 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, introducido en Android 10, para exponer el TAC que devuelve la información del fabricante y el modelo. La información del TAC es insuficiente 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 el IMSI requieren recursos técnicos significativos para cambiar al MSISDN.

Todas las apps de operador pueden acceder a los identificadores de dispositivos si actualizan el archivo CarrierConfig.xml con el hash del certificado de firma de la app de operador. Cuando la app de operador 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 muestra 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 QPR1+ (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 anunciantes permitidos con permisos con privilegios para otorgar el permiso de READ_PRIVILEGED_PHONE_STATE a las apps con privilegios que requieran acceso a identificadores de dispositivos.

Para obtener más información sobre las listas de entidades permitidas, consulta Inclusión de permisos con privilegios en la lista de entidades permitidas.

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 el permiso READ_PRIVILEGED_PHONE_STATE declarado 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 del propietario del dispositivo o del 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 está segmentada para 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 segmenta su público para versiones anteriores a Android 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 requisitos nuevos, recibirá una SecurityException.

Validación y pruebas

El conjunto de pruebas de compatibilidad (CTS) incluye pruebas para verificar el comportamiento esperado del acceso al identificador del dispositivo para las apps con privilegios de operador, propietarios del dispositivo y del perfil, y aquellas apps que no deberían tener acceso a los identificadores del dispositivo.

Las siguientes pruebas de 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 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 está insertada 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[] a 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>