Android源码分析 - Framework层的ContentProvider全解析

开篇

本篇以android-11.0.0_r25作为基础解析

在四大组件中,可能我们平时用到最少的便是ContentProvider了,ContentProvider是用来帮助应用管理其自身和其他应用所存储数据的访问,并提供与其他应用共享数据的方法,使用ContentProvider可以安全的在应用之间共享和修改数据,比如说访问图库,通讯录等

在之前的文章中,我们提到了ContentProvider的启动时机,不妨顺水推舟,干脆把这一块分析个明白,本篇文章并不会教大家怎样使用ContentProvider,只将精力集中在ContentProvider在系统层面的启动与交互上

基础知识

ContentResolver

想要通过ContentProvider访问应用数据,我们通常需要借助ContentResolver的API,我们可以通过Context.getContentResolver方法获取其实例对象

ContentResolver是一个抽象类,它的抽象方法由ContextImpl.ApplicationContentResolver继承实现,我们实际上获取到的也是这个实例对象

Uri格式

ContentProvider的使用需要先获得提供者的Uri,它的格式如下:

  1. Scheme:固定为content://
  2. Authority:为提供者在AndroidManifest里设置的android:authorities属性
  3. 资源相对路径
  4. 资源ID

其中,资源相对路径和资源ID不是必须的,要看资源存储的数量及形式

举个栗子,外部存储中某张图片的Uri为:content://media/external/images/media/${id},其中media为Authority,/external/images/media为外部存储图片的相对路径,id为这张图片资源在数据库中存储的id

获取ContentProvider

ContentProvider作为共享数据的桥梁,最主要的几个功能无非是增、删、改、查,我们就以查作为入口来分析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
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
//ContentResolver.query
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
...

//尝试获取unstableProvider
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
...
try {
//调用远程对象query
qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
//尝试获取stableProvider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
//调用远程对象query
qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}

// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
...

// Wrap the cursor object into CursorWrapperInner object.
//将qCursor和provider包装成CursorWrapperInner对象返回
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
//释放资源
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}

我们可以将这个方法大致分成以下几个步骤:

  1. 获取unstableProvider远程对象
  2. 调用unstableProvider对象的query方法,获取qCursor
  3. 如果query过程中远程对象死亡,尝试获取stableProvider并调用query方法获取qCursor
  4. 获取stableProvider(如果之前没获取的话)
  5. qCursorstableProvider包装成CursorWrapperInner对象返回
  6. 释放资源

既然ContentProvider可以在应用之前共享数据,那它必然是支持跨进程的,没错,用的还是我们熟悉的Binder通信,IContentProvider对象即是给调用方进程使用的远程Binder对象,回顾这个方法我们发现,IContentProvider远程对象是通过acquireUnstableProvideracquireProvider获取的,我们接下来看看这两个方法做了什么

这里有一个关于unstablestable的概念,对于通过这两种方式获取的ContentProvider分别会有unstableCountstableCount两种引用计数,如果远程ContentProvider所在进程死亡,且其stableCount > 0的话,则会将其通过stable方式关联的调用方进程一同杀死,具体的流程我们会在后面分析

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

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

public final IContentProvider acquireUnstableProvider(String name) {
if (name == null) {
return null;
}
return acquireUnstableProvider(mContext, name);
}

public final IContentProvider acquireProvider(String name) {
if (name == null) {
return null;
}
return acquireProvider(mContext, name);
}

// ContextImpl.ApplicationContentResolver 内实现
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}

// ContextImpl.ApplicationContentResolver 内实现
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}

ActivityThread.acquireProvider

Android系统是通过Authority来区分不同的ContentProvider的,经过一些简单的判断处理后,最终调用了ActivityThread.acquireProvider方法去获取ContentProvider,而acquireUnstableProvideracquireProvider的区别只是最后一个布尔值入参不同罢了

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
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
//尝试从本地缓存中获取ContentProvider对象
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}

// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
ContentProviderHolder holder = null;
try {
synchronized (getGetProviderLock(auth, userId)) {
//使用AMS获取ContentProvider对象
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
...
return null;
}

// Install provider will increment the reference count for us, and break
// any ties in the race.
//安装ContentProvider
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}

这个方法大概做了以下几件事:

  1. 首先从缓存中尝试获取IContentProvider对象
  2. 使用AMS获取ContentProviderHolder对象
  3. 安装ContentProvider
  4. 返回IContentProvider对象

ActivityThread.acquireExistingProvider

我们首先看通过acquireExistingProvider方法尝试从缓存中获取IContentProvider对象

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
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
//从缓存Map中查找
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}

IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
//判断远端进程是否已被杀死
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
//清理ContentProvider
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}

// Only increment the ref count if we have one. If we don't then the
// provider is not reference counted and never needs to be released.
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//更新引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}

首先通过AuthorityuserId来从Map中查找是否已存在对应的ProviderClientRecord对象,然后从中取出IContentProvider对象,再检查其中的远程Binder对象是否已被杀死,最后一切无误,增加ContentProvider的引用计数

AMS.getContentProvider

如果这一步没有获取到,程序会继续从AMS获取ContentProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name, int userId,
boolean stable) {
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
final int callingUid = Binder.getCallingUid();
if (callingPackage != null && mAppOpsService.checkPackage(callingUid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
throw new SecurityException("Given calling package " + callingPackage
+ " does not match caller's uid " + callingUid);
}
return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
null, stable, userId);
}

经过一些检查后调用getContentProviderImpl方法,这个方法有点长,我们分段来看

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
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;

synchronized(this) {
//获取调用方所在进程记录
ProcessRecord r = null;
if (caller != null) {
r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
}
}

boolean checkCrossUser = true;

// First check if this content provider has been published...
//检查需要的ContentProvider是否已被发布
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
//如果没找到,尝试从系统用户中查找已发布的ContentProvider
//并确保它是可用的单例组件,条件如下:
//是用户级应用程序且组件设置了单例flag且拥有INTERACT_ACROSS_USERS权限 或 App运行在system进程中 或 组件设置了单例flag且是同一个App
if (cpr == null && userId != UserHandle.USER_SYSTEM) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r == null ? callingUid : r.uid,
cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}

