Compatibilidad con el modo de inicio directo

Android 7.0 se ejecuta en un modo de inicio directo seguro cuando el dispositivo está encendido, pero el usuario no lo desbloqueó. Para permitir esto, el sistema brinda dos ubicaciones de almacenamiento para los datos:

  • Almacenamiento encriptado por credenciales, que es la ubicación de almacenamiento predeterminada y solo está disponible después de que el usuario desbloquea el dispositivo.
  • Almacenamiento encriptado por dispositivo, que es una ubicación de almacenamiento disponible tanto durante el modo de inicio directo como después de que el usuario desbloquea el dispositivo.

De forma predeterminada, las apps no se ejecutan durante el modo de inicio directo. Si necesitas que tu app se ejecute durante ese modo, registra los componentes que deberían hacerlo. Entre algunos de los casos comunes de apps que necesitan ejecutarse durante el modo de inicio directo, se incluyen los siguientes:

  • Apps que tienen notificaciones programadas, como las de alarma.
  • Apps que proporcionan notificaciones importantes al usuario, como las de mensajes SMS.
  • Apps que brindan servicios de accesibilidad, como TalkBack.

Si necesitas que tu app acceda a datos mientras se ejecuta el modo de inicio directo, usa el almacenamiento que encripta el dispositivo. Este tipo de almacenamiento contiene datos encriptados con una clave que solo está disponible luego de que el dispositivo realiza un inicio verificado.

En el caso de los datos que se deben encriptar a través de una clave asociada con las credenciales del usuario, como un PIN o una contraseña, usa el almacenamiento encriptado con credenciales. El almacenamiento encriptado con credenciales está disponible después de que el usuario desbloquea correctamente el dispositivo y hasta que lo reinicia. Si el usuario habilita la pantalla de bloqueo después de desbloquear el dispositivo, el almacenamiento encriptado a través de credenciales seguirá disponible.

Cómo solicitar acceso de ejecución durante el inicio directo

Debes registrar los componentes de las apps en el sistema para que estas puedan ejecutarse durante el modo de inicio directo o acceder al almacenamiento encriptado por el dispositivo. Para registrar una app en el sistema, debes marcar los componentes como con reconocimiento de encriptación. Para marcar tu componente como con reconocimiento de encriptación, configura el atributo android:directBootAware como verdadero en el manifiesto.

Los componentes con reconocimiento de encriptación pueden registrarse para recibir un mensaje de transmisión ACTION_LOCKED_BOOT_COMPLETED del sistema cuando se reinicia el dispositivo. En este punto, ya está disponible el almacenamiento encriptado por dispositivo, y el componente puede realizar tareas que se deben ejecutar durante el modo de inicio directo, como activar una alarma programada.

El siguiente fragmento de código es un ejemplo de cómo registrar un BroadcastReceiver como con reconocimiento de encriptación y de cómo agregar un filtro de intents para ACTION_LOCKED_BOOT_COMPLETED en el manifiesto de la app:

<receiver
  android:directBootAware="true" >
  ...
  <intent-filter>
    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
  </intent-filter>
</receiver>

Una vez que el usuario haya desbloqueado el dispositivo, todos los componentes podrán acceder tanto al almacenamiento encriptado por dispositivo como al almacenamiento encriptado por credenciales.

Cómo acceder al almacenamiento encriptado por dispositivo

Para acceder al almacenamiento encriptado por dispositivo, llama a Context.createDeviceProtectedStorageContext() para crear una segunda instancia de Context. Todas las llamadas a las APIs de almacenamiento realizadas usando este contexto acceden al almacenamiento encriptado por dispositivo. En el siguiente ejemplo, se accede al almacenamiento encriptado por dispositivo y se abre un archivo de datos de la app existente:

Kotlin

val directBootContext: Context = appContext.createDeviceProtectedStorageContext()
// Access appDataFilename that lives in device encrypted storage
val inStream: InputStream = directBootContext.openFileInput(appDataFilename)
// Use inStream to read content...

Java

Context directBootContext = appContext.createDeviceProtectedStorageContext();
// Access appDataFilename that lives in device encrypted storage
FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
// Use inStream to read content...

Usa el almacenamiento encriptado por dispositivo solo para información a la que se deba poder acceder durante el modo de inicio directo. No lo uses como almacenamiento de propósito general. En el caso de la información privada del usuario o de los datos encriptados que no sean necesarios durante el modo de inicio directo, usa el almacenamiento encriptado con credenciales.

Cómo recibir notificaciones sobre el desbloqueo del usuario

Una vez que el usuario desbloquee el dispositivo después del reinicio, tu app podrá cambiar a la opción de acceder al almacenamiento encriptado por credenciales y usar los servicios comunes del sistema que dependen de credenciales del usuario.

Si quieres recibir una notificación cuando el usuario desbloquee el dispositivo luego de reiniciarlo, registra un BroadcastReceiver de un componente en ejecución para detectar mensajes de notificación de desbloqueo. Cuando el usuario desbloquee el dispositivo después del reinicio:

  • Si en tu app hay procesos en primer plano que requieren notificación inmediata, busca el mensaje ACTION_USER_UNLOCKED.
  • Si tu app solo usa procesos en segundo plano que no requieren notificación inmediata, busca el mensaje ACTION_BOOT_COMPLETED.

