Android system file access permission notes

File access permissions are a very complex and important content in the Android system, which determines which files and directories an application can access and operate. The Android system has strict restrictions and management on file access permissions. As the Android system version is constantly updated, there are also some changes and changes in file access permissions, which require us to understand and learn in time to meet the needs. This content is very complex and complex. . This article briefly studies the concept, classification, application method, framework layer source code location and key functions of the Android system, as well as the changes and adaptation methods of file access permissions in Android 11, 12 and 13.

Series of articles:

Android system file access permission notes
Android system understands /sys/ directory permissions and UID and GID?
Android system application storage paths and permissions
Android system custom system and application permissions
Android system AppOps grants corresponding permissions to applications by default
Android system permission group management and compatibility

Reference study:

Overview of Google Android data and file storage
Android 11 system_server Read and write SDCARD
to solve the problem that Android10 cannot read /sdcard/, /storage/emulated/0/ files
Discussion on Android 9.0 external sdcard Read and write
permissions and mounting of sdcard in Android 9.0 Question
Android system understands /sys/ directory permissions and UID and GID?
Experience record of modifying android/data and obb content under Android 11/12/13
Android 13 features and change list | Android Developers | Android Developers
android 11 applies to allow management of all file permissions
Android11 ​​opens failed: EACCES (Permission denied) when processing files ) question

Changes and adaptations of Android external storage permissions

Starting from the Android 10 version, ordinary applications cannot directly read the sdcard under the system /sdcard/, /mnt/, and the USB disk under /mnt/. This is because Android 10 introduces a partitioned storage mechanism designed to prevent apps from reading other apps’ data. Each application should have its own storage space and cannot access public directories without permission. Applications need to go through permission checks when requesting data.

System applications and permissions

If the application is modified to the system platform signature or setting android:sharedUserId="android.uid.system", and the corresponding read and write permissions are added, it can read and write the sdcard under the system /sdcard/, /mnt/, and the USB disk under /mnt/. This is because such an application will have the same signature as the system and can be used to android:sharedUserId="android.uid.system"share the system's UID to access the system's core functions and data.

Through modification android:sharedUserId="android.uid.system", the UID of the application can be changed to the UID of the system, so that some directories can be accessed. This is because the system's UID is 1000, which has the highest permissions.
This file can be found in the system/core/include/private/android_filesystem_config.h path of the Android source code.

#define AID_ROOT 0 /* traditional unix root user */
/* The following are for LTP and should only be used for testing */
#define AID_DAEMON 1 /* traditional unix daemon owner */
#define AID_BIN 2    /* traditional unix binaries owner */

#define AID_SYSTEM 1000 /* system server */
。。。。。。。。。。

Android source code and permission detection

File access permissions in the Android system determine which files and directories an application can access and operate. The Android system has strict restrictions and management on file access permissions, including some key classes and methods.

The source code location and key functions of the Android system's file access permissions can be distinguished according to different functions and modules. The main ones are as follows:

StorageManagerService.java

  • xref: http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java: This class is responsible for managing the mounting and unmounting of external storage devices, as well as allocating and reclaiming storage space. It is a system service and its instance can be obtained through Context.getSystemService(Context.STORAGE_SERVICE). It provides some key methods, such as:
mount(String volId):
// 这个方法是 StorageManagerService 类的一个公开方法,用于挂载指定 ID 的外部存储设备卷
2309      @Override
2310      public void mount(String volId) {
    
    
2311          // 检查调用者是否有 MOUNT_UNMOUNT_FILESYSTEMS 权限,如果没有,抛出 SecurityException 异常
2312          enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2313  
2314          // 根据卷的 ID 找到对应的 VolumeInfo 对象,如果找不到,抛出 IllegalArgumentException 异常
2315          final VolumeInfo vol = findVolumeByIdOrThrow(volId);
2316          // 判断是否允许挂载该卷,如果不允许,抛出 SecurityException 异常
2317          if (isMountDisallowed(vol)) {
    
    
2318              throw new SecurityException("Mounting " + volId + " restricted by policy");
2319          }
2320  
2321          // 调用私有的 mount 方法,传入 VolumeInfo 对象,用于执行挂载操作
2322          mount(vol);
2323      }
2324  
2325      // 这个方法是 StorageManagerService 类的一个私有方法,用于挂载指定的 VolumeInfo 对象
2326      private void mount(VolumeInfo vol) {
    
    
2327          try {
    
    
2328              // TODO(b/135341433): Remove cautious logging when FUSE is stable
2329              // 记录日志,表示正在挂载卷
2330              Slog.i(TAG, "Mounting volume " + vol);
2331              // 调用 mVold 的 mount 方法,传入卷的 ID、挂载标志、挂载用户 ID 和一个回调对象
2332              mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
    
    
2333                  // 这个回调对象实现了 IVoldMountCallback 接口,它有一个 onVolumeChecking 方法,用于在挂载前对卷进行检查
2334                  @Override
2335                  public boolean onVolumeChecking(FileDescriptor fd, String path,
2336                          String internalPath) {
    
    
2337                      // 将卷的路径和内部路径设置为传入的参数值
2338                      vol.path = path;
2339                      vol.internalPath = internalPath;
2340                      // 将文件描述符封装成一个 ParcelFileDescriptor 对象
2341                      ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
2342                      try {
    
    
2343                          // 调用 mStorageSessionController 的 onVolumeMount 方法,传入该对象和卷的信息
2344                          mStorageSessionController.onVolumeMount(pfd, vol);
2345                          // 如果 onVolumeMount 方法成功返回,表示挂载成功,返回 true
2346                          return true;
2347                      } catch (ExternalStorageServiceException e) {
    
    
2348                          // 如果 onVolumeMount 方法抛出 ExternalStorageServiceException 异常,表示挂载失败,返回 false,并在一定时间后重新尝试挂载
2349                          Slog.e(TAG, "Failed to mount volume " + vol, e);
2350  
2351                          int nextResetSeconds = FAILED_MOUNT_RESET_TIMEOUT_SECONDS;
2352                          Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
2353                          mHandler.removeMessages(H_RESET);
2354                          mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
2355                                  TimeUnit.SECONDS.toMillis(nextResetSeconds));
2356                          return false;
2357                      } finally {
    
    
2358                          // 无论成功或失败,都要关闭文件描述符对象
2359                          try {
    
    
2360                              pfd.close();
2361                          } catch (Exception e) {
    
    
2362                              Slog.e(TAG, "Failed to close FUSE device fd", e);
2363                          }
2364                      }
2365                  }
2366              });
2367              // 记录日志,表示已经挂载卷
2368              Slog.i(TAG, "Mounted volume " + vol);
2369          } catch (Exception e) {
    
    
2370              // 如果发生其他异常,记录错误日志
2371              Slog.wtf(TAG, e);
2372          }
2373      }
unmount(String volId):
// 这个方法是 StorageManagerService 类的一个公开方法,用于卸载指定 ID 的外部存储设备卷
2377      @Override
2378      public void unmount(String volId) {
    
    
2379          // 检查调用者是否有 MOUNT_UNMOUNT_FILESYSTEMS 权限,如果没有,抛出 SecurityException 异常
2380          enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2381  
2382          // 根据卷的 ID 找到对应的 VolumeInfo 对象,如果找不到,抛出 IllegalArgumentException 异常
2383          final VolumeInfo vol = findVolumeByIdOrThrow(volId);
2384          // 调用私有的 unmount 方法,传入 VolumeInfo 对象,用于执行卸载操作
2385          unmount(vol);
2386      }
2387  
// 这个方法是 StorageManagerService 类的一个私有方法,用于卸载指定的 VolumeInfo 对象
2389      private void unmount(VolumeInfo vol) {
    
    
2390          try {
    
    
2391              try {
    
    
2392                  // 判断卷的类型是否为 VolumeInfo.TYPE_PRIVATE,如果是,调用 mInstaller 的 onPrivateVolumeRemoved 方法,传入卷的 UUID,用于移除私有卷的镜像数据
2393                  if (vol.type == VolumeInfo.TYPE_PRIVATE) {
    
    
2394                      mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
2395                  }
2396              } catch (Installer.InstallerException e) {
    
    
2397                  // 如果 onPrivateVolumeRemoved 方法抛出 Installer.InstallerException 异常,记录错误日志
2398                  Slog.e(TAG, "Failed unmount mirror data", e);
2399              }
2400              // 调用 mVold 的 unmount 方法,传入卷的 ID,用于卸载卷
2401              mVold.unmount(vol.id);
2402              // 调用 mStorageSessionController 的 onVolumeUnmount 方法,传入卷的信息,用于处理卸载后的逻辑
2403              mStorageSessionController.onVolumeUnmount(vol);
2404          } catch (Exception e) {
    
    
2405              // 如果发生其他异常,记录错误日志
2406              Slog.wtf(TAG, e);
2407          }
2408      }
getVolumes():
// 这个方法是 StorageManagerService 类的一个公开方法,用于获取所有已挂载的外部存储设备卷的列表
4001      @Override
4002      public VolumeInfo[] getVolumes(int flags) {
    
    
4003          // 同步锁定 mLock 对象,用于保证线程安全
4004          synchronized (mLock) {
    
    
4005              // 创建一个 VolumeInfo 类型的数组,大小为 mVolumes 集合的大小
4006              final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
4007              // 遍历 mVolumes 集合,将每个元素复制到数组中
4008              for (int i = 0; i < mVolumes.size(); i++) {
    
    
4009                  res[i] = mVolumes.valueAt(i);
4010              }
4011              // 返回数组
4012              return res;
4013          }
4014      }

