前言

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

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

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

public class ContentProviderActivity extends AppCompatActivity {
private final static String TAG = "ContentProviderActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_provider);
Uri uri = Uri.parse("content://com.example.liuwangshu.mooncontentprovide.GameProvider");
ContentValues mContentValues = new ContentValues();
mContentValues.put("_id", );
mContentValues.put("name", "大航海时代ol");
mContentValues.put("describe", "最好玩的航海网游");
getContentResolver().insert(uri, mContentValues);//
Cursor gameCursor = getContentResolver().query(uri, new String[]{"name", "describe"}, null, null, null);
...
}
}

要想调用Content Provider,首先需要使用注释1处的getContentResolver方法,如下所示。
frameworks/base/core/Java/android/content/ContextWrapper.java

@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}

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

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

@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}

上面的代码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

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 {
...
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);//
} catch (DeadObjectException e) {
...
}
...
}

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

public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {//
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
return acquireUnstableProvider(mContext, uri.getAuthority());//
}
return null;
}

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

@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}

return了ActivityThread类型的mMainThread对象的acquireProvider方法:
frameworks/base/core/java/android/app/ActivityThread.java

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();
}
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);//
return holder.provider;
}

注释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

@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
...
return getContentProviderImpl(caller, name, null, stable, userId);
}

getContentProvider方法return了getContentProviderImpl方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
...
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);//
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);//
} catch (RemoteException e) {
}
}
} else {
checkTime(startTime, "getContentProviderImpl: before start process");
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, , "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);//
checkTime(startTime, "getContentProviderImpl: after start process");
...
}
... }

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

public static void main(String[] args) {
...
Looper.prepareMainLooper();//
ActivityThread thread = new ActivityThread();//
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//
throw new RuntimeException("Main thread loop unexpectedly exited");
}

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

  private void attach(boolean system) {
...
final IActivityManager mgr = ActivityManagerNative.getDefault();//
try {
mgr.attachApplication(mAppThread);//
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}

注释1处最终会得到AMS,在注释2处调用AMS的attachApplication方法,并将ApplicationThread类型的mAppThread对象传进去。
query方法到AMS的调用过程,如下面时序图所示(省略应用程序进程启动过程)。

2.AMS启动Content Provider的过程

我们接着来查看AMS的attachApplication方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}

attachApplication方法中又调用了attachApplicationLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
...
}

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

class ApplicationThreadProxy implements IApplicationThread {
...
@Override
public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
Bundle testArgs, IInstrumentationWatcher testWatcher,
IUiAutomationConnection uiAutomationConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
boolean persistent, Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
...
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
...
}

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

public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
...
sendMessage(H.BIND_APPLICATION, data);
}

调用sendMessage方法像H发送BIND_APPLICATION类型消息,H的handleMessage方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
...
}

我们接着查看handleBindApplication方法:
frameworks/base/core/java/android/app/ActivityThread.java

private void handleBindApplication(AppBindData data) {
...
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);//
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();//
} catch (Exception e) {
...
}
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);//
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);//
mInitialApplication = app;
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);//
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, *);
}
}
...
mInstrumentation.callApplicationOnCreate(app);//
...
}

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

private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) {//
...
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//
...
} try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);//
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}

注释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

private IActivityManager.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();//
provider = localProvider.getIContentProvider();
if (provider == null) {
...
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
localProvider.attachInfo(c, info);//
} catch (java.lang.Exception e) {
...
}
return null;
}
}
...
return retHolder;
}

在注释1处通过反射来创建ContentProvider类型的localProvider对象,并在注释2处调用了它的attachInfo方法:
frameworks/base/core/java/android/content/ContentProvider.java

private void attachInfo(Context context, ProviderInfo info, boolean testing) {
...
ContentProvider.this.onCreate();
}
}

在attachInfo方法中调用了onCreate方法,它是一个抽象方法。这样Content Provider就启动完毕。
最后给出AMS启动Content Provider的时序图。

