ContentProvider启动流程源码分析(一)

说明:基于API 26的源码分析

ContentProvider默认启动过程

1. 类图

content_provider_02

ContentProviderHolder: 实现Parcelable,包含了Contentprovider的信息,可以跨进程传递。

ProviderInfo: 继承ComponentInfo, 存储contentprovider的全类名,authorities,权限,是否多进程等信息。

ContentProvider: 抽象类,由子类实现增删改查。

Transport: 是ContentProvider内部类,实现IContentProvider, 并继承Binder,跨进程时是被调用方。实现IContentProvider里的增删改查等方法实质是用contentProvider实例调用ContentProvider的增删改查等方法,从而实现了ContentProvider的跨进程增删改查等操作。

ContentProviderProxy: 是跨进程代理类,提供给调用方使用。

ContentResolver: 是个抽象类,供应用层调用,有增删改查等方法。应用层使用ContentResolver可以进行跨进程通信,不用关心细节。获取ContentResolver需要调用context.getContentResolver()。ContentResolver真正的实现类是在ContextImpl内部类ApplicationContentResolver。

ApplicationContentResolver: ContentResolver的实现类,增删改查操作实质是通过IContentProvider操作。获取IContentProvider通过mMainThread(是ActivityThread实例)跨进程在ActivityManagerService里获取。

ActivityManagerService: 里有个getContentProvider方法获取到ContentProviderHolder,获取到ContentProviderHolder就可以获取到IContentProvider。

2. 源码分析

第一步: 从ActivityThread的handleBindApplication()开始

1
2
3
4
5
6
7
8
9
10
11
12
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, 10*1000);
}
}
...
try {
mInstrumentation.callApplicationOnCreate(app)
}

data.info是一个LoadedApk实例,调用makeApplication创建Application实例,data.providers存储着当前应用所有contentprovider, 通过调用installContentProviders初始化。调用mInstrumentation.callApplicationOnCreate(app)实质是调用application实例的onCreate方法。

第二步: ActivtyThread的 installContentProviders 方法

contentprovider_01

循环ProviderInfo的List, 把每个providerInfo传到installProvider方法中创建ContentProviderHolder实例,把ContentProviderHolder实例放到一个名为results的ArrayList里,最后通过ActivityManager.getService().publishContentProviders方法把results传到ActivityManagerService进程中。

第三步:ActivtyThread的installProvider方法

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
29
30
31
32
33
34
35
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
}

ContentProviderHolder retHolder;
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider,
localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
}
return retHolder;

installProvider方法篇幅比较长,上面的代码是截取了一些关键代码,由第二步调用这个方法时传进来ContentProviderHolder为null,classLoader利用反射调用className和newInstance创建ContentProvider赋值为localProvider,调用localProvider.getIContentProvider()获取到IContentProvider,接着调用localProvider.attachInfo()完成初始化ContentProvider。mLocalProvidersByName.get(cname)获取的pr为空,接着创建ContentProviderHolder实例,并给ContentProviderHolder实例的成员变量info,provider,noReleaseNeeded赋值,接着installProviderAuthoritiesLocked方法生成ProviderClientRecord,并存储在mLocalProviders和mLocalProvidersByName的这两个Map中,最后return ContentProviderHolder实例。

如果mLocalProvidersByName.get(cname)获取的pr不为空,直接从ProviderClientRecord取出holder。

第三步:ActivtyThread的installProviderAuthoritiesLocked()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, ContentProviderHolder holder) {
final String auths[] = holder.info.authority.split(";");
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
......
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
for (String auth : auths) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord existing = mProviderMap.get(key);
if (existing != null) {
Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
+ " already published as " + auth);
} else {
mProviderMap.put(key, pcr);
}
}
return pcr;
}

这个方法生成ProviderClientRecord实例,存储着auths, provider, localProvider, holder,auths是String[]数组, 由authority用”;”分离而成。循环auths数组,把ProviderClientRecord实例存储在mProviderMap这个Map中。

第四步: ContentProvider的getIContentProvider()

1
2
3
4
5
private Transport mTransport = new Transport();

public IContentProvider getIContentProvider() {
return mTransport;
}

getIContentProvider返回IContentProvider接口,实质是一个Transport实例。Transport实现IContentProvider, 并继承Binder,跨进程时是被调用方。

第五步:ContentProvider的attachInfo()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void attachInfo(Context context, ProviderInfo info) {
attachInfo(context, info, false);
}

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();
}
}

这个方法初始ContentProvider,mContext为null时才会初始化,attachInfo方法传进来context是application,接着调用setReadPermission, setWritePermission,setPathPermissions,setAuthorities 这些方法配置读写权限,配置authorities(contentprovider的唯一标识)。最后调用onCreate方法。 回头看第一步,你会发现ContentProvider的onCreate方法比Application的onCreate先调用。

第六步: ActivityManagerService的 publishContentProviders()

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 void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
......
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
......

}
}
}

这个方法主要把来自UI进程providers的信息存储,看上面的代码遍历providers,把ComponentName和names分别调用mProviderMap.putProviderByClass(comp, dst)和mProviderMap.putProviderByName(names[j], dst)存储起来。

3. 总结

  • ContentProvider的过程是先创建Application实例,ProviderInfo存储着存储着当前应用所有contentprovider的信息,遍历每一个contentprovider的信息调用installContentProviders方法生成ContentProviderHolder,并添加到一个List里,最后通过ActivityManager.getService().publishContentProviders()把这个list传递到AMS中。在生成每一个ContentProviderHolder时通过ClassLoader加载包名创建ContentProvider实例,接着调用contentProvider的onCreate()完成初始化。
  • ContentProvider.onCreate调用后才调用Application的onCreate, 目前有一些第三方的sdk会在AndroidManifest清单添加一个provider, 在ContentProvider.onCreate完成sdk初始化,不需要sdk使用者在Application的onCreate里初始化, 简化初始化的流程。
  • 本文ContentProvider启动流程只是一个app内部AndroidManifest清单添加一个provider时启动过程,当调用例如, 通讯录等第三方共享的provider,这时provider启动流程又会有所不同。
Loading comments box needs to over the wall