android11怎么访问data目录,android的data文件夹( 二 )


SAF是通过何种方式访问文件系统的 , MediaStore API ? File API ? Native Code ?SAF为何能访问Android/data目录存储访问框架(SAF)简介
为方便后续讲解,先简单回顾下SAF

android11怎么访问data目录,android的data文件夹

文章插图
SAF架构
APP:
com.example.photos就是我们自己的APP
System UI:
com.google.android.documentsui,一般称作DoucmentUI,就是上文中启动的授权界面APP,它只是个UI壳子
DocumentProvider:
DocumentUI中数据的提供者,这个Provider可以有很多 com.android.externalstorage,是本地文件系统的Provider
关于SAF更详细介绍,请参考官方存储访问框架 经过SAF的简单介绍 , 分析目标很明确,那就是com.android.externalstorage
SAF是通过何种方式访问文件系统的
先安利几个AOSP源码查看网址:
https://cs.android.com/android/platform/superproject/http://aospxref.com/PS:后文源码链接都用的是XREF,方便国内查看
从DocumentFile#listFile入手,经过源码跟踪会发现最终会调用 DocumentsProvider#queryChildDocuments方法
public abstract class DocumentsProvider extends ContentProvider { ....... @Overridepublic final Cursor query(Uri uri, String[] projection, Bundle queryArgs, CancellationSignal cancellationSignal) {switch (mMatcher.match(uri)) {......case MATCH_CHILDREN:case MATCH_CHILDREN_TREE:.......return queryChildDocuments(getDocumentId(uri), projection, queryArgs);......default:throw new UnsupportedOperationException("Unsupported Uri "uri);}} catch (FileNotFoundException e) {Log.w(TAG, "Failed during query", e);return null;}} ......}接下来看看com.android.externalstorage中DocumentProvider的实现类 ExternalStorageProvider:frameworks/base/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
import com.android.internal.content.FileSystemProvider;public class ExternalStorageProvider extends FileSystemProvider queryChildDocuments的实现位于其父类 FileSystemProvider
public abstract class FileSystemProvider extends DocumentsProvider {......private Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder,@NonNull Predicate filter) throws FileNotFoundException {final File parent = getFileForDocId(parentDocumentId);final MatrixCursor result = new DirectoryCursor(resolveProjection(projection), parentDocumentId, parent);if (parent.isDirectory()) {//重点是这行for (File file : FileUtils.listFilesOrEmpty(parent)) {if (filter.test(file)) {includeFile(result, null, file);}}} else {Log.w(TAG, "parentDocumentId '"parentDocumentId"' is not Directory");}return result;} ......}FileUtils#listFilesOrEmpty
/** {@hide} */public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles()): ArrayUtils.EMPTY_FILE;}至此 , 第一个问题,已经理清:SAF的ExternalStorageProvider最终也是通过File API来访问文件系统的
那么第二个问题,就很自然地来了,都是File API操作,为何我们的APP就不能访问呢?
SAF为何能访问Android/data目录
既然,SAF和我们的APP都是File API操作,那我们就去看看com.android.externalstorage属于哪些用户组 。adb shell 查查com.android.externalstorage进程的用户组
#查进程ID generic_x86_arm:/ $ ps -A|grep com.android.external u0_a64 16233 296 1256792 85960 0 0 S com.android.externalstorage #查进程所属的用户组
generic_x86_arm:/ $ cat /proc/16233/statusName:externalstorageUmask:0077State:S (sleeping)Tgid:16233Ngid:0Pid:16233PPid:296TracerPid:0Uid:10064100641006410064Gid:10064100641006410064FDSize: 64#重点关注这行输出Groups: 1015 1077 1078 1079 9997 20064 50064拿着这些神秘的GID在前面介绍的网址中一搜,就会很容易地发现GID的定义类 android_filesystem_config.h
#define AID_SDCARD_RW 1015/* external storage write access */#define AID_EXTERNAL_STORAGE 1077 /* Full external storage access including USB OTG volumes */#define AID_EXT_DATA_RW 1078/* GID for app-private data directories on external storage */#define AID_EXT_OBB_RW 1079/* GID for OBB directories on external storage */#define AID_EVERYBODY 9997/* shared between all apps in the same profile */其中1078和1079分别对应Android/data和Android/obb的访问权限 如果我们APP能通过某种方式获取到1078和1079的用户组权限,岂不妙哉?遗憾的是,对于三方APP这是不可能的,除非是手机厂商的预置的系统APP