Android™ Scoped Storage
Background
In the last few years Google has been introducing enhancements and restrictions to further secure the Android™ operating system. A key area of focus has been the ability of an application to write to any directory within the file system. Google views this is as an unsecure, so as of Android 11 they are restricting where apps can write and read data.
Quick introduction of Scoped Storage
Scoped storage was introduced into Android to ensure that every app only utilizes its own file sandbox for storing its content. Every app has their own directory in internal storage which is found at /android/data/ , everything else is considered shared storage and is not recommended be used for app specific data.
Benefits of Scoped Storage
Improving data security and privacy
App developers will have more control over the files they create. This will allow them to work with files without requesting storage permissions. The use of storage permissions was traditionally abused by developers as it gave them access to the entire external storage. Scoped storage will also provide increased app data protection as other apps will not be able to access files that may contain sensitive data.
Limits file clutter and residual left-over app data
In the past an application may have written to locations outside of its own directory, scoped storage ensures that when an application is uninstalled all the data it created is removed. This eliminates file clutter and storage space usage with unnecessary files that are no longer in use and greatly reduces the risk of left over files potentially performing nefarious activities.
Scoped storage enforcement
In Android 9 Google started setting up the direction to move to scoped storage by limiting access to certain areas of the file system.
Starting with Android 10 apps were forced to use scoped access for storage (app sandbox) by default. Since this was a significant change for developers, Google provided a method for an app to opt out by declaring a requestLegacyExternalStorage flag in their manifest. This flag allows apps to temporarily opt out of the changes associated with scoped storage, such as granting access to different directories and different types of media files.
With Android 11, Google will deprecate the ability for App developers to use the requestlegacyexternalstorage flag to opt out of Scoped Storage. From Android 11 forward all Android devices will comply with Scoped Storage rules.
Options for developers
Migrate data to directories that are visible when using scoped storage
If your app uses the legacy storage model and previously targeted Android 10 or lower, you might be storing data in a directory that your app cannot access when the scoped storage model is enabled. Before you target Android 11+ OS, migrate data to a directory that's compatible with scoped storage. More details can be found at Android storage use cases and best practices | Android Developers.
Share content between apps
To share your app's files with a single other app, use a File Provider (Setting up file sharing | Android Developers). For apps that need to share files between each other, Google recommends using a Content Provider for each app, and then syncing the data as apps are added to the collection (Content provider basics | Android Developers).
Your app may use the android content provider, together providers and provider clients offer a consistent, standard interface to data that also handles inter-process communication and secure data access.
Zebra has also developed a method for applications to securely exchange data, the Secure Storage Manager (SSM) which is documented at the Zebra Techdocs https://techdocs.zebra.com/ssm/1-1/guide/about/
Credit: a special thanks to Azzam Affam for the content
Back to the basics
The previous sections completed the quick introduction to the Scoped Storage, also providing readers with a few options to mitigate its impact. As part of a deeper understanding of Scoped Storage, you might want to see things from a wider perspective.
Recalling locations for storing data
Scoped Storage is part of the wider notion of Storage which includes
Here is an example of how the Android storage is organized
And when a Work Profile (Android Enterprise) is setup along with primary one (e.g. in COPE mode), your filesystem is including paths like
SD-Cards and the Zebra /enterprise partition
- Are removable SD-Cards or USB volumes subject to Scoped Storage? Yes!
- There are specific APIs to query the external storage availability
- getExternalStorageDirectory () Returns the primary shared/external storage directory.
- In devices with multiple shared/external storage directories, access to secondary storage (SD Cards) is available through Context#getExternalFilesDirs(String), Context#getExternalCacheDirs(), and Context#getExternalMediaDirs() and the StorageVolume class.
- From best practices for Android™ 11+:
- If targeting API 29 or lower, declare WRITE_EXTERNAL_STORAGE
- Use MediaStore and/or Direct file access otherwise
- Enterprise folder (Zebra’s proprietary partition) should never be used as a sharing place – it’s meant for different use cases.
Available APIs to deal with external folders
These methods support developers in pointing to the right app folder.
They are even more useful when your app is running in a secondary profile like Work Profile in COPE mode, so you can retrieve the right path which includes the usedID – Never hard-code paths in your apps!
Similarly for an app running in the Work profile:
Taming the Scoped Storage
Sooner or later, as a developer, you’ll find yourself face to face with Scoped Storage. It might happen
- Running an old app on a more recent Android version
- Porting your code to targeting API level where Scoped Storage is enforced
- Writing a brand-new app – and you might want to embrace it from day one!
Having looked-up several documents on this subject and analyzed plenty of code lines, I’ve found out four dimension of Scoped Storage – Dimensions are intended as the focus areas where you should focus when dealing with this matter.
Emerging dimensions of Scoped Storage
- TYPES OF SHARABLE DATA
- PERMISSIONS
- TARGET APIs AND APP DISTRIBUTION
- CONSUMING DATA
About TYPES OF SHARABLE DATA
In the Android™ perspective, data should be shared by using the sharable storage and the specific APIs for each
type of data. Several enterprise use-cases of files do not fall in this schema.
Media content: The system provides standard public directories for these kinds of files.
The user has a common location for all their photos, another common location for all their music and audio files, and so on.
Here MediaStore API is the is the mainstream. It supports items metadata natively (e.g. ISO number for a picture)
Direct file access however is allowed for compatibility reasons.
Documents and other files: The system has a special directory for containing other file types, such as PDF documents
and books that use the EPUB format. Your app can access these files using the platform's Storage Access Framework,
which of course is not an option for many enterprise apps.
Datasets: On Android™ 11 (API level 30) and higher, the system caches large datasets that multiple apps might use.
These datasets can support use cases like machine learning and media playback.
Apps can access these shared datasets using the BlobStoreManager API.
For the enterprise use cases, handling of non-media file might be of high interest
Here is the guide from google
About PERMISSIONS
- Permissions are evolving
The majority of apps that require shared storage access can follow the best practices for sharing media and non-media files. For Media Store, Android™ 13 offers READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO permissions. - Use ACCESS_MEDIA_LOCATION to get pictures’ Exif metadata
- MANAGE_MEDIA since Android™ 12 allows media access
without asking user consent - Getting rid of the Scoped Storage?
Some apps have a core use case that requires broad access of files on a device but cannot do so efficiently using the privacy-friendly storage best practices.- Android™ provides a special app access called “All files access” for these situations. The MANAGE_EXTERNAL_STORAGE permission is reserved for such cases
- This permission can be obtained by declaring it in the manifest and asking the user confirmation with ad-hoc dialog.
Stagenow is able to grant this permission to an application: in that case no user intervention is needed.
Apps using scoped storage can have the following levels of access (Android™ 11+)
- WRITE_EXTERNAL_STORAGE permission and WRITE_MEDIA_STORAGE privileged permission no longer provide any additional access
- Read and write access to their own files with no permissions
- Read access to other apps' media files with READ_EXTERNAL_STORAGE permission
- Write access to other apps' media files is allowed only with direct user consent
- No read or write access to other apps' external app data directories
- “android.permission.MANAGE_EXTERNAL_STORAGE” plays a big role since it lets
your app access the whole filesystem (with some caveats depending on the platform)
About TARGET API & DISTRIBUTION
Google Play (for GMS developers)
- There are Target API requirements for Google Play Apps.
E.g. Since Nov.1, 2022 apps target APIs<30 are not discoverable on Play by new users. See below for dates valid at the time of writing of this blog
- Such constraint is limiting your options in terms of choosing a lower target API to mitigate the Scoped Storage enforcement.
- On the Play theme, be mindful there are further requirements for App discoverability and updates:
Finally, an additional requirement for Play store is about Permissions
- As part of the Permissions and APIs that Access Sensitive Information document
- Apps should only request access to device storage which is critical for the app to function and may not request access to device storage on behalf of any third-party for any purpose that is unrelated to critical user-facing app functionality.
- With Android™ 11+ apps requesting broad access to shared storage (“All files access”) must successfully pass an appropriate access review prior to publishing. This is about the MANAGE_EXTERNAL_STORAGE flag: “Intended to be used by few apps that need to manage files on behalf of the users.”
Constraints on Target API
- On Android™ 13, adb/manually installing an app targeting API<26 causes a blocking message to popup
- Same for Android™ 11 when API<23
- Even StageNow can’t help here
- Trying to circumvent scoped storage with older Target API levels?
- That would be a short-lived solution
- https://developer.android.com/about/versions/11/privacy/storage#other-apps-data
E.g. if your app targets Android™ 11, it cannot access the files in any other app's data directory, even if the other app targets Android™ 8.1 (API level 27) or lower and has made the files in its data directory world-readable.
CONSUMING DATA
How two or more apps share data
- Keep apart data concerning only the app itself, use internal storage
- For sharable data, stick to the Media rules for those kind of files
- For non-media data, understand how Zebra implemented scoped storage on its devices
- Available options are direct file, content providers, Zebra Secure Storage Manager
Conclusions
This blog was intended to provide you with both a general and a detailed view of Android™ Scoped Storage. The upcoming release of Android™ 13 is still under development now. As soon as it will reach a stability, I’ll add more details on this subject specifically from the Zebra perspective so that you can take fully advantage of our powerful devices. In the meanwhile, I’m whishing you happy coding and see you soon!
External links on Scoped Storage
- Links to Android™ doc
- https://source.android.com/docs/core/storage/scoped
- https://source.android.com/docs/core/storage/adoptable
- https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory()
- https://developer.android.com/training/data-storage/use-cases#write-files-secondary-storage-volumes
- https://developer.android.com/training/data-storage/shared/media#media_store
- https://developer.android.com/training/data-storage/shared/media#direct-file-paths
- https://developer.android.com/reference/android/app/blob/BlobStoreManager
- https://developer.android.com/training/data-storage/use-cases#handle-non-media-files
- https://developer.android.com/training/data-storage/shared/media#request-permissions
- https://developer.android.com/training/data-storage/manage-all-files
- https://support.google.com/googleplay/android-developer/answer/11926878?hl=en#:~:text=Starting%20November%201%2C%202022%20if,time%20to%20update%20your%20app.
- https://support.google.com/googleplay/android-developer/answer/9888170
- https://developer.android.com/about/versions/11/privacy/storage#other-apps-data
- https://developer.android.com/about/versions/13/behavior-changes-all
- https://developer.android.com/about/versions/13/behavior-changes-13
- https://developer.android.com/about/versions/13/migration
- Daniel’s post on Access all files permission
Nicola De Zolt
.