默认情况下,如果应用以 Android Q 为目标平台,则在访问外部存储设备中的文件时会进入过滤视图。应用可以使用 Context.getExternalFilesDir() 将专用于自己的文件存储在特定于自己的目录中。
1. 临时停用分区存储行为:
以 Android 9(API 级别 28)或更低版本为目标平台。
如果您以 Android Q 为目标平台,请在应用的清单文件中将 requestLegacyExternalStorage 的值设为 true。
...
2. 如何实现隔离存储:
2.1 ApplicationInfo新增PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE标记
PackageParser.java:
if (sa.getBoolean(
R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
}
ApplicationInfo.java:
public boolean hasRequestedLegacyExternalStorage() {
return (privateFlags & PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
}
2.2 grantRuntimePermission()重新挂载视图
apk启动时默认挂载runtime/default视图,grantRuntimePermission()时如果是READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE,则会获取挂载模式重新挂载对应视图。
PermissionManagerService.java:
private void grantRuntimePermission(String permName, String packageName, boolean overridePolicy,
int callingUid, final int userId, PermissionCallback callback) {
......
if (READ_EXTERNAL_STORAGE.equals(permName)
|| WRITE_EXTERNAL_STORAGE.equals(permName)) {
final long token = Binder.clearCallingIdentity();
try {
if (mUserManagerInt.isUserInitialized(userId)) {
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
获取挂载模式这块android10有修改,没有设置Legacy标志的话,总是获取default挂载模式,没有读写权限。
android 10会设置属性[persist.sys.isolated_storage]: [true],因此走到if(ENABLE_ISOLATED_STORAGE)中的getMountMode()。
public static boolean hasIsolatedStorage() {
//[persist.sys.isolated_storage]: [true]
//[sys.isolated_storage_snapshot]: [true]
return SystemProperties.getBoolean("sys.isolated_storage_snapshot",
SystemProperties.getBo