Redes y telefonía

En las funciones de esta guía, se describen las funciones de administración de redes y telefonía que puedes implementar en tu app del controlador de políticas de dispositivos (DPC). Este documento contiene muestras de código y también puedes usar la app DPC de prueba como fuente de código de muestra para las funciones empresariales de Android.

Una app de DPC puede ejecutarse en modo de propietario de perfil en dispositivos personales o en modo de propietario de dispositivo en dispositivos completamente administrados. En esta tabla, se indica qué funciones están disponibles cuando el DPC se ejecuta en modo de propietario del perfil o modo de propietario del dispositivo:

Función Propietario del perfil Propietario del dispositivo
Cómo acceder a contactos de trabajo en diferentes perfiles
Garantiza una conexión de red segura para el tráfico laboral
Configura un único ID de red inalámbrica entre las regiones
Cómo especificar un marcador independiente para el perfil de trabajo

Accede a los contactos de trabajo en los diferentes perfiles

Los EMM pueden permitir que el perfil personal de un usuario acceda a sus contactos de trabajo para que se pueda acceder a ellos mediante una búsqueda local y una búsqueda en un directorio remoto. En los dispositivos personales, un solo marcador del perfil personal puede realizar y recibir llamadas personales, así como llamadas de trabajo. Además, los contactos de trabajo están bien integrados en la IU del sistema. Si el perfil de trabajo está encriptado, sus datos no están disponibles para el perfil personal.

Integrado con la IU del sistema

La IU del sistema indica las llamadas de trabajo entrantes mediante un ícono de maletín. En el callLog también se muestra el ícono para designar llamadas de trabajo entrantes y salientes. El marcador personal y las apps de contacto pueden mostrar la información del identificador de llamadas de un contacto de trabajo mediante una búsqueda en el directorio remoto, por lo que no es necesario que el contacto ya esté sincronizado en el dispositivo local. La app de mensajería puede realizar búsquedas y el identificador de llamadas locales.

El Documento de definición de compatibilidad de Android (CDD) incluye los requisitos para que los contactos de trabajo se muestren en el marcador predeterminado y los requisitos que exigen que las apps de mensajería y los contactos tengan una insignia para indicar que pertenecen al perfil de trabajo.

Se puede acceder a los contactos de trabajo y buscarlos.

El usuario puede acceder a sus contactos laborales y llamarlos desde su perfil personal, que aparece en la pantalla de búsqueda de la app de Teléfono. El usuario puede buscar contactos laborales (mediante la función de autocompletar) que se sincronicen de forma local con el dispositivo y aparezcan por medio de una búsqueda en el directorio remoto.

Controlar los contactos de trabajo en el perfil principal

El DPC controla el permiso para buscar contactos de trabajo. Si se ejecuta en el modo de propietario del perfil, el DPC administra la visibilidad de los contactos de trabajo en el perfil personal. Para obtener más información, consulta Cómo compilar un controlador de política de dispositivo.

La búsqueda de contactos laborales por medio del perfil personal está habilitada de forma predeterminada.

Asegúrate de que la conexión de red sea segura para el tráfico laboral

Cuando se ejecuta en modo de propietario de dispositivo o de propietario de perfil, un controlador de política de dispositivo puede usar una conexión de red privada virtual (VPN) siempre activa para forzar a las aplicaciones a pasar el tráfico a través de una app VPN específica que no se puede omitir. Con una conexión de VPN siempre activa, el DPC puede garantizar que el tráfico de red de un perfil de trabajo o un dispositivo administrado pase por un servicio de VPN y sin intervención del usuario. Este proceso crea una conexión de red segura para el tráfico continuo dentro de un perfil de trabajo.

Información acerca de las conexiones VPN siempre activas

Como parte del framework del sistema, el enrutamiento de VPN se administra automáticamente para que el usuario no pueda omitir el servicio de VPN. Si el servicio de VPN se desconecta en el modo de bloqueo, el tráfico no puede filtrarse a la Internet abierta. En el caso de las aplicaciones que implementan VpnService, la VPN siempre activa proporciona un framework para administrar y mantener una conexión de VPN segura a través de un servidor de confianza. El servicio de VPN reinicia automáticamente la conexión entre las actualizaciones de la app, sin importar si la conexión es mediante Wi-Fi o una red móvil. Y si se reinicia el dispositivo, el framework reinicia la conexión VPN.