//判断ContentProvider所在进程是否已死亡
ProcessRecord dyingProc = null;
if (cpr != null && cpr.proc != null) {
providerRunning = !cpr.proc.killed;

// Note if killedByAm is also set, this means the provider process has just been
// killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
// yet. So we need to call appDiedLocked() here and let it clean up.
// (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
// how to test this case.)
if (cpr.proc.killed && cpr.proc.killedByAm) {
Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
// Now we are going to wait for the death before starting the new process.
dyingProc = cpr.proc;
}
}
...
}
...
}

首先,第一部分,检查目标ContentProvider是否已被发布并记录在了mProviderMap中,注意这里的mProviderMapAMS中的一个成员变量,一系列Map的一个集合,和ActivityThread中的mProviderMap不是一个东西。如果在当前用户中找不到,且当前用户不是系统用户(UserHandle.USER_SYSTEM == 0),则尝试从系统用户中查找合法可用的单例ContentProvider,符合以下任一一个条件的ContentProvider即可被视作单例ContentProvider

  • App是用户级应用程序(uid >= 10000)且ContentProvider组件设置了单例flag(android:singleUser)且App拥有INTERACT_ACROSS_USERS权限
  • App运行在system进程中
  • ContentProvider组件设置了单例flag(android:singleUser)且是同一个App

至于为什么跨用户访问需要单例这个条件,这个和多用户相关,我也不是很清楚,以后如果分析到了多用户这块再回来补充。目前国内厂商的应用分身、手机分身功能大部分用的就是多用户技术

接着通过目标ContentProviderRecord是否存在和其所在进程是否还存活判断目标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
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
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;

synchronized(this) {
...
//ContentProvider正在运行中
if (providerRunning) {
cpi = cpr.info;

//如果此ContentProvider可以在调用者进程中直接运行(同一个App的同进程 或 同一个App且Provider组件支持多进程)
//直接返回一个新的ContentProviderHolder让调用者进程自己启动ContentProvider
if (r != null && cpr.canRunHere(r)) {
... //权限检查

// This provider has been published or is in the process
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
holder.provider = null;
return holder;
}

// Don't expose providers between normal apps and instant apps
try {
if (AppGlobals.getPackageManager()
.resolveContentProvider(name, 0 /*flags*/, userId) == null) {
return null;
}
} catch (RemoteException e) {
}

... //权限检查

final long origId = Binder.clearCallingIdentity();

// In this case the provider instance already exists, so we can
// return it right away.
//获取连接并更新引用计数
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null
&& r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
//更新进程优先级
mProcessList.updateLruProcessLocked(cpr.proc, false, null);
}
}

final int verifiedAdj = cpr.proc.verifiedAdj;
//更新进程adj
boolean success = updateOomAdjLocked(cpr.proc, true,
OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
// completely get rid of races with LMK killing the process, but should make
// them much smaller.
if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
success = false;
}
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
// the race is now smaller.
if (!success) {
// Uh oh... it looks like the provider's process
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
//ContentProvider所在进程被杀了,更新引用计数
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
//仍有别的地方对这个ContentProvider有引用,直接返回null(需要等待进程清理干净才能重启)
if (!lastRef) {
// This wasn't the last ref our process had on
// the provider... we will be killed during cleaning up, bail.
return null;
}
// We'll just start a new process to host the content provider
//将运行状态标为false,使得重新启动ContentProvider所在进程
providerRunning = false;
conn = null;
dyingProc = cpr.proc;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}

Binder.restoreCallingIdentity(origId);
}
...
}
...
}

第二部分,如果目标ContentProvider正在运行中,首先检查目标ContentProvider是否可以在调用者进程中直接运行,需要满足以下任一一个条件:

  • 调用者和目标ContentProvider是同一个App中的同进程
  • 调用者和目标ContentProvider属同一个App且ContentProvider组件支持多进程(android:multiprocess

在这种情况下,直接返回一个新的ContentProviderHolder让调用者进程自己处理获得ContentProvider即可,具体逻辑在ActivityThread.installProvider方法中,后面会分析

如果不满足这种情况,即调用方进程和目标ContentProvider不在一个进程中,需要跨进程调用,获取ContentProviderConnection连接并更新引用计数

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;

synchronized(this) {
...
//ContentProvider未在运行
if (!providerRunning) {
//通过PMS获取ContentProvider信息
try {
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
if (cpi == null) {
return null;
}
// If the provider is a singleton AND
// (it's a call within the same user || the provider is a
// privileged app)
// Then allow connecting to the singleton provider
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r == null ? callingUid : r.uid,
cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);

... //各项检查

ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
//通过Class(android:name属性)获取ContentProviderRecord
cpr = mProviderMap.getProviderByClass(comp, userId);
//此ContentProvider是第一次运行
boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();

... //权限处理

try {
//获取应用信息
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
if (ai == null) {
Slog.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
}
ai = getAppInfoForUser(ai, userId);
//新建ContentProvider记录
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
} finally {
Binder.restoreCallingIdentity(ident);
}
} else if (dyingProc == cpr.proc && dyingProc != null) {
// The old stable connection's client should be killed during proc cleaning up,
// so do not re-use the old ContentProviderRecord, otherwise the new clients
// could get killed unexpectedly.
//旧的ContentProvider进程在死亡过程中,不要复用旧的ContentProviderRecord,避免出现预期之外的问题
cpr = new ContentProviderRecord(cpr);
// This is sort of "firstClass"
firstClass = true;
}

//如果此ContentProvider可以在调用者进程中直接运行(同一个App的同进程 或 同一个App且Provider组件支持多进程)
//直接返回一个新的ContentProviderHolder让调用者进程自己启动ContentProvider
if (r != null && cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr.newHolder(null);
}

// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
//查找正在启动中的ContentProvider
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}

// If the provider is not already being launched, then get it
// started.
//目标ContentProvider不在启动中
if (i >= N) {
final long origId = Binder.clearCallingIdentity();

try {
// Content provider is now in use, its package can't be stopped.
//将App状态置为unstopped,设置休眠状态为false
try {
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ cpr.appInfo.packageName + ": " + e);
}

// Use existing process if already started
//获取目标ContentProvider所在进程记录
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) { //进程存活
if (!proc.pubProviders.containsKey(cpi.name)) {
//将ContentProviderRecord保存到进程已发布ContentProvider列表中
proc.pubProviders.put(cpi.name, cpr);
try {
//调度ActivityThread直接安装ContentProvider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else { //进程死亡
//启动App(App启动过程中会自动启动ContentProvider)
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0,
new HostingRecord("content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name)),
ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
if (proc == null) {
...
return null;
}
}
cpr.launchingApp = proc;
//将目标ContentProvider添加到启动中列表
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}

// Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}

mProviderMap.putProviderByName(name, cpr);
//获取连接并更新引用计数
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
stable);
if (conn != null) {
conn.waiting = true;
}
}

grantImplicitAccess(userId, null /*intent*/, callingUid,
UserHandle.getAppId(cpi.applicationInfo.uid));
}
...
}

