文章目录

ContentProvider是一种内容共享性组件,它通过Binder向其他组件乃至其他应用提供数据。

首先来看一下流程图:

img

一个应用的入口方法为ActivityThread的main方法,该方法是一个静态方法,在main方法中会创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThread的attach方法中会远程调用AMS的attachApplication方法并将ApplicationThread对象提供给AMS,ApplicationThread是一个Binder对象,它的接口是IApplicattionThread,它主要用于ActivityThread和AMS之间通信。

访问ContentProvider需要通过ContentResolver,它是一个抽象类,通过Context的getContentResolver方法获取的实际上是ApplicationContentResolver对象,该类继承了ContentResolver并实现了ContentResolver中的抽象方法。通过ContentProvider的四个方法中任何一个都可以触发ContentProvider的启动。这里选择query方法。

ContentProvider的query方法首先会获取IContentProvider对象,最终会通过ApplicationContentResolver的acquireProvider方法,该方法没有做任何逻辑,直接调用了ActivityThread的acquireExistingProvider方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}

上面代码中首先会从ActivityThread中查找是否已经存在ContentProvider,如果存在就直接返回,ActivityThread中通过mProviderMap来存储已经启动的ContentProvider对象,该容器的声明如下:

1
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap= new ArrayMap<ProviderKey, ProviderClientRecord>();

如果不存在就发送一个进程间请求给AMS让其启动,再通过installProvider方法来修改引用计数。
AMS是通过startProcessLocked方法来完成进程的启动,内部主要通过Process的start方法来完成进程的启动,新进程启动后的入口方法为ActivityThread的main方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) {
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");
}

在该方法中首先会调用ActivityThread的实例并调用attach方法进行初始化,然后进行消息循环,attach方法会将ApplicationThread对象通过AMS的attachApplication方法跨进程传给AMS,最终完成Contentprovider的创建。

1
2
3
4
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
}

APS的attachApplication方法调用了attachApplicationLocked方法,该方法又调用了ApplicationThread的bindApplication方法

1
2
3
4
5
6
7
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());

ApplicationThread的bindApplication方法发送一个BIND_APPLICATION类型定位消息给mH,mH收到消息后会调用ActivityThread的handleBindApplication方法,该方法就完成了Application的创建以及Contentprovider的创建,可以分为四步:

1 创建ContextImpl和Instrumentation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
java.lang.ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);

2 创建Application对象

1
2
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;

3 启动当前进程的ContentProvider并调用其中onCreate方法

1
2
3
4
5
6
7
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}

installContentProviders完成的ContentProvider的启动工作,首先会遍历当前进程的ProviderInfo的列表,并一一调用installProvider方法来启动他们,然后将启动的ContentProvider发布到AMS中,AMS会把他们存储在ProviderMap中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}

下面来看一下COntentProvider对象的创建过程,在installProvider方法中有下面一段代码,通过类加载器完成对象创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);

上面代码还会调用COntentProvider的attachInfo方法来调用他的onCreate方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
if (mContext == null) {
mContext = context;
if (context != null) {
mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
}
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
ContentProvider.this.onCreate();
}
}

到此为止onCreate方法已经被调用,意味着ContentProvider已经启动完成。

4 调用Application的onCreate方法

经过上面四个步骤,ContentPorovider已经成功启动,然后其他应用就可通过AMS来访问这个ContentProvider,拿到该对象之后就可以通过它所提供的接口来访问它了。


未经许可不得转载,转载请注明zilianliuxue的blog,本人保留所有版权。

文章目录