最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

androidQ sd卡權限使用詳解

 更新時間:2020年06月23日 11:27:44   作者:十八磚  
這篇文章主要介紹了androidQ sd卡權限使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

默認情況下,如果應用以 Android Q 為目標平臺,則在訪問外部存儲設備中的文件時會進入過濾視圖。應用可以使用 Context.getExternalFilesDir() 將專用于自己的文件存儲在特定于自己的目錄中。

1. 臨時停用分區(qū)存儲行為:

以 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. 如何實現(xiàn)隔離存儲:

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;
}

正常模式下hasLegacy=false,走到if判斷的DEFAULT分支;legacy模式hasLegacy=true,與之前保持一致,有write權限就走到WRITE模式分支。

private int getMountModeInternal(int uid, String packageName) {
 try {
  ......
  final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
    uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
  final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
    uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
  ......
  final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
    uid, packageName) == MODE_ALLOWED;
  if (hasLegacy && hasWrite) {
   return Zygote.MOUNT_EXTERNAL_WRITE;
  } else if (hasLegacy && hasRead) {
   return Zygote.MOUNT_EXTERNAL_READ;
  } else {
   return Zygote.MOUNT_EXTERNAL_DEFAULT;
  }
 } catch (RemoteException e) {
  // Should not happen
 }
 return Zygote.MOUNT_EXTERNAL_NONE;
}

2.3 Legacy Storage屬性對權限的影響

安裝apk時,就會根據(jù)requestLegacyExternalStorage屬性來對ops state進行設置,修改OP_LEGACY_STORAGE的默認狀態(tài)。

<manifest ... >
 <application android:requestLegacyExternalStorage="true" ... >
 </application>
</manifest>

 
//Q 正常模式
LEGACY_STORAGE: mode=ignore
//Q legacy模式
LEGACY_STORAGE: mode=allow

PermissionPolicyService啟動時首先進行權限變化監(jiān)聽:

public void onStart() {
 permManagerInternal.addOnRuntimePermissionStateChangedListener(
 this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
}

private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
  @UserIdInt int changedUserId) {
 if (isStarted(changedUserId)) {
  synchronized (mLock) {
   if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
      PermissionPolicyService
        ::synchronizePackagePermissionsAndAppOpsForUser,
      this, packageName, changedUserId));
   }
   ......
  }
 }
}

APK安裝時,會根據(jù)requestLegacyExternalStorage屬性來通知storage權限變化,調(diào)用關系如下:

//調(diào)用關系:
1.PackageManagerService.java:
 installPackagesLI()
  commitPackagesLocked()
   updateSettingsLI()
    updateSettingsInternalLI()
     2.PermissionManagerService.java:
      mPermissionManager.updatePermissions()
       restorePermissionState()

//關鍵代碼:
private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
  @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
......
  //判斷requestLegacyExternalStorage屬性
  updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, updatedUserIds);
......
 for (int userId : updatedUserIds) {
  notifyRuntimePermissionStateChanged(pkg.packageName, userId);
 }
}

最終調(diào)用到PermissionPolicyService的監(jiān)聽函數(shù)synchronizePackagePermissionsAndAppOpsForUser(),進行默認權限獲取和設置。

當apk安裝時,聲明了requestLegacyExternalStorage="true"屬性,并且聲明了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE,那么addOpIfRestricted()就會將LEGACY_STORAGE設置為allow模式。

//調(diào)用關系:
synchronizePackagePermissionsAndAppOpsForUser():
 synchroniser.addPackage()
  addOpIfRestricted()//LEGACY_STORAGE加入到mOpsToAllow
 synchroniser.syncPackages()
  setUidModeAllowed()
   setUidMode()//設置LEGACY_STORAGE為allow

