[toc]
基于 Android 7.1.1,分析 ContentProvider 的架构和原理。
0 综述
ContentProvider 是进程间通信的利器之一,充当数据存储和出具共享的中间者,其和核心是 Binder 和匿名共享内存!
我们在访问一个 ContentProvider 的时候,一般情况下都会先拉起该 ContentProvider 所在的进程,然后对其的增删改查:
1 | ContentResolver cr = getContentResolver(); |
下面我们来分析下,其主要的流程:
1 ContextImpl
1.1 getContentResolver
1 |
|
这里的 mContentResolver 是一个 ApplicationContentResolver 的实例:
1 | private final ApplicationContentResolver mContentResolver; |
其创建是在 ContentImpl 初始化的时候:
1 | private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, |
1.2 new ApplicationContentResolver
可以看到 ApplicationContentResolver 继承了 ContentResolver
1 | private static final class ApplicationContentResolver extends ContentResolver { |
同时,ApplicationContentResolver 继承了 ContentResolver 中和增删改查相关的接口:
1 | public final Cursor query(...) {...} |
下面,我们通过分析 query 接口,来了解下 ContentProvider 的启动流程!
2 ContentResolver
2.1 query - 查询
下面我们来看下查询的调用!
1 | public final Cursor query(final @RequiresPermission.Read @NonNull Uri uri, |
这里简单的说下,stable provider 和 unstable provider 的区别:
- 获取 stable provider 的进程会因为 provider 所在进程死亡而被杀死;而获取 unstable provider 的进程则不会出现这种情况;
具体的原因我们后面再分析!
这个流程很简单,不多说了!!
2.1.1 acquireUnstableProvider - 获取 unstable provider
1 | public final IContentProvider acquireUnstableProvider(Uri uri) { |
2.1.2 acquireProvider - 获取 stable provider
1 | public final IContentProvider acquireProvider(Uri uri) { |
3 ApplicationContentResolver
3.1 acquireUnstableProvider - 获取 unstable provider
获取 unstable provider
1 |
|
3.2 unstableProviderDied
处理 unstable provider 所在进程死亡后的工作!
1 |
|
3.3 acquireProvider - 获取 stable provider
获取 stable provider
1 |
|
可以看到 ApplicationContentResolver 最终都访问了 ActivityThread 中的逻辑!
4 ActivityThread
4.1 acquireProvider - 获取 provider
无论是 unstable provider 还是 stable provider,最终都会调用 ActivityThread 的 acquireProvider 方法,参数传递:
- String auth:authority 属性;
- int userId:设备用户 id;
- boolean stable:provider 的类型;
1 | public final IContentProvider acquireProvider( |
关于 holder 和 holder.provider 我们后面再分析!
继续来看:
4.1.1 acquireExistingProvider
尝试获得已经存在的一个 provider:
1 | public final IContentProvider acquireExistingProvider( |
主要逻辑如下:
- 尝试从 ActivityThread 的 mProviderMap 查询已存在相对应的 provider,若不存在,则返回 null;
- 如果 ActivityThread 存在该 provider ,但其所在的进程已经死亡,则调用 handleUnstableProviderDiedLocked 清理 provider 信息,并返回 null;
- 当 provider 记录存在,并且其进程仍然存活,则在 provider 引用计数不为空时继续增加引用计数。然后返回当前进程已经存在的 provider。
4.1.1.1 handleUnstableProviderDiedLocked
如果 provdier 所在的进程已经死亡,那么我们会将该 provider 从引用它的进程中的相关结构体中移除!
boolean fromClient 是否是客户端移除的!
1 | final void handleUnstableProviderDiedLocked(IBinder provider, boolean fromClient) { |
这里的逻辑就不多说了!
4.1.1.2 incProviderRefLocked
增加 provider 的引用计数, 参数 boolean stable 表示的是稳定引用,还是非稳定引用:
1 | private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) { |
可以看到,如果是第一次引用,那么会做一些额外的处理!
4.2 handleUnstableProviderDied
处理 unstable provider 死亡的清理操作,boolean fromClient 表示本次操作是否来自客户端进程,通过前面的参数传递
1 | final void handleUnstableProviderDied(IBinder provider, boolean fromClient) { |
这里就不多说了,继续看!
4.2.1 handleUnstableProviderDiedLocked
根据参数,这里的 boolean fromClient 为 true,当该进程持有的 unstable provider 所在进程死亡后,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
27final void handleUnstableProviderDiedLocked(IBinder provider, boolean fromClient) {
//【1】尝试从当前进程的引用集合中获得该 provider 的引用计数对象,并移除!
ProviderRefCount prc = mProviderRefCountMap.get(provider);
if (prc != null) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Cleaning up dead provider "
+ provider + " " + prc.holder.info.name);
mProviderRefCountMap.remove(provider);
for (int i=mProviderMap.size()-1; i>=0; i--) {
//【1.2】移除该进程持有的 provider 的 ProviderClientRecord 客户端对象!
ProviderClientRecord pr = mProviderMap.valueAt(i);
if (pr != null && pr.mProvider.asBinder() == provider) {
Slog.i(TAG, "Removing dead content provider:" + pr.mProvider.toString());
mProviderMap.removeAt(i);
}
}
if (fromClient) {
try {
//【×7.4】通知 ams,客户端进程移除了该 provider 相关的引用计数和客户端实例!
ActivityManagerNative.getDefault().unstableProviderDied(
prc.holder.connection);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
}
}
这里就不多说了!
5 ActivityManagerService - 系统进程1
当我们拉起了 Content provider 所在的进程,并且执行了一些初始化的操作后,就需要将创建的 provider 注册到系统进程中进行管理!
5.1 getContentProvider[Impl]
下面我们来看 ActivityManagerService 中的 getContentProvider 方法:
1 |
|
继续来看,getContentProviderImpl 方法的逻辑很长,
1 | private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, |
在 ams 中有如下的集合:
1 | //【1】用于保存正在启动的 provider! |
5.1.1 Provider 正在运行的情况
5.1.1.1 isSingleton
判断该 provider 时候是否是单例模式!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
36boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
String className, int flags) {
boolean result = false;
if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
//【1】如果 provider 所属应用的 uid 大于等于 FIRST_APPLICATION_UID,那么其必须要设置 FLAG_SINGLE_USER
// 标志位,同时也要被授予 INTERACT_ACROSS_USERS 权限才行!
if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
INTERACT_ACROSS_USERS,
aInfo.uid) != PackageManager.PERMISSION_GRANTED) {
ComponentName comp = new ComponentName(aInfo.packageName, className);
String msg = "Permission Denial: Component " + comp.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
+ INTERACT_ACROSS_USERS;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
result = true;
}
} else if ("system".equals(componentProcessName)) {
//【2】如果 1 满足,那么 provider 所在进程必须是 system 进程!
result = true;
} else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
//【3】如果 1 和 2 都不满足,那么必须是 Phone app 或者 persistent apps,才能提供单例 provider!
result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
|| (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
}
if (DEBUG_MU) Slog.v(TAG_MU,
"isSingleton(" + componentProcessName + ", " + aInfo + ", " + className + ", 0x"
+ Integer.toHexString(flags) + ") = " + result);
return result;
}
属性:
android:singleUser,取值为 true 或者 false,如果为 true,那么该 privider 将会是一个单例组件,系统中将有且只会存在一个单例组件运行在所有的设备用户下!
判断一个 provider 是否是单例模式,要满足一下条件之一:
- 如果 provider 所属 appId 大于等于 FIRST_APPLICATION_UID,并且其 flags 设置了 FLAG_SINGLE_USER 位,同时其被授予了 INTERACT_ACROSS_USERS 权限;
- 如果条件 1 不满足,那么如果 provider 所属进程是 system 进程,那么其就是单例的!
- 条件 1,2 都不满足,如果 provider 所属进程不是系统进程,同时其设置了 FLAG_SINGLE_USER 位,那么其所属应必须用是 phone app 或者是 persistent app,那么才是单例的!
逻辑很简单,不多说了!
5.1.1.2 isValidSingletonCall
用于判断调用单例 provider 的操作是否有效:
1 | boolean isValidSingletonCall(int callingUid, int componentUid) { |
判断是否可以访问单例 provider,至少要满足以下的条件之一:
- 单例的 provider 组件和调用者是同一个 app;
- 单例的 provider 是 system uid 或者 phone uid;
- 单例的 provider 所属应用有 INTERACT_ACROSS_USERS_FULL 的权限!
不多说了!
5.1.1.3 checkContentProviderPermissionLocked
1 | private final String checkContentProviderPermissionLocked( |
5.1.1.4 ContentProviderRecord.canRunHere
判断该 provider 是否可以在指定的进程中运行:1
2
3
4
5
6public boolean canRunHere(ProcessRecord app) {
//【1】provider 设置了 multiprocess 属性,或者 provider 的进程是该进程
// 并且该 provider 所属 userId 和该进程所属应用程序的 userId 一样(相同用户下)!
return (info.multiprocess || info.processName.equals(app.processName))
&& uid == app.info.uid;
}
不多说了!
5.1.1.5 ContentProviderRecord.newHolder
根据系统中已经 publish 的 provider,创建一个 ContentProviderHolder 对象!
1 | public ContentProviderHolder newHolder(ContentProviderConnection conn) { |
关于 ContentProviderHolder,我们后面会分析!
5.1.1.6 incProviderCountLocked
增加 provider 的引用计数,参数 r 是访问 provider 的进程:
1 | ContentProviderConnection incProviderCountLocked(ProcessRecord r, |
不多说了!
5.1.1.6.1 new ContentProviderConnection
创建连接对象,本质上是一个 Binder 对象:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public final class ContentProviderConnection extends Binder {
public final ContentProviderRecord provider; // provider 对象;
public final ProcessRecord client; // 连接到该 provider 的进程;
public final long createTime;
public int stableCount; // stable provider 的引用计数;
public int unstableCount; // unstable provider 的引用计数;
public boolean waiting; // 是否正在等待 provider publish,被锁保护!
public boolean dead; // provider 是否死亡!
public int numStableIncs; // 用于调试!
public int numUnstableIncs;
public ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client) {
provider = _provider;
client = _client;
createTime = SystemClock.elapsedRealtime();
}
... ... ...
}
数据结构都很简答,不多说了!!
5.1.1.7 decProviderCountLocked
减少 provider 的引用计数,参数 conn 是该 provider 的连接对象:
1 | boolean decProviderCountLocked(ContentProviderConnection conn, |
不多说了!
5.1.2 Provider 没在运行的情况
5.1.2.1 ProviderMap
在 ams 有一个这样的数据结构:
1 | ProviderMap mProviderMap = new ProviderMap(this); |
用来记录系统中所有 publish 的 provider:
1 | public final class ProviderMap { |
这里就不多说了!
同时也提供了如下的 get set 接口:
5.1.2.2.1 ProviderMap.get
5.1.2.2 new ContentProviderRecord
创建一个 ContentProviderRecord 实例,用于在系统进程中描述一个 provider!
1 | final class ContentProviderRecord { |
继续分析!
5.1.3 ActivityManagerProxy.getContentProvider
对于 getContentProvider,我们再去看下 ActivityManagerProxy 中是如何调用的:
1 | public ContentProviderHolder getContentProvider(IApplicationThread caller, |
getContentProvider 会返回一个 ContentProviderHolder 实例,ContentProviderHolder 看源码,实现了 Parcelable 接口,可以序列化!
5.1.3.1 ContentProviderHolder.CREATOR.createFromParcel
我们来看下 ContentProviderHolder.CREATOR 的 createFromParcel 方法:
1 | public static final Parcelable.Creator<ContentProviderHolder> CREATOR |
5.1.3.2 new ContentProviderHolder[Parcel]
这里通过 ContentProviderHolder 另外一个构造器创建了访问者进程中的 ContentProviderHolder 实例!
1 | private ContentProviderHolder(Parcel source) { |
我们知道在 provider 的宿主进程里,这里的 provider 是 Transport 实例!!
但是在访问者进程中,这里的 provider 是一个 ContentProviderProxy 实例,也就是 Transport 的客户端代理对象!
这样访问者进程就可以通过 ContentProviderProxy -> Transport 来跨进程通信啦!!
6 ActivityThread
6.1 provider 未启动但是其进程已经启动
6.1.1 scheduleInstallProvider
发送了 INSTALL_PROVIDER 消息:1
2
3
4
5
public void scheduleInstallProvider(ProviderInfo provider) {
//【1】发送了 INSTALL_PROVIDER 消息!
sendMessage(H.INSTALL_PROVIDER, provider);
}
6.1.2 H.handleMessage[INSTALL_PROVIDER]
1 | case INSTALL_PROVIDER: |
6.1.3 handleInstallProvider
1 | public void handleInstallProvider(ProviderInfo info) { |
这里就不多说了!!
6.2 provider 未启动同时其进程也未启动
6.2.1 AMS.attachApplicationLocked
startProcessLocked 方法,先会调用 attachApplicationLocked 方法,这里省略掉了和 ContentProvider 无关的逻辑和代码:
attachApplicationLocked 我们在进程的启动中有分析过!
1 | private final boolean attachApplicationLocked(IApplicationThread thread, |
6.2.1.1 generateApplicationProvidersLocked
收集该进程中需要启动的 provider!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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
//【1】获得该进程中所有 provider!
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
| MATCH_DEBUG_TRIAGED_MISSING)
.getList();
} catch (RemoteException ex) {
}
if (DEBUG_MU) Slog.v(TAG_MU,
"generateApplicationProvidersLocked, app.info.uid = " + app.uid);
int userId = app.userId;
//【2】遍历获得的所有的 provider!
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
//【×5.1.1.1】判断 provider 是否是单例模式的!
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
//【2.1】如果 provider 是单例模式,那么他们只能在默认用户下的进程中运行,如果
// 进程的所属用户不是默认用户,那就不能运行!
if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
//【2.1.1】将该 provider 从集合中移除!
providers.remove(i);
N--;
i--;
continue;
}
//【2.3】创建 provider 对应的组件对象,并创建 provider 对应的 ContentProviderRecord 实例
// 将其添加到 mProviderMap 和 mProviderMap 中!
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
if (DEBUG_MU) Slog.v(TAG_MU,
"generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
//【2.4】将该 provdier 添加到所属进程的 app.pubProviders 集合中!
app.pubProviders.put(cpi.name, cpr);
//【2.5】如果 provider 不是 multiprocess;
// 或者 provider 是 multiprocess 同时其宿主进程名不是 android,我们会将其所属包名加入到该进程中!
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
// 如果是平台组件的话,那么是不会加入的,因为其属于框架层!
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
mProcessStats);
}
notifyPackageUse(cpi.applicationInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
}
}
//【2】返回要启动的 provider!
return providers;
}
这里就不多说了!!
6.2.1.2 checkAppInLaunchingProvidersLocked
判断是否有 content provider 等待该进程的启动!
1 | boolean checkAppInLaunchingProvidersLocked(ProcessRecord app) { |
6.2.2 handleBindApplication
startProcessLocked 方法,最后会调用 handleBindApplication 方法,这里省略掉了和 ContentProvider 无关的逻辑和代码:
handleBindApplication 我们在进程的启动中有分析过!
1 | private void handleBindApplication(AppBindData data) { |
6.3 installContentProviders - 安装 provider
安装 contentprovider: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
35private void installContentProviders(
Context context, List<ProviderInfo> providers) {
//【1】该进程中的所有 provider!
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());
}
//【×6.4】封装 provider!
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
//【2】设置 ContentProviderHolder 的 noReleaseNeeded 属性
// 同时将其添加到 results 集合中!
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
//【×7.1】将 provider 注册到 ams 中!
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
这里我们要注意下参数:
- Context context:进程的上下文环境!
- IActivityManager.ContentProviderHolder holder:null
- ProviderInfo info:provider 的信息对象;
- boolean noisy:false
- boolean noReleaseNeeded:true
- boolean stable:true
6.4 installProvider
封装 provider,返回对应的 ContentProviderHolder 实例,注意,这里由于 provider 的进程刚启动,所以 installProvider 的
IActivityManager.ContentProviderHolder holder 参数为 null!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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
//【1】如果 if 条件满足,说明进程要创建自己的本地 provider 实例!!
if (holder == null || holder.provider == null) {
if (DEBUG_PROVIDER || noisy) {
Slog.d(TAG, "Loading provider " + info.authority + ": "
+ info.name);
}
//【1.1】获取 Context 上下文环境!
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
}
}
if (c == null) {
Slog.w(TAG, "Unable to get context for package " +
ai.packageName +
" while loading content provider " +
info.name);
return null;
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
//【×6.4.1】第一次创建时,会通过反射,创建 ContentProvider 对象!
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
//【×6.4.2】获得内部的 IContentProvider 对象,用于 Binder 通信;
// 返回的是其内部的一个 Transport 实例!
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);
//【*6.4.3】设置 Context,解析保存 providerInfo 中的信息!
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if (!mInstrumentation.onException(null, e)) {
throw new RuntimeException(
"Unable to get provider " + info.name
+ ": " + e.toString(), e);
}
return null;
}
} else {
//【1.2】如果 if 条件不满足,说明进程不需要创建本地 provider 而是需要获得远程的 provider 连接对象!
// holder.provider 就是 6.4.2.1 的 Transport 实例,后面我们再看!!
provider = holder.provider;
if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
//【2】获得 provider 的 Transport 对象!
IBinder jBinder = provider.asBinder();
//【3】如果进程需要创建自己的 local provider(比如 multi process 情况下),
// 那么此时 localProvider 不为 null!
if (localProvider != null) {
//【3.1】创建对应的 ComponentName!
ComponentName cname = new ComponentName(info.packageName, info.name);
//【3.2】判断当前进程中是否已经有该 provider 对应的 ProviderClientRecord,当然,
// 如果是第一次创建,是不会有的;
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
//【3.2.1】获得其 Transport 实例
provider = pr.mProvider;
} else {
//【*6.4.4】如果本地还未创建,那就创建 ContentProviderHolder 对象!
// 并设置 holder.provider!!
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
//【*6.4.5】处理 authority 返回一个 ProviderClientRecord 对象!
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
//【3.3】将应用关系保存到进程内部的指定集合中!
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
//【2.4】将创建的 Holder 保存到 retHolder 中;
retHolder = pr.mHolder;
} else {
//【4】如果进程不需要创建自己的 local provider,而是需要访问远程的 provider,
// 那么我们需要和远程的 provider,建立引用关系!
//【4.1】尝试根据 provider 的 Transport 对象,获得其对应的引用计数对象!
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//【2.5.1】如果引用计数对象存在,那就增加引用计数!
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
if (!noReleaseNeeded) { // 如果需要 release 的话,我们会增加引用,同时释放掉旧的引用;
//【1.3.6】增加引用计数!
incProviderRefLocked(prc, stable);
try {
//【×2.2】释放旧的引用!
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
}
}
} else {
//【2.5.2】如果引用计数对象为 null,那就会创建引用计数对象,这里会分为稳定引用和不稳定引用!
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
//【2.3.7】创建引用计数对象!
if (noReleaseNeeded) { // 如果这个引用无需释放,那么会设置为 1000!
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
// 将 Transport 和引用计数对象的映射关系保存到 mProviderRefCountMap 中!
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
//【3】返回创建的 Holder!
return retHolder;
}
在 ActivityThread 中有如下和 provider 相关的集合:
1 | //【1】用于保存 Transport 和对其他进程中的 provider 的引用计数 ProviderRefCount 的映射关系! |
6.4.1 new ContentProvider
创建 ContentProvider 实例,表示该进程中的 provider!
1 | public abstract class ContentProvider implements ComponentCallbacks2 { |
这里不多说!
6.4.2 ContentProvider.getIContentProvider
返回内部的一个 Transport 实例,该实例实现了 IContentProvider 接口!
1 | public IContentProvider getIContentProvider() { |
6.4.2.1 new Transport
1 | class Transport extends ContentProviderNative { |
Transport 继承了 ContentProviderNative,其本质上是一个 Binder 对象,用于跨进程通信,作为 Binder 通信的服务端:
1 | abstract public class ContentProviderNative extends Binder implements IContentProvider { |
继续来看!!
6.4.3 ContentProvider.attachInfo[2]->[3]
attachInfo 方法的作用是,解析 provider 的属性!
1 | public void attachInfo(Context context, ProviderInfo info) { |
继续分析: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
26private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
if (mContext == null) {
//【1】将当前进程的 Context 保存到 mContext 中!
mContext = context;
if (context != null) {
//【2】初始化内部 Transport 的 appOps 属性!
mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
}
//【3】初始化 uid
mMyUid = Process.myUid();
if (info != null) {
//【*6.4.3.1】解析 provider 的属性!
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
//【*6.4.3.2】拉起 provider 的 onCreate 方法!
ContentProvider.this.onCreate();
}
}
6.4.3.1 parse attribute
- 读/写权限
1
2
3
4protected final void setReadPermission(@Nullable String permission) {
//【1】读权限;
mReadPermission = permission;
}
1 | protected final void setWritePermission(@Nullable String permission) { |
Path 权限
1
2
3
4protected final void setPathPermissions(@Nullable PathPermission[] permissions) {
//【1】path 权限;
mPathPermissions = permissions;
}authority 权限
1
2
3
4
5
6
7
8
9
10
11protected final void setAuthorities(String authorities) {
if (authorities != null) {
if (authorities.indexOf(';') == -1) {
mAuthority = authorities;
mAuthorities = null;
} else {
mAuthority = null;
mAuthorities = authorities.split(";");
}
}
}
不多说了!
6.4.3.2 ContentProvider.onCreate - 生命周期方法 onCreate
拉起 provider 的 onCreate 方法:
1 | public abstract boolean onCreate(); |
当然,这个方法是抽象方法,因为我们 ContentProvider 这个类本身就是抽喜类,我们要实现自己的 provider 实例!!
6.4.4 new ContentProviderHolder
创建 ContentProviderHolder 对象!!
1 | public static class ContentProviderHolder implements Parcelable { |
看到了 ContentProviderHolder 是实现了 Parcelable 接口,可以跨进程传输!!
不多说,继续看:
6.4.5 installProviderAuthoritiesLocked
处理 provider 的 authority 属性,同时创建 ProviderClientRecord 对象并返回:
1 | private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, |
在 ActivityThread 中有一个 mProviderMap 哈希表:1
2
3//【1】保存该 authority 属性和其所属 provider 的 ProviderClientRecord 映射关系!
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
继续看!
6.4.5.1 new ProviderClientRecord
创建 ProviderClientRecord 实例!
1 | final class ProviderClientRecord { |
不多说!!
6.4.5.2 new ProviderKey
创建 authority 属性对应的 ProviderKey 实例!
1 | private static final class ProviderKey { |
不多说!
6.4.6 incProviderRefLocked
增加 provider 的引用计数, 参数 boolean stable 表示的是稳定引用,还是非稳定引用:
1 | private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) { |
可以看到,如果是第一次引用,那么会做一些额外的处理!
6.4.7 new ProviderRefCount
创建一个 provider 的引用计数对象:
1 | private static final class ProviderRefCount { |
先看到这里!
7 ActivityManagerService - 系统进程2
这里我们又从 provider 进程进入了系统进程!
7.1 publishContentProviders
publishContentProviders 用于将 provider publish 到系统中!
首先来看下 ActivityManagerNative 中的代码,
1 | case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: { |
接着,进入了 ActivityManagerService 中: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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
//【1】获得 provider 所在的进程 ProcessRecord!
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}
final long origId = Binder.clearCallingIdentity();
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;
}
//【2】我们知道 provider 对应的 ContentProviderRecord 在前面就已经添加到 r.pubProviders 中了!
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
//【2.1】将 ContentProviderRecord 实例添加到 ProviderMap 中!
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);
}
int launchingCount = mLaunchingProviders.size();
int j;
//【2.2】判断其是否在 mLaunchingProviders 中,如果有,那就从中移除!
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
//【2.3】移除 provider publish 超时消息!
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
//【2.4】更新 ContentProviderRecord 中的属性,包括 dst.provider 等等!
dst.provider = src.provider;
dst.proc = r;
//【important】这里调用了 Object.notifyAll 方法,唤醒在等待队列中等待的 Binder 线程
// 这里就回到了 5.1 getContentProvider[Impl] 方法中了!
dst.notifyAll();
}
// 更新进程的优先级!
updateOomAdjLocked(r);
// 更新进程的使用情况!
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
不多说了!
7.2 removeContentProvider
减少系统进程中的 provider 的引用计数!
1 | case REMOVE_CONTENT_PROVIDER_TRANSACTION: { |
继续来看: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
27public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
ContentProviderConnection conn;
try {
//【1】获得 ContentProviderConnection 连接对象!
conn = (ContentProviderConnection)connection;
} catch (ClassCastException e) {
String msg ="removeContentProvider: " + connection
+ " not a ContentProviderConnection";
Slog.w(TAG, msg);
throw new IllegalArgumentException(msg);
}
if (conn == null) {
throw new NullPointerException("connection is null");
}
//【×5.1.1.7】减少对 provider 的引用计数!
if (decProviderCountLocked(conn, null, null, stable)) {
updateOomAdjLocked(); // 调整进程优先级!
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这里就不多说了!
7.3 refContentProvider
增加系统进程中的 provider 的引用计数!
1 | public boolean refContentProvider(IBinder connection, int stable, int unstable) |
继续来看:
1 | public boolean refContentProvider(IBinder connection, int stable, int unstable) { |
不多说了!
7.4 unstableProviderDied
处理 unstable provider 进程的死亡后事:
1 | public void unstableProviderDied(IBinder connection) { |
不多说了!
8 总结
我们来看下 provider 相关的类图: