[Serie Android Framework] Capítulo 17 Modo Sandbox de Android Q (almacenamiento con alcance)

1. Antecedentes

El capítulo anterior [Serie Android Framework] Capítulo 16 Marco de acceso al almacenamiento (SAF) analizó principalmente el marco de acceso al almacenamiento (SAF) introducido en Android 4.4 存储访问框架(SAF). En este capítulo analizamos Android10(Q)el almacenamiento relacionado y comprendemos sus métodos de almacenamiento restringidos.

GooglePara brindar a los usuarios más control sobre sus archivos y limitar el desorden de archivos, la forma de acceder al almacenamiento de su dispositivo Android Q ha cambiado .App

Antes de 1.1 Android Q

Siempre que el programa obtenga READ_EXTERNAL_STORAGEpermiso, puede leer libremente el directorio público del almacenamiento externo;
siempre que el programa obtenga WRITE_EXTERNAL_STORAGEpermiso, puede crear libremente nuevos archivos o carpetas en el directorio público escrito en el almacenamiento externo.
Insertar descripción de la imagen aquí

1.2 Android Q y posteriores

Así lo propuso Google en Android Q 分区存储, con la intención de limitar el uso de directorios públicos en almacenamiento externo por parte de los programas .
El almacenamiento particionado no tiene ningún impacto ni en los directorios privados de almacenamiento interno ni en los directorios privados de almacenamiento externo.
Insertar descripción de la imagen aquí

2 modo caja de arena

2.1 Android Q estipula que la aplicación tiene dos vistas de modo de espacio de almacenamiento: Vista heredada y Vista filtrada.

2.1.1 Vista heredada (modo de compatibilidad)

Cuando el proyecto targetSdkVersion <= 28, el modo de compatibilidad se usa de forma predeterminada en el dispositivo AndroidQ, el método de almacenamiento es el mismo que Android Qantes Appy el acceso Sdcardes completo, con permisos de acceso completos.

2.1.2 Vista filtrada (modo sandbox)

Cuando el proyecto targetSdkVersion> 28, el dispositivo AndroidQ Appsolo puede acceder directamente App-specifica los archivos del directorio y no tiene permiso para acceder App-specifica archivos externos. El acceso a otros directorios sólo se puede proporcionar a través de MediaStore, SAFu otras aplicaciones ContentProvider.

2.2 Scoped Storage divide el espacio de almacenamiento en dos partes

2.2.1 Directorio público de la tarjeta SD: Descargas, Documentos, Imágenes, DCIM, Películas, Música, Tonos de llamada

  1. Los archivos en el directorio público Appno se eliminarán después de la desinstalación
  2. Se puede acceder a través de SAFla MediaStoreinterfaz.

2.2…2 datos/directorio privado de datos (directorio específico de la aplicación)

  1. Para Filtered View App, App-specificsolo usted puede acceder directamente al directorio
  2. AppDesinstale y los datos se borrarán.

2.3 Impacto de la compatibilidad

Scoped StorageTiene un gran impacto en App访问存储方式y App数据存放.App间数据共享

2.4 Adaptación

Para una adaptación específica, consulte la documentación oficial.

2.4.1 Vista de aplicación en ejecución

El sistema determina el modo de ejecución de la aplicación mediante lo siguiente:

  1. App TargetSDK > 28,por defectoFiltered View(沙箱模式)
  1. App TargetSDK <= 28, declara el permiso READ_EXTERNAL_STORAGE o WRITE_EXTERNAL_STORAGE, predeterminadoLegacy View(兼容模式)
  1. La aplicación puede configurar requestLegacyExternalStorage a través de AndroidManifest.xml y seleccionar el método correspondiente:
    declarado READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGEpermiso (ignorado si no declarado):
    requestLegacyExternalStorage=truesignificaLegacy View(兼容模式)
    requestLegacyExternalStorage=falseFiltered View(沙箱模式)
    (注意:该方式Android11后失效了)

    Insertar descripción de la imagen aquí
  1. Las aplicaciones del sistema pueden solicitar android.permission.WRITE_MEDIA_STORAGEpermisos del sistema y también tener permisos completos de espacio de almacenamiento y pueden acceder a todos los archivos. Sin embargo, en la prueba CTS, solo pueden postularse las aplicaciones que no tienen interacción con el usuario y son visibles. Referencia específica 《Android Bootcamp 2019 - Privacy Overview.pdf》.
  1. La aplicación es propiedad cuando se cumplen las siguientes condiciones
    : ① Declaración INSTALL_PACKAGESo 动态申请INSTALL_PACKAGESpermiso
    ② Propiedad WRITE_EXTERNAL_STORAGE权限
    ③ Propiedad de la aplicación 外置存储空间Read、Write权限.
    Sin embargo, Environment.isExternalStorageLegacya juzgar por la interfaz, la devolución no es necesariamente una Vista heredada.

