Android-Speicher: intern, extern, entfernbar. Teil 1/3

An alle, die es trotz allem geschafft haben, die richtige Wahl zu treffen.

Dies ist eine Übersetzung einer Reihe von Artikeln von Mark Murphy von CommonsWare, die im Stackoverflow weithin bekannt sind, sowie des Autors der Bücher „The Busy Coder's Guide to Android Development“, „Android's Architecture Components“. Einige Begriffe werden nicht speziell übersetzt.


Interner Speicher


Es gibt viel Verwirrung bezüglich des Android-Speichermodells. Die Verwirrung hat mit den Änderungen in Android 4.4 im Speichermodell erheblich zugenommen, und seitdem hat sich die Situation nicht verbessert. Es gibt unzählige Fragen zu Stack Overflow und ähnlichen Ressourcen, bei denen die Benutzer mit den verschiedenen Android-Speichermodellen eindeutig nicht vollständig vertraut sind.


Was Benutzer als internen Speicher betrachten


Abhängig vom Modell Ihres Geräts gelangen Benutzer schließlich zu Einstellungen -> Speicher auf ihrem Gerät oder einem gleichwertigen Speicherort und sehen einen Bildschirm mit der Beschreibung „Interner Speicher“. .


Der Benutzer glaubt, dass das gesamte integrierte Flash-Laufwerk "Interner Speicher" ist. Glücklicherweise begann Google, diesen Begriff mit Android 8.0 zu ändern und wechselte zu "allgemeinem Speicher" anstelle von "internem Speicher".


Benutzer können den „internen Speicher“ jedoch weiterhin an Orten wie dem Windows Explorer-Fenster sehen, wenn ihr Gerät über USB angeschlossen ist.


Was Google als internen Speicher betrachtet


Leider ist das, was Benutzer sehen, nicht dasselbe wie das, was das Android SDK als „internen Speicher“ betrachtet, was zu Verwirrung führt. Wenn Sie die Android-Dokumentation im internen Repository lesen , ist diese Beschreibung ... zumindest neblig (der Text hat sich seit dem Schreiben geändert):


Sie können Dateien direkt im internen Speicher des Geräts speichern. Standardmäßig sind im internen Speicher gespeicherte Dateien für Ihre Anwendung privat, und andere Anwendungen können nicht darauf zugreifen (ebenso wie der Benutzer). Wenn der Benutzer die Anwendung deinstalliert, werden diese Dateien gelöscht.

In Wahrheit definiert das Android SDK „internen Speicher“ als ein spezielles Verzeichnis, das für Ihre Anwendung eindeutig ist und in dem Ihre Anwendung Dateien hosten kann. Wie in der Dokumentation vorgeschlagen, sind diese Dateien standardmäßig zum Lesen und Schreiben in Ihre Anwendung vorgesehen und für jede andere Anwendung verboten (Ausnahme: Benutzer, die mit Dateimanagern mit Superuser-Berechtigungen auf gerooteten Geräten arbeiten, können auf alles zugreifen).


Der Kontext verfügt über einige grundlegende Methoden, mit denen Sie auf den internen Speicher zugreifen können, darunter:


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

Andere Methoden werden sich auf sie stützen, z. B. openOrCreateDatabase() . Andere Klassen, wie SQLiteOpenHelper und SharedPreferences werden ebenfalls auf sie SharedPreferences .


Wo ist der interne Speicher gespeichert ... Manchmal


Wenn Sie sich verschiedene Blog-Beiträge, StackOverflow-Antworten und Bücher ansehen, die 2012 oder früher veröffentlicht wurden, werden Sie darüber informiert, dass sich der „interne Speicher“ Ihrer Anwendung unter /data/data/your.application.package.name .


Im Inneren befinden sich einige Verzeichnisse, die automatisch von Android erstellt werden, da Sie einige der Kontextmethoden verwenden. Beispielsweise gibt getFilesDir() ein getFilesDir() zurück, das auf die files/ Verzeichnis im internen Speicher Ihrer Anwendung verweist.


Wo wird der interne Speicher gespeichert? Der Rest der Zeit


Der interne Speicher Ihrer Anwendung befindet sich jedoch nicht immer am angegebenen Speicherort. Für Entwickler gibt es eine Regel, die Sie aus dieser Reihe von Blog-Posts lernen müssen:


NIEMALS HARDCODE-WEGE .