//關鍵代碼:
private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo,
  @NonNull PackageInfo pkg) {
......
  //forPermission()會根據(jù)requestLegacyExternalStorage的值進行返回
  final SoftRestrictedPermissionPolicy policy =
    SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo,
      mContext.getUser(), permission);

  final int op = policy.resolveAppOp();
  if (op != OP_NONE) {
   switch (policy.getDesiredOpMode()) {
    case MODE_DEFAULT:
     mOpsToDefault.add(new OpToChange(uid, pkg.packageName, op));
     break;
    case MODE_ALLOWED:
     //在聲明READ_EXTERNAL_STORAGE權限下,會將LEGACY_STORAGE加入到mOpsToAllow
     if (policy.shouldSetAppOpIfNotDefault()) {
      mOpsToAllow.add(new OpToChange(uid, pkg.packageName, op));
     } else {
      mOpsToAllowIfDefault.add(
        new OpToChange(uid, pkg.packageName, op));
     }
     break;
......
}

public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
  @Nullable ApplicationInfo appInfo, @Nullable UserHandle user,
  @NonNull String permission) {
 switch (permission) {
  case READ_EXTERNAL_STORAGE: {
   if (appInfo != null) {
    boolean hasAnyRequestedLegacyExternalStorage =
      appInfo.hasRequestedLegacyExternalStorage();

    hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage;
   }

   return new SoftRestrictedPermissionPolicy() {
    @Override
    public int getDesiredOpMode() {
     if (applyRestriction) {
      return MODE_DEFAULT;
     } else if (hasRequestedLegacyExternalStorage) {
      //聲明了requestLegacyExternalStorage就返回allow
      return MODE_ALLOWED;
     } else {
      return MODE_IGNORED;
     }
    }

    @Override
    public boolean shouldSetAppOpIfNotDefault() {
     return getDesiredOpMode() != MODE_IGNORED;
    }
   };
  }

3. sdcard路徑權限說明:

  • rwx:421,umask默認為八進制022(----w--w-)
  • /mnt/runtime/default的gid為1015,也就是sdcard_rw;mask 為6,八進制006,group sdcard_rw可讀寫,也就是other沒有rw權限
  • /mnt/runtime/read的gid為9997,也就是everybody;mask 為23,八進制027,group everybody可讀、不可寫,other沒有讀寫執(zhí)行權限
  • /mnt/runtime/write的gid為9997,也就是everybody;mask 為7,八進制007,group everybody可讀寫,other沒有讀寫可執(zhí)行權限
  • /data/media on /mnt/runtime/default/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6,derive_gid,default_normal)

/data/media on /mnt/runtime/read/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,multiuser,mask=23,derive_gid,default_normal)
/data/media on /mnt/runtime/write/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,multiuser,mask=7,derive_gid,default_normal)

/mnt/runtime/default:

drwxrwx--x 3 root sdcard_rw 4096 2018-12-18 03:41 Android
drwxrwx--x 3 root sdcard_rw 4096 2018-12-18 06:11 DCIM

/mnt/runtime/read:

drwxr-x--- 3 root everybody 4096 2018-12-18 03:41 Android
drwxr-x--- 3 root everybody 4096 2018-12-18 06:11 DCIM

/mnt/runtime/write:

drwxrwx--- 3 root everybody 4096 2018-12-18 03:41 Android
drwxrwx--- 3 root everybody 4096 2018-12-18 06:11 DCIM

/sdcard/Android/data:

drwxrwx--- 4 u0_a64 everybody 4096 2018-12-18 06:11 com.android.camera2
drwxrwx--- 3 u0_a15 everybody 4096 2018-12-18 03:41 com.google.android.gms
drwxrwx--- 4 u0_a84 everybody 4096 2018-12-18 03:41 com.google.android.youtube

4. sdcard文件存儲示例:

4.1 getExternalFilesDir()隨卸載而刪除

///storage/emulated/0/Android/data/com.xx.xx/files
File file = File(context.getExternalFilesDir(null), "test.txt");

4.2 媒體文件
媒體文件使用MediaStore操作,卸載后不會刪除。
訪問其他應用生成的照片、視頻、音頻,需要READ_EXTERNAL_STORAGE權限。

