Stockage Android: interne, externe, amovible. Partie 1/3

À tous ceux qui, malgré tout, ont réussi à faire le bon choix.

Il s'agit d'une traduction d'une série d'articles de Mark Murphy de CommonsWare, largement connu sur stackoverflow, ainsi que de l'auteur des livres «Le guide du codeur occupé pour le développement Android», «Composants d'architecture Android». Certains termes ne sont pas spécifiquement traduits.


Stockage interne


Il y a beaucoup de confusion concernant le modèle de stockage Android. La confusion a considérablement augmenté avec les changements d'Android 4.4 dans le modèle de stockage, et depuis lors, la situation ne s'est pas améliorée. Il existe d'innombrables questions sur Stack Overflow et des ressources similaires, où les gens ne sont clairement pas complètement familiarisés avec les différents modèles de stockage Android.


Ce que les utilisateurs considèrent comme le stockage interne


Selon le modèle de votre appareil, les utilisateurs accèdent en fin de compte à Paramètres -> Stockage sur leur appareil ou à un emplacement équivalent, et peuvent voir un écran décrivant «Stockage interne» .


L'utilisateur pense que l'intégralité du lecteur flash intégré est du «stockage interne». Heureusement, Google a commencé à changer ce terme avec Android 8.0, en passant au «stockage général» au lieu du «stockage interne».


Cependant, les utilisateurs peuvent toujours voir le «stockage interne» dans des endroits tels que la fenêtre de l'Explorateur Windows lorsque leur appareil est connecté via USB.


Ce que Google considère comme le stockage interne


Hélas, ce que les utilisateurs voient n'est pas le même que ce que le SDK Android considère comme «stockage interne», ce qui crée une certaine confusion. Si vous lisez la documentation Android sur le référentiel interne , alors cette description ... est au moins vague (le texte du commentaire a changé depuis la rédaction de cet article):


Vous pouvez enregistrer des fichiers directement dans la mémoire interne de l'appareil. Par défaut, les fichiers stockés dans le stockage interne sont privés de votre application et les autres applications ne peuvent pas y accéder (ainsi que l'utilisateur). Lorsque l'utilisateur désinstalle l'application, ces fichiers sont supprimés.

En vérité, le SDK Android définit le «stockage interne» comme un répertoire spécial unique à votre application, où votre application peut héberger des fichiers. Comme suggéré dans la documentation, ces fichiers sont destinés à la lecture et à l'écriture par défaut pour votre application et sont interdits pour toute autre application (exception: les utilisateurs travaillant avec des gestionnaires de fichiers avec des privilèges de superutilisateur sur des appareils rootés peuvent accéder à tout).


Context dispose de quelques méthodes de base qui vous donnent accès au stockage interne, notamment:


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

D'autres méthodes s'appuieront sur elles, comme openOrCreateDatabase() . D'autres classes s'appuieront également sur elles, telles que SQLiteOpenHelper et SharedPreferences .


Où est stocké le stockage interne ... Parfois


Si vous consultez divers articles de blog, réponses StackOverflow et livres publiés en 2012 ou avant, vous êtes informé que le «stockage interne» de votre application se trouve dans /data/data/your.application.package.name .


À l'intérieur, il y aura des répertoires créés automatiquement par Android, car vous utilisez certaines des méthodes de contexte. Par exemple, getFilesDir() renvoie un objet File pointant vers le files/ dans le stockage interne de votre application.


Où est stocké le stockage interne ... Le reste du temps


Cependant, le stockage interne de votre application n'est pas toujours à l'emplacement spécifié. Pour les développeurs, il y a une règle que vous devez apprendre de cette série de billets de blog:


JAMAIS CHEMINS DE CODE DUR .


De temps en temps, je vois des développeurs faire quelque chose comme ça:


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


Ce n'est pas un crime, c'est pire, c'est une erreur.


Le bon coup, et écrivez moins:


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


Plus important encore, le stockage interne n'est pas toujours au même endroit . Il est à noter que nous avons le concept de profils utilisateur distincts (profils utilisateur distincts), à commencer par Android 4.2 pour les tablettes et Android 5.0 pour les téléphones. Chaque utilisateur dispose de son propre "stockage interne". Bien que le répertoire ci-dessus soit toujours utilisé pour l'utilisateur principal, il n'est pas garanti qu'il sera utilisé pour les comptes secondaires.


Explorer le stockage interne


L'outil Device File Explorer dans Android Studio 3.0+ peut afficher tout le stockage interne sur l'émulateur, ainsi que le stockage interne des applications déboguées sur les appareils de production.


Sur la ligne de commande, vous pouvez utiliser adb avec l'option run-as .


Par exemple, pour télécharger une base de données depuis le stockage interne de l'utilisateur principal vers votre machine de développement, vous pouvez utiliser:


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


Veuillez noter que:


  • Vous devrez modifier la destination à l'endroit où le stockage externe est monté sur votre appareil (affiché ici sous la forme /sdcard/ , qui ne sera pas le même sur tous les appareils)
  • Vous devrez peut-être utiliser cat au lieu de cp sur les appareils plus anciens
  • Une fois le fichier stocké sur un stockage externe, vous pouvez utiliser adb pull pour le télécharger sur votre ordinateur, ou y accéder par d'autres moyens habituels (par exemple, en montant l'appareil en tant que disque).

Limitations du stockage interne


Sur les anciens appareils Android 1.x et 2.x, le stockage interne était généralement situé dans une section dédiée du système de fichiers, et cette section était généralement assez petite. HTC Dream (alias T-Mobile G1), l'appareil Android d'origine, avait une énorme mémoire interne de 70 Mo à utiliser par toutes les applications (ce n'est pas une faute de frappe, à l'époque, nous avons mesuré la mémoire en mégaoctets).


Au moment de la sortie de 2,3 appareils, le stockage interne pouvait avoir une taille de 1 Go.


Android 3.0 a changé le modèle de stockage, car le stockage interne est devenu plus volumineux. Pour les appareils dont la publicité est de 4 Go, 8 Go, 16 Go, etc. l'espace de stockage, généralement il y avait tout cela (moins le contenu existant) disponible pour le stockage interne. Nous verrons ce qui a changé dans Android 3.0 et son impact sur le modèle de stockage dans les articles suivants sur le stockage externe.


Pour Android 1.x et 2.x, le stockage interne n'était valable que pour les petits fichiers, et vous deviez utiliser le stockage externe pour tout le reste. Android 3.0+ signifie que pour la plupart des appareils et la plupart des utilisateurs, le stockage interne est idéal pour les fichiers qui ne sont pas destinés à une utilisation normale par d'autres applications ou qui sont accessibles à l'utilisateur quelle que soit votre application. Cependant, certains utilisateurs expérimentés trouvent que même un flash intégré ne suffit pas pour ce qu'ils veulent stocker, alors ils passent au stockage amovible ... qui est une boîte de vers (note λμινς) - une source de nombreux problèmes imprévisibles et complexes.


FAQ sur le stockage interne


Dois-je créer des fichiers dans le stockage interne World-Readable ou World-Writeable?


Oh, $ DIEUX, non. Utilisez FileProvider et FileProvider ce contenu avec l'implémentation de ContentProvider . Après cela, vous avez au moins la possibilité d'utiliser le système d'autorisation Android pour contrôler l'accès à ces fichiers, contrairement à votre version, lorsqu'une application du système peut ruiner ces fichiers.


Eh bien, qu'en est-il d' android:sharedUserId ?


Je ne conseille pas.


android: sharedUserId est un attribut que vous pouvez mettre dans un manifeste qui indique l'identifiant logique de l'utilisateur qui sera utilisé pour votre application. Toute autre application installée qui signe avec la même clé de signature et demande le même android:sharedUserId utilisera le même utilisateur Linux du point de vue de la sécurité. L'effet est que ces deux applications peuvent fonctionner en toute impunité avec leurs fichiers respectifs, car ces fichiers appartiennent au même utilisateur Linux.


Cet attribut est vraiment destiné aux applications préinstallées, telles que la suite logicielle préchargée par le fabricant de l'appareil, l'opérateur mobile ou le développeur d'un firmware ROM modifié. En particulier, dès que vous installez votre application une fois, vous ne pouvez pas modifier sans douleur votre valeur android:sharedUserId sans bloquer l'accès de l'utilisateur à tous les fichiers existants ... car Android ne modifie pas les droits du propriétaire sur les fichiers existants lors du changement de compte d'utilisateur Linux, qui exécute l'application.


Il existe différents risques lorsque plusieurs processus accèdent à des fichiers. Certains sous-systèmes, tels que SQLite, ont une logique intégrée pour résoudre ce problème. Mais si vous organisez vous-même votre propre accès au fichier (par exemple, via File et Java I / O), vous devez faire quelque chose avec un accès simultané, et c'est difficile.


Vous devez également gérer une situation où une application se désinstalle en supprimant les fichiers qu'une autre application a utilisés. Dans un modèle en étoile, par exemple, avec une application et un ensemble de plugins, ce n'est peut-être pas si risqué. Dans d'autres modèles, où les applications sont plus équitables, vous ne pouvez pas vous permettre de perdre les données de votre application simplement parce que l'utilisateur a décidé de supprimer une application distincte.


Enfin, vous ne savez pas ce que l'avenir peut vous apporter. À l'heure actuelle, vous pouvez afficher votre suite d'applications comme une suite étroitement couplée. Une personne qui achète ces applications ou acquiert votre entreprise peut souhaiter opter pour l'autre voie. L'utilisation de fonctionnalités de partage de données moins connectées, telles que ContentProvider , vous offre plus de flexibilité. Dans un monde idéal, votre application devrait traiter les autres applications comme une ressource assez fiable, mais pas toujours accessible, tout comme votre propre service Web.


Comment empêcher les utilisateurs d'appareils rootés d'accéder à mes fichiers dans le stockage interne?


Ne mettez simplement pas de fichiers dans le stockage interne. Les utilisateurs d'appareils rootés peuvent accéder à ce dont ils ont besoin sur l'appareil, donc la seule façon de les empêcher d'accéder à vos données est de ne pas les avoir sur l'appareil.


Certains développeurs tenteront de crypter leurs fichiers avec un mot de passe codé en dur afin que les utilisateurs d'appareils rootés ne puissent pas utiliser ces fichiers. Cela créera l'effet d'un ralentisseur pendant une courte période. Tout ce qui est requis est une personne intéressée par la rétro-ingénierie de votre application, qui a déterminé comment déchiffrer ces fichiers, puis a écrit un message sur un blog ou un forum sur la façon de procéder.


En général, relativement peu de personnes avec des appareils rootés - je les note à moins de 1%. À mon humble avis, vous réussirez davantage en concentrant votre travail d'ingénierie sur l'écriture d'une meilleure application, au lieu de passer du temps à vous protéger des appareils enracinés.

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


All Articles