androidQ sd卡权限使用详解

2020-06-23 13:01 来源:易采站长站 作者:于丽 点击: 评论:

A-A+

原标题:androidQ sd卡权限使用详解

默认情况下,如果应用以 Android Q 为目标平台,则在访问外部存储设备中的文件时会进入过滤视图。应用可以使用 Context.getExternalFilesDir() 将专用于自己的文件存储在特定于自己的目录中。

1. 临时停用分区存储行为:

以 Android 9(API 级别 28)或更低版本为目标平台。
如果您以 Android Q 为目标平台,请在应用的清单文件中将 requestLegacyExternalStorage 的值设为 true。

<manifest ... >
 <!-- This attribute is "false" by default on apps targeting Android Q. -->
 <application android:requestLegacyExternalStorage="true" ... >
 ...
 </application>
</manifest>

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.getBoolean("persist.sys.isolated_storage", true));
}

private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();

public int getExternalStorageMountMode(int uid, String packageName) {
+ //android 10新增逻辑
+ if (ENABLE_ISOLATED_STORAGE) {
+  return getMountMode(uid, packageName);
+ }
 ......
 int mountMode = Integer.MAX_VALUE;
 for (ExternalStorageMountPolicy policy : mPolicies) {
  final int policyMode = policy.getMountMode(uid, packageName);
  if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
   return Zygote.MOUNT_EXTERNAL_NONE;
  }
  mountMode = Math.min(mountMode, policyMode);
 }
 if (mountMode == Integer.MAX_VALUE) {
  return Zygote.MOUNT_EXTERNAL_NONE;
 }
 return mountMode;
}

【易采站长站编辑:秋军】