Android ContentProvider原理分析
目录
- ContentProvider概述
- 类图
- 时序图
- 源码解析
- installProvider
- ContentResolver中的CURD
- acquireProvider
- 到AMS获取ContentProvider
- publishContentProvider
- removeDyingProvider
- 总结
1. ContentProvider概述
ContentProvider作为Android四大组件之一,重要性肯定是不言而喻的,顾名思义,内容提供者,其最重要的作用就在于提供了一种跨进程获取数据的方式,provider组件不仅可以自己的进程使用,还可以提供给其他的进程使用,大大方便了不同进程之间的数据交换,本文将详细介绍provider运行的原理。
注:本文基于Android 8.1
2. 类图
看起来涉及到的类非常多,一下有种不知道从何看起的感觉,所以这里对于其中的重点关注部分加上了颜色:
白色:provider运行过程中涉及到的内部类或私有类,一般APP开发过程中不太会涉及
蓝色:APP开发过程中经常会接触到的类
紫色:在system server
进程中provider相关的类
3. 时序图
其中白色部分:发起获取provider的client进程
红色部分:systemserver进程
蓝色部分:提供provider的server进程
时序图解读:
- 1~4流程是在APP自己的进程(进程A)中,一般来讲APP在进程启动之后初始化时,就会installProvider(流程7~10),如果APP请求的provider在自己进程,那么到4就能获取到。
- 如果请求的provider另外一个进程(进程B)中,则会触发进程5~6
- 如果进程B不存在则先启动进程B并installprovider(7~10),告诉AMS之后,由AMS返回给进程A对方的provider信息(此过程中由进程A发起的请求provider的线程会一直等待)
- 如果进程B存在则AMS直接返回给进程A对方的provider信息
- 查询到provider信息之后,如果需要跨进程调用,则通过ContentProviderProxy发起binder call到对端进程执行query
在这其中,AMS充当一个中间管理员的角色,每个进程在启动之后需要把自己应该install的providerinstall之后告诉AMS,这样后面有其他进程请求这个provider的话,AMS可以告诉你所请求的对端的信息。
4. 源码解析
4.1 ActivityThread.installProvider
installProvider,顾名思义就是安装provider,说的通俗一点就是把APP进程中的provider组件封装成对象保存起来,方便使用
在APP的进程启动的时候,handleBindApplication中会触发installProvider:
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
// 此处的provider信息是在AMS启动进程时
// 从manifest收集到的需要install的provider信息
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
// 执行installProvider,注意此处的stable参数默认为true
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
// install完成之后,要告诉AMS
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
进一步看一下ActivityThread.installProvider的具体实现
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
// holder为null表示还没有install过
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 {
try {
// 创建context
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
...
try {
final java.lang.ClassLoader cl = c.getClassLoader();
// 通过反射创建provider对象
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
// 获取IContentProvider对象,用于跨进程binder call
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
// provider的attach,其中最重要的是会执行provider的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 {
provider = holder.provider;
}
// 到这里,provider的对象创建好了,那么接下来需要做的就是数据结构的封装
// 把provider相关信息保存起来
ContentProviderHolder retHolder;
// mProviderMap的key时providerKey,value是ProviderClientReocrd
// 这两个类主要是封装了一些provider的基本信息,可以到上面看一下类图
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
// mLocalProvidersByName的key是component信息,value是对应的ProviderClientReocrd
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
// 不为空代表install过
provider = pr.mProvider;
} else {
// 对于新创建的provider,创建其对应的ContentProviderHolder对象
holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
// install Authorities
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
// mLocalProviders的key是IContentProvider的binder对象,value是ProviderClientRecord
// 将封装好的provider放入map中
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
// mProviderRefCountMap的key是binder对象,value是ProviderRefCount
// ProviderRefCount中记录了这个provider的stable和unstable的数量
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
}
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
// 创建ProviderRefCount
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
// 根据参数中的stable和unstable创建对象
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
// 放入map
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
这里需要提一下其中的getIContentProvider:
返回的是一个Transport对象,而这又是ContentProviderNative的子类,主要作用就是用来binder通信的
它的创建:在ContentProvider类中private Transport mTransport = new Transport();
也就是说在对象创建的时候就默认创建了
然后是ActivityThread.installProviderAuthoritiesLocked
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) {
for (String auth : auths) {
// 对于一些特殊的auth,允许跨进程binder call
// Binder.allowBlocking代表允许执行同步的binder call
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());
}
}
}
// 创建ProviderClientRecord
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
for (String auth : auths) {
// 根据auth和userId创建ProviderKey,放入mProviderMap
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;
}
小结:
- 创建了provider对象,其中也创建了IContentProvider对象(Transport)
- 创建ContentProviderHolder
- 创建ProviderKey
- 创建ProviderClientRecord,这是一个provider在client进程中对应的对象
- 分别放入
mProviderMap
/mLocalProviders
/mLocalProvidersByName
- 创建ProviderRefCount,放入
mProviderRefCountMap
这里先说一下
stable
和unstable
:
- 代表的是client和server的链接,主要取决于获取provider的传参,默认情况下,insert/update/delete建立的链接都是stable,而query则是unstable,不过在query的时候如果失败,还会重新创建stable
- stable和unstable最重大的差别在于unstable的情况下,即使对端挂掉了,client也没关系,但是stable的话,如果对端进程挂掉了,client也会被跟着级联kill掉。(后面会介绍)
4.2 ContentResolver中的CURD
4.2.1 ContentResolver.insert
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
// 请求provider,经过调用之后,最终传参获取的是stable类型provider
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
// 执行通过IContentProvider执行insert,其实是发起了binder call到了provider所在进程执行
Uri createdRow = provider.insert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
return createdRow;
} catch (RemoteException e) {
return null;
} finally {
releaseProvider(provider);
}
}
ContentResolver.delete
:执行provider的deleteContentResolver.update
:执行provider的updateContentResolver.call
:执行provider的call,这个比较灵活,传递的参数比较多,不固定于某一个
这三个方法的实现都跟instert基本类似,此处不再罗列
下面需要重点说一下query
:
4.2.2 query
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
// 这里执行的方法是acquireUnstableProvider
// 也就是说建立的链接是unstable类型
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
// 执行query
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 如果query失败
// 因为unstable类型,失败代表对端挂掉了,那么重新请求stable类型链接
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
// 再次query
qCursor = stableProvider.query(
mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
...
}
}
- query的时候先建立的unstable链接,然后发起了binder call
- 如果catchRemoteException,那说明对段进程挂了,此时重新请求stable类型链接把对方进程拉起来,再执行query
4.3 ActivityThread.acquireProvider
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
// 如果已经存在则直接返回
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
ContentProviderHolder holder = null;
// 如果不存在则需要向AMS查询
try {
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// 在本进程中installProvider
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
到这里可能有有一些迷糊,前面已经installProvider过了,为什么acquireProvider的时候需要再install一次呢?
答案是因为这是两个不同的进程
- 在bindApplication的时候执行的installProvider是提供provider的进程,也就是server进程
- 而在此处查询的则是需要获取provider的进程,也就是client进程
- server进程installProvider的作用是为了自己进程内使用的话在
acquireExistingProvider
的时候就能查到了,不需要在跨进程到AMS去查询 - client进程installProvider的作用是经过了一次向AMS的查询之后,客户端就可以缓存起来,这样就不用每次都向AMS查询
4.3.1 ActivityThread.acquireExistingProvider
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()) {
// 对端进程挂掉了
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
4.4 ActivityManagerService.getContentProvider
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
return getContentProviderImpl(caller, name, null, stable, userId);
}
简单对caller进行了判断,重点在getContentProviderImpl
4.4.1 getContentProviderImpl
方法比较长,删除了其中一些无用的log以及checkTime
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
// 对caller判断
boolean checkCrossUser = true;
// 在AMS的providermap中先看看是不是已经存在了
cpr = mProviderMap.getProviderByName(name, userId);
// 如果不存在且system,校验Singleton,也就是只能有一个
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.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
// 看看这个provider当前是不是已经在运行了
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
// 如果已经在运行了,也就说明各个数据结构都已经添加过了,进程也都已经存在了
if (providerRunning) {
cpi = cpr.info;
if (r != null && cpr.canRunHere(r)) {
// canRunHere主要针对自己请求的provider在自己进程中的情况,一般不会遇到
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
...
final long origId = Binder.clearCallingIdentity();
// 建立provider之间的链接
conn = incProviderCountLocked(r, cpr, token, stable);
// 需要更新lru队列
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
updateLruProcessLocked(cpr.proc, false, null);
}
}
final int verifiedAdj = cpr.proc.verifiedAdj;
// 更新进程优先级
boolean success = updateOomAdjLocked(cpr.proc, true);
if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
success = false;
}
// 记录usageStates
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
if (!success) {
// 更新lru失败代表那个进程挂掉了
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
// 需要处理进程挂掉的流程
// 并且标志provider当前不在运行状态,这样会走进下面的provider不在运行的流程中
appDiedLocked(cpr.proc);
if (!lastRef) {
return null;
}
providerRunning = false;
conn = null;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
Binder.restoreCallingIdentity(origId);
}
// 如果provider当前不在运行
if (!providerRunning) {
try {
// 先从packageManager那边查询到相关的信息
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
// 没查到的话那就说明这个是一个无效的provider
if (cpi == null) {
return null;
}
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
// 获取applicationInfo
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
// 在system启动之前不允许非system的进程获取provider
if (!mProcessesReady
&& !cpi.processName.equals("system")) {
throw new IllegalArgumentException(
"Attempt to launch content provider before system ready");
}
// 校验user是否正在运行中
if (!mUserController.isUserRunningLocked(userId, 0)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": user " + userId + " is stopped");
return null;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
// 从getProviderByClass中获取,看看这个provider是不是AMS这边已经有保存了
// 如果没有,代表这个provider从来没有向AMS注册过
// 此时需要创建一个新的ContentProviderRecord
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
if (mPermissionReviewRequired) {
if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
return null;
}
}
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);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
} finally {
Binder.restoreCallingIdentity(ident);
}
}
...
// 看看当前请求的provider是不是在mLaunchingProviders
// 如果一个 provider被请求过,但是因为对方进程没有启动没有publishProvider
// 则会加入mLaunchingProviders中
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// launching中没有
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
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);
}
// 看看这个进程是不是存在
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
// 如果进程已经存在,那么就让这个进程去installProvider即可
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
// 如果进程不存在,那就得先启动进程
// 因为provider必然运行在某一个进程中,对端进程不在肯定无法获取provider
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
}
}
// 因为需要启动进程,记录这个provider的launchingApp
// 并把这个provider加入到mLaunchingProviders中,等待对方publish之后
// 再从mLaunchingProviders中移除
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
// 如果是第一次创建的provider,还需要放入mProviderMap
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
// 建立privier之间的链接
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
grantEphemeralAccessLocked(userId, null /*intent*/,
cpi.applicationInfo.uid, UserHandle.getAppId(Binder.getCallingUid()));
}
// 代码执行到这里就说明当前的provider不存在,需要等待对端publish
synchronized (cpr) {
while (cpr.provider == null) {
...
try {
if (conn != null) {
conn.waiting = true;
}
// 在需要获取的provider上wait
// 直到对端provider被publish之后,方可notify
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
这段逻辑比较长,总结来说流程如下:
- 校验caller/权限等
- 如果provider已经在运行,那么建立连接
- 更新进程优先级,如果更新失败则代表进程被kill了,标记provider不在运行状态
- provider不在运行状态,则需要看一下provider是否mProviderMap中曾经有记录
- 如果没有需要创建新的ContentProviderRecord对象,并加到mProviderMap
- 判断进程是否存在
- 如果进程存在则直接调度进程installProvider
- 如果进程不存在则需要先启动进程
- 添加mProviderMap以及mLaunchingProviders
- 在需要获取的provider上等待对方notify
4.4.2 incProviderCountLocked
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, 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 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;
}
这个方法相对简单,所以没有写太多注释,就是根绝provider是否存在以及是否stable,记录stable和unstable的数量
4.5 ActivityManagerService.publishContentProviders
上面的流程中多次提到进程启动的时候会installProvider以及publishContentProviders
,接下来就来看一下到底是怎么回事,在前面4.1
节中也有提到,在installProvider之后,会通过binder call告诉AMS,publishContentProvider:
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(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}
final long origId = Binder.clearCallingIdentity();
final int N = providers.size();
// 遍历所有已经安装的provider
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) {
// 将这个providerRecord放入到mProviderMap中
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
int launchingCount = mLaunchingProviders.size();
int j;
// 从mLaunchingProviders中移除
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
// notify当前正在等待这个provider呗publish的所有的binder线程
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
// 更新进程优先级
updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
- 把所有的已经install的Provider放入到mProviderMap,简而言之相当于是注册,让AMS知道这个provider已经在运行了
- 把provider从从mLaunchingProviders中移除
- 通知等待在这个provider上的binder线程,那些binder线程就可以拿到provider信息返回各自进程继续干活了
4.6 removeDyingProvider
前面多次说了stable与unstable,而且前面基本都是在操作计数,那么到底什么时候会用到这个计数呢?
重点就在这个removeDyingProviderLocked
,这个方法作用是当一个进程死亡之后,把其中的所有的provider也remove掉:
private final boolean removeDyingProviderLocked(ProcessRecord proc,
ContentProviderRecord cpr, boolean always) {
final boolean inLaunching = mLaunchingProviders.contains(cpr);
// 如果这个provider还在等待launching就被remove了
// 需要把当前等待这个provider的线程都notifyAll,否则就再也没有机会notify了
if (!inLaunching || always) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
}
// 从mProviderMap中移除
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));
}
}
// 判断这个provider上的所有链接
for (int i = cpr.connections.size() - 1; i >= 0; i--) {
ContentProviderConnection conn = cpr.connections.get(i);
if (conn.waiting) {
if (inLaunching && !always) {
continue;
}
}
ProcessRecord capp = conn.client;
conn.dead = true;
// 如果stableCount大于0,也就是说存在stable的链接
// server挂掉了,那么就会把client也给kill掉
// 这正是我们前面提到的stable和unstable的重大区别
if (conn.stableCount > 0) {
if (!capp.persistent && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
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) {
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;
}
5. 总结
经过上面的解读,主要需要了解到的有以下几点:
- application初始化的时候会installProvider
- 向AMS请求provider的时候如果对端进程不存在则请求的那个线程需要一直等待
- 当对方的进程启动之后并publish之后,请求provider的线程才可返回,所以尽量不要在主线程请求provider
- 请求provider分为stable以及unsbale,stable类型链接在server进程挂掉之后,client进程会跟着被株连kill
-
insert/delete/update
默认建立stable链接,query默认建立unstable链接,如果失败会重新建立stable链接 - AMS作为一个中间管理员的身份,所有的provider会向它注册
- 向AMS请求到provider之后,就可以在client和server之间自行binder通信,不需要再经过systemserver