10.5.2 安装Content Provider

安装Content Provider由ActivityThread的installSystemProviders方法完成。这里要安装的便是上文中查询的SettingsProvider。installSystemProviders的代码如下:


public final class ActivityThread{

……

public final void installSystemProviders(List<ProviderInfo>providers){

if(providers!=null){

installContentProviders(mInitialApplication, providers);

}

}


installSystemProviders方法将请求转发给installContentProviders方法,installContent Providers是安装Content Provider的通用接口。针对SettingsProvider,需要接收参数mInitialApplication,该参数是在ActivityThread.systemMain阶段由Instrumentation创建的Application。

installSystemProviders方法的代码如下:


public final class ActivityThread{

……

private void installContentProviders(

Context context, List<ProviderInfo>providers){

final ArrayList<IActivityManager.ContentProviderHolder>results=

new ArrayList<IActivityManager.ContentProviderHolder>();

for(ProviderInfo cpi:providers){

//调用installProvider,返回ContentProviderHolder

IActivityManager.ContentProviderHolder cph=

installProvider(context, null, cpi,

false/noisy/,true/noReleaseNeeded/,true/stable/);

if(cph!=null){

cph.noReleaseNeeded=true;

results.add(cph);//存入results中,用于发布

}

}

//向ActivityManagerService发布该Content Provider

try{

ActivityManagerNative.getDefault().publishContentProviders(

getApplicationThread(),results);

}catch(RemoteException ex){

}

}


installContentProviders是安装Content Provider的通用接口,其主要执行以下两步操作:

1)调用installProvider方法创建Content Provider,存入ContentProviderHolder中。

2)调用publishContentProviders方法向ActivityManagerService发布该Content Provider。

1.调用installProvider方法创建Content Provider

接下来分析ActivityThread的installProvider方法如何创建Content Provider,代码如下:


//参数分别为context, null, cpi, false, true, true

