0%

Android-ContentProvider原理

概述

ContentProvider用于提供数据的统一访问格式,封装了底层的具体实现。对于数据的使用者来说,无需知晓数据的来源是数据库、本地文件或者网络等,使用者只需简单地使用ContentProvider提供的数据增删查改操作接口即可,基本使用可参考Android四大组件之ContentProvider

注:本文基于Android 10源码,为了文章的简洁性,引用源码的地方可能有所删减。

注:下面使用CR代表ContentResolver,CP代表ContentProvider,CPR代表ContentProviderRecord,AT代表ActivityThread,AMS代表ActivityManagerService。

ContextImpl.getContentResolver

1
2
3
4
5
6
7
8
9
10
11
12
class ContextImpl extends Context {
private final ApplicationContentResolver mContentResolver;

private ContextImpl(@NonNull ActivityThread mainThread/*...*/) {
mContentResolver = new ApplicationContentResolver(this, mainThread);
}

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

CR.insert/delete/query/update

CR.insert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, @Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
Uri createdRow = provider.insert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
return createdRow;
} catch (RemoteException e) {
return null;
} finally {
releaseProvider(provider);
}
}

通过调用acquireProvider()方法尝试获取provider,然后执行insert操作。

CR.delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where, @Nullable String[] selectionArgs) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
long durationMillis = SystemClock.uptimeMillis() - startTime;
return rowsDeleted;
} catch (RemoteException e) {
return -1;
} finally {
releaseProvider(provider);
}
}

通过调用acquireProvider()方法尝试获取provider,然后执行delete操作。

CR.query

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
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(uri, null, null, null, null);

public abstract class ContentResolver {
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder);
return query(uri, projection, queryArgs, cancellationSignal);
}

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
// 获取unstableProvider
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
try {
// 执行查询
qCursor = unstableProvider.query(mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 远程进程死亡,处理unstableProvider死亡过程
unstableProviderDied(unstableProvider);
// unstableProvider死亡后,再创建stable类型的provider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
// 再次执行查询操作
qCursor = stableProvider.query(mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}

// 强制执行查询操作,可能会失败并抛出RuntimeException异常
qCursor.getCount();
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider : acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
}

首先调用acquireUnstableProvider()方法尝试获取unstable的ContentProvider,然后执行query操作,如果query过程抛出DeadObjectException异常,即代表ContentProvider所在进程死亡,则通过acquireProvider()方法尝试获取stable的ContentProvider,然后接着执行query操作。

CR.update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public final int update(@RequiresPermission.Write @NonNull Uri uri, @Nullable ContentValues values,
@Nullable String where, @Nullable String[] selectionArgs) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
try {
long startTime = SystemClock.uptimeMillis();
int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
long durationMillis = SystemClock.uptimeMillis() - startTime;
return rowsUpdated;
} catch (RemoteException e) {
return -1;
} finally {
releaseProvider(provider);
}
}

通过调用acquireProvider()方法尝试获取provider,然后执行update操作。

CR.acquire(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
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;
}

protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
protected abstract IContentProvider acquireProvider(Context c, String name);

acquireProvider和acquireUnstableProvider都是抽象方法,具体看看ApplicationContentResolver中的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static final class ApplicationContentResolver extends ContentResolver {

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

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

可以看到不论是acquireUnstableProvider还是acquireProvider方法,最终都会调用ActivityThread的acquireProvider()方法。

AT.acquireProvider

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
// ActivityThread
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
// 成功获取到已存储的CP则直接返回
return provider;
}

// 这里可能会存在问题。当另一个线程同时尝试获取同一个provider时,保证第一个尝试获取的线程成功。
// 我们不能在获取和安装provider的时候持有锁,因为这个过程可能很长
// 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)) {
holder = ActivityManager.getService().getContentProvider(getApplicationThread(), auth, userId, stable);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
return null;
}
// 安装provider将会增加引用计数
holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}

该方法过程:

  • 首先通过acquireExistingProvider()方法尝试获取已存储的provider,获取成功则直接返回,否则继续执行;
  • 通过AMS.getContentProvider()方法来获取provider,当无法获取对应的provider则直接返回,否则继续执行;
  • 采用installProvider()安装provider,并该provider的增加引用计数。

AT.acquireExistingProvider

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
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();

