Files
notes/docs/lectures/mdp/10_storage.md
T

7.7 KiB
Raw Blame History

Storage

Storage Principles

App-Specific Requirements

  • Store files that are meant for our use only
  • Store files that we intend to share with other apps
    • e.g. taking a photo
  • Store private, primitive data
    • Config data, passwords, cookies & keys, etc.
  • Store private, structured data
    • text messages

Mobile Storage Principles

  • Efficiency and sharing vs privacy and security
    • Limited storage capacity
    • Highly personal information stored
    • Lots of different data types stored on phone
  • Media
    • Images, videos, music

Access to the mail should be protected since this is sensitive user data. However, if a reference to an image attachment is given to an image viewer, that image viewer will not have permission to open the attachment since it has no reason to hold a permission to access all e-mail.

Storage Directories

/system -> stores Android OS & libraries

/data -> where user data is stored (every application is a user)

/mnt/sdcard (symlinked as sdcard) -> External Storage

Basic Logical Data Storage on Android

Different Volumes
Internal
  • Limited space for app-specific data
  • Reliable (not removable)
  • Soldered RAM
External
  • Lots of data
  • May (or may not) be physically removable
Different kinds of data
  • Data that is only meaningful for our app should use app-specific storage
  • Shareable media content should use shared storage so that other apps can access the content
    • Also called scoped storage
File-based abstractions
  • Shared preferences
  • File-based storage
  • SQLite database
    • Structured data, small binary blobs

image-20220107004129910

Internal File Storage

Internal data storage is private to the app

  • Other apps (and the user) cannot access it
    • Kernel-enforced user perms
  • Removed on uninstall
  • Data is stored in files
    • /data/data/com.example.project/files/
    • Full path not accessible; files/ becomes the chroot
    • This ensures we cannot traverse the directory upwards and gain access to other applications' files
Cache Files

/data/data/com.example.project/cache

getCacheDir() -> gets application’s file directory

Programmer should manage the files

  • May be deleted when internal storage becomes full
  • Will be deleted when application is uninstalled
  • A well-behaved application will delete them when no longer in use
  • Recommended to use less than 1MB

Shared Preferences

  • Stored on a per-application basis
    • e.g. saving config info (settings)
    • Should not be used for data transfer (use intents and binders instead)
  • Primitive data in key-value pairs
  • Can have multiple preference files per application
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="colourscheme">light</string>
</map>
SharedPreferences settings = getSharedPreferences(CONFIG_STORAGE_NAME, 0);
SharedPreferences.Editor editor = settings.editor;

if (settings.getBoolean(MainActivity.CONFIG_THEME, false))
    setTheme(...);
else
    ...

External Storage

Legacy name

  • Every Android device provides externally accessible storage (SD card)
    • Even phones without a physical SD card must have a logical representation of external storage
      • Most phones will have one storage device partitioned into internal / external
      • Phones must do this to conform to the Android API
    • Private Application files
      • Internal storage on the external partition
      • getExternalFilesDir()
      • /sdcard/Android/data/com.example.project/
    • Public general files
      • World reachable
      • Other apps can read and modify these files
      • Each user has their own virtual SD card
  • Can be mounted externally (and unmounted/disconnected)
Getting Access to External Storage
  • Should check state with Enviroment.getExternalStorageState()
    • It is a separate file system, potentially removable
      • Environment.MEDIA_MOUNTED
      • Environment.MEDIA_MOUNTED_READ_ONLY
  • Use getExternalStoragePublicDirectory (String type) to obtain file for the directory
    • Media is stored by type
      • Music in the music dir, etc.
    • Pass a type to obtain the subdirectory for that type
Getting Scoped storage access
  • To access files that other apps have created
    • We must have READ_EXTERNAL_STORAGE permission (in the manifest)
      • With this one permission, the app can do whatever (look at downloads, listen to music, look at pictures, etc.)
      • This is where scoped storage comes into play
    • The files must reside in the media collection (images/music/videos, etc.)
    • or request legacy storage MANAGE_EXTERNAL_STORAGE (before Android 11)
  • Apps only have access to
    • App-specific directory on external storage
    • Specific types of media that the app has created and contributed to well-defined collections
      • If the app takes a picture, it is allowed to store and look at that picture but not allowed to access pictures not taken by that app
      • You don't need to request perms to read/write images that we are writing to the MediaStorage

Android Databases

When the data stored is logically structured, queries are needed to find it based on the structure.

  • Android provides local database support
    • Can run full SQL queries
  • Each app’s databases are local to it
    • Database.db stored in internal storage
  • Powered by SQLite

Android and SQLite

  • Wrapped in two main classes
    • Database represented by SQLiteDatabase object
      • Allows us to run SQL queries on the database
    • SQLiteOpenHelper
      • Supports the application lifecycle
      • SQLiteOpenHelper -> onCreate()
        • Creates the database the first time it is called
        • This database will exist until the application is installed
      • SQLiteOpenHelper -> onUpdate(int oldVer, int newVer)
        • Changing the version number allows the database to be dropped and recreated
  • Create an instance of our SQLiteOpenHelper subclass
  • Get reference to SQLiteDatabase using
    • getReadableDatabase()
    • getWriteableDatabase()
Querying a Database

void execSQL() -> used to execute SQL queries that don't return anything

query() and rawQuery()

  • These return a Cursor object pointing to the results

Cursor rawQuery (String sql, String[] selectionArgs)

Cursors
  • Provide random access to results of a query
  • Enable us to enumerate the rows returned by the query
    • moveToFirst(), moveToNext()
    • getString(colIndex), getInt(colIndex)
  • Have a close() method to close the query when finished

We can pass cursors to other applications

CursorLoader
  • A query may last some time
    • Database may be large
    • May be in a different process
    • Don’t block the main thread
  • CursorLoader
    • Populates views asynchronously
    • Auto-updating

(deprecated)

Data-Driven Views

  • Connect a cursor to a CursorAdapter and a ListView
    • Think mapping rows of a database to which entry in the list
    • Each row must have an ID field
  • RecyclerView
    • An optimised, flexible version of the above
    • Only creates views for visible data
      • As the user scrolls, more data is added
    • We can define our own adaptor

Database Abstraction

Abstraction of database architecture

  • Easier to update storage code
  • Expose column indices as static class variables
    • c.getInt(0) ✗
    • c.getInt(DBHelper.NAME) ✓
  • Helper methods keep database internals from leaking into other classes
    • Return a collection of results rather than the cursor
  • Sanitise user inputs
    • SQL injections still apply