[Android Framework Series] Chapter 17 Android Q Sandbox Mode (Scoped Storage)

1 background

The previous chapter [Android Framework Series] Chapter 16 Storage Access Framework (SAF) mainly analyzed the storage access framework (SAF) introduced in Android 4.4 存储访问框架(SAF). In this chapter we Android10(Q)analyze the storage related and understand its restricted storage methods.

GoogleTo give users more control over their files and limit file clutter, the way you access your device's storage Android Q has changed .App

Before 1.1 Android Q

As long as the program obtains READ_EXTERNAL_STORAGEpermission, it can freely read the external storage public directory;
as long as the program obtains WRITE_EXTERNAL_STORAGEpermission, it can freely create new files or folders on the public directory written to the external storage.
Insert image description here

1.2 Android Q and later

So Google proposed it in Android Q 分区存储, intending to limit the use of public directories in external storage by programs .
Partitioned storage has no impact on both internal storage private directories and external storage private directories.
Insert image description here

2 Sandbox mode

2.1 Android Q stipulates that the App has two storage space mode views: Legacy View and Filtered View.

2.1.1 Legacy View (compatibility mode)

When the project targetSdkVersion <= 28, the compatibility mode is used by default on the AndroidQ device, the storage method is the same as Android Qbefore, Appand the access Sdcardis complete, with full access permissions.

2.1.2 Filtered View (sandbox mode)

When the project targetSdkVersion > 28, the AndroidQ device Appcan only directly access App-specificdirectory files and does not have permission to access App-specificexternal files. Access to other directories can only be provided through MediaStore, SAF, or other Apps ContentProvider.

2.2 Scoped Storage divides the storage space into two parts

2.2.1 SD card public directory: Downloads, Documents, Pictures, DCIM, Movies, Music, Ringtones

  1. Files in the public directory Appwill not be deleted after uninstallation
  2. Can be accessed through SAFthe MediaStoreinterface

2.2…2 data/data private directory (App-specific directory)

  1. For Filtered View App, App-specificthe directory can only be accessed directly by yourself
  2. AppUninstall and the data will be cleared.

2.3 Compatibility impact

Scoped StorageIt has a great impact on App访问存储方式, App数据存放and App间数据共享.

2.4 Adaptation

For specific adaptation, please refer to the official documentation.

2.4.1 App running view

The system determines the App running mode through the following:

  1. App TargetSDK > 28,defaultFiltered View(沙箱模式)
  1. App TargetSDK <= 28, declares READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permission, defaultLegacy View(兼容模式)
  1. The application can set requestLegacyExternalStorage through AndroidManifest.xml and select the corresponding method:
    declared READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGEpermission (ignored if not declared):
    requestLegacyExternalStorage=truemeansLegacy View(兼容模式)
    requestLegacyExternalStorage=falseFiltered View(沙箱模式)
    (注意:该方式Android11后失效了)

    Insert image description here
  1. System applications can apply for android.permission.WRITE_MEDIA_STORAGEsystem permissions and also have full storage space permissions and can access all files. However, in the CTS test, only apps that have no user interaction and are visible can apply. Specific reference 《Android Bootcamp 2019 - Privacy Overview.pdf》.
  1. App is owned when the following conditions are met
    : ① Statement INSTALL_PACKAGES, or 动态申请INSTALL_PACKAGESpermission
    ② Ownership WRITE_EXTERNAL_STORAGE权限
    ③ App ownership 外置存储空间Read、Write权限.
    However, Environment.isExternalStorageLegacyjudging by the interface, the return is not necessarily a Legacy View.

2.4.2 Determine the current App running mode

To determine what mode the current App is running, you can use this API to determine:

Environment.isExternalStorageLegacy();

2.5 Reading and writing public directories

After the App is started Filtered View, it can only access itself directly App-specific目录, so Android Qtwo methods of accessing the public directory are provided:

2.5.1 Uri defined by MediaStore

MediaStoreThe following types of access are provided Uri, and the purpose of access is achieved by searching for the corresponding Uri data.
Each of the following types is divided into three types Uri, Internal, External, 可移动存储:

Audio

  1. Internal: MediaStore.Audio.Media.INTERNAL_CONTENT_URI
    content://media/internal/audio/media。
  2. External: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
    content://media/external/audio/media。
  3. Removable storage: MediaStore.Audio.Media.getContentUri
    content://media//audio/media.

