The Storage Access Framework: Counterpoints
Last Friday, XDA Developers ran an article entitled
���The Storage Access Framework is the only way for apps to work with all your files in Android Q. And it���s terrible.���.
As you might expect from that title, the author rails against the Storage
Access Framework. The commenters do as well, by and large.
I agree that the Storage Access Framework API has issues, and I agree with
some of the arguments posed in that article. Other arguments, though, seem to
reflect the fact that the author develops a file manager, and therefore takes a
particular view of Android app development that does not reflect app development
in general.
So, let me offer some counterpoints.
With Q, Google is introducing (and requiring) ���Scoped Storage,��� which makes Android work more like an iPhone, where storage is isolated to each app. An app can only access its own files, and if it���s uninstalled, all its files are deleted.
Note the comparison to the iPhone. We���ll come back to that.
SAF has been available since Android 5.0 Lollipop, but developers tend to not use it unless required, as it has a difficult and poorly documented API, a poor user experience, poor performance, and poor reliability (largely in the form of device vendor-specific implementation issues).
The API for getting a Uri from the Storage Access Framework is fairly trivial.
The API for using the Uri is disjointed, with a mish-mash of ContentResolver
and DocumentFile being needed if you want something reasonable. And the documentation
is limited, but that is fairly common. But once you find the right methods
on those two classes, the API is not especially difficult and resembles that
of traditional file I/O.
(hey, Yi��it, if you���re reading this: how about a sexy new StorageX library in the
Architecture Components? ����)
The SAF API has gaps, to be certain, such as:
There is no ACTION_CREATE_DOCUMENT_TREE analog for ACTION_CREATE_DOCUMENT
and ACTION_OPEN_DOCUMENT_TREE, leading to some developers to
try hacks that prove to be unreliable
There is no way to specify that we need a read-write document in ACTION_OPEN_DOCUMENT,
leading to users getting screwed by Google���s ���Audio��� documents provider
Performance will be worse than with the filesystem API, but whether it matters for
the app will vary ��� more on this later.
And, ideally, Google would have been doing more from a testing standpoint, such as:
Writing a conformance test suite, so DocumentsProvider implementations can be
easily tested to determine if they comply with expectations; and
Applying that conformance test suite to any pre-installed DocumentsProvider
implementations as part of the Compatibility Test Suite
The most obvious user-facing change with SAF is the experience of granting an app access to storage. For an app to get access, it makes a request to the OS, which then displays a directory chooser screen. On this screen the user selects the root of a folder hierarchy in which that app will be able to read and write files.
Few apps need access to the complete contents of an arbitrary directory on external
or removable storage. Many apps do not need access to external or removable storage
at all. Many of those that do can get by with just getExternalFilesDir(). And
even those that need access to arbitrary content often need just a single file.
For this,
the resulting UI is not significantly different than the ���file open��� and ���file save-as���
dialogs that people have been using in desktop operating systems for decades.
Even the dialog that the author decries here is the same as the ���choose directory���
dialog that desktop users encounter from time to time.
File I/O performance takes somewhat of a hit under SAF, but the most outstanding problem lies in file directory operations, where it���s ~25 to 50 times slower than the conventional file access possible in Pie.
I have not run the benchmarks, but that result does not shock me. There are two
rounds of IPC for every SAF API call (your app to the SAF, then the SAF to the
DocumentsProvider). That is going to add overhead, compared to doing the same
thing with the filesystem.
Few apps will need to do this, though. File managers do, as they are not only working
with arbitrary directories on external/removable storage, but arbitrary
directories with arbitrary contents. Few apps are file managers or have the
storage-access characteristics of a file manager. Plus, this is the sort of thing
that the SAF could improve upon over time, such as via more aggressive caching.
An even greater performance issue is that some apps will have to copy files to their local ���scoped storage��� area before they are able to work with them.
I agree. I have been begging library authors to support streams for years.
Many Android apps take advantage of the amazing number of open-source Java libraries in the developer community, and these libraries commonly require direct filesystem access to work.
The real problem comes from libraries that need random access
to the contents of files. Those are basically SAF-resistant and will require data
copying. However, some libraries
take a File as a parameter, then turn right around, open a FileInputStream, and
work with that. Such libraries should be able to accept an InputStream as an
alternative to a File, and if they don���t, that could get fixed. For open source
libraries, code contributions may be welcome.
Of course, more of these libraries would already have been adapted had more developers
asked them to adapt rather than using script-kiddie workarounds to try to avoid
using a Uri correctly. Just sayin���.
Google touts the security and privacy benefits of this change, but technically speaking, there is no improvement.
Recall that the author compared scoped storage to the iPhone. Well, in the eyes
of the privacy and security experts that I follow, the iPhone is the gold standard, and Android is
a trash fire. People hold fundraisers to get iPhones in the hands of at-risk
people who otherwise would only be able to afford an Android device.
I hope that privacy and security experts will appreciate Android���s move towards
being more iPhone-like in this area.
Being able to control storage access on a more granular basis is a fairly massive
win. Just because App X needs access to one particular file on external storage
does not mean that App X should be granted access to all of external storage.
Yet that is what the classic READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE
permissions offer.
When you grant an app access to the root directory of your storage via SAF, it can read, write, and send any file it wants to its nefarious developer in the exact same fashion it could when you granted an app access to storage in Pie.
Few apps need access to the complete contents of an arbitrary directory on external
or removable storage. Hopefully, users will think through whether they want to
grant that right when an app asks for directory access.
There is more work that could be done to improve privacy and security here.
For example, Android needs a Settings screen where users can review what durable storage access
grants are outstanding and be able to revoke them. Users ought to be able to control
whether access is durable or not at the point of choosing the directory (or even how long the
permission grant should be, with values between ���session only��� and ���forever���).
A warning dialog
might be warranted if the user grants durable access to a root directory, to help ensure
the user understands the ramifications of that choice.
Ideally, in the long term, most users will get the ���gimme access to everything forever���
dialog once or twice a year. Hopefully everything else will get handled with things that are
more tightly scoped in terms of breadth (e.g., individual files) or time (e.g., access
for less time than ���forever���).
Some power users are going to get irritated, though. I am not going to deny that.
The only ���security improvement��� comes about because it���s now a more arduous process for a user to do this.
Users have used file dialogs in desktop programs for decades. It is possible that
those dialogs are a cause of global warming or tooth decay or something, but I doubt it.
The official stated reason in the Android Q beta documentation is to ���give users more control over their files and to limit file clutter.���
That part of the documentation needs to get fixed. The revisions in Q Beta 3
basically eliminated that rationale.
If Google is truly concerned about giving users more control over files and clutter, they should architect a solution that directly addresses that, rather than falsely branding the current Android Q design as such an improvement.
It is an improvement. It may not be the best possible improvement; there will
be collateral damage stemming from this particular approach. And, as I have written about
extensively, I think the rollout had loads of issues. But, it is an improvement.
And while it may sound hyperbolic, I can honestly say that lives might be saved
in the long run by this change.