第三部分,如果目标ContentProvider未在运行,先通过PMS获取ContentProvider信息,接着尝试通过Class(android:name属性)获取ContentProviderRecord,如果获取不到,说明这个ContentProvider是第一次运行(开机后),这种情况下需要新建ContentProviderRecord,如果获取到了,但是其所在进程被标记为正在死亡,此时同样需要新建ContentProviderRecord,不要复用旧的ContentProviderRecord,避免出现预期之外的问题

接下来同样检查目标ContentProvider是否可以在调用者进程中直接运行,如果可以直接返回一个新的ContentProviderHolder让调用者进程自己启动获取ContentProvider

接着检查正在启动中的ContentProvider列表,如果不在列表中,我们可能需要手动启动它,此时又有两种情况:

  1. ContentProvider所在进程已启动:如果进程已发布ContentProvider列表中不包含这个ContentProviderRecord,则将其添加到列表中,然后调用目标进程中的ApplicationThread.scheduleInstallProvider方法安装启动ContentProvider
  2. ContentProvider所在进程未启动:启动目标进程,目标进程启动过程中会自动安装启动ContentProviderActivityThread.handleBindApplication方法中)

最后更新mProviderMap,获取ContentProviderConnection连接并更新引用计数

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
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;

// Wait for the provider to be published...
final long timeout =
SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
while (cpr.provider == null) {
//ContentProvider启动过程中进程死亡,返回null
if (cpr.launchingApp == null) {
...
return null;
}
try {
//计算最大等待时间
final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (conn != null) {
conn.waiting = true;
}
//释放锁,等待ContentProvider启动完成
cpr.wait(wait);
//等待时间已过,ContentProvider还是没能启动完成并发布,超时
if (cpr.provider == null) {
timedOut = true;
break;
}
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
if (timedOut) {
... //超时处理
return null;
}

//返回新的ContentProviderHolder
return cpr.newHolder(conn);
}

第四部分,如果ContentProvider已存在,直接新建一个ContentProviderHolder返回,如果ContentProvider之前不存在,现在正在启动中,则以当前时间加上CONTENT_PROVIDER_READY_TIMEOUT_MILLIS推算出一个超时时间,给目标ContentProviderRecord上锁后,调用wait方法等待,直到ContentProvider成功发布后notify解除wait状态(在AMS.publishContentProviders方法中,之后会分析到),或一直等待直到超时。wait状态解除后,判断内部ContentProvider是否已被赋值,如果没有,则可以断定超时,此时返回null,如有,则返回一个新的ContentProviderHolder

ActivityThread.installProvider

由于这个方法同时包含了启动安装本地ContentProvider和获取安装远程ContentProvider的逻辑,所以放到后面启动ContentProvider章节里一起分析

启动ContentProvider

从前面的章节获取ContentProvider中,我们已经归纳出ContentProvider的启动分为两种情况,接着我们就来分析在这两种情况下,ContentProvider的启动路径

进程已启动

在进程已启动的情况下,如果进程已发布ContentProvider列表中不包含这个ContentProviderRecord,则将其添加到列表中,然后调用目标进程中的ApplicationThread.scheduleInstallProvider方法安装启动ContentProvider

ApplicationThread.scheduleInstallProvider会通过Hander发送一条what值为H.INSTALL_PROVIDER的消息,我们根据这个what值搜索,发现会走到ActivityThread.handleInstallProvider方法中,在这个方法内又会调用installContentProviders方法安装启动ContentProvider

进程未启动

在进程未启动的情况下,直接启动目标进程,在之前的文章 Android源码分析 - Activity启动流程(中) 里,我们分析了App的启动流程,其中有两个地方对启动ContentProvider至关重要

AMS.attachApplicationLocked

在这个方法中会调用generateApplicationProvidersLocked方法

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
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
//normalMode一般情况下均为true
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
...
}

private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
//通过PMS获取App中同一个进程内的所有的ContentProvider组件信息
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
| MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
} catch (RemoteException ex) {
}
int userId = app.userId;
if (providers != null) {
int N = providers.size();
//有必要的情况下进行Map扩容
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
// TODO: keep logic in sync with installEncryptionUnawareProviders
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
//对于单例ContentProvider,需要在默认用户中启动,如果不是默认用户的话则直接将其丢弃掉,不启动
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
// This is a singleton provider, but a user besides the
// default user is asking to initialize a process it runs
// in... well, no, it doesn't actually run in this process,
// it runs in the process of the default user. Get rid of it.
providers.remove(i);
N--;
i--;
continue;
}

ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
//新建ContentProviderRecord并将其加入到缓存中
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
//将ContentProviderRecord保存到进程已发布ContentProvider列表中
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
//将App添加至进程中运行的包列表中
app.addPackage(cpi.applicationInfo.packageName,
cpi.applicationInfo.longVersionCode, mProcessStats);
}
notifyPackageUse(cpi.applicationInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
}
}
return providers;
}