4.3 存儲訪問框架(SAF)
訪問其他應用創(chuàng)建的文件,例如"Download"目錄,必須使用存儲訪問框架,用戶通過框架選擇特定文件。

4.4 照片中的位置信息
需要ACCESS_MEDIA_LOCATION權限,才能獲取元數(shù)據(jù)中的位置信息。

<permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
 android:permissionGroup="android.permission-group.UNDEFINED"
 android:label="@string/permlab_mediaLocation"
 android:description="@string/permdesc_mediaLocation"
 android:protectionLevel="dangerous" />

到此這篇關于androidQ sd卡權限使用詳解的文章就介紹到這了,更多相關androidQ sd卡權限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java如何找出數(shù)組中重復的數(shù)字

    Java如何找出數(shù)組中重復的數(shù)字

    這篇文章主要為大家詳細介紹了Java如何找出數(shù)組中重復的數(shù)字,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • idea常用配置之注釋快捷鍵方式

    idea常用配置之注釋快捷鍵方式

    這篇文章主要介紹了idea常用配置之注釋快捷鍵方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java之CSV大批量數(shù)據(jù)入庫的實現(xiàn)

    java之CSV大批量數(shù)據(jù)入庫的實現(xiàn)

    本文主要介紹了java之CSV大批量數(shù)據(jù)入庫的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • SpringBoot啟動原理深入解析

    SpringBoot啟動原理深入解析

    我們開發(fā)任何一個Spring Boot項目都會用到啟動類,下面這篇文章主要給大家介紹了關于SpringBoot啟動原理解析的相關資料,文中通過圖文以及實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-04-04
  • Spring?Cloud?Eureka(全面解析)?大白話

    Spring?Cloud?Eureka(全面解析)?大白話

    這篇文章主要介紹了Spring?Cloud?Eureka(全面解析)?大白話,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot如何通過自定義注解實現(xiàn)權限檢查詳解

    SpringBoot如何通過自定義注解實現(xiàn)權限檢查詳解

    這篇文章主要給大家介紹了關于SpringBoot如何通過自定義注解實現(xiàn)權限檢查的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • 2024最新版Java?JDK安裝配置圖文詳解全攻略

    2024最新版Java?JDK安裝配置圖文詳解全攻略

    這篇文章主要介紹了2024最新版Java?JDK安裝配置圖文詳解的相關資料,包含準備工作、下載步驟、安裝指南及環(huán)境變量配置驗證,供用戶輕松搭建Java開發(fā)環(huán)境,需要的朋友可以參考下
    2024-09-09
  • Java 轉型(向上或向下轉型)詳解及簡單實例

    Java 轉型(向上或向下轉型)詳解及簡單實例

    這篇文章主要介紹了Java 轉型(向上或向下轉型)詳解及簡單實例的相關資料,需要的朋友可以參考下
    2017-02-02
  • Java日常練習題,每天進步一點點(22)

    Java日常練習題,每天進步一點點(22)

    下面小編就為大家?guī)硪黄狫ava基礎的幾道練習題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • SpringMVC+Mybatis二維碼實現(xiàn)多平臺付款(附源碼)

    SpringMVC+Mybatis二維碼實現(xiàn)多平臺付款(附源碼)

    本文主要實現(xiàn)微信支付寶等支付平臺合多為一的二維碼支付,并且實現(xiàn)有效時間內(nèi)支付有效,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論

富阳市| 城口县| 和龙市| 桦川县| 惠州市| 宁德市| 云龙县| 兴安县| 罗田县| 金沙县| 泰和县| 新闻| 宁陵县| 繁昌县| 夏津县| 济宁市| 阳新县| 西乌珠穆沁旗| 信丰县| 阿拉善左旗| 台湾省| 东明县| 静海县| 濉溪县| 鹿邑县| 潢川县| 邵东县| 韶山市| 鹤壁市| 隆回县| 海阳市| 芜湖县| 山西省| 轮台县| 五河县| 永胜县| 东兴市| 宝坻区| 拉萨市| 衡阳市| 集安市|