Si el usuario desbloqueó el dispositivo, puedes llamar a UserManager.isUserUnlocked() para detectarlo.

Cómo migrar datos existentes

Si un usuario actualiza el dispositivo para usar el modo de inicio directo, es posible que haya datos existentes que se deban migrar al almacenamiento encriptado por dispositivo. Usa Context.moveSharedPreferencesFrom() y Context.moveDatabaseFrom(), con el contexto de destino como la llamada del método y el contexto de origen como el argumento, para migrar datos de preferencias y de base de datos del almacenamiento encriptado por credenciales al almacenamiento encriptado por el dispositivo.

No migres información privada del usuario, como contraseñas o tokens de autorización, del almacenamiento encriptado por credenciales al almacenamiento encriptado por el dispositivo. Usa tu mejor criterio cuando decidas qué otros datos migrarás al almacenamiento encriptado por el dispositivo. En algunos casos, es posible que debas gestionar conjuntos separados de datos en ambos tipos de almacenamiento encriptado.

Cómo probar tu app con reconocimiento de encriptación

Prueba tu app con el reconocimiento de encriptación en el modo de inicio directo habilitado.

La mayoría de los dispositivos que ejecutan versiones recientes de Android habilitan el modo de inicio directo cada vez que se establece una credencial de pantalla bloqueada (PIN, patrón o contraseña). En concreto, este es el caso de todos los dispositivos que usan encriptación basada en archivos. Para verificar si un dispositivo usa encriptación basada en archivos, ejecuta el siguiente comando de shell:

adb shell getprop ro.crypto.type

Si el resultado es file, significa que el dispositivo tiene habilitada la encriptación basada en archivos.

En los dispositivos que no usan la encriptación basada en archivos de forma predeterminada, puede haber otras opciones para probar el modo de inicio directo:

  • Algunos dispositivos que usan encriptación de disco completo (ro.crypto.type=block) y ejecutan entre Android 7.0 y Android 12 se pueden convertir a encriptación basada en archivos. Existen dos maneras de hacerlo:

      Advertencia: Cualquiera de los dos métodos para convertir a encriptación basada en archivos borra todos los datos del usuario del dispositivo.

    • En el dispositivo, habilita Opciones para desarrolladores si aún no lo hiciste. Para ello, ve a Configuración > Acerca del teléfono y presiona Número de compilación siete veces. Luego, ve a Configuración > Opciones para desarrolladores y selecciona Convertir a encriptación de archivo.
    • Como alternativa, ejecuta los siguientes comandos de shell:
      adb reboot-bootloader
      fastboot --wipe-and-use-fbe
      
  • Los dispositivos que ejecutan Android 13 o versiones anteriores admiten un modo de inicio directo "emulado" que usa permisos de archivo para simular los efectos del bloqueo y desbloqueo de archivos encriptados. Usa el modo emulado solo durante el desarrollo, ya que puede producir la pérdida de datos. Para habilitar el modo de inicio directo emulado, debes establecer un patrón de bloqueo en el dispositivo, elegir "No, gracias" si se te pregunta si deseas un inicio seguro al configurar un patrón de bloqueo y, luego, ejecutar el siguiente comando de shell:

    adb shell sm set-emulate-fbe true
    

    Para desactivar el modo de inicio directo emulado, ejecuta el siguiente comando de shell:

    adb shell sm set-emulate-fbe false
    

    Si ejecutas cualquiera de estos comandos, el dispositivo se reinicia.

Cómo comprobar el estado de encriptación de la política de dispositivo

Las apps de administración de dispositivos pueden usar DevicePolicyManager.getStorageEncryptionStatus() para comprobar el estado de encriptación actual del dispositivo.

Si tu app se orienta a un nivel de API inferior a Android 7.0 (nivel de API 24), getStorageEncryptionStatus() devuelve ENCRYPTION_STATUS_ACTIVE si el dispositivo usa encriptación de disco completo o la encriptación basada en archivos en el inicio directo. En ambos casos, los datos se almacenan siempre encriptados en reposo.

Si tu app se orienta a Android 7.0 (nivel de API 24) o versiones posteriores, getStorageEncryptionStatus() devuelve ENCRYPTION_STATUS_ACTIVE si el dispositivo usa encriptación de disco completo. Devuelve ENCRYPTION_STATUS_ACTIVE_PER_USER si el dispositivo usa encriptación basada en archivos con inicio directo.

Si compilas una app de administración de dispositivos dirigida a Android 7.0, asegúrate de buscar ENCRYPTION_STATUS_ACTIVE y ENCRYPTION_STATUS_ACTIVE_PER_USER para determinar si el dispositivo está encriptado.

Muestras de código adicionales

El ejemplo de DirectBoot también muestra cómo usar las APIs que se indican en esta página.