getAllocatableBytes(String volumeUuid, int flags, String callingPackage):
// 这个方法是 StorageManagerService 类的一个公开方法,用于获取指定 UUID 的外部存储设备卷上可分配给应用程序的字节数
4082      @Override
4083      public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
    
    
4084          // 调整分配标志,根据调用者的 UID 和包名,判断是否需要添加 FLAG_ALLOCATE_AGGRESSIVE 标志
4085          flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
4086  
4087          // 获取 StorageManager 和 StorageStatsManager 的实例,用于操作存储相关的数据
4088          final StorageManager storage = mContext.getSystemService(StorageManager.class);
4089          final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
4090          // 保存当前的调用标识,并清除调用者的身份,用于跨进程调用
4091          final long token = Binder.clearCallingIdentity();
4092          try {
    
    
4093              // 一般情况下,应用程序可以分配尽可能多的空间,除非超过了最小缓存空间或低磁盘警告空间的限制。为了避免用户混淆,这个逻辑应该和 getFreeBytes() 方法保持一致
4094              // 根据卷的 UUID 找到对应的文件路径
4095              final File path = storage.findPathForUuid(volumeUuid);
4096  
4097              // 初始化可用空间、低保留空间、满保留空间和可清除缓存空间为 0
4098              long usable = 0;
4099              long lowReserved = 0;
4100              long fullReserved = 0;
4101              long cacheClearable = 0;
4102  
4103              // 如果没有设置 FLAG_ALLOCATE_CACHE_ONLY 标志,表示可以分配非缓存空间
4104              if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) {
    
    
4105                  // 获取文件路径上的可用空间大小
4106                  usable = path.getUsableSpace();
4107                  // 获取文件路径上的低磁盘警告空间大小
4108                  lowReserved = storage.getStorageLowBytes(path);
4109                  // 获取文件路径上的磁盘满空间大小
4110                  fullReserved = storage.getStorageFullBytes(path);
4111              }
4112  
4113              // 如果没有设置 FLAG_ALLOCATE_NON_CACHE_ONLY 标志,并且卷支持配额功能,表示可以分配缓存空间
4114              if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0
4115                      && stats.isQuotaSupported(volumeUuid)) {
    
    
4116                  // 获取卷上的缓存总大小
4117                  final long cacheTotal = stats.getCacheBytes(volumeUuid);
4118                  // 获取卷上的缓存保留大小
4119                  final long cacheReserved = storage.getStorageCacheBytes(path, flags);
4120                  // 计算卷上的可清除缓存大小,即缓存总大小减去缓存保留大小,如果为负数,则取 0
4121                  cacheClearable = Math.max(0, cacheTotal - cacheReserved);
4122              }
4123  
4124              // 如果设置了 FLAG_ALLOCATE_AGGRESSIVE 标志,表示可以分配更多的空间,但可能会影响系统性能或稳定性
4125              if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
    
    
4126                  // 返回可用空间加上可清除缓存空间再减去磁盘满空间大小,如果为负数,则取 0
4127                  return Math.max(0, (usable + cacheClearable) - fullReserved);
4128              } else {
    
    
4129                  // 否则,返回可用空间加上可清除缓存空间再减去低磁盘警告空间大小,如果为负数,则取 0
4130                  return Math.max(0, (usable + cacheClearable) - lowReserved);
4131              }
4132          } catch (IOException e) {
    
    
4133              // 如果发生 IOException 异常,将其封装成一个 ParcelableException 对象,并抛出
4134              throw new ParcelableException(e);
4135          } finally {
    
    
4136              // 无论成功或失败,都要恢复之前的调用标识
4137              Binder.restoreCallingIdentity(token);
4138          }
4139      }

