本文基于android 12.0
主要讲解的是A进程访问B进程的ContentProvider的流程, 主要涉及到的代码路径:
frameworks/base/core/java/android/content/ContentResolver.java
frameworks/base/core/java/android/app/ContextImpl$ApplicationContentResolver.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ContentProviderHelper.java
frameworks/base/services/core/java/com/android/server/am/ContentProviderRecord.java
frameworks/base/services/core/java/com/android/server/am/ContentProviderConnection.java
运行在A进程中,即客户端进程。这里需要注意发生anr时若堆栈卡在acquireProvider则是跟system server端通信;若是访问IContentProvider的接口,则是跟B进程(provider的server端)通信。
代表client端和server端的连接,query方式若失败,还会重新创建stable连接。只有query和其他操作同时进行时,ContentProviderConnection的unstableCount和stableCount才会同时为1。
@Override
public final @Nullable Bundle call(@NonNull String authority, @NonNull String method,
@Nullable String arg, @Nullable Bundle extras) {
Objects.requireNonNull(authority, "authority");
Objects.requireNonNull(method, "method");
try {
if (mWrapped != null) return mWrapped.call(authority, method, arg, extras);
} catch (RemoteException e) {
return null;
}
// call方法默认去获取stable的provider
IContentProvider provider = acquireProvider(authority);
// 获取不到provider,抛出如下log的异常
if (provider == null) {
throw new IllegalArgumentException("Unknown authority " + authority);
}
try {
// call流程,binder对端是B进程,非system server
final Bundle res = provider.call(mPackageName, mAttributionTag, authority, method, arg,
extras);
Bundle.setDefusable(res, true);
return res;
} catch (RemoteException e) {
return null;
} finally {
// 访问完后都会释放provider
releaseProvider(provider);
}
}
@UnsupportedAppUsage
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
// 先在本地查询是否有保存这个auth对应的IContentProvider,有则直接返回
// 1.运行在自己进程的provider
// 2. 已经访问过的其他进程的provider
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
// 根据auth,userId封装获取provider key
ContentProviderHolder holder = null;
final ProviderKey key = getGetProviderKey(auth, userId);
try {
synchronized (key) {
// 不存在通过AMS查询 , 直接返回一个ContentProviderHolder的实例
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
// 如果对端进程不存在或进程存在provider未发布,则需要等待对端provider发布成功
if (holder != null && holder.provider == null && !holder.mLocal) {
synchronized (key.mLock) {
// 等待provider进程发布provider完成,超时时间为20s
// 会在ContentProviderRecord的notifyContentProviderPublishStatus方法回调时notify
key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
// notify后,将key中的holder赋值给holder
holder = key.mHolder;
}
// 如果超时仍未收到notify,holder会为null
if (holder != null && holder.provider == null) {
// probably timed out
holder = null;
}
}
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
} catch (InterruptedException e) {
holder = null;
} finally {
// Clear the holder from the key since the key itself is never cleared.
synchronized (key.mLock) {
key.mHolder = null;
}
}
// 打印失败log,user未解锁情况大部分不允许访问provider
if (holder == null) {
if (UserManager.get(c).isUserUnlocked(userId)) {
Slog.e(TAG, "Failed to find provider info for " + auth);
} else {
Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)");
}
return null;
}
// 在本进程中installProvider,增加引用计数
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
获取本地存在的IContentProvider对象
@UnsupportedAppUsage
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
// 通过key获取provider clent 对象,如果不为null,说明当前进程已经install该provider
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
// 对端进程挂掉了, 返回null,在acquireProvider重新向ams获取
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// 查看是否是自己进程的provider
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
// 增加访问其他进程ContentProvider的引用计数
// 否则引用计数从来不需要被释放
if (prc != null) {
incProviderRefLocked(prc,stable);
}
return provider;
}
}
运行在system server进程,android 12.0后ContentProvider相关的逻辑都从AMS.java中拆出到ContentProviderHelper.java中了。
代码过于庞大,去除一些浅显易懂的判断代码
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;
final int expectedUserId = userId;
synchronized (mService) {
long startTime = SystemClock.uptimeMillis();
// 对caller判断
..........
boolean checkCrossUser = true;
checkTime(startTime, "getContentProviderImpl: getProviderByName");
// 检查mProviderMap中该provider是不是已经发布了
cpr = mProviderMap.getProviderByName(name, userId);
// 如果当前查询的user不是system,且要查找的provider是只能存在system的单例
..........
ProcessRecord dyingProc = null;
if (cpr != null && cpr.proc != null) {
// 判断当前provider是不是已经在运行了
providerRunning = !cpr.proc.isKilled();
// 如果provider所在进程被AMS查杀了,但是没有回调appDiedLocked方法,标记为dyingProc
..............
// 1. 当前provider正在运行
if (providerRunning) {
cpi = cpr.info;
// canRunHere主要针对自己请求的provider运行在自己进程中的情况
if (r != null && cpr.canRunHere(r)) {
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
cpr.name.flattenToShortString(), startTime);
//1.1 这种情况,无须制造一个connection,且local为true
ContentProviderHolder holder = cpr.newHolder(null, true);
// 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
..........
// 清除caling相关信息,以免校验callingUid等问题
final long origId = Binder.clearCallingIdentity();
try {
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
// 1.2 建立provider之间的链接.
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage,
callingTag, stable, true, startTime, mService.mProcessList,
expectedUserId);
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
// 更新进程优先级
boolean success = mService.updateOomAdjLocked(cpr.proc,
OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
// 如果verify adj和计算后的adj不相等且provider的持有进程死亡
if (success && verifiedAdj != cpr.proc.mState.getSetAdj()
&& !isProcessAliveLocked(cpr.proc)) {
success = false;
}
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
// 如果更新adj失败(持有provider的进程死亡等)
if (!success) {
//打印异常log
Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable,
false, false);
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
providerRunning = false;
conn = null;
dyingProc = cpr.proc;
} else {
// provider对应进程存在,设置当前adj为erify adj
cpr.proc.mState.setVerifiedAdj(cpr.proc.mState.getSetAdj());
}
} finally {
// 恢复calling相关信息
Binder.restoreCallingIdentity(origId);
}
}
// provider未发布
if (!providerRunning) {
try {
// 获取provider的info信息
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.GET_URI_PERMISSION_PATTERNS,
userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
}
// 获取失败,直接返回null
if (cpi == null) {
return null;
}
// 跟上面一次的判读一样
boolean singleton = mService.isSingleton(
cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
&& mService.isValidSingletonCall(
r == null ? callingUid : r.uid, cpi.applicationInfo.uid);
// 一样
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton,
name, startTime);
// 系统还没ready,抛出异常
........
// user未运行,返回null
if (!mService.mUserController.isUserRunning(userId, 0)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ " for provider " + name + ": user " + userId + " is stopped");
return null;
}
// 构造component
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
// 检查AMS这边是否有保存该provider
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
boolean firstClass = cpr == null;
// 第一次创建
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
// If permissions need a review before any of the app components can run,
// we return no provider and launch a review activity if the calling app
// is in the foreground.
if (!requestTargetProviderPermissionsReviewIfNeededLocked(
cpi, r, userId, mService.mContext)) {
return null;
}
try {
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
// 获取provider相关的application信息
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
cpi.applicationInfo.packageName,
ActivityManagerService.STOCK_PM_FLAGS, userId);
checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
if (ai == null) {
Slog.w(TAG, "No package info for content provider " + cpi.name);
return null;
}
// 构造新的content provider对象
ai = mService.getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(mService, 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.
cpr = new ContentProviderRecord(cpr);
// This is sort of "firstClass"
firstClass = true;
}
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
if (r != null && cpr.canRunHere(r)) {
// 上面一样的逻辑
return cpr.newHolder(null, true);
}
// 看看当前请求的provider是不是在mLaunchingProviders
// 如果一个 provider被请求过,但是因为对方进程没有启动没有publishProvider
// 则会加入mLaunchingProviders中
final int numLaunchingProviders = mLaunchingProviders.size();
int i;
for (i = 0; i < numLaunchingProviders; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// 没有正在启动该provider进程
if (i >= numLaunchingProviders) {
final long origId = Binder.clearCallingIdentity();
try {
.....
// Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime,
"getContentProviderImpl: before set stopped state");
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ cpr.appInfo.packageName + ": " + e);
}
// Use existing process if already started
checkTime(startTime, "getContentProviderImpl: looking for process record");
//进程已经存在
ProcessRecord proc = mService.getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid);
IApplicationThread thread;
if (proc != null && (thread = proc.getThread()) != null
&& !proc.isKilled()) {
// 2. 进程存在,但是没有对应的provider,则通知app端install provider
final ProcessProviderRecord pr = proc.mProviders;
if (!pr.hasProvider(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
pr.installProvider(cpi.name, cpr);
try {
thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
// 3. 进程不存在,启动进程
checkTime(startTime, "getContentProviderImpl: before start process");
proc = mService.startProcessLocked(
cpi.processName, cpr.appInfo, false, 0,
new HostingRecord("content provider",
new ComponentName(
cpi.applicationInfo.packageName, cpi.name)),
Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false);
checkTime(startTime, "getContentProviderImpl: after start process");
// 短时间内crash多次,启动失败,打印异常log
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider " + name
+ ": process is bad");
return null;
}
}
cpr.launchingApp = proc;
// 将当前provider加到laucnhing列表,避免二次创建进程
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
checkTime(startTime, "getContentProviderImpl: updating data structures");
// 第一次创建,将当前provider加入mProviderMap map中
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
// 根据name加入map中
mProviderMap.putProviderByName(name, cpr);
// 创建连接
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
stable, false, startTime, mService.mProcessList, expectedUserId);
// 等待对端publish provider
if (conn != null) {
conn.waiting = true;
}
}
checkTime(startTime, "getContentProviderImpl: done!");
mService.grantImplicitAccess(userId, null, callingUid,
UserHandle.getAppId(cpi.applicationInfo.uid));
if (caller != null) {
// The client will be waiting, and we'll notify it when the provider is ready.
synchronized (cpr) {
if (cpr.provider == null) {
if (cpr.launchingApp == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
EventLogTags.writeAmProviderLostProcess(
UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
return null;
}
if (conn != null) {
conn.waiting = true;
}
Message msg = mService.mHandler.obtainMessage(
ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG);
msg.obj = cpr;
mService.mHandler.sendMessageDelayed(msg,
ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
}
}
// Return a holder instance even if we are waiting for the publishing of the
// provider, client will check for the holder.provider to see if it needs to wait
// for it.
// 返回holder
return cpr.newHolder(conn, false);
}
}
// 以下这些逻辑在S上基本不会走到,超时逻辑移到app端
final long timeout =
SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
Slog.w(TAG, "Unable to launch app 中间B进程的创建&app的初始化过程省略
"
+ cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ " for provider " + name + ": launching app became null");
EventLogTags.writeAmProviderLostProcess(
UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name);
return null;
}
try {
final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (DEBUG_MU) {
Slog.v(TAG_MU, "Waiting to start provider " + cpr
+ " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
}
if (conn != null) {
conn.waiting = true;
}
cpr.wait(wait);
if (cpr.provider == null) {
timedOut = true;
break;
}
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
if (timedOut) {
// Note we do it after releasing the lock.
String callerName = "unknown";
if (caller != null) {
synchronized (mService.mProcLock) {
final ProcessRecord record =
mService.mProcessList.getLRURecordForAppLOSP(caller);
if (record != null) {
callerName = record.processName;
}
}
}
Slog.wtf(TAG, "Timeout waiting for provider "
+ cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ " for provider " + name + " providerRunning=" + providerRunning
+ " caller=" + callerName + "/" + Binder.getCallingUid());
return null;
}
return cpr.newHolder(conn, false);
}
中间B进程的创建&app的初始化过程省略
主要运行在B进程,app端install完成后binder ams去publish该provider
install场景有两种,对应上面查询过程中的2 3场景
ApplicationThread的binder线程发送消息到ActivityThread的主线程中去执行。
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
......
try {
.......
// 先安装providers(严格备份模式下不会拉起providers)
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
.......
// 再执行application的onCreate逻辑
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "app.onCreate");
mInstrumentation.callApplicationOnCreate(app);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} ......
@UnsupportedAppUsage
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
// 遍历providers去安装
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);
}
}
// 告知system server 发布完成
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
@UnsupportedAppUsage
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
// 这里holder为null
if (holder == null || holder.provider == null) {
// 打印provider的debug log
.....
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
// 一般走到这里
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
........
try {
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
// System startup case.
packageInfo = getSystemContext().mPackageInfo;
}
//如果是本地自己app的provider
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
// 打印contentprovider的初始化的debug log
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
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;
if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}
ContentProviderHolder retHolder;
synchronized (mProviderMap) {
// 增加引用计数的debug log
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
IBinder jBinder = provider.asBinder();
// 如果是本地自己app的provider
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
// 第一次创建
holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
// 初始化客户端provider实例,通过providerkey将当前的ProviderClientRecord保存到mroviderMap中
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
// 通过IBinder和component保存到对应的map中
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
// 其他app的provider
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
// 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);
try {
ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} 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;
}
install 安装的时候会将key添加到mProviderMap中去,这样下次查询就可以查到
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;
}
发布成功后通知A进程
超时20s没有发布成功也会通知A进程client端
进程死亡也会通知到A进程client端
void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
mService.enforceNotIsolatedCaller("publishContentProviders");
// 需要拿AMS 锁
synchronized (mService) {
// 通过app端的binder对象获取system server端对应的进程实例
final ProcessRecord r = mService.getRecordForAppLOSP(caller);
// app端发布时,传入的caller对应的进程实例得存在
if (r == null) {
throw new SecurityException("Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}
// 清除calling 标识
final long origId = Binder.clearCallingIdentity();
boolean providersPublished = false;
// 遍历providers
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
// holder未被初始化赋值,跳出当前循环
if (src == null || src.info == null || src.provider == null) {
continue;
}
// 从进程的ProcessProviderRecord中通过provider的name获取ContentProviderRecord实例
// ProcessProviderRecord中mPubProviders列表在CPH的generateApplicationProvidersLocked中初始化
ContentProviderRecord dst = r.mProviders.getProvider(src.info.name);
if (dst == null) {
continue;
}
if (DEBUG_MU) {
Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
}
providersPublished = true;
// 按照Component和name添加provider实例到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);
}
// 查看当前provider是否是需要等待拉起的provider,是的话从mLaunchingProviders中移除
boolean wasInLaunchingProviders = false;
for (int j = 0, numLaunching = mLaunchingProviders.size(); j < numLaunching; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
numLaunching--;
}
}
// 移除content provider的超时消息
if (wasInLaunchingProviders) {
mService.mHandler.removeMessages(
ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, dst);
mService.mHandler.removeMessages(
ActivityManagerService.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, mService.mProcessStats);
synchronized (dst) {
dst.provider = src.provider;
dst.setProcess(r);
// 唤醒,告知app端可以获取holder了
dst.notifyAll();
dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
}
// update the app's oom adj value and each provider's usage stats
if (providersPublished) {
mService.updateOomAdjLocked(r, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
maybeUpdateProviderUsageStatsLocked(r,
src.info.packageName, src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
/**
* Notify all clients that the provider has been published and ready to use,
* or timed out.
*
* @param status true: successfully published; false: timed out
*/
void onProviderPublishStatusLocked(boolean status) {
final int numOfConns = connections.size();
for (int i = 0; i < numOfConns; i++) {
final ContentProviderConnection conn = connections.get(i);
if (conn.waiting && conn.client != null) {
final ProcessRecord client = conn.client;
if (!status) {
if (launchingApp == null) {
Slog.w(TAG_AM, "Unable to launch app "
+ appInfo.packageName + "/"
+ appInfo.uid + " for provider "
+ info.authority + ": launching app became null");
EventLogTags.writeAmProviderLostProcess(
UserHandle.getUserId(appInfo.uid),
appInfo.packageName,
appInfo.uid, info.authority);
} else {
Slog.wtf(TAG_AM, "Timeout waiting for provider "
+ appInfo.packageName + "/"
+ appInfo.uid + " for provider "
+ info.authority
+ " caller=" + client);
}
}
final IApplicationThread thread = client.getThread();
if (thread != null) {
try {
// 告知app端发布成功,可以去获取holder
thread.notifyContentProviderPublishStatus(
newHolder(status ? conn : null, false),
info.authority, conn.mExpectedUserId, status);
} catch (RemoteException e) {
}
}
}
conn.waiting = false;
}
}
A进程收到binder回调,并notify 告知acquireProvider不再wait
@Override
public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder,
@NonNull String authorities, int userId, boolean published) {
final String auths[] = authorities.split(";");
for (String auth: auths) {
final ProviderKey key = getGetProviderKey(auth, userId);
synchronized (key.mLock) {
key.mHolder = holder;
key.mLock.notifyAll();
}
}
}
A获取到B进程的IContentProvider后会创建一个连接,具体表现为ContentProviderConnection。
@GuardedBy("mLock")
private int mStableCount;
@GuardedBy("mLock")
private int mUnstableCount;
A进程app端流程同上面查询流程,不做赘述。
system server端如下:
@GuardedBy("mService")
private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
String callingPackage, String callingTag, boolean stable, boolean updateLru,
long startTime, ProcessList processList, @UserIdInt int expectedUserId) {
if (r == null) {
cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
return null;
}
// 获取caller进程的ProcessProviderRecord
final ProcessProviderRecord pr = r.mProviders;
for (int i = 0, size = pr.numberOfProviderConnections(); i < size; i++) {
ContentProviderConnection conn = pr.getProviderConnectionAt(i);
// 如果当前要获取的provider在该caller进程中已有相关连接,则计数+1
if (conn.provider == cpr) {
conn.incrementCount(stable);
// 获取链接直接返回
return conn;
}
}
//否则 新建一个content provider的连接
ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage,
expectedUserId);
conn.startAssociationIfNeeded();
// 初始化count为1
conn.initializeCount(stable);
// 将当前连接添加到content provider的连接列表里
cpr.connections.add(conn);
// 将当前链接保存到进程provider列表里
pr.addProviderConnection(conn);
mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(),
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
if (updateLru && cpr.proc != null
&& r.mState.getSetAdj() <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
// caller的adj <= 250,更新持有provider进程的adj
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
processList.updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
return conn;
}
@UnsupportedAppUsage
public final boolean releaseProvider(IContentProvider provider, boolean stable) {
if (provider == null) {
return false;
}
IBinder jBinder = provider.asBinder();
synchronized (mProviderMap) {
// 其他进程的provider
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
// 自己进程的provider,没有引用计数,无需release
if (prc == null) {
// The provider has no ref count, no release is needed.
return false;
}
boolean lastRef = false;
// call 方式调用
if (stable) {
if (prc.stableCount == 0) {
return false;
}
prc.stableCount -= 1;
// 是否是其他进程provider
if (prc.stableCount == 0) {
// stable 和unstable 引用计数均为0,则此次是最后一个引用
lastRef = prc.unstableCount == 0;
try {
// 告知ams
ActivityManager.getService().refContentProvider(
prc.holder.connection, -1, lastRef ? 1 : 0);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
if (prc.unstableCount == 0) {
return false;
}
prc.unstableCount -= 1;
if (prc.unstableCount == 0) {
// 当前是最后一个引用
lastRef = prc.stableCount == 0;
if (!lastRef) {
try {
// 还有stable引用的话告知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) {
// 延时1s后从本地移除
prc.removePending = true;
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;
}
}
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.
if (DEBUG_PROVIDER) Slog.v(TAG, "completeRemoveProvider: lost the race, "
+ "provider still in use");
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();
// 从mProviderMap中移除,这样下次acquire时,acquireExistingProvider就返回null
if (myBinder == jBinder) {
mProviderMap.removeAt(i);
}
}
}
try {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "removeProvider: Invoking ActivityManagerService."
+ "removeContentProvider(" + prc.holder.info.name + ")");
}
ActivityManager.getService().removeContentProvider(
prc.holder.connection, false);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
```这样下次acquire时,acquireExistingProvider就返回null
if (myBinder == jBinder) {
mProviderMap.removeAt(i);
}
}
}
try {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "removeProvider: Invoking ActivityManagerService."
+ "removeContentProvider(" + prc.holder.info.name + ")");
}
ActivityManager.getService().removeContentProvider(
prc.holder.connection, false);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
/**
* Drop a content provider from a ProcessRecord's bookkeeping
*/
void removeContentProvider(IBinder connection, boolean stable) {
mService.enforceNotIsolatedCaller("removeContentProvider");
final long ident = Binder.clearCallingIdentity();
try {
ContentProviderConnection conn;
try {
conn = (ContentProviderConnection) connection;
} catch (ClassCastException e) {
String msg = "removeContentProvider: " + connection
+ " not a ContentProviderConnection";
Slog.w(TAG, msg);
throw new IllegalArgumentException(msg);
}
if (conn == null) {
throw new NullPointerException("connection is null");
}
ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"removeContentProvider: ",
(conn.provider != null && conn.provider.info != null如果在acquireExistingProvider发现对端进程binder died了,则也会执行handleUnstableProviderDiedLocked
? conn.provider.info.authority : ""));
try {
synchronized (mService) {
decProviderCountLocked(conn, null, null, stable, true, true);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@GuardedBy("mService")
private boolean decProviderCountLocked(ContentProviderConnection conn,
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable,
boolean enforceDelay, boolean updateOomAdj) {
if (conn == null) {
cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}
if (conn.totalRefCount() > 1) {
conn.decrementCount(stable);
return false;
}
if (enforceDelay) {
// delay the removal of the provider for 5 seconds - this optimizes for those cases
// where providers are released and then quickly re-acquired, causing lots of churn.
BackgroundThread.getHandler().postDelayed(() -> {
handleProviderRemoval(conn, stable, updateOomAdj);
}, 5 * 1000);
} else {
handleProviderRemoval(conn, stable, updateOomAdj);
}
return true;
}
private void handleProviderRemoval(ContentProviderConnection conn, boolean stable,
boolean updateOomAdj) {
synchronized (mService) {
// if the proc was already killed or this is not the last reference, simply exit.
if (conn == null || conn.provider == null || conn.decrementCount(stable) != 0) {
return;
}
final ContentProviderRecord cpr = conn.provider;
conn.stopAssociation();
cpr.connections.remove(conn);
conn.client.mProviders.removeProviderConnection(conn);
if (conn.client.mState.getSetProcState()
< ActivityManager.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.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
}
}
mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
if (updateOomAdj) {
mService.updateOomAdjLocked(conn.provider.proc,
OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
}
}
}
boolean refContentProvider(IBinder connection, int stable, int unstable) {
ContentProviderConnection conn;
try {
conn = (ContentProviderConnection) connection;
} catch (ClassCastException e) {
String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
Slog.w(TAG, msg);
throw new IllegalArgumentException(msg);
}
if (conn == null) {
throw new NullPointerException("connection is null");
}
ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "refContentProvider: ",
(conn.provider != null && conn.provider.info != null
? conn.provider.info.authority : ""));
try {
conn.adjustCounts(stable, unstable);
return !conn.dead;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
/**
* Adjusts the reference counts up or down (the inputs may be positive,
* zero, or negative. This method does not return a total count because
* a return is not needed for the current use case.
*/
public void adjustCounts(int stableIncrement, int unstableIncrement) {
synchronized (mLock) {
if (stableIncrement > 0) {
mNumStableIncs += stableIncrement;
}
final int stable = mStableCount + stableIncrement;
if (stable < 0) {
throw new IllegalStateException("stableCount < 0: " + stable);
}
if (unstableIncrement > 0) {
mNumUnstableIncs += unstableIncrement;
}
final int unstable = mUnstableCount + unstableIncrement;
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);
}
mStableCount = stable;
mUnstableCount = unstable;
}
}
在目标CP进程死后,AMS会去调用removeDyingProviderLocked,其中会根据ContentProviderConnection的stableCount和unstableCount处理引用该CP的进程。如果stableCount不为0,则杀死该客户进程。如果stableCount为0,而unstableCount不为0,则通过ApplicationThread#unstableProviderDied通知客户进程,并从ContentProviderRecord中移除该ContentProviderConnection。
如果在acquireExistingProvider发现对端进程binder died了,则也会执行handleUnstableProviderDiedLocked
final void handleUnstableProviderDiedLocked(IBinder provider, boolean fromClient) {
ProviderRefCount prc = mProviderRefCountMap.get(provider);
if (prc != null) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Cleaning up dead provider "
+ provider + " " + prc.holder.info.name);
// 引用计数移除
mProviderRefCountMap.remove(provider);
for (int i=mProviderMap.size()-1; i>=0; i--) {
ProviderClientRecord pr = mProviderMap.valueAt(i);
if (pr != null && pr.mProvider.asBinder() == provider) {
Slog.i(TAG, "Removing dead content provider:" + pr.mProvider.toString());
// 从map中移除
mProviderMap.removeAt(i);
}
}
if (fromClient) {
// We found out about this due to execution in our client
// code. Tell the activity manager about it now, to ensure
// that the next time we go to do anything with the provider
// it knows it is dead (so we don't race with its death
// notification).
try {
ActivityManager.getService().unstableProviderDied(
prc.holder.connection);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
}
}