private IActivityManager.ContentProviderHolder installProvider(

Context context, IActivityManager.ContentProviderHolder holder,

ProviderInfo info, boolean noisy,

boolean noReleaseNeeded, boolean stable){

ContentProvider localProvider=null;

IContentProvider provider;

if(holder==null||holder.provider==null){//holder参数为null

Context c=null;

ApplicationInfo ai=info.applicationInfo;

/*context即mInitialApplication,表示frameworks-res.apk

ai是SettingProvider对应的应用信息,这里不相等/

if(context.getPackageName().equals(ai.packageName)){

c=context;

}else if(mInitialApplication!=null&&

mInitialApplication.getPackageName().equals(ai.packageName)){

c=mInitialApplication;

}else{//执行该分支

try{

//创建SettingsProvider对应的Context

c=context.createPackageContext(ai.packageName,

Context.CONTEXT_INCLUDE_CODE);

}catch(PackageManager.NameNotFoundException e){

//忽略

}

}

if(c==null){

return null;//Context必须创建成功,否则直接返回

}

try{

//通过Context获取类加载器

final java.lang.ClassLoader cl=c.getClassLoader();

//通过Java反射机制在本进程创建SettingsProvider的实例

localProvider=(ContentProvider)cl.loadClass(info.name).newInstance();

/*返回Content Provider的mTransport成员变量,Content Provider需要发布到

ActivityManagerService,因此需要一个Binder服务接口/

provider=localProvider.getIContentProvider();

//Binder服务接口不能为null,否则无法发布,其他组件也无法使用

if(provider==null){

return null;

}

/*设置Content Provider的权限并调用其子类的onCreate

方法,本例中即调用SettingsProvider的onCreate方法/

localProvider.attachInfo(c, info);

}catch(java.lang.Exception e){

return null;

}

}else{//对应最外层if

provider=holder.provider;

}

IActivityManager.ContentProviderHolder retHolder;

synchronized(mProviderMap){

IBinder jBinder=provider.asBinder();

if(localProvider!=null){

//查询是否已经发布过该Content Provider

ComponentName cname=new ComponentName(info.packageName, info.name);

ProviderClientRecord pr=mLocalProvidersByName.get(cname);

if(pr!=null){

provider=pr.mProvider;//使用已有的

}else{

/*以ProviderInfo为参数构造holder, ProviderInfo存储了ContentProvider

的权限和AndroidManifest.xml中android:authorities属性值/

holder=new IActivityManager.ContentProviderHolder(info);

//holder存储Provider的Binder服务接口

holder.provider=provider;

holder.noReleaseNeeded=true;

/*创建ProviderClientRecord,并将其存入mProviderMap中。android:authorities

属性值以“;”分割,这里以每个authority为键存储ProviderClientRecord/

pr=installProviderAuthoritiesLocked(provider, localProvider, holder);

//以Binder为键存储ProviderClientRecord

mLocalProviders.put(jBinder, pr);

//以组件名为键存储ProviderClientRecord

mLocalProvidersByName.put(cname, pr);

}

retHolder=pr.mHolder;

}else{//对应localProvider为null,本例中不为null

//获取该ContentProvider的引用计数

ProviderRefCount prc=mProviderRefCountMap.get(jBinder);

if(prc!=null){

//更新引用计数

if(!noReleaseNeeded){

incProviderRefLocked(prc, stable);

try{

ActivityManagerNative.getDefault().removeContentProvider(

holder.connection, stable);

}catch(RemoteException e){

//do nothing content provider object is dead any way

}

}

}else{//对应prc为null,添加新的引用计数

ProviderClientRecord client=

installProviderAuthoritiesLocked(

provider, localProvider, holder);

if(noReleaseNeeded){

prc=new ProviderRefCount(holder, client,1000,1000);

}else{

prc=stable

?new ProviderRefCount(holder, client,1,0)

:new ProviderRefCount(holder, client,0,1);

}

mProviderRefCountMap.put(jBinder, prc);

}

retHolder=prc.holder;

}

}

return retHolder;

}


installProvider的执行过程比较复杂,需要结合其类图关系分析,如图10-6所示。

10.5.2 安装Content Provider - 图1

图 10-6 installProvider的类图关系

从上图可以归纳如下信息:

SettingsProvider继承自ContentProvider,用于提供数据共享接口,其覆盖了父类的onCreate方法。

ContentProvider的mContext成员变量用于描述当前Content Provider的运行环境,mTransact成员变量用于描述当前Content Provider的Binder服务接口。

mTransact类型是Transact,该类相当于Binder体系结构中的工具类,用于提供远程访问功能。Content Provider需要将mTransact发布给ActivityManagerService,以便使用Content Provider的Client组件可以向ActivityManagerService查询所需要的Content Provider, ActivityManagerService根据mTransact返回对应的ContentProviderProxy给Client。

mTransact最终存储到ContentProviderHolder的provider成员变量中,Content Provider Holder是Parcelable的子类,可以跨进程传输。因此当传入ActivityThread.install方法的holder参数为null时,说明要安装的Content Provider运行于当前进程,需要通过反射机制加载并创建具体的Content Provider对象;而当holder参数不为null时,说明要安装的Content Provider来自于其他进程,此时只需要从holder中取出Content Provider并更新或增加其引用计数即可。

ActivityThread定义了内部类ProviderClient Record,用于存储具体的ContentProvider。其mProvider成员变量存储的是本进程运行的Content Provider的引用,其成员变量mLocalProvider存储的是本进程运行的Content Provider的Binder服务接口,其成员变量mNames存储的是android:authorities配置信息。

ActivityThread的成员变量mProviderMap,以Content Provider的authority为键存储Provider Client Record,成员变量mLocalProviders以Binder引用为键存储ProviderClientRecord,成员变量mLocalProvidersByName以组件名为键存储ProviderClientRecord。

2.调用publishContentProviders方法发布Content Provider

Content Provider的发布过程最终由ActivityManagerService的publishContentProviders方法完成,其代码如下:


public final void publishContentProviders(IApplicationThread caller,

List<ContentProviderHolder>providers){

……

synchronized(this){

//获取调用方进程的ProcessRecord

final ProcessRecord r=getRecordForAppLocked(caller);

……

final long origId=Binder.clearCallingIdentity();

/*遍历传入的列表,该列表的元素是ContentProviderHolder,其中

一个元素就存储了本例分析的SettingsProvider/

final int N=providers.size();

for(int i=0;i<N;i++){

ContentProviderHolder src=providers.get(i);

……

//从调用进程中获取ContentProviderRecord

ContentProviderRecord dst=r.pubProviders.get(src.info.name);

if(dst!=null){

ComponentName comp=new ComponentName(dst.info.packageName,

dst.info.name);

/*ActivityManagerService内部通过mProviderMap以组件名为键

保存Content Provider信息/

mProviderMap.putProviderByClass(comp, dst);

String names[]=dst.info.authority.split(";");

/同时以authority为键保存Content Provider信息/

for(int j=0;j<names.length;j++){

mProviderMap.putProviderByName(names[j],dst);

}

//等待启动的Content Provider,一旦启动并发布,将从该列表删除

int NL=mLaunchingProviders.size();

int j;

for(j=0;j<NL;j++){

if(mLaunchingProviders.get(j)==dst){

mLaunchingProviders.remove(j);

j—;

NL—;

}

}

synchronized(dst){

dst.provider=src.provider;

//ContentProviderRecord需要关联ProcessRecord

dst.proc=r;

//通知正在等待该Content Provider启动的Client

dst.notifyAll();

}

//发布Content Provider后,需要调整进程的OOM adj值

updateOomAdjLocked(r);

}

}

Binder.restoreCallingIdentity(origId);

}

}


publishContentProviders的工作流程很简单,其流程如下:

1)根据调用者传入的IApplicationThread参数,获取调用进程的ProcessRecord。

2)将Content Provider信息存入ActivityManagerService的成员变量mProviderMap中。存储方法有两种,即对应两种检索方法。

3)mLaunchingProviders中存储了Client请求使用的Content Provider信息。当前Content Provider已启动,因此需要从mLaunchingProviders中移除该Content Provider的信息。

4)将Content Provider与其ProcessRecord关联。

5)通知Client,其请求使用的Content Provider已发布。

以上步骤完成后,ActivityManagerService便进入第四阶段。