allocateBytes(UUID storageUuid, long bytes):
// 这个方法是 StorageManagerService 类的一个公开方法,用于在指定 UUID 的外部存储设备卷上为应用程序分配指定字节数的空间
4126      @Override
4127      public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
    
    
4128          // 调整分配标志,根据调用者的 UID 和包名,判断是否需要添加 FLAG_ALLOCATE_AGGRESSIVE 标志
4129          flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
4130  
4131          // 获取卷上可分配给应用程序的非缓存空间大小
4132          final long allocatableBytes = getAllocatableBytes(volumeUuid,
4133                  flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage);
4134          // 如果要分配的字节数大于可分配的非缓存空间大小,表示空间不足
4135          if (bytes > allocatableBytes) {
    
    
4136              // 如果空间不足,检查卷上可分配给应用程序的缓存空间大小
4137              final long cacheClearable = getAllocatableBytes(volumeUuid,
4138                      flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage);
4139              // 如果要分配的字节数大于可分配的非缓存空间大小加上可分配的缓存空间大小,表示即使清除缓存也无法满足需求,抛出 IOException 异常
4140              if (bytes > allocatableBytes + cacheClearable) {
    
    
4141                  throw new ParcelableException(new IOException("Failed to allocate " + bytes
4142                      + " because only " + (allocatableBytes + cacheClearable) + " allocatable"));
4143              }
4144          }
4145  
4146          // 获取 StorageManager 的实例,用于操作存储相关的数据
4147          final StorageManager storage = mContext.getSystemService(StorageManager.class);
4148          // 保存当前的调用标识,并清除调用者的身份,用于跨进程调用
4149          final long token = Binder.clearCallingIdentity();
4150          try {
    
    
4151              // 为了满足分配需求和低磁盘警告空间的限制,释放足够的磁盘空间
4152              final File path = storage.findPathForUuid(volumeUuid);
4153              // 如果设置了 FLAG_ALLOCATE_AGGRESSIVE 标志,表示可以分配更多的空间,但可能会影响系统性能或稳定性,需要加上磁盘满空间大小
4154              if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
    
    
4155                  bytes += storage.getStorageFullBytes(path);
4156              } else {
    
    
4157                  // 否则,只需要加上低磁盘警告空间大小
4158                  bytes += storage.getStorageLowBytes(path);
4159              }
4160  
4161              // 调用 mPmInternal 的 freeStorage 方法,传入卷的 UUID、要释放的字节数和分配标志,用于清理不必要的数据
4162              mPmInternal.freeStorage(volumeUuid, bytes, flags);
4163          } catch (IOException e) {
    
    
4164              // 如果发生 IOException 异常,将其封装成一个 ParcelableException 对象,并抛出
4165              throw new ParcelableException(e);
4166          } finally {
    
    
4167              // 无论成功或失败,都要恢复之前的调用标识
4168              Binder.restoreCallingIdentity(token);
4169          }
4170      }