Von Zeit zu Zeit sehe ich Entwickler, die so etwas tun:


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


Das ist kein Verbrechen, es ist schlimmer, das ist ein Fehler.


Der richtige Schritt und weniger schreiben:


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


Noch wichtiger ist, dass sich der interne Speicher nicht immer am selben Ort befindet . Es ist bemerkenswert, dass wir das Konzept separater Benutzerprofile (separate Benutzerprofile) haben, beginnend mit Android 4.2 für Tablets und Android 5.0 für Telefone. Jeder Benutzer erhält seinen eigenen "internen Speicher". Obwohl das obige Verzeichnis weiterhin für den primären Benutzer verwendet wird, kann nicht garantiert werden, dass es für sekundäre Konten verwendet wird.


Erkundung des internen Speichers


Das Gerätedateie-Explorer-Tool in Android Studio 3.0+ kann den gesamten internen Speicher auf dem Emulator sowie den internen Speicher von debuggten Anwendungen auf Produktionsgeräten anzeigen.


In der Befehlszeile können Sie adb mit der Option run-as .


Zum Hochladen einer Datenbank aus dem internen Speicher des primären Benutzers auf Ihren Entwicklungscomputer können Sie beispielsweise Folgendes verwenden:


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


Bitte beachten Sie Folgendes:


  • Sie müssen das Ziel so ändern, dass der externe Speicher auf Ihrem Gerät /sdcard/ wird (hier als /sdcard/ , was nicht auf allen Geräten gleich ist).
  • Auf älteren Geräten müssen Sie möglicherweise cat anstelle von cp verwenden
  • Nachdem sich die Datei auf einem externen Speicher befindet, können Sie sie mit adb pull auf Ihren Computer herunterladen oder auf andere übliche Weise darauf zugreifen (z. B. indem Sie das Gerät als Festplatte bereitstellen).

Interne Speicherbeschränkungen


Auf älteren Android 1.x- und 2.x-Geräten befand sich der interne Speicher normalerweise in einem dedizierten Bereich des Dateisystems, und dieser Abschnitt war normalerweise recht klein. Das HTC Dream (auch bekannt als T-Mobile G1), das ursprüngliche Android-Gerät, verfügte über einen riesigen internen Speicher von 70 MB, der von allen Anwendungen verwendet werden konnte (dies ist kein Tippfehler, zu diesem Zeitpunkt haben wir den Speicher in Megabyte gemessen).


Zum Zeitpunkt der Veröffentlichung von 2.3-Geräten konnte der interne Speicher 1 GB groß sein.


Android 3.0 hat das Speichermodell geändert, da der interne Speicher mehr Volumen hat. Für Geräte mit 4 GB, 8 GB, 16 GB usw. Speicherplatz, normalerweise war all dies (abzüglich vorhandener Inhalte) für den internen Speicher verfügbar. In den folgenden Beiträgen zum externen Speicher werden wir untersuchen, was sich in Android 3.0 geändert hat und welche Auswirkungen dies auf das Speichermodell hat.


Für Android 1.x und 2.x war der interne Speicher nur für kleine Dateien gültig, und Sie mussten für alles andere externen Speicher verwenden. Android 3.0+ bedeutet, dass der interne Speicher für die meisten Geräte und die meisten Benutzer ideal für Dateien ist, die nicht für die normale Verwendung durch andere Anwendungen vorgesehen sind oder auf die der Benutzer unabhängig von Ihrer Anwendung zugreifen kann. Einige erfahrene Benutzer sind jedoch der Meinung, dass selbst ein integrierter Flash nicht ausreicht, um das zu speichern, was sie speichern möchten. Daher wechseln sie zu Wechseldatenträgern, bei denen es sich um eine Dose Würmer handelt (Anmerkung λμινς) - eine Quelle für viele unvorhersehbare und komplexe Probleme.


Häufig gestellte Fragen zum internen Speicher


Sollte ich Dateien im internen Speicher World-Readable oder World-Writeable erstellen?


Oh, $ GODS, nein. Verwenden Sie FileProvider und stellen Sie diesen Inhalt mit der Implementierung von ContentProvider . Danach haben Sie zumindest die Möglichkeit, das Android-Berechtigungssystem zu verwenden, um den Zugriff auf diese Dateien im Gegensatz zu Ihrer Version zu steuern, wenn eine Anwendung im System diese Dateien ruinieren kann.


Was ist mit android:sharedUserId ?