2.4.2 Determinar el modo de ejecución actual de la aplicación

Para determinar en qué modo se está ejecutando la aplicación actual, puede utilizar esta API para determinar:

Environment.isExternalStorageLegacy();

2.5 Lectura y redacción de directorios públicos

Una vez iniciada la aplicación Filtered View, solo puede acceder a sí misma directamente App-specific目录, por lo que Android Qse proporcionan dos métodos para acceder al directorio público:

2.5.1 Uri definido por MediaStore

MediaStoreSe proporcionan los siguientes tipos de acceso Uri, y el propósito del acceso se logra mediante la búsqueda de los datos Uri correspondientes.
Cada uno de los siguientes tipos se divide en tres tipos Uri, Internal, External, 可移动存储:

Audio

  1. Interno: MediaStore.Audio.Media.INTERNAL_CONTENT_URI
    contenido://media/internal/audio/media。
  2. Externo: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    contenido://media/external/audio/media。
  3. Almacenamiento extraíble: MediaStore.Audio.Media.getContentUri
    content://media//audio/media.

Video

  1. Interno: MediaStore.Video.Media.INTERNAL_CONTENT_URI
    contenido://media/internal/video/media。
  2. Externo: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    contenido://media/external/video/media。
  3. Almacenamiento extraíble: MediaStore.Video.Media.getContentUri
    content://media//video/media.

Imagen

  1. Interno: MediaStore.Images.Media.INTERNAL_CONTENT_URI
    contenido: //media/internal/images/media。
  2. Externo: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    contenido://media/external/images/media。
  3. Almacenamiento extraíble: MediaStore.Images.Media.getContentUri
    content://media//images/media.

Archivo

  1. Tienda de medios. Files.Media.getContentUri
    content://media//file。

Descargas

  1. Interno: MediaStore.Downloads.INTERNAL_CONTENT_URI
    contenido://media/internal/downloads。
  2. Externo: MediaStore.Downloads.EXTERNAL_CONTENT_URI
    contenido://media/external/downloads。
  3. Almacenamiento extraíble: MediaStore.Downloads.getContentUri
    content://media//downloads.
2.5.1.1 Obtener todos los volúmenes

Para los Uri descritos anteriormente, getContentUricómo obtenerlos todos se puede hacer de la siguiente manera:

for(String volume:MediaStore.getExternalVolumeNames(this)){
    
    
	MediaStore.Audio.Media.getContentUri(volume);
}
2.5.1.2 Relación entre Uri y directorio público

MediaProviderPara que la aplicación se almacene en un archivo de directorio público, está determinado por el Uri en el método. La ruta relativa se ContentResolver insertmuestra en la siguiente tabla y el archivo completo es: content://media//<ruta de Uri>.<Uri路径>

Insertar descripción de la imagen aquí

2.5.1.3 Permisos

MediaStoreA través de diferentes métodos Uri, los usuarios pueden agregar, eliminar (si los archivos no se pueden eliminar a través de File Uri, debe usar la interfaz SAF) y modificar.
Los permisos correspondientes de la App son los siguientes:
Insertar descripción de la imagen aquí

2.5.1.4 Consultar archivos

Al ContentResolverconsultar contenido diferente según diferentes Uri:

  try (Cursor c = getContentResolver()
                .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, null, null, null)) {
    
    
            while (c.moveToNext()) {
    
    
                Uri contentUri =
                        ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, c.getLong(0));
            }
        }

PD: Durante MediaStore.Filesel proceso Query, solo se mostrarán imágenes, videos y archivos de audio.

2.5.1.5 Lectura de archivos

A través ContentResolver queryde la interfaz, cómo leer el archivo después de encontrarlo se puede hacer de la siguiente manera:

  1. A través de ContentResolver openFileDescriptorla interfaz, seleccione el método de apertura correspondiente,
    por ejemplo, "r" significa lectura, "w" significa escritura y el ParcelFileDescriptortipo de retorno FD.
  2. Se accede Thumbnaila través de ContentResolver loadThumbnailla interfaz
    Al pasar el tamaño, MediaProviderse devuelve el tamaño especificado Thumbnail.
  3. El código nativo accede a los archivos.
    Si el código nativo necesita acceder a los archivos, puede consultar los siguientes métodos:
    openFileDescriptorRegresando ParcelFileDescriptor
    ParcelFileDescriptor.detachFd()Leyendo FD
    FDPasando Nativeal código de capa
    AppDebe ser responsable de cerrar a través de closela interfazFD
   	ParcelFileDescriptor parcelFd = resolver.openFileDescriptor(uri, file0penMode);
	if (parcelFd != null) {
    
    
	      int fd = parcelFd.detachFd();
	      // Pass the integer value "fd" into your native code. Remember to call
	      // close(2) on the file descriptor when you're done using it.
	}
2.5.1.6 Crear nuevo archivo

Si necesita almacenar un archivo nuevo en un directorio público, debe ContentResolver insertusar una interfaz diferente Uriy elegir almacenarlo en un directorio diferente.
Insertar descripción de la imagen aquí

2.5.1.7 Modificar archivos

Si necesita modificar un archivo multimedia, debe ContentResolver queryencontrar el Uri del archivo correspondiente a través de la interfaz.
Si no creó un archivo nuevo usted mismo, debe prestar atención a la descripción en 2.5.1.3 Permisos. Debe solicitarlo WRITE_EXTERNAL_STORAGE权限o catch RecoverableSecurityExceptionun cuadro emergente le dará al usuario una opción.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
A través de la siguiente interfaz, obtenga el archivo que necesita ser modificado FDo OutputStream:

  1. getContentResolver().openOutputStream(contentUri)
    obtiene el OutputStream del archivo correspondiente.
  2. getContentResolver().openFile o getContentResolver().openFileDescriptor
    abre el archivo a través de openFile o openFileDescriptor. Debe seleccionar Modo como "w", que indica permiso de escritura. Estas interfaces devuelven un ParcelFileDescriptor.
    getContentResolver().openFileDescriptor(contentUri,“w”);
    getContentResolver().openFile(contentUri,“w”,null);
2.5.1.8 Eliminar archivos

Elimine archivos a través de la interfaz ContentResolver y el Uri es el Uri de la consulta:

getContentResolver().delete(contentUri,null,null);

2.5.2 A través de la interfaz SAF

2.5.2.1 Introducción a SAF

SAF, es decir , brindar a los usuarios la posibilidad de abrir y explorar archivos Storage Access Frameworkseleccionando diferentes . DocumentsProviderPodemos mirar atrás al capítulo anterior.

Android proporciona lo siguiente de forma predeterminada DocumentsProvider:
MediaDocumentsProvider, ExternalStorageProvider, DownloadStorageProvider.
La diferencia entre ellos es:
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

En esta imagen, hay tres áreas, a saber:

  1. MediosDocumentosProporcionar
  2. Descargar proveedor de almacenamiento
  3. Proveedor de almacenamiento externo
  4. Proveedor de documentos de terceros
2.5.2.2 Cómo utilizar

Consulte la documentación oficial para obtener más detalles.

El método general es el siguiente:

  1. Seleccione un solo archivoInsertar descripción de la imagen aquí
  2. Seleccione el directorio,
    Insertar descripción de la imagen aquí
    el programa de administración de archivos y el programa de limpieza. Puede utilizar este método para obtener todos los permisos de administración para el directorio y los subdirectorios correspondientes.
  3. crear un nuevo archivo
    Insertar descripción de la imagen aquí
  4. borrar
DocumentsContract.deleteDocument(getContentResolver(),uri);
  1. Revisar

①Obtener flujo de salida

getContentResolver().openOutputStream(uri);

②Obtenga el ParcelFileDescriptor grabable

getContentResolver().openFileDescriptor(contentUri,"w");
getContentResolver().openFile (contentUri,"w",null);

Referencia de demostración específica

2.6 Acceder a directorios específicos de la aplicación

Hay dos situaciones de acceso App-specific, la primera es acceso App自身App-specific目录y la segunda es acceso 其他App目录文件.

2.6.1 Directorio específico de la aplicación propia

Android Q, si se inicia la aplicación Filtered View, solo puede acceder directamente a los archivos en su propio directorio:

  1. Las interfaces Environment.getExternalStorageDirectory y getExternalStoragePublicDirectory
    están obsoletas en Android Q. La aplicación es una vista filtrada y no puede acceder directamente a este directorio.
  2. Acceder
    a la aplicación a través de un archivo ("/sdcard/") es una vista filtrada y no puede acceder directamente a este directorio.
  3. Obtenga el directorio específico de la aplicación
    Obtenga la interfaz de medios: getExternalMediaDirs
    Obtenga la interfaz de caché: getExternalCacheDirs
    Obtenga la interfaz de Obb: getObbDirs
    Obtenga la interfaz de datos: getExternalFilesDirs