La conexión al servicio de VPN es transparente para el usuario. En el caso de un dispositivo empresarial, no es necesario que el usuario confirme un cuadro de diálogo de consentimiento para una VPN en el modo siempre activa. La configuración de red VPN del usuario permite habilitar una conexión siempre activa de forma manual.

Si DISALLOW_CONFIG_VPN es true, el usuario no puede configurar la VPN. Habilita DISALLOW_DEBUGGING_FEATURES para evitar que los usuarios anulen la VPN siempre activa mediante el comando de depuración adb. Para evitar que un usuario desinstale la VPN, llama a DevicePolicyManager.setUninstallBlocked.

Configura el servicio de VPN

La organización que usa tu solución empresarial para Android configura la VPN.

  1. Instala una app de VPN que implemente VpnService. Puedes encontrar servicios de VPN activos mediante un filtro de intents que coincida con la acción VpnService.SERVICE_INTERFACE.
  2. Declara un VpnService en el manifiesto de la app protegido por el permiso BIND_VPN_SERVICE.
  3. Configura el VpnService de modo que el sistema lo inicie. Para evitar configurar la app de VPN para que se inicie, detecta el inicio del sistema y controla su propio ciclo de vida.
  4. Establece las configuraciones administradas para la app de VPN (consulta ejemplo a continuación).

Cómo habilitar la conexión de VPN siempre activa

El DPC puede configurar una conexión de VPN siempre activa a través de una app específica llamando a DevicePolicyManager.setAlwaysOnVpnPackage().

Esta conexión se otorga automáticamente y persiste después de un reinicio. Si lockdownEnabled es falso, es posible que el tráfico de red no esté protegido desde el momento en que se reinicia el teléfono y se conecta la VPN. Esto es útil si no deseas detener la conectividad de red cuando la VPN falla o si la VPN no es esencial.

Verifica la conexión de VPN siempre activa

El DPC puede leer el nombre del paquete que administra una conexión de VPN siempre activa para el usuario actual con DevicePolicyManager.getAlwaysOnVpnPackage()..

Si no existe ese paquete o si la VPN se creó en la app de Configuración del sistema, se muestra null.

Ejemplo

En la app TestDPC, AlwaysOnVpnFragment.java usa estas APIs para habilitar el parámetro de configuración de una conexión de VPN siempre activa.

En el siguiente ejemplo:

  • DevicePolicyManager establece las configuraciones administradas del servicio de VPN con su método setApplicationRestrictions().
  • Las configuraciones administradas usan pares clave-valor arbitrarios y esta app de ejemplo los usa en otro lugar para establecer la configuración de red de la VPN (consulta Verifica las configuraciones administradas).
  • En el ejemplo, se agrega el instalador del paquete de Android a una lista de bloqueo para que no se actualicen los paquetes del sistema a través de la VPN. Todo el tráfico de red del usuario dentro del perfil de trabajo o dispositivo pasa por esta app de VPN, excepto el instalador del paquete; sus actualizaciones usan la Internet abierta.
  • Luego, DevicePolicyManager habilita la conexión de VPN siempre activa para el paquete de VPN mediante setAlwaysOnVpnPackage() y habilita el modo de bloqueo.

Kotlin

// Set VPN's managed configurations
val config = Bundle().apply {
  putString(Extras.VpnApp.ADDRESS, "192.0.2.0")
  putString(Extras.VpnApp.IDENTITY, "vpn.account1")
  putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate")
  putStringArray(Extras.VpnApp.DENYLIST,
        arrayOf("com.android.packageinstaller"))
}

val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager

val admin = myDeviceAdminReceiver.getComponentName(this)

// Name of package to update managed configurations
val vpnPackageName = "com.example.vpnservice"

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config)

// Enable always-on VPN connection through VPN package
try {
  val lockdownEnabled = true
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled)
} catch (ex: Exception) {
  throw PolicyException()
}

Java