Ich rate nicht.


android: sharedUserId ist ein Attribut, das Sie in ein Manifest android: sharedUserId können, das die logische Kennung des Benutzers angibt, der für Ihre Anwendung verwendet wird. Jede andere installierte Anwendung, die mit demselben Signaturschlüssel signiert und dasselbe android:sharedUserId verwendet aus Sicherheitsgründen denselben Linux-Benutzer. Dies hat zur Folge, dass diese beiden Anwendungen ungestraft mit den Dateien des anderen arbeiten können, da diese Dateien demselben Linux-Benutzer gehören.


Dieses Attribut ist wirklich für vorinstallierte Anwendungen gedacht, z. B. Software-Suite, die vom Gerätehersteller, Mobilfunkbetreiber oder Entwickler einer modifizierten ROM-Firmware vorinstalliert wurde. Insbesondere können Sie, sobald Sie Ihre Anwendung einmal installiert haben, Ihren android:sharedUserId Wert schmerzlos ändern android:sharedUserId ohne den Zugriff des Benutzers auf vorhandene Dateien zu blockieren ... da Android die Rechte des Besitzers an vorhandenen Dateien beim Ändern des Linux-Benutzerkontos nicht ändert, welches die Anwendung ausführt.


Es gibt verschiedene Risiken, wenn mehrere Prozesse auf Dateien zugreifen. Einige Subsysteme, wie z. B. SQLite, verfügen über eine integrierte Logik, um dieses Problem zu lösen. Wenn Sie jedoch selbst Ihren eigenen Zugriff auf die Datei organisieren (z. B. über File und Java-E / A), müssen Sie etwas mit gleichzeitigem Zugriff tun, was schwierig ist.


Sie müssen auch eine Situation bewältigen, in der eine Anwendung deinstalliert wird, indem Sie Dateien löschen, die von einer anderen Anwendung verwendet wurden. In einem Hub-and-Spoke-Modell, beispielsweise mit einer Anwendung und einer Reihe von Plugins, ist dies möglicherweise nicht so riskant. In anderen Modellen, in denen Anwendungen gerechter sind, können Sie es sich nicht leisten, die Daten Ihrer Anwendung zu verlieren, nur weil der Benutzer beschlossen hat, eine separate Anwendung zu löschen.


Schließlich wissen Sie nicht, was die Zukunft bringen kann. Im Moment können Sie Ihre Anwendungssuite als eng gekoppelte Suite anzeigen. Jemand, der diese Anwendungen kauft oder Ihr Unternehmen erwirbt, möchte möglicherweise den anderen Weg gehen. Die Verwendung von ContentProvider , die ContentProvider verbunden sind, wie z. B. ContentProvider , bietet Ihnen mehr Flexibilität. In einer idealen Welt sollte Ihre Anwendung andere Anwendungen als ziemlich zuverlässige, aber nicht immer zugängliche Ressource behandeln, genau wie Ihren eigenen Webdienst.


Wie kann verhindert werden, dass Benutzer von gerooteten Geräten auf meine Dateien im internen Speicher zugreifen?


Legen Sie nur keine Dateien im internen Speicher ab. Benutzer von gerooteten Geräten können auf das zugreifen, was sie auf dem Gerät benötigen. Die einzige Möglichkeit, sie am Zugriff auf Ihre Daten zu hindern, besteht darin, sie nicht auf dem Gerät zu haben.


Einige Entwickler werden versuchen, ihre Dateien mit einem fest codierten Kennwort zu verschlüsseln, damit Benutzer von gerooteten Geräten diese Dateien nicht verwenden können. Dies erzeugt für kurze Zeit den Effekt einer Geschwindigkeitsbegrenzung. Alles, was erforderlich ist, ist eine Person, die an der Rückentwicklung Ihrer Anwendung interessiert ist, die festgelegt hat, wie diese Dateien entschlüsselt werden sollen, und dann in einem Blog oder Forum eine Nachricht dazu geschrieben hat.


Im Allgemeinen relativ wenige Menschen mit gerooteten Geräten - ich bewerte sie mit weniger als 1%. Meiner Meinung nach werden Sie mehr Erfolg haben, wenn Sie Ihre Engineering-Arbeit darauf konzentrieren, eine bessere Anwendung zu schreiben, anstatt Zeit damit zu verbringen, sich vor gerooteten Geräten zu schützen.

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


All Articles