本文为原创文章,欢迎转载!转载时请注明出处:http://blog.csdn.net/windskier
android在实现进程间数据访问时,对不同的进程不同Application的数据访问提供了一套解决方案,这套解决方案便是ContentProvider。在开发应用程序时,想要访问其他进程的数据,ContentProvider便是不二的选择。
Content Provider其实很简单,其实质就是IPC通信,通过提供一个IInterface给Client来访问当前进程的数据。下面来分析一下Content Provider的管理过程。
android:multiprocess
属性, 并且Client的UID和Provider的UID相同时;
android:multiprocess
属性, 并且Client的UID和Provider的UID不相同时,但是Client的UID是System UID;
android:multiprocess
属性,那么则会在Client访问时在本地创建一个Provider,但是事实上并不是这样的,除了
android:multiprocess
属性的设置,还需要UID的匹配。相关的代码在
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& (uid == Process.SYSTEM_UID || uid == app.info.uid);
}
public ContentProviderResult[] applyBatch(String authority,
ArrayList operations)
throws RemoteException, OperationApplicationException {
ContentProviderClient provider = acquireContentProviderClient(authority);
if (provider == null) {
throw new IllegalArgumentException("Unknown authority " + authority);
}
try {
return provider.applyBatch(operations);
} finally {
provider.release();
}
}
我们知道Android设备在启动时会要求用户创建并登录一个Google account,并且提供了向该account同步设备信息的功能,如联系人,日程,email等内容。对于应用程序来说,ContentResolver提供了一套Sync同步的接口,在这篇文章中就不再详细的分析数据的Sync过程了,我打算在以后的文章中再分析Sync。如果在做应用程序开发时,的确需要向Account上同步数据,最好的方法是将数据设计为ContentProvider,利用ContentResolver的Sync接口去进行同步工作。
既然android通过ContentProvdier来实现进程间的数据访问,那么它就需要对保护的数据在被访问时进行权限检测,不但要检测读权限,同时要检测写权限。在AndroidManifest.xml中设置Provider的属性时,有3种permission可以设置,分别为android:permission, android:readPermission, android:writePermission.后2个Permission即为读写权限。而android:permission则代表着读和写2种权限, 但是android:permission只有在readPermission和writePermission未被设置时才有效。
android文档有关于grantUriPermissions的详细说明,这里就简单的提两句,阐述一下grantUriPermissions的使用情况。比如当application A需要使用Component B去访问Provider C,但是Component B并未添加Provider C的Read/Write permission,如果这个Provider设置了属性android:grantUriPermissions,那么就有办法使Component B访问C。通过设置A 启动 B时的Inent属性FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION,即可授权B在启动后去访问C。
对于授权permission的具体实现在方法grantUriPermissionFromIntentLocked()中。
有两种通过Inent属性来授权Permission,一种是Client启动新的Activity去访问Provider;
startActivityUncheckedLocked()@ActivityManagerService.java
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r.getUriPermissionsLocked());
另一种,client启动了一个activity去获取了Uri,这个activity在返回并通过send Result的方式向Client传递Uri的同时(返回的resultCode即是Intent),授权client对Provider的操作权限。下面是两种不同情况下Send result中授权的代码
sendActivityResultLocked()ActivityManagerService.java
if (callingUid > 0) {
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
data, r.getUriPermissionsLocked());
}
finishActivityLocked()@ActivityManagerService.java
if (r.info.applicationInfo.uid > 0) {
mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
resultTo.packageName, resultData,
resultTo.getUriPermissionsLocked());
}
AndroidManifest.xml文件中的element path-permission类似于grant-uri-permission,同样是指定某个Provider子集的权限设定;不同的是使用path-permission不需要设置Client Intent属性,并且path-permission单独设置了Read/Write Permission,这样可以使Provider更灵活的给不同的Provider子集设置不同的权限。
我们知道ContentProvider就是一个提供了数据接入的实现,开发人员在设计一个ContentProvider时,需要确定采用什么样的方式来存储数据,对于不同的数据操作方式,ContentProvide需要提供不同的接入操作,因此在这篇文章中不再介绍具体的ContentProvider操作。ContentProvider最常用的数据存储方式是通过sqlite数据库,在以后有机会分析android的数据库实现机制时在进行详细的说明与分析。