-
-
[原创]Android Storage Access Framework(SAF)框架实现外置SD卡的写入(JAVA层与JNI层HOOK)
-
发表于:
2020-1-14 20:48
6837
-
[原创]Android Storage Access Framework(SAF)框架实现外置SD卡的写入(JAVA层与JNI层HOOK)
之前折腾了了一下MINE模拟器,发现SDL全是在JNI层fopen
操作的,而安卓的SAF则是JAVA层通过DocumentFile和docUri来实现写入的。一种方法是通过去的File Descriptor然后传给JNI层,通过fdopen
实现写入[1]。于是成功在MINE模拟器添加外置sd卡写入功能,详见我在贴吧布的 mine模拟器外置SD卡写入修复版。完整版源码我已经封装好了发布到github上,理论上通用。
通过DocumentFile来实现写入,Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
发送请求docUri
,然后onActivityResult
来得到并储存docUri
,通过SharedPreference来实现共享。已经封装在静态类SafFile.java
中。
这里用到了xhook架构,原理上是运行的时候来替换目标动态库的.got
表到自己编译的函数地址,通过JNI来调用JAVA层我们写好通过SAF机制得到的文件描述符。
[1] https://stackoverflow.com/questions/30593964/how-to-access-android-lollipop-documentfile-files-via-ndk/31677287
[2] https://developer.android.com/guide/topics/providers/document-provider.html?hl=zh-cn
public static DocumentFile getBaseDocumentFile(final Context context, final SharedPreferences share) {
if(context==null) {
Log.e(LOGTAG, "SafFile.getBaseDocumentFile context is null!");
return null;
}
if(share==null){
Log.e(LOGTAG, "SafFile.getBaseDocumentFile share is null!");
return null;
}
DocumentFile base = null;
Uri docUri = null;
final String p = share.getString("docUri", null);
if (p != null)
docUri = Uri.parse(p);
base = DocumentFile.fromTreeUri(context, docUri);
return base;
}
public static DocumentFile getTargetDirDocumentFile(final DocumentFile base, String path) {
DocumentFile target = null;
if (base == null) {
Log.e(LOGTAG, "SafFile.getTargetDirDocumentFile base is null!");
return null;
}
if(path==null) path="";
path = path.replace("\\", "/");
final String paths[] = path.split("/");
int i;
final int end = paths[paths.length - 1].length() > 0 ? paths.length - 1 : paths.length - 2;
for (i = 0; i < end; i++) {
// Log.i(LOGTAG, "getTar... path["+String.valueOf(i)+"], "+paths[i]);
if (paths[i].equals(base.getName())) {
if (i >= end - 1) {
// Log.i(LOGTAG, "getTar... "+path+" end="+paths[paths.length-1]+" "+ paths[end]);
return base;
}
i++;
break;
}
}
// Log.i(LOGTAG, "getTarget... "+base.getName()+" "+path);
target = base.findFile(paths[i++]);
// Log.i(LOGTAG, "target, "+ target.getName());
for (; i < end; i++) {
if (target == null)
break;
// Log.i(LOGTAG, "getTar..., "+path+" "+ target.getName());
target = target.findFile(paths[i]);
}
return target;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-1-14 22:12
被devseed编辑
,原因: