Is SAF Android's death knell?

881 views
Skip to first unread message

ama...@gmail.com

unread,
Jan 26, 2016, 4:54:12 PM1/26/16
to android-platform
I really let this go for far too long.  First and foremost all the flaws I point out here would be easily avoided by simply implementing the tried and true filesystem securities within Linux.  Why they didn't do so, we will forever lament...

Instead we get a rushed half-baked platform that tries to deliver security to corporations who weren't and aren't interested in Android, while the developer community suffers this endless blunder.

History:
4.4  - The "quite rich API" Storage Access Framework was introduced. It completely broke external SD cards.  There was no fix; there was a sketchy work-around (and even that got patched).  Designers were unapologetic and simply pointed to this half-baked, barely functional new tool as if it actually did something. 

5.0 - The "quite rich API" finally gets patched to be marginally useful.  Now that developers can actually fix their apps that haven't worked for over a year, we all scramble to implement a new solution. We find that the "quite rich API" is a nightmare to work with intimately.  Every simple file access method becomes hundreds of lines of unwieldy code.  Yay!

6.0 - Android now supports USB drives.  "...wait what?", says 95% of the Android community, "didn't it always?".  Yes it did through fragmented manufacturer-specific implementations.  "Great, this will really simplify things!", says the developer community, and we all scramble to implement a new unified system.  We quickly come to find that the new built-in support is even worse than with SD cards in 5.0.  For one it doesn't truly mount the device, causing all sorts of nightmares in java and native.  A level of ambiguity that's entirely unnecessary under any consideration.  It also precludes ever doing anything quickly with an external device.  After weeks of work we sit back and realize we've got a hack of a solution that was 100x harder than supporting thousands of device-specific implementations.  I'm seriously flabbergasted that a platform like this could make it through even minimal critical review. 

Specifics:
  • The idea behind SAF was a unified interface that adheres to Android design concepts which any app can go to for access to the file-system (and more).  Sounds great on paper, but in reality it completely jacks up the Android life-cycle.  For ex.:
    1. User requests an 'Interaction A' with a file. 
    2. User sees an explanation of what the app would like the user to do with an ACTION_OPEN_DOCUMENT_TREE.
    3. User now sees another dialog (SAF) and does as instructed.
    4. User returns to app and 'Interaction A' didn't happen
    • Since the life-cycle was interrupted to request permission the user is now confused as to why they obeyed all instructions and the action was not executed. This is atrocious HMI, but this is what we're expected to develop. To work around this I have a 1000 line wrapper on Activity that handles requested file actions and allows them to be saved and resumed with minimal wiring. That is not an acceptable platform. I really hope the designers don't think it is.
    • There are two simple solutions to this:
      • Ideally offer a SAF dialog that does not interrupt the life-cycle.  It's not like the intent system is really a necessity to access fundamental Android features.
      • For a quick hack just allow SAF intents to pass through extras allowing the requesting activity a means to trace their actions without poor practices like globals and method constants.
  •  DocumentFile.findFile is so slow it's completely unusable.  Therefore you have to rely on slicing and dicing document uris with the hope that in Android 6.1 they will still be hierarchical tree structures. The Document API in general is just plain slow.  Any heavy disk usage takes a heavy performance penalty.  All this to avoid the pesky Linux routines that have only worked for over 20 years.  I really can't express enough how critical the performance hit is.  I've spent endless hours fine-tuning the speed of my app and the move to 6.0 makes it feel sluggish with no possible remedy.
  • DocumentFile.getParent ONLY works with the File factory.  This means that as of 6.0 and the assassination of File we no longer have a means of walking a hierarchical tree.  This is even more amazing given that DocumentsContract already contains almost all the code to reliably produce parents of singleUri and treeUri.  It really didn't take much to write a UsefuleDocumentFile wrapper that made DocumentFile actually useful.
  • USB drives:
    • a) are not truly mounted.  This is a completely unnecessary ambiguity.
    • b) cannot be identified uniquely with the UsbDevice interface.
    • Due to a & b, every time a usb drive is connected an app would need to access the SAF interface even if they already have permission.  The only possible way around this is to try to access any previous UriPermission that you know were USB to see if they still exist (with the overhead of at least opening a stream).  If they do exist, skip the unnecessary SAF interface that the user doesn't want to see on EVERY connection. But wait! that doesn't work because the USB drive takes SECONDS to pseudo-mount.  So we're left with a hack to check for device permission, that has another hack to wait for the Android system hack to kinda sorta mount the usb drive.  This is coding for Android in 2016 folks.  It's an evolution of the process for removing teeth.
    • Possible solutions:
      • Ideally just mount the device.  You've managed to protect SD cards in that manner, why rewrite the wheel and why make it square?
      • Another option is a new intent (ACTION_SAF_ROOT_ADDED, etc) to monitor the availability of a new SAF root.
      • Last ditch solution, make ACTION_USB_ATTACHED wait until the SAF pseudo-mount is complete.

Honestly, someone out there really owes an apology to any developer that had so much time already invested in their app that they actually tried to work with SAF.  These kinds of draconian restrictions and blunders are what drove many of us from Apple to Android for advanced apps.

ama...@gmail.com

unread,
Jan 26, 2016, 5:22:40 PM1/26/16
to android-platform
I actually forgot one of the best examples of what an afterthought SAF is.  It's actually impossible to use MtpDevice with the new system:

MtpDevice.importFile(int handle, String path)

So even though USB storage support was a focus of 6.0, somehow an outstanding fundamental USB storage deficiency wasn't addressed?

ama...@gmail.com

unread,
Feb 16, 2016, 2:56:48 PM2/16/16
to android-platform
This solves most of the DocumentFile issues:

https://github.com/rcketscientist/DocumentActivity/blob/master/library/src/main/java/com/anthonymandra/framework/UsefulDocumentFile.java

The project in general is a hack at making write actions more user friendly and resume-able, but the Activity portion is still a little rough around the edges.
Reply all
Reply to author
Forward
0 new messages