这个方法主要是获取需要启动的ContentProviderContentProviderRecord,如果是第一次启动这个ContentProvider则需要新建一个ContentProviderRecord并将其存入缓存,然后将其保存到进程已发布ContentProvider列表中,以供后面使用。同时这个方法返回了需要启动的ProviderInfo列表,AMS.attachApplicationLocked方法可以根据这个列表判断是否有需要启动的ContentProvider并设置ContentProvider启动超时检测

ActivityThread.handleBindApplication

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
private void handleBindApplication(AppBindData data) {
...
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
//创建Application
app = data.info.makeApplication(data.restrictedBackupMode, null);

...

mInitialApplication = app;

// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
//在非受限模式下启动ContentProvider
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}

...

//执行Application的onCreate方法
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
} finally {
// If the app targets < O-MR1, or doesn't change the thread policy
// during startup, clobber the policy to maintain behavior of b/36951662
if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
StrictMode.setThreadPolicy(savedPolicy);
}
}
...
}

可以看到,在这个方法中直接调用了installContentProviders方法安装启动ContentProvider

另外提一点,为什么我要把Application的创建和onCreate也放进来呢?现在市面上有很多库,包括很多教程告诉我们,可以通过注册ContentProvider的方式初始化SDK,获取全局Context,比如说著名的内存泄漏检测工具LeakCanary的新版本,想要使用它,直接添加它的依赖就行了,不需要对代码做哪怕一点的改动,究其原理,就是因为ContentProvider的启动时机是在Application创建后,Application.onCreate调用前,并且ContentProvider内的Context成员变量大概率就是Application,大家以后在开发过程中也可以妙用这一点

ActivityThread.installContentProviders

好了,现在这两种情况最终都走到了ActivityThread.installContentProviders方法中,那我们接下来就好好分析ContentProvider实际的启动安装流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();

for (ProviderInfo cpi : providers) {
//逐个启动
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}

try {
//发布ContentProvider
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}

这个方法很简单,便利所有待启动的ContentProvider信息列表,逐个启动安装ContentProvider,最后一起发布

ActivityThread.installProvider

我们先看installProvider方法,我们在上一章中分析到,获取ContentProvider的时候也会调用这个方法,这次我们就结合起来一起分析

通过上文的代码,我们发现,有两处地方会调用installProvider方法,方法的入参有三种形式,分别为:

  • holder不为nullinfo不为nullholder.providernull:在ActivityThread.acquireProvider方法中被调用,路径为 没有获取到已存在的ContentProvider -> AMS.getContentProvider -> AMS.getContentProviderImpl -> 发现目标ContentProvider可以在调用者进程中直接运行 -> 直接返回一个新的ContentProviderHolder(包含ProviderInfo) -> ActivityThread.installProvider,在这种情况下installProvider方法会在本地启动安装ContentProvider

  • holdernullinfo不为null:在ActivityThread.installContentProviders方法中被调用,两条路径,一是App进程启动后自动执行,二是在AMS.getContentProvider方法中发现目标进程已启动但是ContentProvider未启动,调用ActivityThread.scheduleInstallProvider方法执行,在这种情况下installProvider方法会在本地启动安装ContentProvider

  • holder不为nullholder.provider不为null:在ActivityThread.acquireProvider方法中被调用,路径为 没有获取到已存在的ContentProvider -> AMS.getContentProvider -> AMS.getContentProviderImpl -> 获取到目标进程的远程ContentProvider引用 -> 包装成ContentProviderHolder返回 -> ActivityThread.installProvider,在这种情况下installProvider方法直接可以获取到远程ContentProvider引用,然后进行处理

我们将这三种情况分成两种case分别分析

本地启动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
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
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) { //启动本地ContentProvider
Context c = null;
ApplicationInfo ai = info.applicationInfo;
//首先获取Context,一般情况下就是Application
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) {
// Ignore
}
}
if (c == null) {
return null;
}

//Split Apks动态加载相关
if (info.splitName != null) {
try {
c = c.createContextForSplit(info.splitName);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}

try {
final java.lang.ClassLoader cl = c.getClassLoader();
//获取应用信息
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
// System startup case.
packageInfo = getSystemContext().mPackageInfo;
}
//通过AppComponentFactory实例化ContentProvider
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
//Transport类,继承自ContentProviderNative(Binder服务端)
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
// XXX Need to create the correct context for this provider.
//初始化ContentProvider,调用其onCreate方法
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 { //获取外部ContentProvider
...
}

ContentProviderHolder retHolder;

synchronized (mProviderMap) {
//对于本地ContentProvider来说,这里的实际类型是Transport,继承自ContentProviderNative(Binder服务端)
IBinder jBinder = provider.asBinder();
if (localProvider != null) { //本地启动ContentProvider的情况
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
//如果已经存在相应的ContentProvider记录,使用其内部已存在的ContentProvider
provider = pr.mProvider;
} else {
//否则使用新创建的ContentProvider
holder = new ContentProviderHolder(info);
holder.provider = provider;
//对于本地ContentProvider来说,不存在释放引用这种情况
holder.noReleaseNeeded = true;
//创建ProviderClientRecord并将其保存到mProviderMap本地缓存中
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
//保存ProviderClientRecord到本地缓存中
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else { //获取远程ContentProvider的情况
...
}
}
return retHolder;
}

我们在这里找到了ContentProvider创建并启动的入口,首先通过传入的Context(实际上就是Application)判断并确定创建并给ContentProvider使用的的Context是什么(一般情况下也是Application),然后获取到应用信息LoadedApk,再通过它得到AppComponentFactory(前面的文章中介绍过,如果没有在AndroidManifest中设置android:appComponentFactory属性,使用的便是默认的AppComponentFactory),接着通过AppComponentFactory.instantiateProvider方法实例化ContentProvider对象

1
2
3
4
5
public @NonNull ContentProvider instantiateProvider(@NonNull ClassLoader cl,
@NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (ContentProvider) cl.loadClass(className).newInstance();
}

默认的话就是通过ClassName反射调用默认构造函数实例化ContentProvider对象,最后再调用ContentProvider.attachInfo方法初始化

1
2
3
4
5
6
7
8
9
10
11
12
public void attachInfo(Context context, ProviderInfo info) {
attachInfo(context, info, false);
}

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

详细内容我们就不分析了,只需要知道这里给mContext赋了值,然后调用了ContentProvider.onCreate方法就可以了

到了这一步,ContentProvider就算是启动完成了,接下来需要执行一些安装步骤,其实也就是对缓存等进行一些处理。在ContentProvider实例化后,会调用其getIContentProvider方法给provider变量赋值,这里获得的对象其实是一个Transport对象,继承自ContentProviderNative,是一个Binder服务端对象,在ContentProvider初始化后,会对Transport对象调用asBinder方法获得Binder对象,这里获得的其实还是自己本身,接着从缓存中尝试获取ProviderClientRecord对象,如果获取到了,说明已经存在了相应的ContentProvider,使用ProviderClientRecord内部的ContentProvider,刚刚新创建的那个就可以丢弃了,如果没获取到,就去新建ContentProviderHolder以及ProviderClientRecord,然后将他们添加到各种缓存中,至此,ContentProvider的安装过程也到此结束

获取处理远程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
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
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) { //启动本地ContentProvider
...
} else { //获取外部ContentProvider
//实际类型为ContentProviderProxy
provider = holder.provider;
}