VolumeInfo.java

  • http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/java/android/os/storage/VolumeInfo.java: This class represents the volume information of an external storage device, including volume ID, type, status, path and other attributes. It is a Parcelable object that can be passed through Intent or Bundle. It provides some key properties and methods, such as:
isMountedReadable():
// 这判断该卷是否已挂载且可读取。
@UnsupportedAppUsage
public boolean isMountedReadable() {
    
    
    // 这个方法检查存储卷的状态是否是已挂载或只读挂载
    return state == STATE_MOUNTED || state == STATE_MOUNTED_READ_ONLY;
}
isMountedWritable():
//判断该卷是否已挂载且可写入。
@UnsupportedAppUsage
public boolean isMountedWritable() {
    
    
    // 这个方法检查存储卷的状态是否是已挂载
    return state == STATE_MOUNTED;
}

FileUtils.java

  • http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/java/android/os/FileUtils.java: This class provides some tool methods for file operations, setting file permissions, etc. , no need to create an instance. It provides some key methods, such as:
setPermissions(File path, int mode, int uid, int gid)
151      @UnsupportedAppUsage
152      public static int setPermissions(File path, int mode, int uid, int gid) {
    
    
153          // 调用另一个重载的方法,传入文件的绝对路径作为参数
153          return setPermissions(path.getAbsolutePath(), mode, uid, gid);
154      }
155  
156      /**
157       * 设置给定路径的所有者和模式。
158       *
159       * @param mode 通过 {@code chmod} 应用的模式
160       * @param uid 通过 {@code chown} 应用的用户ID,或 -1 表示不改变
161       * @param gid 通过 {@code chown} 应用的组ID,或 -1 表示不改变
162       * @return 成功时返回 0,否则返回错误码。
163       * @hide
164       */
165      @UnsupportedAppUsage
166      public static int setPermissions(String path, int mode, int uid, int gid) {
    
    
167          try {
    
    
168              // 使用 Os 类的 chmod 方法修改文件的权限
168              Os.chmod(path, mode);
169          } catch (ErrnoException e) {
    
    
170              // 如果出现异常,打印警告信息,并返回错误码
170              Slog.w(TAG, "Failed to chmod(" + path + "): " + e);
171              return e.errno;
172          }
173  
174          // 如果 uid 或 gid 不为 -1,表示需要修改文件的所有者
174          if (uid >= 0 || gid >= 0) {
    
    
175              try {
    
    
176                  // 使用 Os 类的 chown 方法修改文件的所有者
176                  Os.chown(path, uid, gid);
177              } catch (ErrnoException e) {
    
    
178                  // 如果出现异常,打印警告信息,并返回错误码
178                  Slog.w(TAG, "Failed to chown(" + path + "): " + e);
179                  return e.errno;
180              }
181          }
182  
183          // 如果没有异常,返回 0 表示成功
183          return 0;
184      }
185  
186      /**
187       * 设置给定 {@link FileDescriptor} 的所有者和模式。
188       *
189       * @param mode 通过 {@code chmod} 应用的模式
190       * @param uid 通过 {@code chown} 应用的用户ID,或 -1 表示不改变
191       * @param gid 通过 {@code chown} 应用的组ID,或 -1 表示不改变
192       * @return 成功时返回 0,否则返回错误码。
193       * @hide
194       */
195      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
196      public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
    
    
197          try {
    
    
198              // 使用 Os 类的 fchmod 方法修改文件描述符的权限
198              Os.fchmod(fd, mode);
199          } catch (ErrnoException e) {
    
    
200              // 如果出现异常,打印警告信息,并返回错误码
200              Slog.w(TAG, "Failed to fchmod(): " + e);
201              return e.errno;
202          }
203  
204          // 如果 uid 或 gid 不为 -1,表示需要修改文件描述符的所有者
204          if (uid >= 0 || gid >= 0) {
    
    
205              try {
    
    
206                  // 使用 Os 类的 fchown 方法修改文件描述符的所有者
206                  Os.fchown(fd, uid, gid);
207              } catch (ErrnoException e) {
    
    
208                  // 如果出现异常,打印警告信息,并返回错误码
208                  Slog.w(TAG, "Failed to fchown(): " + e);
209                  return e.errno;
210              }
211          }
212  
213          // 如果没有异常,返回 0 表示成功
213          return 0;
214      }

