Android Storage: Internal, External, Removable. Part 1/3

    Anyone who, despite everything, has managed to make the right choice.

    This is a translation of a series of articles by Mark Murphy from CommonsWare, widely known on stackoverflow, as well as the author of the books “The Busy Coder’s Guide to Android Development”, “Android’s Architecture Components”. Some terms are left untranslated.


    Internal Storage


    There is a lot of confusion regarding the Android storage model. The confusion has become much more with the changes of Android 4.4 in the Storage Model, and the situation has not improved since then. There are countless questions on Stack Overflow and other similar resources, where people clearly do not quite understand the various models of Android storage.


    What Users Consider Internal Storage


    Depending on the model of your device, users will eventually come to “Settings” -> “Storage on this device” (Settings -> Storage on their device) or in an equivalent place, and can see a screen that describes “Internal storage” .


    The user thinks that the entire built-in flash drive is “Internal Storage” (Internal Storage). Fortunately, Google began to change this term with Android 8.0, going to “general storage” instead of “internal storage”.


    However, users can still see “internal storage” in places like the Windows Explorer window when their device is connected via USB.


    What Google Considers Internal Storage


    Alas, what users see is not the same as the Android SDK considers “internal storage”, which leads to some confusion. If you read the Android documentation on the internal storage , then this description ... at least vague (note the text has changed since the writing of the article):


    You can save files directly to the device’s internal memory. By default, files stored in the internal storage are private to your application, and other applications cannot access them (as well as the user). When the user deletes the application, these files are deleted.

    Truth be told, the Android SDK defines “internal storage” as a special directory unique to your application, where your application can host files. As suggested in the documentation, these files are by default intended for reading and writing for your application and are prohibited for any other application (exception: users working with file managers with root privileges on rooted devices can access everything).


    In Context, there are several basic methods that give you access to internal storage, including:


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

    Other methods will rely on them, such as openOrCreateDatabase(). Other classes will also rely on them, such as SQLiteOpenHelperand SharedPreferences.


    Where Internal Storage is Stored ... Sometimes


    If you browse the various blog posts, answers to StackOverflow and books published in 2012 or earlier, you reported that "internal storage" of your application is available at: /data/data/your.application.package.name.


    Inside there will be some directories automatically created by Android, since you are using some of the Context methods. For example, getFilesDir()returns an object Filepointing to a directory files/in your application's internal storage.


    Where is the internal storage stored ... Rest of the time


    However, the internal storage of your application is not always located in the specified location. For developers, there is one rule that you should learn from this series of blog posts:


    NEVER HARDCODE PATHS .


    From time to time, I see developers doing something like this:


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


    This is not a crime, it is worse, it is a mistake.


    The right move, and write less:


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


    More importantly, the internal storage is not always in one place . It is noteworthy that we have the concept of separate user profiles (separate user profiles), starting with Android 4.2 for tablets and Android 5.0 for phones. Each user gets their own "internal storage". Although the above directory is still used for the primary user, it is not guaranteed that it will also be used for secondary accounts.


    We investigate Internal Storage


    The Device File Explorer tool in Android Studio 3.0+ can view all internal storage on the emulator, as well as internal storage of debugged applications on production devices.


    The command line you can use adbwith the option run-as.


    For example, to load a database from the main user's internal storage to your development machine, you can use:


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


    Note that:


    • You will need to change your destination to where external storage is mounted on your device (shown here as /sdcard/, which will not be the same on all devices)
    • You may have to use catinstead of cpolder devices.
    • After the file is located on external storage, you can use adb pullit to download it to your computer, or access it in other usual ways (for example, by mounting the device as a disk).

    Internal storage restrictions


    On older Android 1.x and 2.x devices, internal storage was usually located in a dedicated section of the file system, and this section was usually quite tiny. HTC Dream (aka, T-Mobile G1), the original Android device, had a huge 70 MB of internal memory for use by all applications (this is not a typo, at the time we measured the memory in megabytes).


    By the time 2.3 devices came out, the internal storage could be 1 GB in size.


    Android 3.0 has changed the storage model, as the internal storage has become more volume. Devices that advertise as having 4 GB, 8 GB, 16 GB, etc. storage space, there was usually all this (minus existing content) available for internal storage. We will look at what has changed in Android 3.0 and its effect on the storage model in the following posts about external storage.


    For Android 1.x and 2.x, internal storage was really only for small files, and you needed to use external storage for everything else. Android 3.0+ means that for most devices and most users, internal storage is great for files that are not intended for normal use by other applications or are accessible to the user regardless of your application. However, some experienced users find that even on-board flash is not enough for what they want to store, so they switch to removable storage ... which is a jar of worms (note ἕλμινς) - the source of many unpredictable and complex problems.


    FAQ on Internal Storage


    Should I make files in the World-Readable or World-Writeable internal storage?


    Oh, $ gods, no. Use FileProviderand maintain this content through implementation ContentProvider. After that, you at least have the ability to use the Android permission system to control access to these files, unlike your version, when any application on the system can corrupt these files.


    Well, what about android:sharedUserId?


    I do not advise.


    android: sharedUserId- This is an attribute that you can put in a manifest that indicates the logical user ID that will be used for your application. Any other application that is installed that is signed by the same signing key and requests the same one android:sharedUserIdwill use the same Linux user from a security point of view. The effect is that these two applications will be able to work with each other's files with impunity, since these files belong to the same Linux user.


    This attribute is really intended for pre-installed applications, such as the software suite pre-loaded by the device manufacturer, mobile operator or developer of a modified ROM firmware. In particular, once you install your application once, you will not be able to change your value android:sharedUserIdwithout painlessly without blocking the user from accessing any existing files ... since Android does not change the owner’s rights to existing files when changing the Linux user account under which the application runs .


    There are various risks with simultaneous access of several processes to files. Some subsystems, such as SQLite, have built-in logic to solve this problem. But if you are organizing your own access to the file yourself (for example, via FileJava I / O), you need to do something with simultaneous access, and this is difficult.


    You also need to handle the situation when one application is uninstalled by deleting files that another application used. In the hub-and-spoke model, for example, with an application and a set of plug-ins, this may not be so risky. In other models, where applications are more equal, you cannot afford to lose the data of your application just because the user decided to delete a separate application.


    Finally, you do not know what the future can bring. Right now you can view your suite of applications as a set with a close connection. Someone who acquires these applications or acquires your company may wish to go some other way. Using data sharing features that are more loosely coupled, for example ContentProvider, gives you more flexibility. In an ideal world, your application should treat other applications as a fairly reliable, but not always accessible resource, just like your own web service.


    How to prevent users of rooted devices from accessing my files in the internal storage?


    Just do not place files in the internal storage. Users of rooted devices can gain access to what they need on the device, so the only way to prevent them from accessing your data is to not have them on the device.


    Some developers will try to encrypt their files with a hard-coded password so that users of rooted devices cannot use these files. This will create a “speed bump” effect for a short time. All that is required is one person who is interested in reverse engineering your application, determined how to decrypt these files, and then wrote a blog or forum post about how to do this.


    In general, there are relatively few people with rooted devices - I rate them at less than 1%. IMHO, you will succeed more by focusing your engineering work on writing the best application, instead of wasting time on protection from rooted devices.


    Also popular now: