Android应用程序组件Content Provider的启动过程源代码分析.docx
- 文档编号:3833658
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:35
- 大小:108.97KB
Android应用程序组件Content Provider的启动过程源代码分析.docx
《Android应用程序组件Content Provider的启动过程源代码分析.docx》由会员分享,可在线阅读,更多相关《Android应用程序组件Content Provider的启动过程源代码分析.docx(35页珍藏版)》请在冰豆网上搜索。
Android应用程序组件ContentProvider的启动过程源代码分析
Android应用程序组件ContentProvider的启动过程源代码分析
通过前面的学习,我们知道在Android系统中,ContentProvider可以为不同的应用程序访问相同的数据提供统一的入口。
ContentProvider一般是运行在独立的进程中的,每一个ContentProvider在系统中只有一个实例存在,其它应用程序首先要找到这个实例,然后才能访问它的数据。
那么,系统中的ContentProvider实例是由谁来负责启动的呢?
本文将回答这个问题。
ContentProvider和应用程序组件Activity、Service一样,需要在AndroidManifest.xml文件中配置之后才能使用。
系统在安装包含ContentProvider的应用程序的时候,会把这些ContentProvider的描述信息保存起来,其中最重要的就是ContentProvider的Authority信息,Android应用程序的安装过程具体可以参考一文。
注意,安装应用程序的时候,并不会把相应的ContentProvider加载到内存中来,系统采取的是懒加载的机制,等到第一次要使用这个ContentProvider的时候,系统才会把它加载到内存中来,下次再要使用这个ContentProvider的时候,就可以直接返回了。
本文以前面一篇文章中的例子来详细分析ContentProvider的启动过程。
在这篇文章介绍的应用程序Article中,第一次使用ArticlesProvider这个ContentProvider的地方是ArticlesAdapter类的getArticleCount函数,因为MainActivity要在ListView中显示文章信息列表时,首先要知道ArticlesProvider中的文章信息的数量。
从ArticlesAdapter类的getArticleCount函数调用开始,一直到ArticlesProvider类的onCreate函数被调用,就是ArticlesProvider的完整启动过程,下面我们就先看看这个过程的序列图,然后再详细分析每一个步骤:
这个函数定义在前面一篇文章介绍的应用程序Artilce源代码工程目录下,在文件为packages/experimental/Article/src/shy/luo/article/ArticlesAdapter.Java中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassArticlesAdapter{
......
privateContentResolverresolver=null;
publicArticlesAdapter(Contextcontext){
resolver=context.getContentResolver();
}
......
publicintgetArticleCount(){
intcount=0;
try{
IContentProviderprovider=resolver.acquireProvider(Articles.CONTENT_URI);
Bundlebundle=provider.call(Articles.METHOD_GET_ITEM_COUNT,null,null);
count=bundle.getInt(Articles.KEY_ITEM_COUNT,0);
}catch(RemoteExceptione){
e.printStackTrace();
}
returncount;
}
......
}
这个函数通过应用程序上下文的ContentResolver接口resolver的acquireProvider函数来获得与Articles.CONTENT_URI对应的ContentProvider对象的IContentProvider接口。
常量Articles.CONTENT_URI是在应用程序ArticlesProvider中定义的,它的值为“content:
//shy.luo.providers.articles/item”,对应的ContentProvider就是ArticlesProvider了。
Step2.ContentResolver.acqireProvider
这个函数定义在frameworks/base/core/java/android/content/ContentResolver.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicabstractclassContentResolver{
......
publicfinalIContentProvideracquireProvider(Uriuri){
if(!
SCHEME_CONTENT.equals(uri.getScheme())){
returnnull;
}
Stringauth=uri.getAuthority();
if(auth!
=null){
returnacquireProvider(mContext,uri.getAuthority());
}
returnnull;
}
......
}
函数首先验证参数uri的scheme是否正确,即是否是以content:
//开头,然后取出它的authority部分,最后调用另外一个成员函数acquireProvider执行获取ContentProvider接口的操作。
在我们这个情景中,参数uri的authority的内容便是“shy.luo.providers.articles”了。
从ContentResolver类的定义我们可以看出,它是一个抽象类,两个参数版本的acquireProvider函数是由它的子类来实现的。
回到Step1中,这个ContentResolver接口是通过应用程序上下文Context对象的getContentResolver函数来获得的,而应用程序上下文Context是由ContextImpl类来实现的,它定义在frameworks/base/core/java/android/app/ContextImpl.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
classContextImplextendsContext{
......
privateApplicationContentResolvermContentResolver;
......
finalvoidinit(LoadedApkpackageInfo,
IBinderactivityToken,ActivityThreadmainThread,
Resourcescontainer){
......
mContentResolver=newApplicationContentResolver(this,mainThread);
......
}
......
@Override
publicContentResolvergetContentResolver(){
returnmContentResolver;
}
......
}
ContextImpl类的init函数是在应用程序启动的时候调用的,具体可以参考一文中的Step34。
因此,在上面的ContentResolver类的acquireProvider函数里面接下来要调用的ApplicationContentResolver类的acquireProvider函数。
Step3.ApplicationContentResolve.acquireProvider
这个函数定义在frameworks/base/core/java/android/app/ContextImpl.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
classContextImplextendsContext{
......
privatestaticfinalclassApplicationContentResolverextendsContentResolver{
......
@Override
protectedIContentProvideracquireProvider(Contextcontext,Stringname){
returnmMainThread.acquireProvider(context,name);
}
......
privatefinalActivityThreadmMainThread;
}
......
}
它调用ActivityThread类的acquireProvider函数进一步执行获取ContentProvider接口的操作。
Step4.ActivityThread.acquireProvider
这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassActivityThread{
......
publicfinalIContentProvideracquireProvider(Contextc,Stringname){
IContentProviderprovider=getProvider(c,name);
if(provider==null)
returnnull;
......
returnprovider;
}
......
}
它又是调用了另外一个成员函数getProvider来进一步执行获取ContentProvider接口的操作。
Step5.ActivityThread.getProvider
这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassActivityThread{
......
privatefinalIContentProvidergetExistingProvider(Contextcontext,Stringname){
synchronized(mProviderMap){
finalProviderClientRecordpr=mProviderMap.get(name);
if(pr!
=null){
returnpr.mProvider;
}
returnnull;
}
}
......
privatefinalIContentProvidergetProvider(Contextcontext,Stringname){
IContentProviderexisting=getExistingProvider(context,name);
if(existing!
=null){
returnexisting;
}
IActivityManager.ContentProviderHolderholder=null;
try{
holder=ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(),name);
}catch(RemoteExceptionex){
}
IContentProviderprov=installProvider(context,holder.provider,
holder.info,true);
......
returnprov;
}
......
}
这个函数首先会通过getExistingProvider函数来检查本地是否已经存在这个要获取的ContentProvider接口,如果存在,就直接返回了。
本地已经存在的ContextProvider接口保存在ActivityThread类的mProviderMap成员变量中,以ContentProvider对应的URI的authority为键值保存。
在我们这个情景中,因为是第一次调用ArticlesProvider接口,因此,这时候通过getExistingProvider函数得到的IContentProvider接口为null,于是下面就会调用ActivityManagerService服务的getContentProvider接口来获取一个ContentProviderHolder对象holder,这个对象就包含了我们所要获取的ArticlesProvider接口,在将这个接口返回给调用者之后,还会调用installProvider函数来把这个接口保存在本地中,以便下次要使用这个ContentProvider接口时,直接就可以通过getExistingProvider函数获取了。
我们先进入到ActivityManagerService服务的getContentProvider函数中看看它是如何获取我们所需要的ArticlesProvider接口的,然后再返回来看看installProvider函数的实现。
Step6.ActivityManagerService.getContentProvider
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassActivityManagerServiceextendsActivityManagerNative
implementsWatchdog.Monitor,BatteryStatsImpl.BatteryCallback{
......
publicfinalContentProviderHoldergetContentProvider(
IApplicationThreadcaller,Stringname){
......
returngetContentProviderImpl(caller,name);
}
......
}
它调用getContentProviderImpl函数来进一步执行操作。
Step7.ActivityManagerService.getContentProviderImpl
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassActivityManagerServiceextendsActivityManagerNative
implementsWatchdog.Monitor,BatteryStatsImpl.BatteryCallback{
......
privatefinalContentProviderHoldergetContentProviderImpl(
IApplicationThreadcaller,Stringname){
ContentProviderRecordcpr;
ProviderInfocpi=null;
synchronized(this){
ProcessRecordr=null;
if(caller!
=null){
r=getRecordForAppLocked(caller);
......
}
//Firstcheckifthiscontentproviderhasbeenpublished...
cpr=mProvidersByName.get(name);
if(cpr!
=null){
......
}else{
try{
cpi=AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS|PackageManager.GET_URI_PERMISSION_PATTERNS);
}catch(RemoteExceptionex){
}
......
}
cpr=mProvidersByClass.get(cpi.name);
finalbooleanfirstClass=cpr==null;
if(firstClass){
try{
ApplicationInfoai=
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS);
......
cpr=newContentProviderRecord(cpi,ai);
}catch(RemoteExceptionex){
//pmisinsameprocess,thiswillneverhappen.
}
}
if(r!
=null&&cpr.canRunHere(r)){
//Ifthisisamultiprocessprovider,thenjustreturnits
//infoandallowthecallertoinstantiateit.Onlydo
//thisiftheprovideristhesameuserasthecaller's
//process,orcanrunasroot(socanbeinanyprocess).
returncpr;
}
......
//Thisissingleprocess,andourappisnowconnectingtoit.
//Seeifwearealreadyintheprocessoflaunchingthis
//provider.
finalintN=mLaunchingProviders.size();
inti;
for(i=0;i if(mLaunchingProviders.get(i)==cpr){ break; } } //Iftheproviderisnotalreadybeinglaunched,thengetit //started. if(i>=N){ finallongorigId=Binder.clearCallingIdentity(); ProcessRecordproc=startProcessLocked(cpi.processName, cpr.appInfo,false,0,"contentprovider", newComponentName(cpi.applicationInfo.packageName, cpi.name),false); ...... mLaunchingProviders.add(cpr); ...... } //Makesuretheproviderispublished(thesameproviderclass //maybepublishedundermultiplenames). if(firstClass){ mProvidersByClass.put(cpi.name,cpr); } cpr.launchingApp=proc; mProvidersByName.put(name,cpr); ...... } //Waitfortheprovidertobepublished... synchronized(cpr){ while(cpr.provider==null){ ...... try{ cpr.wait(); }catch(InterruptedExceptionex){ } } } returncpr; } ...... } 这个函数比较长,我们一步一步地分析。 函数首先是获取调用者的进程记录块信息: [java]viewplaincopy在CODE上查看代码片派生到我的代码片 ProcessRecordr=null; if(caller! =null){ r=getRecordForAppLocked(caller); ...... } 在我们这个情景中,要获取的就是应用程序Artic
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android应用程序组件Content Provider的启动过程源代码分析 Android 应用程序 组件 Content Provider 启动 过程 源代码 分析