ContentProviderHolder retHolder;

synchronized (mProviderMap) {
//对于外部ContentProvider来说,这里的实际类型是BinderProxy
IBinder jBinder = provider.asBinder();
if (localProvider != null) { //本地启动ContentProvider的情况
...
} else { //获取远程ContentProvider的情况
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) { //如果ContentProvider引用已存在
// We need to transfer our new reference to the existing
// ref count, releasing the old one... but only if
// release is needed (that is, it is not running in the
// system process).
//对于远程ContentProvider来说,如果目标App为system应用(UID为ROOT_UID或SYSTEM_UID)
//并且目标App不为设置(包名不为com.android.settings),则noReleaseNeeded为true
if (!noReleaseNeeded) {
//增加已存在的ContentProvider引用的引用计数
incProviderRefLocked(prc, stable);
try {
//释放传入的引用,移除ContentProviderConnection相关信息,更新引用计数
ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
//创建ProviderClientRecord并将其保存到mProviderMap本地缓存中
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) { //同上,目标App为system应用,不需要释放引用
//新建一个ProviderRefCount,但引用计数初始化为一个较大的数值
//这样后续无论调用方进程的ContentProvider引用计数如何变动都不会影响到AMS
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else { //需要释放引用的情况下
//正常的新建初始化一个ProviderRefCount
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
//保存至缓存
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}

对于holder.provider不为null的情况,直接获取远程ContentProvider引用,然后进行处理就可以了。这里获取到的IContentProvider的实际类型是ContentProviderProxy,然后对其调用asBinder方法,获取到的是BinderProxy对象,接着从缓存中尝试获取ProviderRefCount对象,如果缓存中已经有相应的引用对象了,则在需要释放引用(!noReleaseNeeded)的情况下使用原有的引用,释放参数传入进来的ContentProvider引用

这里noReleaseNeeded是在ContentProviderRecord构造时赋值的,为true的条件是目标App为system应用(UIDROOT_UIDSYSTEM_UID)并且目标App不为设置(包名不为com.android.settings

如果缓存中没有查找到相应的ProviderRefCount对象,新建ProviderClientRecordProviderRefCount对象,并将他们保存到缓存中,至于为什么在noReleaseNeeded的情况下,新建的ProviderRefCount的引用计数初始值为1000,我猜测是因为noReleaseNeeded代表了不需要释放引用,所以这里干脆设置一个比较大的值,这样无论调用方进程的ContentProvider引用计数怎样变动,都不会再调用到AMS的方法中去处理引用的变化,在非常早期的Android版本中(Android 4.0.1),这个值曾被设置为10000

至此,远程ContentProvider的安装也结束了

ActivityThread.installProviderAuthoritiesLocked

接下来我们再简单的看一下两种case都会走到的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并将其添加到mProviderMap缓存中,这里的操作对应着最前面的acquireExistingProvider方法,有了这个缓存,以后就可以直接拿,而不用再复杂的经过一系列的AMS跨进程操作了

AMS.publishContentProviders

ContentProvider全部启动安装完后,便要调用AMS.publishContentProviders将他们发布出去,供外部使用了

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
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}

synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
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;
}
//App进程启动时或AMS.getContentProvider中已经将相应ContentProviderRecord添加到了pubProviders中
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
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);
}

//ContentProvider已经启动完毕,将其从正在启动的ContentProvider列表中移除
int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
//移除ContentProvider启动超时监听
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
// Make sure the package is associated with the process.
// XXX We shouldn't need to do this, since we have added the package
// when we generated the providers in generateApplicationProvidersLocked().
// But for some reason in some cases we get here with the package no longer
// added... for now just patch it in to make things happy.
r.addPackage(dst.info.applicationInfo.packageName,
dst.info.applicationInfo.longVersionCode, mProcessStats);
synchronized (dst) {
dst.provider = src.provider;
dst.setProcess(r);
//让出锁,通知其他wait的地方
//对应着AMS.getContentProvider的第四部分:等待ContentProvider启动完成
dst.notifyAll();
}
dst.mRestartCount = 0;
updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}

Binder.restoreCallingIdentity(origId);
}
}

