contentprovider java_Android深入四大组件(九)Content Provider的启动过程

本文详细解析了Android中ContentProvider的启动流程,从Activity通过ContentResolver调用query方法开始,逐步深入到AMS(ActivityManagerService)如何启动ContentProvider所在的进程,再到ContentProvider的onCreate方法执行,完整展示了ContentProvider的生命周期启动过程。
摘要由CSDN通过智能技术生成

前言

Content Provider做为四大组件之一,通常情况下并没有其他的组件使用频繁,但这不能作为我们不去深入学习它的理由。关于Content Provider一篇文章是写不完的,这一篇文章先来介绍它的启动过程。

1.query方法到AMS的调用过程

在Android IPC机制(四)用ContentProvider进行进程间通信这篇文章我举了一个Content Provider使用的例子,在Activity中我是使用如下代码调用Content Provider的:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classContentProviderActivity extends AppCompatActivity {private final static String TAG = "ContentProviderActivity";

@Overrideprotected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_content_provider);

Uri uri= Uri.parse("content://com.example.liuwangshu.mooncontentprovide.GameProvider");

ContentValues mContentValues= newContentValues();

mContentValues.put("_id", 2);

mContentValues.put("name", "大航海时代ol");

mContentValues.put("describe", "最好玩的航海网游");

getContentResolver().insert(uri, mContentValues);//1

Cursor gameCursor = getContentResolver().query(uri, new String[]{"name", "describe"}, null, null, null);

...

}

}

View Code

要想调用Content Provider,首先需要使用注释1处的getContentResolver方法,如下所示。

frameworks/base/core/Java/android/content/ContextWrapper.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@OverridepublicContentResolver getContentResolver() {returnmBase.getContentResolver();

}

View Code

这里mBase指的是ContextImpl,ContextImpl的getContentResolver方法如下所示。

frameworks/base/core/java/android/app/ContextImpl.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@OverridepublicContentResolver getContentResolver() {returnmContentResolver;

}

View Code

上面的代码return了ApplicationContentResolver类型的mContentResolver对象,ApplicationContentResolver是ContextImpl中的静态内部类,继承自ContentResolver,它在ContextImpl的构造方法中被创建。

当我们调用ContentResolver的insert、query、update等方法时就会启动Content Provider,这里拿query方法来进行举例。

query方法的实现在ApplicationContentResolver的父类ContentResolver中,代码如下所示。

frameworks/base/core/java/android/content/ContentResolver.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

publicfinal @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);//1

...try{

...try{

qCursor=unstableProvider.query(mPackageName, uri, projection,

selection, selectionArgs, sortOrder, remoteCancellationSignal);//2

} catch(DeadObjectException e) {

...

}

...

}

View Code

在注释1处通过acquireUnstableProvider方法返回IContentProvider类型的unstableProvider对象,在注释2处调用unstableProvider的query方法。我们查看acquireUnstableProvider方法做了什么,如下所示。

frameworks/base/core/java/android/content/ContentResolver.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

publicfinal IContentProvider acquireUnstableProvider(Uri uri) {if (!SCHEME_CONTENT.equals(uri.getScheme())) {//1

return null;

}

String auth=uri.getAuthority();if (auth != null) {return acquireUnstableProvider(mContext, uri.getAuthority());//2

}return null;

}

View Code

注释1处用来检查Uri的scheme是否等于”content”,如果不是则返回null。注释2处调用了acquireUnstableProvider方法,这是个抽象方法,它的实现在ContentResolver的子类ApplicationContentResolver中:

frameworks/base/core/java/android/app/ContextImpl.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@OverrideprotectedIContentProvider acquireUnstableProvider(Context c, String auth) {returnmMainThread.acquireProvider(c,

ContentProvider.getAuthorityWithoutUserId(auth),

resolveUserIdFromAuthority(auth),false);

}

View Code

return了ActivityThread类型的mMainThread对象的acquireProvider方法:

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

publicfinal IContentProvider acquireProvider(

Context c, String auth,intuserId, boolean stable) {

final IContentProvider provider= acquireExistingProvider(c, auth, userId, stable);//1

if (provider != null) {returnprovider;

}

IActivityManager.ContentProviderHolder holder= null;try{

holder=ActivityManagerNative.getDefault().getContentProvider(

getApplicationThread(), auth, userId, stable);//2

} catch(RemoteException ex) {throwex.rethrowFromSystemServer();

}if (holder == null) {

Slog.e(TAG,"Failed to find provider info for" +auth);return null;

}

holder=installProvider(c, holder, holder.info,true /*noisy*/, holder.noReleaseNeeded, stable);//3

returnholder.provider;

}

View Code

注释1处检查ActivityThread中的ArrayMap类型的mProviderMap中是否有目标ContentProvider存在,有则返回,没有就会在注释2处调用AMP的getContentProvider方法,最终会调用AMS的getContentProvider方法。注释3处的installProvider方法用来将注释2处返回的ContentProvider相关的数据存储在mProviderMap中,起到缓存的作用,这样使用相同的Content Provider时,就不需要每次都要调用AMS的getContentProvider方法。使用我们接着查看AMS的getContentProvider方法,代码如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Overridepublicfinal ContentProviderHolder getContentProvider(

IApplicationThread caller, String name,intuserId, boolean stable) {

...return getContentProviderImpl(caller, name, null, stable, userId);

}

View Code

getContentProvider方法return了getContentProviderImpl方法:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

privateContentProviderHolder getContentProviderImpl(IApplicationThread caller,

String name, IBinder token, boolean stable,intuserId) {

...

ProcessRecord proc=getProcessRecordLocked(

cpi.processName, cpr.appInfo.uid,false);//1

if (proc != null && proc.thread != null && !proc.killed) {

...if (!proc.pubProviders.containsKey(cpi.name)) {

checkTime(startTime,"getContentProviderImpl: scheduling install");

proc.pubProviders.put(cpi.name, cpr);try{

proc.thread.scheduleInstallProvider(cpi);//2

} catch(RemoteException e) {

}

}

}else{

checkTime(startTime,"getContentProviderImpl: before start process");

proc=startProcessLocked(cpi.processName,

cpr.appInfo,false, 0, "content provider",newComponentName(cpi.applicationInfo.packageName,

cpi.name),false, false, false);//3

checkTime(startTime, "getContentProviderImpl: after start process");

...

}

...

}

View Code

getContentProviderImpl方法的代码很多,这里截取了关键的部分。注释1处通过getProcessRecordLocked方法来获取目标ContentProvider的应用程序进程信息,这些信息用ProcessRecord类型的proc来表示,如果该应用进程已经启动就会调用注释2处的代码,否则就会调用注释3的startProcessLocked方法来启动进程。这里我们假设ContentProvider的应用进程还没有启动,关于应用进程启动过程,我在Android应用程序进程启动过程(前篇)已经讲过,最终会调用ActivityThread的main方法,代码如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public static voidmain(String[] args) {

...

Looper.prepareMainLooper();//1

ActivityThread thread = new ActivityThread();//2

thread.attach(false);if (sMainThreadHandler == null) {

sMainThreadHandler=thread.getHandler();

}if (false) {

Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG,"ActivityThread"));

}//End of event ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Looper.loop();//3

throw new RuntimeException("Main thread loop unexpectedly exited");

}

View Code

注释1处通过prepareMainLooper方法在ThreadLocal中获取Looper,并在注释3处开启消息循环。在注释2处创建了ActivityThread并调用了它的attach方法:

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

private voidattach(boolean system) {

...

final IActivityManager mgr= ActivityManagerNative.getDefault();//1

try{

mgr.attachApplication(mAppThread);//2

} catch(RemoteException ex) {throwex.rethrowFromSystemServer();

}

...

}

View Code

注释1处最终会得到AMS,在注释2处调用AMS的attachApplication方法,并将ApplicationThread类型的mAppThread对象传进去。

query方法到AMS的调用过程,如下面时序图所示(省略应用程序进程启动过程)。

487c0b565712569ba3ef1793432efc76.png

2.AMS启动Content Provider的过程

我们接着来查看AMS的attachApplication方法,如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Overridepublic final voidattachApplication(IApplicationThread thread) {

synchronized (this) {int callingPid =Binder.getCallingPid();

finallong origId =Binder.clearCallingIdentity();

attachApplicationLocked(thread, callingPid);

Binder.restoreCallingIdentity(origId);

}

}

View Code

attachApplication方法中又调用了attachApplicationLocked方法:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

privatefinal boolean attachApplicationLocked(IApplicationThread thread,intpid) {

...

thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,

profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,

app.instrumentationUiAutomationConnection, testMode,

mBinderTransactionTrackingEnabled, enableTrackAllocation,

isRestrictedBackupMode|| !normalMode, app.persistent,newConfiguration(mConfiguration), app.compat,

getCommonServicesLocked(app.isolated),

mCoreSettingsObserver.getCoreSettingsLocked());

...

}

View Code

attachApplicationLocked方法中调用了thread的bindApplication方法,thread是IApplicationThread类型的,从类型名字就可以看出来是用于进程间通信,这里实现bindApplication方法的是ApplicationThreadProxy类,它实现了IApplicationThread接口。

frameworks/base/core/java/android/app/ApplicationThreadNative.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

classApplicationThreadProxy implements IApplicationThread {

...

@Overridepublic final voidbindApplication(String packageName, ApplicationInfo info,

Listproviders, ComponentName testName, ProfilerInfo profilerInfo,

Bundle testArgs, IInstrumentationWatcher testWatcher,

IUiAutomationConnection uiAutomationConnection,intdebugMode,

boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,

boolean persistent, Configuration config, CompatibilityInfo compatInfo,

Mapservices, Bundle coreSettings) throws RemoteException {

...

mRemote.transact(BIND_APPLICATION_TRANSACTION, data,null,

IBinder.FLAG_ONEWAY);

data.recycle();

}

...

}

