赞
踩
ContentProvider作为Android四大组件之一,是Android应用对外开放的数据接口,只要符合它所定义的Uri格式的请求,均可以正常访问执行操作。其他的Android应用可以使用ContentResolver对象通过与ContentProvider同名的方法请求执行,被执行的就是ContentProvider中的同名的方法。
本文主要介绍ContentProvider的启动流程。
类图1
类图2
时序图1
时序图2
1.A应用发送信息给AMS(ActivityManagerService,进程system_server)要访问B应用的XXXContentProvider
2.AMS检查B应用没有被启动过,则新开一个进程启动B应用
3.启动应用B后,AMS向B应用启动XXXContentProvider,并实行相应的onCreate,返回IActivityManager.ContentProviderHolder,其中实现IContentProvider接口的Transact
4.AMS 把IActivityManager.ContentProviderHolder对象返回给A应用,A应用改造成代理ContentProviderProxy(即IContentProvider),此时A应用就可以调用增删改查等接口到B应用了。
照着类图和时序图的步数来分析:
在A应用进程处理:Step1、2、3、4、5、6、18、19
在AMS system_server进程处理:Step7、10、11、12、17
在B应用进程处理:Step8、9、13、14、15、16、20
Step1:
ContentResolver contentResolver = Conext.getContentResolver();
返回是ApplicationContentResolver,定义在ContextImpl内部静态类。
Step2:
Uri uri = Uri.parse(“content://cn.umbrella.providers.contact/item”);
Cursor cursor = contentResolver.query(uri, new String[]{“id”,“name”,“phone”}, null, null, “id asc”);
在ApplicationContentResolver.acquireProvider()调用ActivityThread类的acquireProvider函数进一步执行获取Content Provider接口的操作。
Step3、4、5:
ActivityThread. acquireProvider:先本地查找,若有,则直接返回,没有则调用ActivityManagerNative.getDefault().getContentProvider(getApplicationThread(), auth, userId, stable)即ActivityManagerProxy到AMS的getContentProvider()。
Step6:
在AMS. getContentProvider()调用getContentProviderImpl进一步处理,
在AMS中:ProviderMap mProviderMap成员变量是保存系统中的ContentProvider信息,boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed先检查XXXContentProvider存在、宿主进程以及没有被杀的情况下,就直接返回。
若不存在,则会通过AppGlobals.getPackageManage().resolveContentProvider和getApplicationInfo来分别获取XXXProvider应用程序的相关信息,并保存cpi和cpr变量中。接下来会判断mLaunchingProviders(系统中所有正在加载的Content Provider都保到这里面)是不是正在被其它应用程序加载XXXContentProvider,如果B应用进程已开启,但对应的contentprovider未初始化过,则会走proc.thread.scheduleInstallProvider(cpi),到B应用的ActivityThread的handleInstallProvider、installContentProviders初始化contentProvider,略过Step7-13步直接Step14。
如果B应用进程未启动,则继续走Step7 调用startProcessLocked函数来启动新进程并加装XXXContentProvider,并且把这个正在加载的信息增加到mLaunchingProviders中去,同步等到XXXContentProvider初始化完,while循环cpr.provider判空,然后cpr.wait(),等到Step17步publishContentProviders会dst.notifyAll()过来。
Step7、8、9、10:
ActivityManagerService.startProcessLocked、Process.start、ActivityThread.main、ActivityThread.attach、ActivityManagerService.attachApplication 新进程的创建完回到AMS的过程,可参考startService源码从AMS进程到service的新进程启动过程分析
Step11:
AMS. attachApplicationLocked, 会对这个B应用进程记录块做一些初始化,并获得需要加装的ContentProvider列表,即包括XXXContentProvider,然后调用从参数传进来的IApplicationThread对象thread(即ApplicationThreadProxy)的bindApplication进入到B应用程序XXXContentProvider进程中的ApplicationThread对象的bindApplication函数中去。
Step12、13:
ApplicationThread(ActivityThread 变量). bindApplication通过H(Handler)到ActivityThread主进程中handleBindApplication处理,调用installContentProviders函数来在初始化XXXContent Providers信息,以及Application等初始化工作。
Step14、15:
ActivityThread.installContentProviders 先调用installContentProviders对XXXContentProvider的初始化attachInfo,并调用onCreate,并把ContextProvider的成员变量Transport(父类ContentProviderNative,是binder对象,并且实现了IContentProvider接口)然后调用ActivityManagerNative.getDefault().publishContentProviders(getApplicationThread(), results),到Step16.
Step16:
ActivityManagerProxy. publishContentProviders(IApplicationThread caller, List providers)通知AMS进程 ,B应用进程及XXXContentProvider都已初始化完毕,并把相应的IContentProvider给过去。
Step17 :
AMS. publishContentProviders:会把B应用进程的的ContentProvider保存起来,并移除mLaunchingProviders里面相应的值,然后通知dst.notifyAll();到Step6的getContentProviderImpl,接着返回给A应用进程的ContentProviderHolder对象。
Step18:
在AMS进程通过binder返回给A应用对象ContentProviderHolder,会把B应用进程的IContentProvider接口(即Transport)通过ContentProviderNative.asInterface(source.readStrongBinder())改造为ContentProviderProxy。
Step19、20:
A应用进程拿到B应用进程的Transport后, ContentResolver.query()中调用ContentProviderProxy.query,这里面会BulkCursorToCursorAdaptor,包含CursorWindow等匿名共享内存方式读取数据。
附上一些关键的源码:
ContextImpl.java:
class ContextImpl extends Context { private final ApplicationContentResolver mContentResolver; @Override public ContentResolver getContentResolver() { return mContentResolver; } ... private static final class ApplicationContentResolver extends ContentResolver { private final ActivityThread mMainThread; private final UserHandle mUser; ... @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); } ... } }
ContentResolver.java:
public abstract class ContentResolver { public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { Preconditions.checkNotNull(uri, "uri"); IContentProvider unstableProvider = acquireUnstableProvider(uri); ... try { qCursor = unstableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal); } ... } }
ActivityThread.java:
public final class ActivityThread { public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } ... IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ... holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider; } public final IContentProvider acquireExistingProvider( Context c, String auth, int userId, boolean stable) { synchronized (mProviderMap) { final ProviderKey key = new ProviderKey(auth, userId); final ProviderClientRecord pr = mProviderMap.get(key); ... IContentProvider provider = pr.mProvider; IBinder jBinder = provider.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。