// Set VPN's managed configurations
final Bundle config = new Bundle();
config.putString(Extras.VpnApp.ADDRESS, "192.0.2.0");
config.putString(Extras.VpnApp.IDENTITY, "vpn.account1");
config.putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate");
config.putStringArray(Extras.VpnApp.DENYLIST,
                      new String[]{"com.android.packageinstaller"});

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

ComponentName admin = myDeviceAdminReceiver.getComponentName(this);

// Name of package to update managed configurations
final String vpnPackageName = "com.example.vpnservice";

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config);

// Enable always-on VPN connection through VPN package
try {
  boolean lockdownEnabled = true;
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled));
} catch (Exception ex) {
  throw new PolicyException(...);
}

Cómo configurar un único ID de red inalámbrica entre las regiones

Cuando se ejecuta en modo de propietario de dispositivo o de propietario de perfil, un controlador de política del dispositivo (DPC) puede asociar varios certificados de autoridades certificadoras (CA) con una sola configuración de red inalámbrica. Con esta configuración, un dispositivo puede conectarse a puntos de acceso inalámbricos que tienen el mismo nombre de red o un identificador de conjunto de servicios (SSID), pero que están configurados con diferentes certificados de CA. Esto es útil si las redes inalámbricas de tu organización se encuentran en varias regiones geográficas y cada región requiere una autoridad certificadora diferente. Por ejemplo, las firmas legales pueden requerir una autoridad local que necesite una CA regional.

Nota: Android admite setCaCertificate desde la API 18 (Jelly Bean), pero los administradores de TI deben aprovisionar sus redes por separado con cada CA para garantizar que los dispositivos tengan una autenticación sin interrupciones en cada punto de acceso, independientemente de su región.

Especifica Certificados de CA para identificar el servidor

Para especificar una lista de certificados X.509 que identifiquen el servidor con el mismo SSID, incluye todas las CA relevantes en la configuración inalámbrica mediante WifiEnterpriseConfig.setCaCertificates().

El certificado de un servidor es válido si su CA coincide con uno de los certificados. Los nombres predeterminados se asignan automáticamente a los certificados y se usan dentro de la configuración. El WifiManager instala el certificado, guarda la configuración de forma automática cuando la red está habilitada y quita el certificado cuando se borra la configuración.

Si quieres obtener todos los certificados de la AC asociados con la configuración inalámbrica, usa WifiEnterpriseConfig.getCaCertificates() para mostrar una lista de objetos X509Certificate.

Agrega una configuración inalámbrica mediante varios certificados de CA

  1. Verifica la identidad del servidor:
    1. Carga los certificados de la AC X.509.
    2. Carga la clave privada y el certificado del cliente. Consulta Seguridad con HTTPS y SSL para ver un ejemplo de cómo leer un archivo de certificado.
  2. Crea un nuevo WifiConfiguration y configura su SSID y administración de claves.
  3. Configura la instancia WifiEnterpriseConfig en este WifiConfiguration.
    1. Identifica el servidor con una lista de objetos X509Certificate mediante setCaCertificates().
    2. Configura las credenciales del cliente, la identidad y la contraseña.
    3. Configura el protocolo de autenticación extensible (EAP) y el método de la fase 2 como parte del establecimiento de la conexión.
  4. Agrega la red con WifiManager.
  5. Habilita la red. WifiManager guarda automáticamente la configuración durante el proceso.

En este ejemplo, se unen los pasos:

Kotlin

// Verify the server's identity
val caCert0 = getCaCert("cert0.crt")
val caCert1 = getCaCert("cert1.crt")
val clientKey = getClientKey()
val clientCert = getClientCert()

// Create Wi-Fi configuration
val wifiConfig = WifiConfiguration().apply {
  SSID = "mynetwork"
  allowedKeyManagement.set(KeyMgmt.WPA_EAP)
  allowedKeyManagement.set(KeyMgmt.IEEE8021X)

  // Set up Wi-Fi enterprise configuration
  enterpriseConfig.setCaCertificates(arrayOf<X509Certificate>(caCert0, caCert1))
  enterpriseConfig.setClientKeyEntry(clientKey, clientCert)
  enterpriseConfig.setIdentity("myusername")
  enterpriseConfig.setEapMethod(Eap.TLS)
  enterpriseConfig.setPhase2Method(Phase2.NONE)
}


// Add network
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val netId = wifiManager.addNetwork(wifiConfig)

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true)
}

Java

// Verify the server's identity
X509Certificate caCert0 = getCaCert("cert0.crt");
X509Certificate caCert1 = getCaCert("cert1.crt");
PrivateKey clientKey = getClientKey();
X509Certificate clientCert = getClientCert();

// Create Wi-Fi configuration
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "mynetwork";
wifiConfig.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
wifiConfig.allowedKeyManagement.set(KeyMgmt.IEEE8021X);

// Set up Wi-Fi enterprise configuration
wifiConfig.enterpriseConfig.setCaCertificates(new X509Certificate[] {caCert0, caCert1});
wifiConfig.enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
wifiConfig.enterpriseConfig.setIdentity("myusername");
wifiConfig.enterpriseConfig.setEapMethod(Eap.TLS);
wifiConfig.enterpriseConfig.setPhase2Method(Phase2.NONE);

// Add network
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
int netId = wifiManager.addNetwork(wifiConfig);

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true);
}

Cómo especificar otro marcador para el perfil de trabajo

Puedes incluir una aplicación de marcador en la lista de entidades permitidas para usar en un perfil de trabajo. Puede ser el marcador o una app de voz sobre IP (VoIP) que implemente la API de ConnectionService para el backend que realiza la llamada. Esto proporciona la misma experiencia de marcación de la IU del sistema integrado a las aplicaciones VoIP en el perfil de trabajo, lo que convierte al marcador de trabajo en una función principal. Las llamadas entrantes a las cuentas de llamadas de trabajo se diferencian de las llamadas entrantes a las cuentas de llamadas personales.

El usuario puede elegir realizar y recibir llamadas desde el marcador del trabajo incluido en la lista de entidades permitidas en una cuenta telefónica. Todas las llamadas realizadas desde ese marcador, o entrantes en la cuenta de teléfono de trabajo, se registran en el proveedor CallLog del perfil de trabajo. Este mantiene un registro de llamadas de trabajo únicamente con acceso únicamente a los contactos laborales. El marcador principal controla las llamadas entrantes de cambio de circuito y las almacena en un registro de llamadas personal. Si se borra un perfil de trabajo, también se borrará el registro de llamadas asociado con ese perfil de trabajo, al igual que todos los datos del perfil de trabajo.

Las apps de terceros deben implementar ConnectionService.

Las apps de VoIP de terceros que necesitan hacer llamadas telefónicas y que las tienen integradas en la app para teléfonos integrada pueden implementar la API de ConnectionService. Esto es obligatorio para todos los servicios de VoIP que se usan para las llamadas de trabajo. Estas apps se benefician porque sus llamadas se tratan como llamadas móviles tradicionales; por ejemplo, aparecen en el marcador del sistema integrado y en el registro de llamadas. Si la app que implementa ConnectionService está instalada en el perfil de trabajo, solo se podrá acceder a ella mediante un marcador que también esté instalado en ese perfil de trabajo.

Una vez que el desarrollador haya implementado ConnectionService, deberá agregarlo al archivo de manifiesto de la app y registrar un PhoneAccount con la TelecomManager. Una cuenta de teléfono representa un método distinto para realizar o recibir llamadas telefónicas, y puede haber varios PhoneAccounts para cada ConnectionService. Una vez que se registra la cuenta telefónica, el usuario puede habilitarla mediante la configuración del marcador.

Integración y notificaciones de la IU del sistema

La IU del sistema proporciona a los usuarios una experiencia de marcación integrada y coherente para apps de terceros que usan la API de ConnectionService como backend para realizar llamadas. Si usas la app en un perfil de trabajo, se mostrará un ícono de maletín en las llamadas entrantes y en la barra de estado. Una app que implementa ConnectionService instalada en el perfil de trabajo puede usar el marcador del sistema o compilar uno independiente. Pueden ser una sola app o apps separadas.

Para determinar si está realizando o recibiendo una llamada de trabajo, la aplicación de Teléfono verifica la marca android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL. Si se trata de una llamada laboral, el teléfono se lo indicará al usuario agregando una insignia de trabajo (el ícono de maletín):

Kotlin

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
val call = getCurrentCall()
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}

Java

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
Call call = getCurrentCall();
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}