遍历整个待发布的ContentProvider列表,从ProcessRecord.pubProviders中查找相对应的ContentProviderRecord,我们在之前的章节中已经分析过了,App进程启动时或AMS.getContentProvider中已经将相应ContentProviderRecord添加到了pubProviders中,然后就是将其保存到各个缓存中,由于ContentProvider已经启动完毕,所以需要将其从正在启动的ContentProvider列表中移除,在ContentProvider正常启动的情况下,我们需要将ContentProvider的启动超时监听移除,最后,获取ContentProviderRecord同步锁,将准备好的ContentProvider赋值到ContentProviderRecord中,接着调用notifyAll方法通知其他调用过wait的地方,将锁让出,这里对应的就是AMS.getContentProvider的第四部分:等待ContentProvider启动完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
...
//这里的cpr和在publishContentProviders获得的dst是一个对象
synchronized (cpr) {
while (cpr.provider == null) {
...
//释放锁,等待ContentProvider启动完成
cpr.wait(wait);
...
}
}
...
}

这样,ContentProvider一发布,这里就会收到通知,解除wait状态,获得到ContentProvider,返回出去,是不是感觉一切都串起来了?

ContentProvider引用计数

ContentProvider的获取与启动分析完了,接下来我们聊聊它的引用计数,为下一小节分析ContentProvider死亡杀死调用方进程的过程做准备

ActivityThread层的引用计数是和AMS层的引用计数分开的,ActivityThread记录的是目标ContentProvider在本进程中有多少处正在使用,而AMS记录的是目标ContentProvider正在被多少个进程使用

ActivityThread层的引用计数

增加引用计数

