Xposed--Android N 以上 XSharedPreferences
Android N 以上使用 XSharedPreferences ,但是还是只读.
资料来源:
https://github.com/ElderDrivers/EdXposed/issues/149
https://github.com/ElderDrivers/EdXposed/issues/260
https://github.com/Mikanoshi/SudoHide
https://github.com/GravityBox/GravityBox更新
1
2
320.04.11 初始化
20.04.27 更新权限
21.02.03 Edxposed New XSharedPreferences
导语
这算是远古巨坑吗?我也不知道,当时 MyPrivacy 直接降级 SDK 版本规避的 XSharedPreferences 问题,但该来的总是要来的…
NoWakeLock 的 IPC 方案分为两个部分,唤醒锁相关的数据保存,这个可以通过 ContentProvider 解决.但是拦截相关的数据确没办法等到系统启动完毕再加载,搞得我非常头疼.. ContentProvider 实在是无法满足要求..就这样停滞了…
于是重新开始看代码模式..直到翻到了重力工具箱..重新搜索 issue ,这个一言难尽啊..
XSharedPreferences
XSharedPreferences 具体的使用就不多说了,这里仅仅是 N 以上如何使用 XSharedPreferences.
N 以前还能改改文件权限,曲线使用 XSharedPreferences ,但是 N 以后这条路也被堵死了,N 以后设备加密等也有很多新变化.随着 rovo89 的弃坑,官方解决遥遥无期..
还有个问题是 N 以后,基本都有全局加密,在用户解锁前无法访问 /data .
重力工具箱作者 @C3C0 发现可以把 xml 放到直接启动的设备加密存储,修改权限后,通过文件建立 XSharedPreferences.这样依旧能够正常读取数据.
至此破案…
但是在 Android sdk > 27 即 Android 9 以上的部分机型,Selinux 限制会导致部分异常.
实现
一个示例Xptest
Android 7.0 以后 /data 加密问题,可以使用直接启动模式,官方介绍
简而言之,系统为了闹钟短信等无需解锁也要使用的应用,提供了两个存储位置.
- 凭据加密存储,这是默认存储位置.仅在用户解锁设备后可用.
- 设备加密存储,该存储位置在”直接启动”模式下和用户解锁设备后均可使用.(这是我们要的)
使用设备加密存储也很简单,使用
Context.createDeviceProtectedStorageContext()
获取到对应设备存储的 Context ,其他一切如常.默认情况下设备加密存储在 “/data/user_de/0/包名” 下,这里是设备正常启动后,解锁前可以正常访问到的地方,当然权限设定少不了.
有些 Rom 总是会默认的把文件/文件夹的权限改回去,如果是重启之后改回去,可以注册一个 ACTION_LOCKED_BOOT_COMPLETED 的广播,在每次启动时,把权限改回去.
但是 @C3C0 还提到了有些自定义 Rom 上,开机状态下读写文件,权限都可能被改回去..重力工具箱的做法是注册文件监听期,每次写入文件后自动再改一次权限.
(还没遇到,遇到再说)已经遇到了…目前是每次读写文件后重新改一次文件,注册文件监听貌似没成.以下就以 SharedPreferences 为例.
新建一个 SharedPreferences,保存测试值.
1
2
3
4
5
6pref = this.createDeviceProtectedStorageContext()
.getSharedPreferences(preferencesFileName, MODE_PRIVATE)
pref?.edit()
?.putString("Test", "Test233")
?.apply()修改权限(抄袭自 SudoHide 😂)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fun fixPermissionsAsync() {
AsyncTask.execute {
try {
Thread.sleep(500)
} catch (t: Throwable) {
}
val pkgFolder = this.createDeviceProtectedStorageContext().filesDir.parentFile
if (pkgFolder.exists()) {
pkgFolder.setExecutable(true, false)
pkgFolder.setReadable(true, false)
//pkgFolder.setWritable(true, false);
val sharedPrefsFolder =
File(pkgFolder.absolutePath + "/shared_prefs")
Log.d("Xposed.Test",": activity ${pkgFolder.absolutePath}/shared_prefs")
if (sharedPrefsFolder.exists()) {
sharedPrefsFolder.setExecutable(true, false)
sharedPrefsFolder.setReadable(true, false)
//sharedPrefsFolder.setWritable(true, false);
val f =
File(sharedPrefsFolder.absolutePath + "/" + preferencesFileName + "xml")
if (f.exists()) {
f.setReadable(true, false)
f.setExecutable(true, false)
//f.setWritable(true, false);
}
}
}
}
}initZygote 时读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16private val prefsFileProt =
File("/data/user_de/0/com.js.xptest/shared_prefs/com.js.xptest_preferences.xml")
var pref: XSharedPreferences? = null
try {
pref = XSharedPreferences(prefsFileProt)
pref!!.edit().putString("Test2", "2333").apply
} catch (t: Throwable) {
XposedBridge.log("$TAG : $t")
}
XposedBridge.log(
"$TAG : 1 ${pref?.getString("Test", "default")}," +
"2 ${pref?.getString("Test2", "default"
)}"
)这里可以尝试一下写入,会提示只读错误.
New XSharedPreferences
写 deepsleep 翻阅 edxposed 资料时发现了 New XSharedPreferences,可以用在 android 9 及以上版本.
但是为了保证兼容性,还需要考虑太极等模块,暂时还是观望.
结语
- 这篇有点敷衍的感觉..终于解决了 XSharedPreferences 问题,接下来..就没了..要加班一段时间了.😂.