Video

  1. Internal: MediaStore.Video.Media.INTERNAL_CONTENT_URI
    content://media/internal/video/media。
  2. External: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    content://media/external/video/media。
  3. Removable storage: MediaStore.Video.Media.getContentUri
    content://media//video/media.

Image

  1. Internal: MediaStore.Images.Media.INTERNAL_CONTENT_URI
    content://media/internal/images/media。
  2. External: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    content://media/external/images/media。
  3. Removable storage: MediaStore.Images.Media.getContentUri
    content://media//images/media.

File

  1. MediaStore. Files.Media.getContentUri
    content://media//file。

Downloads

  1. Internal: MediaStore.Downloads.INTERNAL_CONTENT_URI
    content://media/internal/downloads。
  2. External: MediaStore.Downloads.EXTERNAL_CONTENT_URI
    content://media/external/downloads。
  3. Removable storage: MediaStore.Downloads.getContentUri
    content://media//downloads.
2.5.1.1 Get all Volumes

For the Uri described earlier, getContentUrihow to get all of them can be done in the following way:

for(String volume:MediaStore.getExternalVolumeNames(this)){
    
    
	MediaStore.Audio.Media.getContentUri(volume);
}
2.5.1.2 Relationship between Uri and public directory

MediaProviderFor the App to be stored in a public directory file, it is determined by the Uri in the method. The relative path is ContentResolver insertshown in the following table , and the complete file is: content://media//<Uri path>.<Uri路径>

Insert image description here

2.5.1.3 Permissions

MediaStoreThrough different methods Uri, users can add, delete (if files cannot be deleted through File Uri, you need to use the SAF interface), and modify.
The corresponding permissions of the App are as follows:
Insert image description here

2.5.1.4 Query files

By ContentResolverquerying different content based on different Uri:

  try (Cursor c = getContentResolver()
                .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, null, null, null)) {
    
    
            while (c.moveToNext()) {
    
    
                Uri contentUri =
                        ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, c.getLong(0));
            }
        }

PS: During MediaStore.Filesthe process Query, only pictures, videos and audio files will be displayed.

2.5.1.5 Reading files

Through ContentResolver querythe interface, how to read the file after finding it can be done in the following way:

  1. Through ContentResolver openFileDescriptorthe interface, select the corresponding opening method.
    For example, "r" means reading, "w" means writing, and the return ParcelFileDescriptortype FD.
  2. Accessed Thumbnailvia ContentResolver loadThumbnailthe interface
    By passing the size, MediaProviderthe specified size is returned Thumbnail.
  3. Native code accesses files.
    If Native code needs to access files, you can refer to the following methods:
    ① By openFileDescriptorreturning ParcelFileDescriptor
    ② By ParcelFileDescriptor.detachFd()reading FD
    FDPassing to Nativethe layer code
    AppNeed to be responsible for closing through closethe interfaceFD
   	ParcelFileDescriptor parcelFd = resolver.openFileDescriptor(uri, file0penMode);
	if (parcelFd != null) {
    
    
	      int fd = parcelFd.detachFd();
	      // Pass the integer value "fd" into your native code. Remember to call
	      // close(2) on the file descriptor when you're done using it.
	}
2.5.1.6 Create new file

If you need to store a new file in a public directory, you need to ContentResolver insertuse a different interface Uriand choose to store it in a different directory.
Insert image description here

2.5.1.7 Modify files

If you need to modify a multimedia file, you need to ContentResolver queryfind the Uri of the corresponding file through the interface.
If you did not create a new file yourself, you need to pay attention to the description in 2.5.1.3 Permissions. You need to apply WRITE_EXTERNAL_STORAGE权限or catch RecoverableSecurityExceptiona pop-up box will give the user a choice.
Insert image description here
Insert image description here
Through the following interface, obtain the file that needs to be modified FDor OutputStream:

  1. getContentResolver().openOutputStream(contentUri)
    gets the OutputStream of the corresponding file.
  2. getContentResolver().openFile or getContentResolver().openFileDescriptor
    opens the file through openFile or openFileDescriptor. You need to select Mode as "w", which indicates write permission. These interfaces return a ParcelFileDescriptor.
    getContentResolver().openFileDescriptor(contentUri,“w”);
    getContentResolver().openFile(contentUri,“w”,null);
2.5.1.8 Delete files

Delete files through the ContentResolver interface, and the Uri is the Uri from the query:

getContentResolver().delete(contentUri,null,null);

2.5.2 Via SAF interface

2.5.2.1 Introduction to SAF

SAF, that is , providing users with the ability to open and browse files Storage Access Frameworkby selecting different ones . DocumentsProviderWe can look back at the previous chapter

Android provides the following by default DocumentsProvider:
MediaDocumentsProvider, ExternalStorageProvider, DownloadStorageProvider.
The difference between them is:
Insert image description here
Insert image description here

In this picture, there are three areas, namely:

  1. MediaDocumentsProvide
  2. DownloadStorageProvider
  3. ExternalStorageProvider
  4. Third-party DocumentsProvider
2.5.2.2 How to use

Please refer to the official documentation for details

The general method is as follows:

  1. Select a single fileInsert image description here
  2. Select the directory,
    Insert image description here
    file management program, and cleanup program. You can use this method to obtain all management permissions for the corresponding directory and subdirectories.
  3. create a new file
    Insert image description here
  4. delete
DocumentsContract.deleteDocument(getContentResolver(),uri);
  1. Revise

①Get OutputStream

getContentResolver().openOutputStream(uri);

②Get the writable ParcelFileDescriptor

getContentResolver().openFileDescriptor(contentUri,"w");
getContentResolver().openFile (contentUri,"w",null);

Specific Demo reference

2.6 Access App-specific directories

There are two situations of access App-specific, the first is access App自身App-specific目录and the second is access 其他App目录文件.

2.6.1 App’s own App-specific directory

Android Q, if the App is started Filtered View, it can only directly access files in its own directory:

  1. The interfaces Environment.getExternalStorageDirectory and getExternalStoragePublicDirectory
    are obsolete on Android Q. The App is a Filtered View and cannot directly access this directory.
  2. Accessing
    the App through File ("/sdcard/") is a Filtered View and cannot directly access this directory.
  3. Get the App-specific directory
    Get the Media interface: getExternalMediaDirs
    Get the Cache interface: getExternalCacheDirs
    Get the Obb interface: getObbDirs
    Get the Data interface: getExternalFilesDirs

2.6.2 Multimedia files in the App-specific directory

Multimedia files inside the App-specific directory:

  1. App's own access App-specificis the same as 2.6.1 App's own directory
  2. Access from other Apps
    ① By default , the multimedia files inside Media Scannerwill not be scanned . If scanning is required, it needs to be added to the database. The access method is the same as 2.5 reading and writing public directories. ②App is shared through sharingApp-specificMediaScannerConnection.scanFileMediaProvider

    ContentProvider

2.6.3 Other App directory files

App is a Filtered View. Other apps cannot directly access the current App private directory. You need to use the following method:

2.6.3.1 Through SAF file
  1. Share App customizationDocumentsProvider

App customization DocumentsProviderrequires the following steps:
a) SpecifyDocumentsProvider
Insert image description here

b) DocumentsProviderImplement the basic interface:
Insert image description here
Insert image description here

  1. Access the App ACTION_OPEN_DOCUMENTand start browsing
    Insert image description here

Insert image description here
Insert image description here

2.6.3.2 Sharing App to implement FileProvider

FileProvider specific usage reference

Here is a summary of the general steps:

  1. Specified App FileProvider
    Insert image description here

  2. Specify the file path, the configuration file must be placed in res/xml
    Insert image description here

  3. Get share Uri
    Insert image description here

  4. Set permissions and send Uri
    Insert image description here
    Insert image description here

  5. Receive App and set the accepted inter-filter
    Insert image description here

  6. Receive and process Uri
    Insert image description here

2.6.3.3 App custom private provider

Apps can be customized ContentProvider, especially 内部文件共享, but UI interaction is not expected.

2.7 MediaStore

2.7.1 MediaStore_data field

MediaStoreIn, DATA即(_data)字段, Android Qbegan to be abandoned in. Reading and writing files requires passing openFileDescriptor.

2.7.2 MediaStore file Pending status

On Android Q, MediaStorea was added IS_PENDING Flagto mark Pendingthe status of the current file.
Other apps MediaStorequery files. If no setIncludePendinginterface is set, files set to Pending status cannot be queried. This gives the App exclusive access to this file. Used in some situations, such as when downloading: During downloading, the file is in Pending status and the download is completed, and the Pending status of the file is set to 0.
Insert image description here

2.7.3 MediaColumns.RELATIVE_PATH sets the storage path

On Android Q, by MediaStorestoring files in the public directory, in addition to the first-level directory of each storage space specified in the relationship between Uri and public directory in Section 2.5.1.2, the secondary directory for storage can be specified through MediaColumns.RELATIVE_PATH. This directory Multiple levels can be made, the specific code is as follows:

  1. ContentResolver insert method
    specifies the storage directory through values.put(Media.RELATIVE_PATH,"Pictures/album/family "). Among them, Pictures is a first-level directory and album/family is a subdirectory.
  2. ContentResolver update method
    specifies the storage directory through values.put(Media.RELATIVE_PATH,"Pictures/album/family "). Through the update method, the storage location can be moved.

2.7.4 Access image Exif Metadata

On Android Q, if the App needs to access the Exif Metadata on the image, it needs to do the following:

  1. ApplyACCESS_MEDIA_LOCATION权限
  2. The Demo Code is as MediaStore.setRequireOriginal返回新Uri
    follows:
    Insert image description here

2.7.5 App Filtered View, summary of access permissions

App’s permissions to access different directories are summarized as follows:
Insert image description here

2.7.6 Application uninstallation

If the App AndroidManifest.xmldeclares in: android:hasFragileUserData="true"
When uninstalling the app, you will be prompted whether to retain the App data:
Insert image description here

2.7.7 App data migration

On Android Q, App TargetSDK>=Qthe default is Filtered View. If the App is a Filtered View, it will involve data migration, otherwise the old data will become unusable. You can start data migration from the following aspects:

  1. App needs to Legacy Viewbe downloaded to have full permission to operate storage
  2. App files stored in non-public areas can be accessed by SAF访问selecting directory files through SAF, and users can choose to access App files.
    Insert image description here
  3. The App can put the files that need to be saved:
    Images, Video, Audiointo the corresponding public directory. Other files can be placed Downloadsbelow without deleting the files after uninstalling.

2.7.8 MediaStore Queries

When using MediaStoreto perform queryactions, Projectionwhen using, Column Nameit must MediaStorebe defined in.

2.8 WRITE_MEDIA_STORAGE permission

2.8.1 Background

WRITE_MEDIA_STORAGEIt is a very powerful permission that allows the App to gain access to all storage devices. Permission to access all storage devices, this should only be given to the Media Stack.

2.8.2 Compatibility impact

In the Android system, it is stipulated that the user group WRITE_MEDIA_STORAGEcan be obtained media_rw:
Insert image description here

  1. For all removable storage devices, such as T cards and U disks, when they are mounted to Android, ordinary apps only have read permissions and no write permissions. Only media_rw user group apps can write to removable storage devices.
  2. For Scoped Storage on Android Q, you can use this permission to set the App to run in compatibility mode.
  3. Android CTS will conduct testing. User-launchable Apps cannot apply for this permission.
    For details, please refer to "Android Bootcamp 2019 - Privacy Overview.pdf".

2.8.3 Adaptation

If the App needs to access Mediaor 外置存储设备, you can use MediaStoreor Storage Access Framework(SAF)接口.

3 Summary

Okay, here’s a summary:

  1. App TargetSDK > 28 即 Android10(Q)及以上Project, Google has restricted the storage sandbox mode. In the Android10(Q)以上的设备recommended use 私有目录data/data, it can no longer be accessed directly 外部SD卡存储目录. If you need to use it , you need to access it 外部SD卡存储目录through the interface, and it can only be accessed , such as , , , , , , etc. These external SD card storage directories (public directories) can be accessed by all apps, so they are not very secure.SAFMediaStore特定的外部SD卡存储目录DownloadsDocumentsPicturesDCIMMoviesMusicRingtones
  2. App TargetSDK <= 28 即 Android10(Q)以下The project is unrestricted, as long as it has WRITE_MEDIA_STORAGEpermissions READ_MEDIA_STORAGE. So if you really don’t want to change the external SD storage, then change the project’s targetSdk to <=28.
  3. As for SAFthe MediaStoreinterface access 外部SD卡存储特定目录method, please refer to the above description or refer to the official documentation for details. Here is a demo of MediaStorehow to use it for your reference 外部SD卡存储特定目录. Don’t forget to click Star.

Guess you like

Origin blog.csdn.net/u010687761/article/details/133200887