2.6.2 Archivos multimedia en el directorio específico de la aplicación

Archivos multimedia dentro del directorio específico de la aplicación:

  1. El acceso propio de la aplicación App-specifices el mismo que el directorio propio de la aplicación 2.6.1
  2. Acceso desde otras aplicaciones
    ① De forma predeterminada , los archivos multimedia que contiene Media Scannerno se escanearán . Si es necesario escanear, debe agregarse a la base de datos. El método de acceso es el mismo que 2.5 lectura y escritura de directorios públicos. ②La aplicación se comparte compartiendoApp-specificMediaScannerConnection.scanFileMediaProvider

    ContentProvider

2.6.3 Otros archivos del directorio de aplicaciones

La aplicación es una vista filtrada. Otras aplicaciones no pueden acceder directamente al directorio privado de la aplicación actual. Debe utilizar el siguiente método:

2.6.3.1 A través del archivo SAF
  1. Compartir personalización de la aplicaciónDocumentsProvider

La personalización de la aplicación DocumentsProviderrequiere los siguientes pasos:
a) EspecificarDocumentsProvider
Insertar descripción de la imagen aquí

b) DocumentsProviderImplementar la interfaz básica:
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

  1. Accede a la App ACTION_OPEN_DOCUMENTy empieza a navegar
    Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

2.6.3.2 Compartir aplicación para implementar FileProvider

Referencia de uso específica de FileProvider

A continuación se muestra un resumen de los pasos generales:

  1. Proveedor de archivos de aplicación especificado
    Insertar descripción de la imagen aquí

  2. Especifique la ruta del archivo, el archivo de configuración debe colocarse en res/xml
    Insertar descripción de la imagen aquí

  3. Consigue compartir Uri
    Insertar descripción de la imagen aquí

  4. Establecer permisos y enviar Uri
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí

  5. Reciba la aplicación y configure el interfiltro aceptado
    Insertar descripción de la imagen aquí

  6. Recibir y procesar Uri
    Insertar descripción de la imagen aquí

2.6.3.3 Proveedor privado personalizado de la aplicación

Las aplicaciones se pueden personalizar ContentProvider, especialmente 内部文件共享, pero no se espera interacción con la interfaz de usuario.

2.7 Tienda multimedia

2.7.1 Campo MediaStore_data

MediaStoreEn , DATA即(_data)字段comenzó Android Qa ser abandonado en. Leer y escribir archivos requiere aprobar openFileDescriptor.

2.7.2 Estado pendiente del archivo MediaStore

En Android Q, MediaStorese agregó un IS_PENDING Flagpara marcar Pendingel estado del archivo actual.
Otras aplicaciones MediaStoreconsultan archivos. Si no setIncludePendingse configura ninguna interfaz, los archivos configurados en estado Pendiente no se pueden consultar. Esto le da a la aplicación acceso exclusivo a este archivo. Se utiliza en algunas situaciones, como durante la descarga: durante la descarga, el archivo está en estado Pendiente y la descarga se completa, y el estado Pendiente del archivo se establece en 0.
Insertar descripción de la imagen aquí

2.7.3 MediaColumns.RELATIVE_PATH establece la ruta de almacenamiento

En Android Q, al MediaStorealmacenar archivos en el directorio público, además del directorio de primer nivel de cada espacio de almacenamiento especificado en la relación entre Uri y el directorio público en la Sección 2.5.1.2, el directorio secundario para el almacenamiento se puede especificar a través de MediaColumns. RELATIVE_PATH.Este directorio Se pueden crear múltiples niveles, el código específico es el siguiente:

  1. El método de inserción de ContentResolver
    especifica el directorio de almacenamiento a través de value.put(Media.RELATIVE_PATH,"Pictures/album/family "). Entre ellos, Imágenes es un directorio de primer nivel y álbum/familia es un subdirectorio.
  2. El método de actualización de ContentResolver
    especifica el directorio de almacenamiento a través de value.put(Media.RELATIVE_PATH,"Pictures/album/family "). Mediante el método de actualización, se puede mover la ubicación de almacenamiento.

2.7.4 Acceder a los metadatos Exif de la imagen

En Android Q, si la aplicación necesita acceder a los metadatos Exif de la imagen, debe hacer lo siguiente:

  1. AplicarACCESS_MEDIA_LOCATION权限
  2. El código de demostración es el MediaStore.setRequireOriginal返回新Uri
    siguiente:
    Insertar descripción de la imagen aquí

