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 -l
the 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 firstrw
), can be read by the group to which it belongs (the secondr
), and can be read by other users (the thirdr
). - If the permissions of a directory are
drwxr-x---
, it means that the directory can be read, written and executed by its owner (the firstrwx
), can be read and executed by the group to which it belongs (the secondrx
), and cannot be accessed by other users (the third-
).
- If the permissions of a file are
- Use
stat
the 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 is0644
, which can be expressed as an octal number-rw-r--r--
. The owner of the file is0
the user with UIDroot
and the group to which the file belongs is0
the group with GIDroot
.
- If the information of a file is
- Use
find
the 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/data
in the directory belonging to1000
the user with UID, you can usefind /data/data -uid 1000
the command.
- If you want to find all files
# 查看 /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.