Android深入四大组件(九)Content Provider的启动过程的更多相关文章

  1. Android应用程序组件Content Provider的启动过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6963418 通过前面的学习,我们知道在Andr ...

  2. 第八章:四大组件之Content Provider

    前言 Content Provider——Android四大组件之一. 本文要点 1.Content Provider简介 2.URI简介 3.如何访问Content Provider中数据 一.Co ...

  3. Content Provider的启动过程

    --摘自<Android进阶解密> 第一步:query方法到AMS的调用过程 1)ApplicationContentResolver是ContextImpl中的静态内部类,继承自Cont ...

  4. Android的四大组件之Activity

    Android的四大组件之Activity Activity:是Android组件中最基本也是最为常见用的四大组件(Activity,Service服务,Content Provider内容提供者,B ...

  5. android中四大组件之间相互通信

    好久没有写有关android有关的博客了,今天主要来谈一谈android中四大组件.首先,接触android的人,都应该知道android中有四大组件,activity,service,broadca ...

  6. Android的四大组件

    Android的四大组件:Activity.Service.BroadcastReceiver.Content Provider. Content Provider 属于Android应用程序的组件之 ...

  7. Android开发四大组件概述

    这个文章主要是讲Android开发的四大组件,本文主要分为 一.Activity具体解释 二.Service具体解释 三.Broadcast Receiver具体解释 四.Content Provid ...

  8. Android之四大组件、六大布局、五大存储 总结

    Android之四大组件.六大布局.五大存储 一.四大组件:Android四大组件分别为activity.service.content provider.broadcast receiver.   ...

  9. Android 系统四大组件

    Android 系统四大组件分别是活动(Activity).服务(Service).广播接收器(Broadcast Receiver)和内容提供器(Content Provider). 活动是所有 A ...

随机推荐

  1. iOS学习——iOS开发小知识点集合

    在iOS学习和开发过程中,经常会遇到一些很小的知识点和问题,一两句话就可以解释清楚了,这样的知识点写一篇随笔又没有必要,但是又想mark一下,以备不时之需,所以就有了本文.后面遇到一些小的知识点会不断 ...

  2. Java核心技术及面试指南 IO部分的面试题归纳以及答案

    4.6.1 java中有几种类型的流? Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStr ...

  3. sql server 锁与事务拨云见日(中)

    一.事务的概述 上一章节里,重点讲到了锁,以及锁与事务的关系.离上篇发布时间好几天了,每天利用一点空闲时间还真是要坚持.听<明朝那些事儿>中讲到"人与人最小的差距是聪明,人与人最 ...

  4. sql server 索引阐述系列一索引概述

    一. 索引概述 关于介绍索引,有一种“文章太守,挥毫万字,一饮千钟”的豪迈感觉,因为索引需要讲的知识点太多.在每个关系型数据库里都会作为重点介绍,因为索引关系着数据库的整体性能, 它在数据库性能优化里 ...

  5. PYTHON 中 SQL 带参数

    使用 PYTHON 的字符串填充方式 import mysql.connector sql = 'select \* from school.student where age > {age} ...

  6. 使用ES6新数组方法(象C# Lambda表达式一样写查询语句)

    let people = [ {id: 1, name: "a", age: 12}, {id: 2, name: "b", age: 13}, {id: 3, ...

  7. MFC原理第三讲.RTTI运行时类型识别

    MFC原理第三讲.RTTI运行时类型识别 一丶什么是RTTI RTTI. 运行时的时候类型的识别. 运行时类型信息程序.能够使用基类(父类)指针 或者引用 来检查这些指针或者引用所指的对象. 实际派生 ...

  8. 【转载】wifi的两种工作模式

    AP:即无线接入点,是一个无线网络的中心节点.通常使用的无线路由器就是一个AP,其它无线终端 可以通过AP相互连接. STA:即无线站点,是一个无线网络的终端.如笔记本电脑.PDA等. 1>工作 ...

  9. MySQL索引建立和使用的基本原则

    合理设计和使用索引 在关键字段的索引上,建与不建索引,查询速度相差近100倍.   差的索引和没有索引效果一样.   索引并非越多越好,因为维护索引需要成本.   每个表的索引应在5个以下,应合理利用 ...

  10. Python中斐波那契数列的赋值逻辑

    斐波那契数列 斐波那契数列又称费氏数列,是数学家Leonardoda Fibonacci发现的.指的是0.1.1.2.3.5.8.13.21.34.······这样的数列.即从0和1开始,第n项等于第 ...