XSharedPreference & SharedPreference - XPosed模块中的preference使用
最近在维护一个Xposed模块[]Niwatori-One Handed Mode](https://github.com/tkgktyk/Niwatori)。原作者tkgktyk已经停止更新了,导致模块在Xposed Framework for Nougat发布以后,不能使用。于是我fork了一份代码,开始做Android Nougat上的适配工作,并在XDA上发布了更新链接。
在适配了Nougat之后,希望能添加一些新功能,让用户体验更好。目前想做的是能通过fooview调用Niwatori的快捷方式。并且该快捷方式的功能,例如是small screen还是slide down等等,能通过Niwatori本身进行配置。但是在开发这一功能的时候,发现动态快捷方式的加载需要使用SDK 25以上版本,而从SDK 25开始,原先SharedPreference的打开方式MODE_WORLD_PRIVATE已经被禁止了。使用它会导致security exception。
所以要升到使用SDK 25,必须解决preference引用的问题。那么这个模式的变化,到底会在哪里影响到我们的Xposed模块呢?
Xposed中的preference
Xposed模块中使用preference的时候,通常都是通过XSharedPreference来操作。XSharedPreference在Android标准的SharedPreference类上包了一层,提供了一些security的fix或者work around。例如:XSharedPreference.makeWorldReadable。他们都是加载app data文件夹下的xml文件来读取、存储键值对的。该文件路径为(以Niwatori为例):/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml
。
通常Xposed中如下使用preference会按照如下的时序图,以Niwatori为例:
- XSharedPreference实例创建在模块加载的
initZygote
中 - 数据的使用通过钩子函数,在各个app的Context底下执行
于是当MODE_WORLD_READABLE被废止以后,这里就出问题了。即在默认情况下,app1是没有权限查看Niwatori的preference文件的,也就没法加载配置数据。
Xposed官方或者作者rovo89还没有给出官方的解决办法,但总是会有一些未雨绸缪的勇士,XDA上有一个帖子给出了一个work around:MODE_WORLD_READABLE in Android N
我在Niwatori中也使用了该方法,但仍然不是完美解决,而且目前还不知道如何改进。
遗留的问题
该work around和XSharedPreference.makeWorldReadable同理,我如下调用preference:
mPrefs.makeWorldReadable();Log.e("Ben", "package:" + decorView.getContext().getPackageName() + ", " + decorView + "," + mPrefs.getString("key_boundary_color_ms", "default value"));Log.e("Ben", "file can read: " + mPrefs.getFile().canRead()); <-- 有些app会是true,有些app会是false
当返回true的时候,settings就成功的传到了对应app了。这个时而可以read时而不可以read,我也很苦恼,不知道是怎么回事儿。留待以后再解决了。
解决遗留的问题 - 20180119
以上的问题在于,Android 7.0开始,即从SDK 24开始,Android加入了很多security方面的特性,参考Android 7.0 Security Features: Direct Boot。这和我们的问题不太相关。相关的是如上所说,Nougat不允许world readable的文件了。如果用SDK25编译的app还用MODE_WORLD_READABLE
,系统会报exception。
Google上鲜少有相关的解决方案,有如下几个链接可以参考:
- GravityBox commit - Use device protected storage for preferences and files
- XposedBridge issue 1 - Any place to store world readable preferences on Nougat?
- XposedBridge issue 2 - Preferences of a module cannot be read from different process on some devices running MM
- XposedBridge issue 3 - XSharedPreferences doesn’t work
- [Q] Xposed for nougat to read prefs ith fbe or without
经过验证,是XposedBridge issue 1中GravityBox作者的一个comment提到了最终的解决方法。该comment如下:
setStorageDeviceProtected
createDeviceProtectedStorageContext
将preference文件存到/data/user_de/0/<package name>/shared_prefs
下。并在Xposed的context端,直接打开文件进行操作。
但其实我们并不需如此。只要保证package folder的权限至少是711,preference.xml文件有可读权限即可。