XSharedPreference & SharedPreference - XPosed模块中的preference使用

Edit

最近在维护一个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上鲜少有相关的解决方案,有如下几个链接可以参考:

经过验证,是XposedBridge issue 1中GravityBox作者的一个comment提到了最终的解决方法。该comment如下:

  • setStorageDeviceProtected
  • createDeviceProtectedStorageContext

将preference文件存到/data/user_de/0/<package name>/shared_prefs下。并在Xposed的context端,直接打开文件进行操作。
但其实我们并不需如此。只要保证package folder的权限至少是711,preference.xml文件有可读权限即可。

%23%20XSharedPreference%20%26%20SharedPreference%20-%20XPosed%u6A21%u5757%u4E2D%u7684preference%u4F7F%u7528%0A@%28myblog%29%5BAndroid%2C%20xposed%5D%0A%0A%u6700%u8FD1%u5728%u7EF4%u62A4%u4E00%u4E2AXposed%u6A21%u5757%5B%5DNiwatori-One%20Handed%20Mode%5D%28https%3A//github.com/tkgktyk/Niwatori%29%u3002%u539F%u4F5C%u8005tkgktyk%u5DF2%u7ECF%u505C%u6B62%u66F4%u65B0%u4E86%uFF0C%u5BFC%u81F4%u6A21%u5757%u5728Xposed%20Framework%20for%20Nougat%u53D1%u5E03%u4EE5%u540E%uFF0C%u4E0D%u80FD%u4F7F%u7528%u3002%u4E8E%u662F%u6211fork%u4E86%u4E00%u4EFD%u4EE3%u7801%uFF0C%u5F00%u59CB%u505AAndroid%20Nougat%u4E0A%u7684%u9002%u914D%u5DE5%u4F5C%uFF0C%u5E76%u5728XDA%u4E0A%u53D1%u5E03%u4E86%u66F4%u65B0%5B%u94FE%u63A5%5D%28https%3A//forum.xda-developers.com/xposed/modules/mod-niwatori-one-handed-mode-t3730963%29%u3002%0A%u5728%u9002%u914D%u4E86Nougat%u4E4B%u540E%uFF0C%u5E0C%u671B%u80FD%u6DFB%u52A0%u4E00%u4E9B%u65B0%u529F%u80FD%uFF0C%u8BA9%u7528%u6237%u4F53%u9A8C%u66F4%u597D%u3002%u76EE%u524D%u60F3%u505A%u7684%u662F%u80FD%u901A%u8FC7fooview%u8C03%u7528Niwatori%u7684%u5FEB%u6377%u65B9%u5F0F%u3002%u5E76%u4E14%u8BE5%u5FEB%u6377%u65B9%u5F0F%u7684%u529F%u80FD%uFF0C%u4F8B%u5982%u662Fsmall%20screen%u8FD8%u662Fslide%20down%u7B49%u7B49%uFF0C%u80FD%u901A%u8FC7Niwatori%u672C%u8EAB%u8FDB%u884C%u914D%u7F6E%u3002%u4F46%u662F%u5728%u5F00%u53D1%u8FD9%u4E00%u529F%u80FD%u7684%u65F6%u5019%uFF0C%u53D1%u73B0%u52A8%u6001%u5FEB%u6377%u65B9%u5F0F%u7684%u52A0%u8F7D%u9700%u8981%u4F7F%u7528SDK%2025%u4EE5%u4E0A%u7248%u672C%uFF0C%u800C%u4ECESDK%2025%u5F00%u59CB%uFF0C%u539F%u5148SharedPreference%u7684%u6253%u5F00%u65B9%u5F0FMODE%5C_WORLD%5C_PRIVATE%u5DF2%u7ECF%u88AB%u7981%u6B62%u4E86%u3002%u4F7F%u7528%u5B83%u4F1A%u5BFC%u81F4security%20exception%u3002%0A%u6240%u4EE5%u8981%u5347%u5230%u4F7F%u7528SDK%2025%uFF0C%u5FC5%u987B%u89E3%u51B3preference%u5F15%u7528%u7684%u95EE%u9898%u3002%u90A3%u4E48%u8FD9%u4E2A%u6A21%u5F0F%u7684%u53D8%u5316%uFF0C%u5230%u5E95%u4F1A%u5728%u54EA%u91CC%u5F71%u54CD%u5230%u6211%u4EEC%u7684Xposed%u6A21%u5757%u5462%uFF1F%0A%0A%23%23%20Xposed%u4E2D%u7684preference%0AXposed%u6A21%u5757%u4E2D%u4F7F%u7528preference%u7684%u65F6%u5019%uFF0C%u901A%u5E38%u90FD%u662F%u901A%u8FC7XSharedPreference%u6765%u64CD%u4F5C%u3002XSharedPreference%u5728Android%u6807%u51C6%u7684SharedPreference%u7C7B%u4E0A%u5305%u4E86%u4E00%u5C42%uFF0C%u63D0%u4F9B%u4E86%u4E00%u4E9Bsecurity%u7684fix%u6216%u8005work%20around%u3002%u4F8B%u5982%uFF1AXSharedPreference.makeWorldReadable%u3002%u4ED6%u4EEC%u90FD%u662F%u52A0%u8F7Dapp%20data%u6587%u4EF6%u5939%u4E0B%u7684xml%u6587%u4EF6%u6765%u8BFB%u53D6%u3001%u5B58%u50A8%u952E%u503C%u5BF9%u7684%u3002%u8BE5%u6587%u4EF6%u8DEF%u5F84%u4E3A%uFF08%u4EE5Niwatori%u4E3A%u4F8B%uFF09%uFF1A%60/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml%60%u3002%0A%0A%u901A%u5E38Xposed%u4E2D%u5982%u4E0B%u4F7F%u7528preference%u4F1A%u6309%u7167%u5982%u4E0B%u7684%u65F6%u5E8F%u56FE%uFF0C%u4EE5Niwatori%u4E3A%u4F8B%uFF1A%0A%60%60%60%20sequence%0ANote%20left%20of%20Niwatori%3A%20initZygote%0ANote%20left%20of%20Niwatori%3A%20Construct%20a%20XSharedPreference%0ANiwatori-%3EActivity.class%3A%20hook%0AActivity.class-%3Eapp1%3A%20onCreate%0ANote%20right%20of%20app1%3A%20load%20the%20XSharedPreference%0AActivity.class-%3Eapp2%3A%20onCreate%0ANote%20right%20of%20app2%3A%20load%20the%20XSharedPreference%0A%60%60%60%0A-%20XSharedPreference%u5B9E%u4F8B%u521B%u5EFA%u5728%u6A21%u5757%u52A0%u8F7D%u7684%60initZygote%60%u4E2D%0A-%20%u6570%u636E%u7684%u4F7F%u7528%u901A%u8FC7%u94A9%u5B50%u51FD%u6570%uFF0C%u5728%u5404%u4E2Aapp%u7684Context%u5E95%u4E0B%u6267%u884C%0A%0A%u4E8E%u662F%u5F53MODE%5C_WORLD%5C_READABLE%u88AB%u5E9F%u6B62%u4EE5%u540E%uFF0C%u8FD9%u91CC%u5C31%u51FA%u95EE%u9898%u4E86%u3002%u5373%u5728%u9ED8%u8BA4%u60C5%u51B5%u4E0B%uFF0Capp1%u662F%u6CA1%u6709%u6743%u9650%u67E5%u770BNiwatori%u7684preference%u6587%u4EF6%u7684%uFF0C%u4E5F%u5C31%u6CA1%u6CD5%u52A0%u8F7D%u914D%u7F6E%u6570%u636E%u3002%0A%0AXposed%u5B98%u65B9%u6216%u8005%u4F5C%u8005rovo89%u8FD8%u6CA1%u6709%u7ED9%u51FA%u5B98%u65B9%u7684%u89E3%u51B3%u529E%u6CD5%uFF0C%u4F46%u603B%u662F%u4F1A%u6709%u4E00%u4E9B%u672A%u96E8%u7EF8%u7F2A%u7684%u52C7%u58EB%uFF0CXDA%u4E0A%u6709%u4E00%u4E2A%u5E16%u5B50%u7ED9%u51FA%u4E86%u4E00%u4E2Awork%20around%uFF1A%5BMODE_WORLD_READABLE%20in%20Android%20N%5D%28https%3A//forum.xda-developers.com/xposed/development/modeworldreadable-android-n-t3407123%29%0A%0A%u6211%u5728Niwatori%u4E2D%u4E5F%u4F7F%u7528%u4E86%u8BE5%u65B9%u6CD5%uFF0C%u4F46%u4ECD%u7136%u4E0D%u662F%u5B8C%u7F8E%u89E3%u51B3%uFF0C%u800C%u4E14%u76EE%u524D%u8FD8%u4E0D%u77E5%u9053%u5982%u4F55%u6539%u8FDB%u3002%0A%0A%23%23%20%u9057%u7559%u7684%u95EE%u9898%0A%u8BE5work%20around%u548CXSharedPreference.makeWorldReadable%u540C%u7406%uFF0C%u6211%u5982%u4E0B%u8C03%u7528preference%uFF1A%0A%60%60%60%0AmPrefs.makeWorldReadable%28%29%3B%0ALog.e%28%22Ben%22%2C%20%22package%3A%22%20+%20decorView.getContext%28%29.getPackageName%28%29%20+%20%22%2C%20%22%20+%20decorView%20+%20%22%2C%22%20+%20mPrefs.getString%28%22key_boundary_color_ms%22%2C%20%22default%20value%22%29%29%3B%0ALog.e%28%22Ben%22%2C%20%22file%20can%20read%3A%20%22%20+%20mPrefs.getFile%28%29.canRead%28%29%29%3B%20%3C--%20%u6709%u4E9Bapp%u4F1A%u662Ftrue%uFF0C%u6709%u4E9Bapp%u4F1A%u662Ffalse%0A%60%60%60%0A%u5F53%u8FD4%u56DEtrue%u7684%u65F6%u5019%uFF0Csettings%u5C31%u6210%u529F%u7684%u4F20%u5230%u4E86%u5BF9%u5E94app%u4E86%u3002%u8FD9%u4E2A%u65F6%u800C%u53EF%u4EE5read%u65F6%u800C%u4E0D%u53EF%u4EE5read%uFF0C%u6211%u4E5F%u5F88%u82E6%u607C%uFF0C%u4E0D%u77E5%u9053%u662F%u600E%u4E48%u56DE%u4E8B%u513F%u3002%u7559%u5F85%u4EE5%u540E%u518D%u89E3%u51B3%u4E86%u3002%0A%0A%23%23%20%u89E3%u51B3%u9057%u7559%u7684%u95EE%u9898%20-%2020180119%0A%u4EE5%u4E0A%u7684%u95EE%u9898%u5728%u4E8E%uFF0CAndroid%207.0%u5F00%u59CB%uFF0C%u5373%u4ECESDK%2024%u5F00%u59CB%uFF0CAndroid%u52A0%u5165%u4E86%u5F88%u591Asecurity%u65B9%u9762%u7684%u7279%u6027%uFF0C%u53C2%u8003%5BAndroid%207.0%20Security%20Features%3A%20Direct%20Boot%5D%28https%3A//blog.compass-security.com/2016/10/android-7-0-security-features-direct-boot/%29%u3002%u8FD9%u548C%u6211%u4EEC%u7684%u95EE%u9898%u4E0D%u592A%u76F8%u5173%u3002%u76F8%u5173%u7684%u662F%u5982%u4E0A%u6240%u8BF4%uFF0CNougat%u4E0D%u5141%u8BB8world%20readable%u7684%u6587%u4EF6%u4E86%u3002%u5982%u679C%u7528SDK25%u7F16%u8BD1%u7684app%u8FD8%u7528%60MODE_WORLD_READABLE%60%uFF0C%u7CFB%u7EDF%u4F1A%u62A5exception%u3002%0AGoogle%u4E0A%u9C9C%u5C11%u6709%u76F8%u5173%u7684%u89E3%u51B3%u65B9%u6848%uFF0C%u6709%u5982%u4E0B%u51E0%u4E2A%u94FE%u63A5%u53EF%u4EE5%u53C2%u8003%uFF1A%0A-%20%5BGravityBox%20commit%20-%20Use%20device%20protected%20storage%20for%20preferences%20and%20files%5D%28https%3A//github.com/GravityBox/GravityBox/commit/d825b7be445c18de9a90eb8f77c1c5eb2b74deb8%29%0A-%20%5BXposedBridge%20issue%201%20-%20Any%20place%20to%20store%20world%20readable%20preferences%20on%20Nougat%3F%5D%28https%3A//github.com/rovo89/XposedBridge/issues/206%29%0A-%20%5BXposedBridge%20issue%202%20-%20Preferences%20of%20a%20module%20cannot%20be%20read%20from%20different%20process%20on%20some%20devices%20running%20MM%5D%28https%3A//github.com/rovo89/XposedBridge/issues/74%29%0A-%20%5BXposedBridge%20issue%203%20-%20XSharedPreferences%20doesn%27t%20work%5D%28https%3A//github.com/rovo89/XposedBridge/issues/102%29%0A-%20%5B%5BQ%5D%20Xposed%20for%20nougat%20to%20read%20prefs%20ith%20fbe%20or%20without%5D%28https%3A//forum.xda-developers.com/xposed/xposed-nougat-to-read-prefs-ith-fbe-t3690048%29%0A%0A%u7ECF%u8FC7%u9A8C%u8BC1%uFF0C%u662FXposedBridge%20issue%201%u4E2DGravityBox%u4F5C%u8005%u7684%u4E00%u4E2Acomment%u63D0%u5230%u4E86%u6700%u7EC8%u7684%u89E3%u51B3%u65B9%u6CD5%u3002%u8BE5comment%u5982%u4E0B%uFF1A%0A%21%5BAlt%20text%5D%28./1516334231370.png%29%0A%u5728%u4E0A%u9762XDA%u7684%u5E16%u5B50%uFF0C%u4EE5%u53CAGravityBox%u7684commit%u4E2D%uFF0C%u6211%u4EEC%u53EF%u4EE5%u770B%u5230GravityBox%u7684%u4F5C%u8005%u91C7%u7528%u4E86Android%207.0%u4E2D%u65B0%u7684SharedPreference%u5B58%u50A8%u65B9%u5F0F%uFF0C%u5373%u901A%u8FC7%u4E0B%u9762%u4E24%u4E2A%u51FD%u6570%uFF1A%0A-%20%60setStorageDeviceProtected%60%0A-%20%60createDeviceProtectedStorageContext%60%0A%0A%u5C06preference%u6587%u4EF6%u5B58%u5230%60/data/user_de/0/%3Cpackage%20name%3E/shared_prefs%60%u4E0B%u3002%u5E76%u5728Xposed%u7684context%u7AEF%uFF0C%u76F4%u63A5%u6253%u5F00%u6587%u4EF6%u8FDB%u884C%u64CD%u4F5C%u3002%0A%u4F46%u5176%u5B9E%u6211%u4EEC%u5E76%u4E0D%u9700%u5982%u6B64%u3002%u53EA%u8981%u4FDD%u8BC1package%20folder%u7684%u6743%u9650%u81F3%u5C11%u662F711%uFF0Cpreference.xml%u6587%u4EF6%u6709%u53EF%u8BFB%u6743%u9650%u5373%u53EF%u3002%0A