public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
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()) {
// 当provider所在进程已经死亡则返回
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}

AMS.getContentProvider

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
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
throw new SecurityException(msg);
}
return getContentProviderImpl(caller, name, null, stable, userId);
}

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
// 获取调用者所在进程的ProcessRecord
ProcessRecord r = getRecordForAppLocked(caller);
// 从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, userId);
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;

// 目标provider进程已存在
if (providerRunning) {
// ...
}

// 目标provider进程不存在
if (!providerRunning) {
// ...
}
}

// 等待目标provider发布
synchronized (cpr) {
while (cpr.provider == null) {
// ...
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}

该方法是获取provider的核心代码,可以分成以下3部分:

  1. 目标provider进程已存在;
  2. 目标provider进程不存在;
  3. 循环等待provider发布完成。

该方法的name参数就是前面的auth,即provider标签里面的android:authorities值。

目标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
67
68
69
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
// 获取调用者所在进程的ProcessRecord
ProcessRecord r = getRecordForAppLocked(caller);
// 从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, userId);
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;

// 目标provider进程已存在
if (providerRunning) {
cpi = cpr.info;
String msg;
// 检查该ProcessRecord是否有权限访问给定的ProviderInfo
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) != null) {
throw new SecurityException(msg);
}
if (r != null && cpr.canRunHere(r)) {
// 当provider已经发布,且它允许运行在调用者进程,则直接返回
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs to make its own.
holder.provider = null;
return holder;
}
// 不要在常规app和instant app之间暴露provider
if (AppGlobals.getPackageManager().resolveContentProvider(name, 0 /*flags*/, userId) == null) {
return null;
}

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, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// 更新进程LRU队列
updateLruProcessLocked(cpr.proc, false, null);
}
}
final int verifiedAdj = cpr.proc.verifiedAdj;
// 更新进程adj
boolean success = updateOomAdjLocked(cpr.proc, true);
if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
success = false;
}
if (!success) {
// provider进程被杀,减少引用计数
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc);
if (!lastRef) {
// This wasn't the last ref our process had on the provider... we have now been killed, bail.
return null;
}
providerRunning = false;
conn = null;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
Binder.restoreCallingIdentity(origId);
}
// ...
}
// ...
return cpr != null ? cpr.newHolder(conn) : null;
}

目标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
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
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
// 获取调用者所在进程的ProcessRecord
ProcessRecord r = getRecordForAppLocked(caller);
// 从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, userId);
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;

// ...

// 目标provider不存在
if (!providerRunning) {
// 根据authority,获取ProviderInfo对象
cpi = AppGlobals.getPackageManager().resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
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.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
// 做一些检查
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) != null) {
throw new SecurityException(msg);
}
if (!mProcessesReady && !cpi.processName.equals("system")) {
throw new IllegalArgumentException("Attempt to launch content provider before system ready");
}
if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp() && "system".equals(cpi.processName)) {
throw new IllegalStateException("Cannot access system provider: '" + cpi.authority + "' before system providers are installed!");
}
// 当拥有该provider的用户并没有运行,则直接返回
if (!mUserController.isUserRunning(userId, 0)) {
return null;
}

ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
cpr = mProviderMap.getProviderByClass(comp, userId);
final 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) {
return null;
}
ai = getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
} finally {
Binder.restoreCallingIdentity(ident);
}
}

if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}

// 从mLaunchingProviders中查询是否存在该cpr
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// 当provider并没有处于mLaunchingProviders队列,则启动它
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
// Content provider is now in use, its package can't be stopped.
AppGlobals.getPackageManager().setPackageStoppedState(cpr.appInfo.packageName, false, userId);

// Use existing process if already started
ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
proc.thread.scheduleInstallProvider(cpi);
}
} else {
// 启动进程
proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false);
if (proc == null) {
return null;
}
}
cpr.launchingApp = proc;
// 将cpr添加到mLaunchingProviders
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}

if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
// 增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
// ...
return cpr != null ? cpr.newHolder(conn) : null;
}

当进程没有启动时,调用startProcessLocked方法启动目标provider进程,由Android-Application启动原理可知,AMS的attachApplicationLocked方法会调用IApplicationThread.bindApplication方法,即通过Binder的方式调用到目标进程的ActivityThread会执行handleBindApplication方法:

1
2
3
4
5
6
7
private void handleBindApplication(AppBindData data) {
// ...
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
// ...
}

当目标进程已经启动时,则调用proc.thread.scheduleInstallProvider方法通过Binder调用到目标进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleInstallProvider(ProviderInfo provider) {
sendMessage(H.INSTALL_PROVIDER, provider);
}
}

// ActivityThread
case INSTALL_PROVIDER:
handleInstallProvider((ProviderInfo) msg.obj);
break;

public void handleInstallProvider(ProviderInfo info) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
installContentProviders(mInitialApplication, Arrays.asList(info));
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}

可知无论目标进程启动与否,最终都会调用到installContentProviders方法。

等待目标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
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
// ...
// 等待目标provider发布
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
return null;
}
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}

CPR.newHolder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ContentProviderRecord.java
public ContentProviderHolder newHolder(ContentProviderConnection conn) {
ContentProviderHolder holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = noReleaseNeeded;
holder.connection = conn;
return holder;
}

public class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
}

CPR.canRunHere

1
2
3
4
5
// ContentProviderRecord.java
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& uid == app.info.uid;
}

该ContentProvider是否能运行在调用者所在进程需要满足以下条件:

  1. ContentProvider在AndroidManifest.xml文件配置multiprocess=true或调用者进程与ContentProvider在同一个进程
  2. ContentProvider进程跟调用者所在进程是同一个uid

AT.installContentProviders

该方法会先调用installProvider函数安装provider,然后通过Binder调用AMS的publishContentProviders方法来发布provider。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 {
ActivityManager.getService().publishContentProviders(getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}

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

enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException();
}

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;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
// 将该provider添加到mProviderMap
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
// 将该provider添加到mProviderMap
mProviderMap.putProviderByName(names[j], dst);
}

int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
// 将该provider移除mLaunchingProviders队列
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
if (wasInLaunchingProviders) {
// 移除provider发布超时的消息
// 该超时消息在AMS的attachApplicationLocked方法中发送
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
// 唤醒所有等待的Client端进程,通知发布完成
dst.notifyAll();
}
updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}

AT.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
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
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) {
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 {
c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE);
}
// 无法获取context则直接返回
if (c == null) {
return null;
}

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;
}
// 通过反射,创建目标ContentProvider对象
localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
// 回调目标ContentProvider.onCreate方法
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
return null;
}
} else {
provider = holder.provider;
}

ContentProviderHolder retHolder;

synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
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;
} else {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 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).
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
ActivityManager.getService().removeContentProvider(holder.connection, stable);
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable ? new ProviderRefCount(holder, client, 1, 0) : new ProviderRefCount(holder, client, 0, 1);
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}

CP.getIContentProvider

1
2
3
4
5
6
7
8
9
10
11
public abstract class ContentProvider implements ComponentCallbacks2 {
public IContentProvider getIContentProvider() {
return mTransport;
}

class Transport extends ContentProviderNative {
}
}

abstract public class ContentProviderNative extends Binder implements IContentProvider {
}

AMS.removeContentProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
ContentProviderConnection conn;
try {
conn = (ContentProviderConnection)connection;
} catch (ClassCastException e) {
throw new IllegalArgumentException(msg);
}
if (conn == null) {
throw new NullPointerException("connection is null");
}
if (decProviderCountLocked(conn, null, null, stable)) {
updateOomAdjLocked();
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}

AT.installProviderAuthoritiesLocked

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

if (provider != null) {
// If this provider is hosted by the core OS and cannot be upgraded, then I guess we're okay doing blocking calls to it.
for (String auth : auths) {
switch (auth) {
case ContactsContract.AUTHORITY:
case CallLog.AUTHORITY:
case CallLog.SHADOW_AUTHORITY:
case BlockedNumberContract.AUTHORITY:
case CalendarContract.AUTHORITY:
case Downloads.Impl.AUTHORITY:
case "telephony":
Binder.allowBlocking(provider.asBinder());
}
}
}

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

调用进程: insert/delete/query/update

在获取了ContentProvider后,调用进程(客户端)接着开始远程调用目标进程的ContentProvider(服务端)相对应的接口。由上面AMS的代码可知,服务端的Binder实例是Transport对象,Transport继承自ContentProviderNative:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract public class ContentProviderNative extends Binder implements IContentProvider {
public ContentProviderNative()
{
attachInterface(this, descriptor);
}

static public IContentProvider asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IContentProvider in = (IContentProvider)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ContentProviderProxy(obj);
}
}

因此客户端的Binder代理是ContentProviderProxy对象,调用进程调用增删查改方法时,会通过Binder远程调用到目标ContentProvider进程的onTransact方法。

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
final class ContentProviderProxy implements IContentProvider
{
public ContentProviderProxy(IBinder remote) {
mRemote = remote;
}

@Override
public IBinder asBinder() {
return mRemote;
}

@Override
public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);

data.writeString(callingPkg);
url.writeToParcel(data, 0);
values.writeToParcel(data, 0);

mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);

DatabaseUtils.readExceptionFromParcel(reply);
Uri out = Uri.CREATOR.createFromParcel(reply);
return out;
} finally {
data.recycle();
reply.recycle();
}
}

// 其它方法类似,都是通过mRemote来调用服务端接口
}

目标进程: insert/delete/query/update

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
abstract public class ContentProviderNative extends Binder implements IContentProvider {
@Override
public IBinder asBinder() {
return this;
}

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
// 处理参数
Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
adaptor = new CursorToBulkCursorAdaptor(cursor, observer, getProviderName());
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} finally {
// Close cursor if an exception was thrown while constructing the adaptor.
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
// 其它类似
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}

上面onTransact方法中都是调用的子类Transport中对应的方法:

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
class Transport extends ContentProviderNative {

@Override
public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
if (projection != null) {
return new MatrixCursor(projection, 0);
}
Cursor cursor = ContentProvider.this.query(uri, projection, queryArgs,
CancellationSignal.fromTransport(cancellationSignal));
if (cursor == null) {
return null;
}
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
final String original = setCallingPackage(callingPkg);
try {
// 回调自定义ContentProvider中的query方法
return ContentProvider.this.query(uri, projection, queryArgs, CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}

// 其它方法也是类似回调到自定义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
// ContentProvider与Client之间的连接对象,存于system_server进程的AMS中
public final class ContentProviderConnection extends Binder {
public final ContentProviderRecord provider; // ContentProvider进程
public final ProcessRecord client; // 客户端进程
public final long createTime; // 创建时间
public int stableCount; // stable引用次数
public int unstableCount; // unstable引用次数
public boolean waiting; // 该连接的client正在等待provider发布
public boolean dead; // 该连接的provider已处于死亡状态

// For debugging.
public int numStableIncs; // stable计数总的增加次数
public int numUnstableIncs; // unstable计数总的增加次数
}

// ActivityThread的内部类,该引用保存到Client端
private static final class ProviderRefCount {
public final ContentProviderHolder holder;
public final ProviderClientRecord client;
public int stableCount;
public int unstableCount;
// 当此选项为ture时,stable和unstable的引用计数为0,且将会执行一项待处理操作,以从activity manager中删除引用计数。
// 在activity manager上仍保留unstable引用,尽管它并不反映该引用数目。
public boolean removePending;
}

AMS.incProviderCountLocked

incProviderCountLocked方法运行在system_server进程,增加引用成功后,返回一个表示与客户端连接的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
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (r != null) {
for (int i=0; i<r.conProviders.size(); i++) {
// 从当前进程的provider中查询与目标provider一致的信息
ContentProviderConnection conn = r.conProviders.get(i);
if (conn.provider == cpr) {
if (stable) {
conn.stableCount++;
conn.numStableIncs++;
} else {
conn.unstableCount++;
conn.numUnstableIncs++;
}
return conn;
}
}
// 查询不到则新建provider连接对象
ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
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.curProcState, cpr.uid, cpr.name, cpr.info.processName);
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken);
return null;
}

AMS.decProviderCountLocked

decProviderCountLocked运行在system_server进程,引用减小成功后,当provider连接的stable和unstable引用次数都为0时移除该连接对象信息。

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
boolean decProviderCountLocked(ContentProviderConnection conn,
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (conn != null) {
cpr = conn.provider;
if (stable) {
conn.stableCount--;
} else {
conn.unstableCount--;
}
// 当provider连接的stable和unstable引用次数都为0时移除该连接对象信息
if (conn.stableCount == 0 && conn.unstableCount == 0) {
cpr.connections.remove(conn);
conn.client.conProviders.remove(conn);
if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
if (cpr.proc != null) {
cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
}
}
stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
return true;
}
return false;
}
cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}

AT.incProviderRefLocked

incProviderRefLocked运行在客户端。

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 final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
if (stable) {
prc.stableCount += 1;
if (prc.stableCount == 1) {
// We are acquiring a new stable reference on the provider.
int unstableDelta;
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.
unstableDelta = -1;
// Cancel the removal of the provider.
prc.removePending = false;
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
unstableDelta = 0;
}
ActivityManager.getService().refContentProvider(prc.holder.connection, 1, unstableDelta);
}
} else {
prc.unstableCount += 1;
if (prc.unstableCount == 1) {
// We are acquiring a new unstable reference on the provider.
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.
prc.removePending = false;
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
// First unstable ref, increment our count in the activity manager.
ActivityManager.getService().refContentProvider(prc.holder.connection, 0, 1);
}
}
}
}

removePending是指当前正在处于移除引用计数的过程,当removePending=true代表正处于移除最后引用的情况。而此时有需要增加引用计数,所以会抵消一次unstableCount加1的操作。

AT.releaseProvider

CR.releaseProvider跟CR.releaseUnstableProvider都会调用到AT.releaseProvider方法,releaseProvider运行在客户端,会减小引用计数。

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 boolean releaseProvider(IContentProvider provider, boolean stable) {
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) {
if (prc.stableCount == 0) {
return false; // 引用次数为0则直接返回
}
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;
ActivityManager.getService().refContentProvider(prc.holder.connection, -1, lastRef ? 1 : 0);
}
} else {
if (prc.unstableCount == 0) {
return false;
}
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;
if (!lastRef) {
ActivityManager.getService().refContentProvider(prc.holder.connection, 0, -1);
}
}
}

if (lastRef) {
// 当执行完该方法,引用技术变成0时,则发送REMOVE_PROVIDER消息
if (!prc.removePending) {
prc.removePending = true;
Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc);
mH.sendMessage(msg);
}
}
return true;
}
}

该方法先减小ProviderRefCount对象的引用,再通过Binder调用AMS.refContentProvider来减小ContentProviderConnection的引用。

主线程收到REMOVE_PROVIDER消息后会调用AT.completeRemoveProvider方法。

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

该方法修改了conn的stable和unstable引用次数并返回connection是否存活,修改后的stable和unstable值都必须大于或等于0,且其和必须大于0。

AT.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
40
41
42
43
44
final void completeRemoveProvider(ProviderRefCount prc) {
synchronized (mProviderMap) {
if (!prc.removePending) {
return;
}
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);
}
}
}

ActivityManager.getService().removeContentProvider(prc.holder.connection, false);
}

// AMS.java
public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
ContentProviderConnection conn;
conn = (ContentProviderConnection)connection;
if (conn == null) {
throw new NullPointerException("connection is null");
}
if (decProviderCountLocked(conn, null, null, stable)) {
updateOomAdjLocked();
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}

Provider死亡

AMS.appDiedLocked

当provider进程死亡时,对于unstable的provider可直接调用unstableProviderDied,或者是当provider进程死亡后会有死亡回调binderDied,这两个方法最终都会调用到AMS.appDiedLocked()。

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
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread, boolean fromBinderDied) {
synchronized (mPidsSelfLocked) {
ProcessRecord curProc = mPidsSelfLocked.get(pid);
if (curProc != app) {
return;
}
}
if (!app.killed) {
if (!fromBinderDied) {
killProcessQuiet(pid);
}
killProcessGroup(app.uid, pid);
app.killed = true;
}

// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null && app.thread.asBinder() == thread.asBinder()) {
handleAppDiedLocked(app, false, true);
if (doOomAdj) {
updateOomAdjLocked();
}
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
}
}

private final void handleAppDiedLocked(ProcessRecord app, boolean restarting, boolean allowRestart) {
int pid = app.pid;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1, false /*replacingPid*/);
// ...
}

AMS.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
private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
// ...
for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
// 获取该进程已发布的ContentProvider
ContentProviderRecord cpr = app.pubProviders.valueAt(i);
final boolean always = app.bad || !allowRestart;
boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
// We left the provider in the launching list, need to restart it.
restart = true;
}
cpr.provider = null;
cpr.proc = null;
}
app.pubProviders.clear();

// 处理正在启动并且有client端正在等待的ContentProvider
if (cleanupAppInLaunchingProvidersLocked(app, false)) {
restart = true;
}
// ...
return false;
}

AMS.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
private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) {
final boolean inLaunching = mLaunchingProviders.contains(cpr);

if (!inLaunching || always) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll(); // 通知处于等待状态的进程
}
mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));
String names[] = cpr.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));
}
}

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.persistent && capp.thread != null && capp.pid != 0 && capp.pid != MY_PID) {
// 非persistent进程,则杀掉跟provider具有依赖关系的进程
capp.kill("depends on provider " + cpr.name.flattenToShortString()
+ " in dying proc " + (proc != null ? proc.processName : "??")
+ " (adj " + (proc != null ? proc.setAdj : "??") + ")", true);
}
} else if (capp.thread != null && conn.provider.provider != null) {
// unstable的类型则不会被杀,也会调用到
try {
capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
} catch (RemoteException e) {
}
cpr.connections.remove(i);
if (conn.client.conProviders.remove(conn)) {
stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name);
}
}
}

if (inLaunching && always) {
mLaunchingProviders.remove(cpr);
}
return inLaunching;
}

小结

removePending是指即将被移除的引用,lastRef是指当前引用为0。

当Provider进程死亡后,当Client进程存在对某个provider的引用时,则会根据provider类型进行不同的处理:

  • 对于stable provider(即conn.stableCount > 0): 会杀掉所有跟该provider建立stable连接的非persistent进程。
  • 对于unstable provider(即conn.unstableCount > 0): 不会导致client进程被级联所杀,只会回调unstableProviderDied来清理相关信息。

当stable和unstable引用计数都为0时则移除connection信息。

FileProvider

概述

对于面向Android 7.0及以上的应用,Android禁止在应用外部公开file://url,如果一项包含文件URI的intent离开应用,则应用会抛出FileUriExposedException异常。

解决方案:要在应用间共享文件,应发送一项content://url,并授予URI临时访问权限,进行此授权的最简单方式是使用FileProvider类。FileProvider是ContentProvider的一个特殊的子类,它让应用间共享文件变得更加容易,其通过创建一个Content URI来代替File URI。

具体使用见:Android-FileProvider用法

FileProvider.getUriForFile

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
public class FileProvider extends ContentProvider {
private static final String META_DATA_FILE_PROVIDER_PATHS = "android.support.FILE_PROVIDER_PATHS";

private static final String TAG_ROOT_PATH = "root-path";
private static final String TAG_FILES_PATH = "files-path";
private static final String TAG_CACHE_PATH = "cache-path";
private static final String TAG_EXTERNAL = "external-path";
private static final String TAG_EXTERNAL_FILES = "external-files-path";
private static final String TAG_EXTERNAL_CACHE = "external-cache-path";
private static final String TAG_EXTERNAL_MEDIA = "external-media-path";

private static final String ATTR_NAME = "name";
private static final String ATTR_PATH = "path";

private static final File DEVICE_ROOT = new File("/");

private static HashMap<String, PathStrategy> sCache = new HashMap<String, PathStrategy>();

private PathStrategy mStrategy;

public static Uri getUriForFile(@NonNull Context context, @NonNull String authority,
@NonNull File file) {
final PathStrategy strategy = getPathStrategy(context, authority);
return strategy.getUriForFile(file);
}

private static PathStrategy getPathStrategy(Context context, String authority) {
PathStrategy strat;
synchronized (sCache) {
strat = sCache.get(authority);
if (strat == null) {
// 缓存为null则新建PathStrategy
try {
strat = parsePathStrategy(context, authority);
} catch (IOException e) {
throw new IllegalArgumentException("...");
} catch (XmlPullParserException e) {
throw new IllegalArgumentException("...");
}
}
}
return strat;
}
}

解析xml配置

接下来看看parsePathStrategy方法,这个方法主要是通过解析xml文件,获取到paths标签下配置的路径,并将具体的File对象存储到PathStrategy对象中。

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
private static PathStrategy parsePathStrategy(Context context, String authority) throws IOException, XmlPullParserException {
final SimplePathStrategy strat = new SimplePathStrategy(authority);

final ProviderInfo info = context.getPackageManager().resolveContentProvider(authority, PackageManager.GET_META_DATA);
final XmlResourceParser in = info.loadXmlMetaData(context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);
if (in == null) {
throw new IllegalArgumentException("Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data");
}

int type;
while ((type = in.next()) != END_DOCUMENT) {
if (type == START_TAG) {
final String tag = in.getName();

final String name = in.getAttributeValue(null, ATTR_NAME);
String path = in.getAttributeValue(null, ATTR_PATH);

File target = null;
if (TAG_ROOT_PATH.equals(tag)) {
target = DEVICE_ROOT;
} else if (TAG_FILES_PATH.equals(tag)) {
target = context.getFilesDir();
} else if (TAG_CACHE_PATH.equals(tag)) {
target = context.getCacheDir();
} else if (TAG_EXTERNAL.equals(tag)) {
target = Environment.getExternalStorageDirectory();
} else if (TAG_EXTERNAL_FILES.equals(tag)) {
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs.length > 0) {
target = externalFilesDirs[0];
}
} else if (TAG_EXTERNAL_CACHE.equals(tag)) {
File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(context);
if (externalCacheDirs.length > 0) {
target = externalCacheDirs[0];
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& TAG_EXTERNAL_MEDIA.equals(tag)) {
File[] externalMediaDirs = context.getExternalMediaDirs();
if (externalMediaDirs.length > 0) {
target = externalMediaDirs[0];
}
}

if (target != null) {
strat.addRoot(name, buildPath(target, path));
}
}
}

return strat;
}

PathStrategy

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
interface PathStrategy {
Uri getUriForFile(File file);
File getFileForUri(Uri uri);
}

static class SimplePathStrategy implements PathStrategy {
private final String mAuthority;
// 维护文件对象与name的映射:key--xml配置中的name属性,value--对应的File对象
private final HashMap<String, File> mRoots = new HashMap<String, File>();

SimplePathStrategy(String authority) {
mAuthority = authority;
}

void addRoot(String name, File root) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name must not be empty");
}
root = root.getCanonicalFile();
mRoots.put(name, root);
}

@Override
public Uri getUriForFile(File file) {
String path;
path = file.getCanonicalPath();

// 获取与给定文件路径匹配最深的root路径
Map.Entry<String, File> mostSpecific = null;
for (Map.Entry<String, File> root : mRoots.entrySet()) {
final String rootPath = root.getValue().getPath();
if (path.startsWith(rootPath) && (mostSpecific == null
|| rootPath.length() > mostSpecific.getValue().getPath().length())) {
mostSpecific = root;
}
}

if (mostSpecific == null) {
throw new IllegalArgumentException("Failed to find configured root that contains " + path);
}

// Start at first char of path under root
final String rootPath = mostSpecific.getValue().getPath();
if (rootPath.endsWith("/")) {
path = path.substring(rootPath.length());
} else {
path = path.substring(rootPath.length() + 1);
}

// Encode the tag and path separately
path = Uri.encode(mostSpecific.getKey()) + '/' + Uri.encode(path, "/");
return new Uri.Builder().scheme("content").authority(mAuthority).encodedPath(path).build();
}

@Override
public File getFileForUri(Uri uri) {
String path = uri.getEncodedPath();

final int splitIndex = path.indexOf('/', 1);
final String tag = Uri.decode(path.substring(1, splitIndex));
path = Uri.decode(path.substring(splitIndex + 1));

final File root = mRoots.get(tag);
if (root == null) {
throw new IllegalArgumentException("Unable to find configured root for " + uri);
}

File file = new File(root, path);
try {
file = file.getCanonicalFile();
} catch (IOException e) {
throw new IllegalArgumentException("Failed to resolve canonical path for " + file);
}

if (!file.getPath().startsWith(root.getPath())) {
throw new SecurityException("Resolved path jumped beyond configured root");
}
return file;
}
}

可知分享的应用调用getUriForFile方法获得一个临时的uri,目标应用通过getFileForUri方法将uri解析成对应的文件路径,然后获取目标文件对象。

总结

ContentProvider