我们先从ActivityThread层增加引用计数开始说起,在ActivityThread获取ContentProvider时,便会调用incProviderRefLocked方法来增加引用计数,具体的时机为acquireExistingProviderinstallProvider时,代码我就不重复放了,大家看前面几个小节就行(后同)

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
private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
if (stable) {
//增加ActivityThread的stable引用计数
prc.stableCount += 1;
//本进程对目标ContentProvider产生了stable引用关系
if (prc.stableCount == 1) {
// We are acquiring a new stable reference on the provider.
int unstableDelta;
//正在移除ContentProvider引用中(释放ContentProvider后发现stable和unstable引用计数均为0)
if (prc.removePending) {
// We have a pending remove operation, which is holding the
// last unstable reference. At this point we are converting
// that unstable reference to our new stable reference.
//当ActivityThread释放一个stable的ContentProvider时,如果释放完后,
//发现stable和unstable引用计数均为0,则会暂时保留一个unstable引用
//所以这里需要为 -1 ,将这个unstable引用移除
unstableDelta = -1;
// Cancel the removal of the provider.
prc.removePending = false;
// There is a race! It fails to remove the message, which
// will be handled in completeRemoveProvider().
//取消移除ContentProvider引用
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
//对于正常情况,只需要增加stable引用计数,不需要动unstable引用计数
unstableDelta = 0;
}
try {
//AMS层修改引用计数
ActivityManager.getService().refContentProvider(
prc.holder.connection, 1, unstableDelta);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
//增加ActivityThread的unstable引用计数
prc.unstableCount += 1;
//本进程对目标ContentProvider产生了unstable引用关系
if (prc.unstableCount == 1) {
// We are acquiring a new unstable reference on the provider.
//正在移除ContentProvider引用中(释放ContentProvider后发现stable和unstable引用计数均为0)
if (prc.removePending) {
// Oh look, we actually have a remove pending for the
// provider, which is still holding the last unstable
// reference. We just need to cancel that to take new
// ownership of the reference.
//取消移除ContentProvider引用
prc.removePending = false;
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
// First unstable ref, increment our count in the
// activity manager.
try {
//增加AMS层的unstable引用计数
ActivityManager.getService().refContentProvider(
prc.holder.connection, 0, 1);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
}
}
}

这里的逻辑需要配合着ContentProvider释放引用那里一起看才好理解,我先提前解释一下

首先,removePending这个变量表示此ContentProvider正在移除中,当ActivityThread减少引用计数,检查到stableunstable引用计数均为0后被赋值为true,并且会向Handler发送一条what值为REMOVE_PROVIDER的延时消息,在一定时间后便会触发ContentProvider移除操作,清理本地缓存,再将removePending重新置为false,所以当这里removePendingtrue则说明此ContentProvider还没完全被移除,我们把这个消息取消掉继续使用这个ContentProvider

对于stable引用的情况下,当ActivityThread减少引用计数,检查到stableunstable引用计数均为0后,会暂时保留一个unstable引用,等到后面真正触发到了移除ContentProvider的时候再将这个unstable引用移除,所以在增加引用计数的时候需要考虑到这一点,在这种情况下要将AMS层的unstable引用计数减一

对于其他的情况就是正常的增加ActivityThread层引用计数,然后调用AMS.refContentProvider方法操作AMS层的引用计数

减少引用计数

ContentProvider使用完后会调用ActivityThread.releaseProvider方法,以query方法为例,最后会调用releaseUnstableProviderreleaseProvider方法,最终都会走到这里来

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
public final boolean releaseProvider(IContentProvider provider, boolean stable) {
if (provider == null) {
return false;
}

IBinder jBinder = provider.asBinder();
synchronized (mProviderMap) {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc == null) {
// The provider has no ref count, no release is needed.
return false;
}

boolean lastRef = false;
if (stable) {
//引用计数已经为0,无法再减了
if (prc.stableCount == 0) {
return false;
}
//减少ActivityThread的stable引用计数
prc.stableCount -= 1;
if (prc.stableCount == 0) {
// What we do at this point depends on whether there are
// any unstable refs left: if there are, we just tell the
// activity manager to decrement its stable count; if there
// aren't, we need to enqueue this provider to be removed,
// and convert to holding a single unstable ref while
// doing so.
lastRef = prc.unstableCount == 0;
try {
//如果是最后的引用,则暂时保留一个unstable引用
ActivityManager.getService().refContentProvider(
prc.holder.connection, -1, lastRef ? 1 : 0);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
//引用计数已经为0,无法再减了
if (prc.unstableCount == 0) {
return false;
}
//减少ActivityThread的unstable引用计数
prc.unstableCount -= 1;
if (prc.unstableCount == 0) {
// If this is the last reference, we need to enqueue
// this provider to be removed instead of telling the
// activity manager to remove it at this point.
lastRef = prc.stableCount == 0;
//如果是最后的引用,则不进入到这里,暂时保留一个unstable引用
if (!lastRef) {
try {
//减少AMS引用计数
ActivityManager.getService().refContentProvider(
prc.holder.connection, 0, -1);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
}
}

if (lastRef) {
if (!prc.removePending) {
// Schedule the actual remove asynchronously, since we don't know the context
// this will be called in.
//表面此ContentProvider正在移除中
prc.removePending = true;
//发送延时消息,等待一定时间后移除ContentProvider
Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc);
mH.sendMessageDelayed(msg, CONTENT_PROVIDER_RETAIN_TIME);
} else {
Slog.w(TAG, "Duplicate remove pending of provider " + prc.holder.info.name);
}
}
return true;
}
}

可以看到,在减完引用计数后,如果发现是最后一个引用,即stableunstable引用计数均为0,此时无论是stable还是unstable都会让AMS暂时保留一个unstable引用,然后发送一条what值为REMOVE_PROVIDER的延时消息,等待一定时间后移除ContentProvider,当时间到了触发这条消息时,会调用到ActivityThread.completeRemoveProvider方法

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
final void completeRemoveProvider(ProviderRefCount prc) {
synchronized (mProviderMap) {
if (!prc.removePending) {
// There was a race! Some other client managed to acquire
// the provider before the removal was completed.
// Abort the removal. We will do it later.
return;
}

// More complicated race!! Some client managed to acquire the
// provider and release it before the removal was completed.
// Continue the removal, and abort the next remove message.
prc.removePending = false;

//移除缓存
final IBinder jBinder = prc.holder.provider.asBinder();
ProviderRefCount existingPrc = mProviderRefCountMap.get(jBinder);
if (existingPrc == prc) {
mProviderRefCountMap.remove(jBinder);
}

//移除缓存
for (int i=mProviderMap.size()-1; i>=0; i--) {
ProviderClientRecord pr = mProviderMap.valueAt(i);
IBinder myBinder = pr.mProvider.asBinder();
if (myBinder == jBinder) {
mProviderMap.removeAt(i);
}
}
}

try {
//处理AMS层引用计数
ActivityManager.getService().removeContentProvider(
prc.holder.connection, false);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}

这个方法将进程内所持有的ContentProvider相关缓存清除,然后调用AMS.removeContentProvider方法通知AMS移除ContentProvider,处理相应的引用计数。这里我们发现,调用AMS.removeContentProvider方法传入的最后一个参数stablefalse,因为我们之前在stableunstable引用计数均为0的情况下,保留了一个unstable引用,所以这时移除的ContentProvider引用也是unstable引用

AMS层的引用计数

接着我们来看AMS层的引用计数

AMS.refContentProvider

我们就先从我们刚刚分析的ActivityThread层的引用计数修改后续:refContentProvider 看起

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
public boolean refContentProvider(IBinder connection, int stable, int unstable) {
ContentProviderConnection conn;
...
conn = (ContentProviderConnection)connection;
...

synchronized (this) {
if (stable > 0) {
conn.numStableIncs += stable;
}
stable = conn.stableCount + stable;
if (stable < 0) {
throw new IllegalStateException("stableCount < 0: " + stable);
}

if (unstable > 0) {
conn.numUnstableIncs += unstable;
}
unstable = conn.unstableCount + unstable;
if (unstable < 0) {
throw new IllegalStateException("unstableCount < 0: " + unstable);
}

if ((stable+unstable) <= 0) {
throw new IllegalStateException("ref counts can't go to zero here: stable="
+ stable + " unstable=" + unstable);
}
conn.stableCount = stable;
conn.unstableCount = unstable;
return !conn.dead;
}
}

这个方法很简单,应该不需要再多做分析了吧?就是简单的修改ContentProviderConnection的引用计数值

AMS.incProviderCountLocked

接下来我们看AMS层引用计数的增加,AMS.incProviderCountLocked这个方法的触发时机是在AMS.getContentProviderImpl方法中

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
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
String callingPackage, String callingTag, boolean stable) {
if (r != null) {
for (int i=0; i<r.conProviders.size(); i++) {
ContentProviderConnection conn = r.conProviders.get(i);
//如果连接已存在,在其基础上增加引用计数
if (conn.provider == cpr) {
if (stable) {
conn.stableCount++;
conn.numStableIncs++;
} else {
conn.unstableCount++;
conn.numUnstableIncs++;
}
return conn;
}
}
//新建ContentProviderConnection连接
ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage);
//建立关联
conn.startAssociationIfNeeded();
if (stable) {
conn.stableCount = 1;
conn.numStableIncs = 1;
} else {
conn.unstableCount = 1;
conn.numUnstableIncs = 1;
}
//添加连接
cpr.connections.add(conn);
r.conProviders.add(conn);
//建立关联
startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
return null;
}

如果调用方进程已存在对应ContentProviderConnection连接,则在其基础上增加引用计数,否则新建连接,然后初始化引用计数值

AMS.decProviderCountLocked

然后是减少引用计数,之前在ActivityThread减引用到0后,会延时调用ActivityThread.completeRemoveProvider方法,在这个方法中会调用到AMS.removeContentProvider方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void removeContentProvider(IBinder connection, boolean stable) {
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
ContentProviderConnection conn = (ContentProviderConnection)connection;
...
//减少引用计数
if (decProviderCountLocked(conn, null, null, stable)) {
//更新进程优先级
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}

在这个方法中便会调用AMS.decProviderCountLocked减少引用计数,然后更新进程优先级

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
boolean decProviderCountLocked(ContentProviderConnection conn,
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (conn != null) {
cpr = conn.provider;
//减少引用计数值
if (stable) {
conn.stableCount--;
} else {
conn.unstableCount--;
}
if (conn.stableCount == 0 && conn.unstableCount == 0) {
//停止关联
conn.stopAssociation();
//移除连接
cpr.connections.remove(conn);
conn.client.conProviders.remove(conn);
if (conn.client.setProcState < PROCESS_STATE_LAST_ACTIVITY) {
// The client is more important than last activity -- note the time this
// is happening, so we keep the old provider process around a bit as last
// activity to avoid thrashing it.
if (cpr.proc != null) {
cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
}
}
//停止关联
stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
return true;
}
return false;
}
cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}

减少引用计数值,如果stableunstable引用计数均为0,则将这个连接移除

ContentProvider死亡杀死调用方进程的过程

我们前面提到过,ContentProvider所在进程死亡会将与其所有有stable关联的调用方进程杀死,这是怎么做到的呢?在之前的文章中,我们介绍过进程启动时,在调用AMS.attachApplicationLocked时会注册一个App进程死亡回调,我们就从进程死亡,触发死亡回调开始分析

1
2
3
4
5
6
7
8
9
10
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
//注册App进程死亡回调
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
...
}

注册了死亡回调后,如果对应binder进程死亡,便会回调IBinder.DeathRecipient.binderDied方法,我们来看一下AppDeathRecipient对这个方法的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;

AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
mApp = app;
mPid = pid;
mAppThread = thread;
}

@Override
public void binderDied() {
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true, null);
}
}
}

直接转手调用AMS.appDiedLocked方法,然后经过handleAppDiedLocked调用到cleanUpApplicationRecordLocked方法中

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
final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
...

boolean restart = false;

// Remove published content providers.
//清除已发布的ContentProvider
for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(i);
if (cpr.proc != app) {
// If the hosting process record isn't really us, bail out
continue;
}
final boolean alwaysRemove = app.bad || !allowRestart;
final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);
if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {
// We left the provider in the launching list, need to
// restart it.
restart = true;
}

