在Android应用的开发中应该都会有两个进程中需要互相访问数据的需求,而在APK在安装到设备里的时候该应用的userid就已经确定了,
一般情况下都不会再改变,每个应用的进程在默认情况下的userid是不一样的,如adb shell下top命令显示的进程信息中的UID,
PID PR CPU% S #THR VSS RSS PCY UID Name
1436 2 0% S 15 671956K 33284K bg system com.android.deskclock
1459 2 0% S 13 666772K 29656K bg u0_a35 com.android.managedprovisioning
1483 3 0% S 23 683604K 36020K bg u0_a42 com.android.mms
1519 0 0% S 23 687924K 39484K bg u0_a36 com.android.email
那么UID(userid)都有什么作用呢?
众所周知,Android是基于Linux内核的操作系统,一般理解为User Identifier,UID在Linux中就是用户的ID,表明是哪个用户运行了这个程序,
主要用于权限的管理。Linux系统中不同的两个普通用户之间如果没有赋予权限是不能互相访问数据的。
而在Android 中又有所不同,因为Android为单用户系统,这时UID 便被赋予了新的使命——数据共享,为了实现数据共享,Android为每个
应用几乎都分配了不同的UID,不像传统的Linux,每个进程的用户相同就为之分配相同的UID,(当然这也就表明了一个问题,android只
能是单用户系统,在设计之初就被他们的工程师给阉割了多用户),使之成了数据共享的工具。
那么在Android中UID既然是用来进行数据共享的工具,那么我们怎么样才能做到数据共享呢?
Android中的数据共享方式有两种:
1)通过ContentProvider,这个方式是通过实现ContentProvider的抽象方法将需要共享的数据暴露出去,这个后续在细研究,如果需要实现
组定义的ContentProvider,建议可以参考code/Lollipop/packages/providers/下的原生实现。
2) 通过在AndroidManifest中将android:sharedUserId属性,将需要互相访问的apk中的该属性设置成相同的,这样它们的UID就一样了,就可以
互相访问各自的数据啦,包括数据库和文件等。
示例:
a)首先在AndroidManifest.xml中设置相同的sharedUserId(后面简称为UID),可以看到该id的命名可以随意,当然最好能表达其作用。
应用一
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.anna.hello"
android:sharedUserId="anna.uid">
应用二
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.anna.world"
android:sharedUserId="anna.uid">
b) 两个应用程序设置完相同的UID之后,为了安全起见,建议再到Android.mk中定义相同的签名,因为如果不设置相同的签名,一旦
应用被破解,所设置的UID被暴露,其它应用通过设定相同的UID也可以任意访问我们的数据,这样非安全的共享其实没有什么意义了,
那么这个签名怎么设置呢?
参考如下:
vi Android.mk #应用一和应用二都需要添加
将LOCAL_CERTIFICATE := testkey添加mk文件中
可能在这里对于LOCAL_CERTIFICATE的赋值,大家又会有疑问,可以使用的值都有哪些呢?
在build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:
1、testkey:普通APK,默认情况下使用。
2、platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。
3、shared:该APK需要和home/contacts进程共享数据。
4、media:该APK是media/download系统中的一环。
应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定用哪个key签名,未指定的默认用testkey
四组签名的原生注释可以查看build/target/product/security/README的说明。
c)目前已经具备两个应用之间互相访问数据的权限,那么怎么互相访问呢?
一方面是共享资源,要获取资源只要能拿到对方的context就可以,例如在应用二中创建应用一的context:
Context context1 = this.createPackageContext(“test.anna.hello”,Context.CONTEXT_IGNORE_SECURITY);
这里的this应该是Application或者Activity等有createPackageContext能力的类型相关实例。
这样通过context1可以获取到应用一中的资源,包括:数据库,preference,资源文件等等
例如通过context1获取应用一中的string:
context1.getString(R.string.toast_message)
其余资源获取方式查看Context的相关API进行使用。
另一方面可能你还希望能够在应用二中使用应用一中的一些类,那么你可以通过修改应用二的Android.mk文件就可以mm通过,在该mk文件中添加如
下这个编译变量的定义:
LOCAL_APK_LIBRARIES += Hello
这样你可以编译通过,但是可能会有运行时错误,这个错误可能由于两个apk的classloader不一致,这个待后续验证再补充blog,今天累了。。。
参考:
1.http://www.cnblogs.com/perseus/articles/2354173.html
2.http://blog.csdn.net/wirelessqa/article/details/8581652
3.http://blog.csdn.net/hmg25/article/details/6447067