SELinux.java

  • http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/java/android/os/SELinux.java: This class provides some SELinux-related methods, including checking whether the file has SELinux context tags, etc. SELinux is a security-enhanced Linux system that enables more granular access control of files and processes. It is a static class and does not require the creation of instances. It provides some key methods, such as:
    • isSELinuxEnabled(): Determine whether the SELinux mechanism is enabled in the current system.
    • getFileContext(String path): Get the SELinux context label of the file with the specified path.
    • setFileContext(String path, String context): Sets the SELinux context label of the file with the specified path.
51      /**
52       * 判断 SELinux 是否被禁用或启用。
53       * @return 表示 SELinux 是否启用。
54       */
55      @UnsupportedAppUsage
56      // 声明一个本地方法,使用 native 关键字,不需要提供方法体
56      public static final native boolean isSELinuxEnabled();
72      /**
73       * 改变已存在的文件对象的安全上下文。
74       * @param path 表示要重新标记的文件对象的路径。
75       * @param context 新的安全上下文,以字符串形式给出。
76       * @return 表示操作是否成功。
77       */
78      // 声明一个本地方法,使用 native 关键字,不需要提供方法体
78      public static final native boolean setFileContext(String path, String context);
80      /**
81       * 获取文件对象的安全上下文。
82       * @param path 文件对象的路径名。
83       * @return 表示安全上下文。
84       */
85      @UnsupportedAppUsage
86      // 声明一个本地方法,使用 native 关键字,不需要提供方法体
86      public static final native String getFileContext(String path);
95      /**
96       * 获取文件描述符对应文件的安全上下文。
97       * @param fd 文件的文件描述符。
98       * @return 表示文件描述符的安全上下文。
99       */
100     // 声明一个本地方法,使用 native 关键字,不需要提供方法体
100     public static final native String getFileContext(FileDescriptor fd);

File and directory access permissions

There are several methods to determine which UIDs or groups can access a certain directory or file in the system:

  • Use ls -lthe command to view the permissions and owners of a file or directory. For example:
    • If the permissions of a file are -rw-r--r--, it means that the file can be read and written by its owner (the first rw), can be read by the group to which it belongs (the second r), and can be read by other users (the third r).
    • If the permissions of a directory are drwxr-x---, it means that the directory can be read, written and executed by its owner (the first rwx), can be read and executed by the group to which it belongs (the second rx), and cannot be accessed by other users (the third -).
  • Use statthe command to view detailed information about a file or directory. For example:
    • If the information of a file is Access: (0644/-rw-r--r--) Uid: ( 1000/ system) Gid: ( 0/ root), it means that the permission of the file is 0644, which can be expressed as an octal number -rw-r--r--. The owner of the file is 0the user with UID rootand the group to which the file belongs is 0the group with GID root.
  • Use findthe command to search for files or directories based on the user's owner, group, UID, GID and other conditions. For example:
    • If you want to find all files /data/datain the directory belonging to 1000the user with UID, you can use find /data/data -uid 1000the command.
# 查看 /etc/passwd文件的权限和所有者
rk3568_t:/etc # ls -ll passwd
-rw-r--r-- 1 root root 0 2023-07-31 06:49:44.000000000 +0000 passwd

# 查看 /etc/passwd 文件的详细信息

rk3568_t:/etc # stat passwd
  File: passwd
  Size: 0        Blocks: 0       IO Blocks: 512  regular empty file