View Code

到目前为止,上面的调用过程还是在AMS进程中执行的,因此,需要通过IBinder类型的mRemote对象向新创建的应用程序进程(目标Content Provider所在的进程)发送BIND_APPLICATION_TRANSACTION类型的通信请求。处理这个通信请求的是在新创建的应用程序进程中执行的ApplicationThread的bindApplication方法,如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public final voidbindApplication(String processName, ApplicationInfo appInfo,

Listproviders, ComponentName instrumentationName,

ProfilerInfo profilerInfo, Bundle instrumentationArgs,

IInstrumentationWatcher instrumentationWatcher,

IUiAutomationConnection instrumentationUiConnection,intdebugMode,

boolean enableBinderTracking, boolean trackAllocation,

boolean isRestrictedBackupMode, boolean persistent, Configuration config,

CompatibilityInfo compatInfo, Mapservices, Bundle coreSettings) {

...

sendMessage(H.BIND_APPLICATION, data);

}

View Code

调用sendMessage方法像H发送BIND_APPLICATION类型消息,H的handleMessage方法如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public voidhandleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling:" +codeToString(msg.what));switch(msg.what) {

...caseBIND_APPLICATION:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"bindApplication");

AppBindData data=(AppBindData)msg.obj;

handleBindApplication(data);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;

...

}

...

}

View Code

我们接着查看handleBindApplication方法:

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

private voidhandleBindApplication(AppBindData data) {

...

final ContextImpl appContext= ContextImpl.createAppContext(this, data.info);//1

try{

final ClassLoader cl=instrContext.getClassLoader();

mInstrumentation=(Instrumentation)

cl.loadClass(data.instrumentationName.getClassName()).newInstance();//2

} catch(Exception e) {

...

}

final ComponentName component= newComponentName(ii.packageName, ii.name);

mInstrumentation.init(this, instrContext, appContext, component,

data.instrumentationWatcher, data.instrumentationUiAutomationConnection);//3

...

Application app= data.info.makeApplication(data.restrictedBackupMode, null);//4

mInitialApplication =app;if (!data.restrictedBackupMode) {if (!ArrayUtils.isEmpty(data.providers)) {

installContentProviders(app, data.providers);//5

mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);

}

}

...

mInstrumentation.callApplicationOnCreate(app);//6

...

}

View Code

handleBindApplication方法的代码很长,这里截取了主要的部分。注释1处创建了ContextImpl 。注释2处通过反射创建Instrumentation并在注释3处初始化Instrumentation。注释4处创建Application并且在注释6处调用Application的onCreate方法,这意味着Content Provider所在的应用程序进程已经启动完毕,在这之前,注释5处调用installContentProviders方法来启动Content Provider,代码如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

private voidinstallContentProviders(

Context context, Listproviders) {

final ArrayList results =

new ArrayList();for (ProviderInfo cpi : providers) {//1

...

IActivityManager.ContentProviderHolder cph= installProvider(context, null, cpi,false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//2

...

}try{

ActivityManagerNative.getDefault().publishContentProviders(

getApplicationThread(), results);//3

} catch(RemoteException ex) {throwex.rethrowFromSystemServer();

}

View Code

注释1处遍历当前应用程序进程的ProviderInfo列表,得到每个Content Provider的ProviderInfo(存储Content Provider的信息),并在注释2处调用installProvider方法来启动这些Content Provider。在注释3处通过AMS的publishContentProviders方法将这些Content Provider存储在AMS的mProviderMap中,这个mProviderMap在前面提到过,起到缓存的作用,防止每次使用相同的Content Provider时都会调用AMS的getContentProvider方法。来查看installProvider方法时如何启动Content Provider的,installProvider方法如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

privateIActivityManager.ContentProviderHolder installProvider(Context context,

IActivityManager.ContentProviderHolder holder, ProviderInfo info,

boolean noisy, boolean noReleaseNeeded, boolean stable) {

ContentProvider localProvider= null;

...

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

localProvider=(ContentProvider)cl.

loadClass(info.name).newInstance();//1

provider =localProvider.getIContentProvider();if (provider == null) {

...return null;

}if(DEBUG_PROVIDER) Slog.v(

TAG,"Instantiating local provider" +info.name);

localProvider.attachInfo(c, info);//2

} catch(java.lang.Exception e) {

...

}return null;

}

}

...returnretHolder;

}

View Code

在注释1处通过反射来创建ContentProvider类型的localProvider对象,并在注释2处调用了它的attachInfo方法:

frameworks/base/core/java/android/content/ContentProvider.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

private voidattachInfo(Context context, ProviderInfo info, boolean testing) {

...

ContentProvider.this.onCreate();

}

}

View Code

在attachInfo方法中调用了onCreate方法,它是一个抽象方法。这样Content Provider就启动完毕。

最后给出AMS启动Content Provider的时序图。

3f7d86ae3d8202d8e4b853b0e2547774.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值