2.7.5 Vista filtrada de aplicaciones, resumen de permisos de acceso

Los permisos de la aplicación para acceder a diferentes directorios se resumen a continuación:
Insertar descripción de la imagen aquí

2.7.6 Desinstalación de aplicaciones

Si la aplicación AndroidManifest.xmldeclara: android:hasFragileUserData="true"
Al desinstalar la aplicación, se le preguntará si desea conservar los datos de la aplicación:
Insertar descripción de la imagen aquí

2.7.7 Migración de datos de aplicaciones

En Android Q, App TargetSDK>=Qel valor predeterminado es Filtered View. Si la aplicación es una vista filtrada, implicará la migración de datos; de lo contrario, los datos antiguos quedarán inutilizables. Puede iniciar la migración de datos desde los siguientes aspectos:

  1. Es necesario Legacy Viewdescargar para tener permiso completo para operar el almacenamiento.
  2. Se puede acceder a los archivos de aplicaciones almacenados en áreas no públicas SAF访问seleccionando archivos de directorio a través de SAF, y los usuarios pueden optar por acceder a los archivos de aplicaciones.
    Insertar descripción de la imagen aquí
  3. La aplicación puede colocar los archivos que deben guardarse:
    Images, Video, Audioen el directorio público correspondiente. Otros archivos se pueden colocar Downloadsdebajo sin eliminarlos después de la desinstalación.

2.7.8 Consultas de MediaStore

Cuando se usa MediaStorepara realizar queryacciones, Projectioncuando se usa, Column Namese debe MediaStoredefinir en.

2.8 Permiso WRITE_MEDIA_STORAGE

2.8.1 Antecedentes

WRITE_MEDIA_STORAGEEs un permiso muy poderoso que permite que la aplicación obtenga acceso a todos los dispositivos de almacenamiento. Permiso para acceder a todos los dispositivos de almacenamiento; esto solo se debe otorgar al Media Stack.

2.8.2 Impacto de la compatibilidad

En el sistema Android, se estipula que WRITE_MEDIA_STORAGEse puede obtener el grupo de usuarios media_rw:
Insertar descripción de la imagen aquí

  1. Para todos los dispositivos de almacenamiento extraíbles, como tarjetas T y discos U, cuando se montan en Android, las aplicaciones normales solo tienen permisos de lectura y no de escritura. Sólo las aplicaciones del grupo de usuarios media_rw pueden escribir en dispositivos de almacenamiento extraíbles.
  2. Para Scoped Storage en Android Q, puede usar este permiso para configurar la aplicación para que se ejecute en modo de compatibilidad.
  3. Android CTS realizará pruebas. Las aplicaciones que el usuario puede iniciar no pueden solicitar este permiso.
    Para obtener más información, consulte "Android Bootcamp 2019 - Descripción general de privacidad.pdf".

2.8.3 Adaptación

Si la aplicación necesita acceder Mediaa o 外置存储设备, puede utilizar MediaStoreo Storage Access Framework(SAF)接口.

3 Resumen

Bien, aquí hay un resumen:

  1. App TargetSDK > 28 即 Android10(Q)及以上Proyecto, Google ha restringido el modo de espacio aislado de almacenamiento. En el uso Android10(Q)以上的设备recomendado 私有目录data/data, ya no se puede acceder directamente 外部SD卡存储目录. Si necesita usarlo , debe acceder a él 外部SD卡存储目录a través de la interfaz, y solo se puede acceder a él , como , , , , , etc. Todas las aplicaciones pueden acceder a estos directorios de almacenamiento de tarjetas SD externas (directorios públicos), por lo que no son muy seguros.SAFMediaStore特定的外部SD卡存储目录DownloadsDocumentsPicturesDCIMMoviesMusicRingtones
  2. App TargetSDK <= 28 即 Android10(Q)以下El proyecto no tiene restricciones, siempre que tenga WRITE_MEDIA_STORAGEpermisos READ_MEDIA_STORAGE. Entonces, si realmente no desea cambiar el almacenamiento SD externo, cambie el targetSdk del proyecto a <=28.
  3. En cuanto SAFal método MediaStorede acceso a la interfaz 外部SD卡存储特定目录, consulte la descripción anterior o consulte la documentación oficial para obtener más detalles. Aquí hay una demostración de MediaStorecómo usarlo para su referencia 外部SD卡存储特定目录. No olvide hacer clic en Estrella.

Supongo que te gusta

Origin blog.csdn.net/u010687761/article/details/133200887
Recomendado
Clasificación