Device: fd00h/64768d     Inode: 1782     Links: 1        Device type: 0,0
Access: (0644/-rw-r--r--)       Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-07-31 06:49:44.000000000 +0000
Modify: 2023-07-31 06:49:44.000000000 +0000
Change: 2023-07-31 06:49:44.000000000 +0000

# 查找 /data/data 目录下属于 system  用户或者 system  组的所有目录
rk3568_t:/data/data # find . -user system  -o -group system -type d
.
./com.android.dynsystem
./com.android.dynsystem/cache
./com.android.dynsystem/code_cache

Changes and adaptation methods for file access permissions in Android 11, 12 and 13

Starting from Android 11, Google has made some restrictions and changes on the permissions of applications to access external storage devices to protect user privacy and data security. These limitations and changes may affect the functionality and compatibility of some applications that need to read and write files. You need to understand the meaning and usage of these permissions and adapt them accordingly according to your application needs. The following table lists three permissions related to external storage devices, along with their descriptions, levels, and applicable versions.

Permission name Permission description Permission level Applicable version
android.permission.READ_EXTERNAL_STORAGE Allows the application to read files from external storage devices (such as SD cards or USB flash drives), including media files such as pictures, audios, and videos. Dangerous permissions that require authorization from the user at runtime. Android 4.1 (API level 16) and above.
android.permission.WRITE_EXTERNAL_STORAGE Allows the application to write files to external storage devices (such as SD cards or USB flash drives), including media files such as pictures, audios, and videos. This permission also includes the functions of the READ_EXTERNAL_STORAGE permission. Dangerous permissions that require authorization from the user at runtime. Android 4.1 (API level 16) and above.
android.permission.MANAGE_EXTERNAL_STORAGE Allows the app to access and modify all files on the external storage device, including those of the system and other apps. This permission also includes the functionality of the WRITE_EXTERNAL_STORAGE permission. Special permissions require authorization from the user in the system settings. Android 11 (API level 30) and above.

The following is a brief introduction to the changes and adaptation methods of these permissions:

  • In Android 10 and below, if the application declares the WRITE_EXTERNAL_STORAGE permission and obtains the user's authorization, then it can access all files on the external storage device, including public directories (such as Pictures, Music, etc.) and private files of other applications. Directories (such as Android/data and Android/obb, etc.). This model is called "traditional storage" model.
  • In Android 11, Google introduced a new mode called "Partitioned Storage" mode. In this mode, the application can only access media files of its own type (such as pictures, audio, video, etc.) in its own private directory and public directory. If the application wants to access files of other types or applications, it needs to declare the MANAGE_EXTERNAL_STORAGE permission and guide the user to grant "All file access permissions" in the system settings. This kind of permission is a special permission and needs to be used for a good reason, otherwise it may be rejected by Google Play. In addition, applications can also use the MediaStore API or the system file selector SAF to access or share media files or non-media files without applying for additional permissions.
  • In Android 12, Google has made some improvements and optimizations to the partitioned storage mode. For example, some MediaStore API methods and constants have been added to make it easier for applications to query, insert, update, or delete media files; a new runtime permission POST_NOTIFICATIONS has been added to allow users to better control which applications can send notifications; A new mechanism, Foreground Services (FGS) Task Manager, has been added to allow users to better manage which applications can run foreground services in the background, etc.
  • In Android 13, Google continues to make some adjustments and improvements to the partitioned storage model. For example, a new API is added to determine how audio is routed so that applications can better adapt to different audio devices; a new permission BODY_SENSORS_BACKGROUND is added so that users can better control which applications can access the body in the background. Sensor information; a new API has been added to set or obtain the user's preferred language in each application so that the application can better adapt to different language environments.

Starting from Android 11, the permissions for applications to access external storage devices have become more stringent and detailed. You need to choose appropriate permissions and APIs for adaptation based on your application needs and functions.


Guess you like

Origin blog.csdn.net/SHH_1064994894/article/details/132869552