Almacenamiento de Android: interno, externo, extraíble. Parte 1/3

A todos los que, a pesar de todo, lograron tomar la decisión correcta.

Esta es una traducción de una serie de artículos de Mark Murphy de CommonsWare, ampliamente conocido en stackoverflow, así como el autor de los libros "La guía del codificador ocupado para el desarrollo de Android", "Componentes de arquitectura de Android". Algunos términos no están traducidos específicamente.


Almacenamiento interno


Hay mucha confusión con respecto al modelo de almacenamiento de Android. La confusión ha aumentado significativamente con los cambios en Android 4.4 en el modelo de almacenamiento, y desde entonces la situación no ha mejorado. Hay innumerables preguntas sobre Stack Overflow y recursos similares, donde las personas claramente no están completamente versados ​​en los diversos modelos de almacenamiento de Android.


Lo que los usuarios consideran almacenamiento interno


Dependiendo del modelo de su dispositivo, los usuarios eventualmente llegarán a Configuración -> Almacenamiento en su dispositivo o una ubicación equivalente, y pueden ver una pantalla que describe "Almacenamiento interno" .


El usuario piensa que toda la unidad flash incorporada es "Almacenamiento interno". Afortunadamente, Google comenzó a cambiar este término con Android 8.0, pasando a "almacenamiento general" en lugar de "almacenamiento interno".


Sin embargo, los usuarios aún pueden ver el "almacenamiento interno" en lugares como la ventana del Explorador de Windows cuando su dispositivo está conectado a través de USB.


Lo que Google considera almacenamiento interno


Por desgracia, lo que ven los usuarios no es lo mismo que el SDK de Android considera "almacenamiento interno", lo que genera cierta confusión. Si lee la documentación de Android en el repositorio interno , entonces esta descripción ... es al menos confusa (el texto ha cambiado desde el momento de la escritura):


Puede guardar archivos directamente en la memoria interna del dispositivo. De manera predeterminada, los archivos almacenados en el almacenamiento interno son privados para su aplicación, y otras aplicaciones no pueden acceder a ellos (al igual que el usuario). Cuando el usuario desinstala la aplicación, estos archivos se eliminan.

En verdad, el SDK de Android define el "almacenamiento interno" como un directorio especial exclusivo de su aplicación, donde su aplicación puede alojar archivos. Como se sugiere en la documentación, estos archivos están destinados a leer y escribir en su aplicación de manera predeterminada y están prohibidos para cualquier otra aplicación (excepción: los usuarios que trabajan con administradores de archivos con privilegios de superusuario en dispositivos rooteados pueden acceder a todo).


El contexto tiene algunos métodos básicos que le dan acceso al almacenamiento interno, que incluyen:


  • getCacheDir()
  • getDir()
  • getDatabasePath()
  • getFilesDir()
  • openFileInput()
  • openFileOutput()

Otros métodos dependerán de ellos, como openOrCreateDatabase() . Otras clases también dependerán de ellos, como SQLiteOpenHelper y SharedPreferences .


¿Dónde se almacena el almacenamiento interno ... a veces


Si mira varias publicaciones de blog, respuestas de StackOverflow y libros publicados en 2012 o antes, se le informa que el "almacenamiento interno" de su aplicación se encuentra en /data/data/your.application.package.name .


En el interior habrá algunos directorios creados automáticamente por Android, ya que utiliza algunos de los métodos de contexto. Por ejemplo, getFilesDir() devuelve un objeto File que apunta al directorio files/ en el almacenamiento interno de su aplicación.


Dónde se almacena el almacenamiento interno ... El resto del tiempo


Sin embargo, el almacenamiento interno de su aplicación no siempre se encuentra en la ubicación especificada. Para los desarrolladores, hay una regla que debes aprender de esta serie de publicaciones de blog:


NUNCA CAMINOS DUROS .


De vez en cuando, veo desarrolladores haciendo algo como esto:


File f=new File("/data/data/their.app.package.name/files/foo.txt");


Esto no es un delito, es peor, es un error.


El movimiento correcto, y escribe menos:


File f=new File(getFilesDir(), "foo.txt");


Más importante aún, el almacenamiento interno no siempre está en el mismo lugar . Es de destacar que tenemos el concepto de perfiles de usuario separados (perfiles de usuario separados), comenzando con Android 4.2 para tabletas y Android 5.0 para teléfonos. Cada usuario obtiene su propio "almacenamiento interno". Aunque el directorio anterior todavía se usa para el usuario principal, no se garantiza que se usará para cuentas secundarias.


Explorando el almacenamiento interno


La herramienta Device File Explorer en Android Studio 3.0+ puede ver todo el almacenamiento interno en el emulador, así como el almacenamiento interno de aplicaciones depuradas en dispositivos de producción.


En la línea de comando, puede usar adb con la opción de run-as .


Por ejemplo, para cargar una base de datos desde el almacenamiento interno del usuario principal a su máquina de desarrollo, puede usar:


adb shell 'run-as your.application.package.name cp /data/data/your.application.package.name/databases/dbname.db /sdcard'


Tenga en cuenta que:


  • Deberá cambiar el destino donde está montado el almacenamiento externo en su dispositivo (se muestra aquí como /sdcard/ , que no será el mismo en todos los dispositivos)
  • Es posible que necesite usar cat lugar de cp en dispositivos más antiguos
  • Una vez que el archivo se encuentra en el almacenamiento externo, puede usar adb pull para descargarlo en su computadora o acceder a él de otras maneras habituales (por ejemplo, montando el dispositivo como un disco).

Limitaciones de almacenamiento interno


En dispositivos Android 1.xy 2.x anteriores, el almacenamiento interno generalmente se ubicaba en una sección dedicada del sistema de archivos, y esta sección generalmente era bastante pequeña. HTC Dream (también conocido como T-Mobile G1), el dispositivo Android original, tenía una enorme memoria interna de 70 MB para ser utilizada por todas las aplicaciones (esto no es un error tipográfico, en ese momento medimos la memoria en megabytes).


Para cuando salieron 2.3 dispositivos, el almacenamiento interno podría tener un tamaño de 1 GB.


Android 3.0 ha cambiado el modelo de almacenamiento, ya que el almacenamiento interno se ha vuelto más volumen. Para dispositivos que se anuncian con 4 GB, 8 GB, 16 GB, etc. espacio de almacenamiento, generalmente había todo esto (menos el contenido existente) disponible para almacenamiento interno. Veremos qué ha cambiado en Android 3.0 y su impacto en el modelo de almacenamiento en las siguientes publicaciones sobre almacenamiento externo.


Para Android 1.xy 2.x, el almacenamiento interno solo era válido para archivos pequeños, y tenía que usar almacenamiento externo para todo lo demás. Android 3.0+ significa que para la mayoría de los dispositivos y la mayoría de los usuarios, el almacenamiento interno es ideal para archivos que no están destinados para el uso normal de otras aplicaciones o que son accesibles para el usuario independientemente de su aplicación. Sin embargo, algunos usuarios experimentados encuentran que incluso un flash incorporado no es suficiente para lo que desean almacenar, por lo que cambian al almacenamiento extraíble ... que es una lata de gusanos (nota λμινς) , una fuente de muchos problemas impredecibles y complejos.


Preguntas frecuentes sobre almacenamiento interno


¿Debo hacer archivos en el almacenamiento interno World-Readable o World-Writeable?


Oh, $ DIOSES, no. Use FileProvider y sirva este contenido con la implementación de ContentProvider . Después de eso, al menos, tiene la oportunidad de usar el sistema de permisos de Android para controlar el acceso a estos archivos, a diferencia de su versión, cuando cualquier aplicación en el sistema puede arruinar estos archivos.


Bueno, ¿qué pasa con android:sharedUserId ?


No te aconsejo.


android: sharedUserId es un atributo que puede poner en un manifiesto que indica el identificador lógico del usuario que se utilizará para su aplicación. Cualquier otra aplicación que esté instalada que firme con la misma clave de firma y solicite el mismo android:sharedUserId usará el mismo usuario de Linux desde un punto de vista de seguridad. El efecto es que estas dos aplicaciones pueden trabajar con los archivos del otro con impunidad, ya que estos archivos pertenecen al mismo usuario de Linux.


Este atributo realmente está destinado a aplicaciones preinstaladas, como el paquete de software precargado por el fabricante del dispositivo, el operador móvil o el desarrollador de un firmware ROM modificado. En particular, tan pronto como instale su aplicación una vez, no podrá cambiar sin problemas su valor de android:sharedUserId sin bloquear el acceso del usuario a los archivos existentes ... ya que Android no cambia la propiedad de los archivos existentes al cambiar la cuenta de usuario de Linux, que ejecuta la aplicación


Existen varios riesgos cuando múltiples procesos acceden a los archivos. Algunos subsistemas, como SQLite, tienen lógica incorporada para resolver este problema. Pero si usted mismo organiza su propio acceso al archivo (por ejemplo, a través de File y Java I / O), debe hacer algo con acceso simultáneo, y esto es difícil.


También debe manejar una situación en la que una aplicación se desinstala eliminando archivos que otra aplicación usó. En un modelo de concentrador y radio, por ejemplo, con una aplicación y un conjunto de complementos, quizás esto no sea tan arriesgado. En otros modelos, donde las aplicaciones son más equitativas, no puede permitirse perder los datos de su aplicación solo porque el usuario decidió eliminar alguna aplicación por separado.


Finalmente, no sabes lo que puede traer el futuro. En este momento, puede ver su conjunto de aplicaciones como un conjunto estrechamente acoplado. Alguien que compre estas aplicaciones o adquiera su compañía puede desear ir a otro lado. El uso de capacidades de intercambio de datos que están menos conectadas, como ContentProvider , le brinda más flexibilidad. En un mundo ideal, su aplicación debe tratar a otras aplicaciones como un recurso bastante confiable, pero no siempre accesible, como su propio servicio web.


¿Cómo evitar que los usuarios de dispositivos rooteados accedan a mis archivos en el almacenamiento interno?


Simplemente no coloque archivos en el almacenamiento interno. Los usuarios de dispositivos rooteados pueden acceder a lo que necesitan en el dispositivo, por lo que la única forma de evitar que accedan a sus datos es no tenerlos en el dispositivo.


Algunos desarrolladores intentarán cifrar sus archivos con una contraseña codificada para que los usuarios de dispositivos rooteados no puedan usar estos archivos. Esto creará el efecto de un golpe de velocidad por un corto tiempo. Todo lo que se requiere es una persona interesada en la ingeniería inversa de su aplicación, que ha determinado cómo descifrar estos archivos y luego escribió un mensaje en un blog o foro sobre cómo hacerlo.


En general, relativamente pocas personas con dispositivos rooteados, los califico con menos del 1%. En mi humilde opinión, tendrá más éxito si enfoca su trabajo de ingeniería en escribir una mejor aplicación, en lugar de perder tiempo protegiendo de dispositivos rooteados.

Source: https://habr.com/ru/post/es429338/


All Articles