The Death of External Storage: More of the Story

A month ago, I wrote a blog post about the changes in external storage on Android Q.

I intentionally skipped one finding, because it really seemed like a bug. However, apparently, it is working as intended.

So, let’s revisit what you can do with the external storage filesystem in Android Q.

And, as a reminder: unless Google changes things, these rules affect all apps, regardless of targetSdkVersion (except for apps already installed on a device that gets the Q upgrade).

UPDATE 2019-05-13: Google changed things.

UPDATE 2019-06-08: With Q Beta 4 out, the story is now much simpler. I am leaving the original post here for historical reasons.

Where Can You Write?

You cannot write to the standard directories available from `Environment.getExternalStoragePublicDirectory()`. So, you cannot write to `DIRECTORY_DOWNLOADS` or `DIRECTORY_MUSIC` or places like that. Largely, that is because they already exist and were not created by your app.

UPDATE 2019-04-28: The behavior of Environment.getExternalStoragePublicDirectory() is more complicated than that.

However, you can:

  • Create files in the root of external storage (Environment.getExternalStorageDirectory())

  • Create directories in the root of external storage

  • Create files in those directories that you created

Basically, if it already exists — such as directories that were created as part of setting up the device — you have no write access. If you create it yourself, though, you do have write access.

What Can You Read?

If you wrote it, you can read it.

However, that is it. You cannot read the contents of files or directories that were created by other means, using filesystem APIs.

What Permissions Do You Need?


No, Seriously, What Permissions Do You Need?

None. This was the part that I thought was a security bug. ¯\_(ツ)_/¯

If you have targetSdkVersion 'Q', or if you have targetSdkVersion 28, you can write to the root of external storage and read back what you wrote, without any permissions. Presumably, this holds true for at least some older targetSdkVersion values, but I only tested these two.

The reason why READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are deprecated is that all of external storage — except for existing files and directories — works like getExternalFilesDir():

  • You do not need any permissions
  • What you create is removed when the app is uninstalled or if the user clears storage for the app

What Can Other Apps Do With Your Files?

What you create and write in external storage via the filesystem is inaccessible to other apps via the filesystem, no matter where it is.

What you create in getExternalFilesDir() will be accessible via the Storage Access Framework, but what you create in the root of external storage is not. As a result, anything you put in the root of external storage (or custom directories off of the root) is private to your app, except to the extent that you expose them via FileProvider or something.

What About the User and a USB Cable?

Similarly, what happens here depends on which portion of the external storage filesystem that you use.

For getExternalFilesDir() and kin:

  • Files and directories that you create are visible to the user

  • Files and directories that the user creates are visible to you

For the root of external storage:

  • Files and directories that you create are not visible to the user (MediaScannerConnection seems to not work for those files, and ACTION_MEDIA_SCANNER_SCAN_FILE has been deprecated with no stated replacement)

  • Files and directories that the user creates are not visible to you

Even as a developer, adb does not show app-created files in the external storage root directory. Nor does Android Studio’s Device File Explorer.

So, What Should I Do Now?

In general, my previous recommendations still hold up:

  • Use the methods on Context like getExternalFilesDir() to find places to write, if you need to make the files available to the user via USB

  • Use the Storage Access Framework

  • Use the MediaStore for media

  • Use FileProvider to make your content available to other apps for outbound requests (e.g., ACTION_VIEW and ACTION_SEND Intents)

  • If applicable, support ACTION_VIEW and/or ACTION_SEND in your manifest, so other apps can use those Intent actions to send you content

If you have existing code that writes files to the root of external storage or some custom directory off of it, that code will continue to run. However, the user will be unable to access those files, except through your app. In general, it will be better to migrate those to getExternalFilesDir(), if user access to those files is important.

It is entirely possible that there are yet other combinations, scenarios, and mysteries yet to be discovered. The key is that you should test your app early and often on Android Q.