cpr.provider = null;
cpr.setProcess(null);
}
app.pubProviders.clear();

// Take care of any launching providers waiting for this process.
//清除正在启动中的ContentProvider
if (cleanupAppInLaunchingProvidersLocked(app, false)) {
mProcessList.noteProcessDiedLocked(app);
restart = true;
}

// Unregister from connected content providers.
//清除已连接的ContentProvider
if (!app.conProviders.isEmpty()) {
for (int i = app.conProviders.size() - 1; i >= 0; i--) {
ContentProviderConnection conn = app.conProviders.get(i);
conn.provider.connections.remove(conn);
stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
conn.provider.appInfo.longVersionCode, conn.provider.name,
conn.provider.info.processName);
}
app.conProviders.clear();
}
...
}

可以看到,这个方法中遍历了ProcessRecord.pubProviders,逐个对发布的ContentProvider调用removeDyingProviderLocked方法执行移除操作

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
private final boolean removeDyingProviderLocked(ProcessRecord proc,
ContentProviderRecord cpr, boolean always) {
boolean inLaunching = mLaunchingProviders.contains(cpr);
if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
// It's being launched but we've reached maximum attempts, force the removal
always = true;
}

if (!inLaunching || always) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
}
final int userId = UserHandle.getUserId(cpr.uid);
// Don't remove from provider map if it doesn't match
// could be a new content provider is starting
//移除缓存
if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) {
mProviderMap.removeProviderByClass(cpr.name, userId);
}
String names[] = cpr.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
// Don't remove from provider map if it doesn't match
// could be a new content provider is starting
//移除缓存
if (mProviderMap.getProviderByName(names[j], userId) == cpr) {
mProviderMap.removeProviderByName(names[j], userId);
}
}
}

for (int i = cpr.connections.size() - 1; i >= 0; i--) {
ContentProviderConnection conn = cpr.connections.get(i);
if (conn.waiting) {
// If this connection is waiting for the provider, then we don't
// need to mess with its process unless we are always removing
// or for some reason the provider is not currently launching.
if (inLaunching && !always) {
continue;
}
}
ProcessRecord capp = conn.client;
conn.dead = true;
if (conn.stableCount > 0) {
if (!capp.isPersistent() && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
//当调用方与被杀死的目标ContentProvider进程间有stable连接
//并且调用方App进程非persistent进程并且非system_server进程中的情况下
//杀死调用方进程
capp.kill("depends on provider "
+ cpr.name.flattenToShortString()
+ " in dying proc " + (proc != null ? proc.processName : "??")
+ " (adj " + (proc != null ? proc.setAdj : "??") + ")",
ApplicationExitInfo.REASON_DEPENDENCY_DIED,
ApplicationExitInfo.SUBREASON_UNKNOWN,
true);
}
} else if (capp.thread != null && conn.provider.provider != null) {
try {
//通知调用方移除ContentProvider
capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
} catch (RemoteException e) {
}
// In the protocol here, we don't expect the client to correctly
// clean up this connection, we'll just remove it.
//移除连接
cpr.connections.remove(i);
if (conn.client.conProviders.remove(conn)) {
stopAssociationLocked(capp.uid, capp.processName, cpr.uid,
cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
}
}
}

if (inLaunching && always) {
mLaunchingProviders.remove(cpr);
cpr.mRestartCount = 0;
inLaunching = false;
}
return inLaunching;
}

可以看到,在这个方法中遍历了ContentProvider下的所有连接,当发现有其他进程与自己建立了stable连接(conn.stableCount > 0),且调用方进程不是persistent进程(常驻进程,只有拥有系统签名的App设置这个属性才生效),也不是运行在system_server进程,调用ProcessRecord.kill方法直接杀死进程,对于没有建立stable连接的调用方进程,调用IApplicationThread.unstableProviderDied方法通知调用方进程移除相应的ContentProvider

所以,使用ContentProvider是有一定风险的,大家要注意规避

总结

到这里,整个Framework层关于ContentProvider的内容应该都分析完了,希望大家看完后能获得一些收获,接下来的文章应该会去分析Service相关源码,敬请期待~