先总结一下,在ActivityThread#acquireProvider(...)获取IContentProvider时,stable参数不影响是否能取得这个IContentProvider。首先这个stable reCountf和unstable refCount在本地会保存一份,而且会保存在一个IBinder对象中,类型是ContentProviderConnection,在AMS中,ProcessRecord会保存该进程的所有ContentProviderConnection的Bn端。
无论是使用ContentResolver的insert,delete,update,query,首先都会去acquireProvider(...)或者acquireUnstableProvider(...),而选择Unstable还是Stable,取决于你是做什么操作,就是选择insert还是delete或者update和query。其中query首先是去acquireUnstableProvider,在向AMS获取IContentProvider之前,会先在本地查询是否有保存这个authority对应的IContentProvider,如果有则不用向AMS获取。
insert,delete,update操作都是首先使用acquireProvider,就增加的是stable refCount。而只有query操作是例外,先是使用acquireUnstableProvider,如果使用获取到的IContentProvider去做query操作时,发现抛DeadObjectException,即目标CP所在进程已死。那么就使用acquireProvider重新获取IContentProvider,并增加stable refCount。
在完成insert,query等方法时,都会去调用releaseProvider方法,而这个方法就涉及到refCount的操作,refCount又分为stable和unstable。而releaseProvider并不一定会导致缓存的IContentProvider被remove和AMS中的ProcessRecord(客户端进程)中和ContentProviderRecord(目标ContentProvider在AMS中的代表)中的ContentProviderConnection会被移除。主要要看stable refCount和unstable refCount是否都为0,如果是则调用ActivityThread#completeRemoveProvider(...)
ActivityThread的releaseProvider函数调用后,如果ProviderRefCount的unstableCount和stableCount同时为0,会导致completeRemoveProvider被调用,然后调用AMS的removeContentProvider移除对应的Content Provider Connection。如果ActivityThread的releaseProvider调用后,使得unstableCount或者stableCount从非0变为0,那么将调用refContentProvider(IBinder connection, int stable, int unstable),以改变AMS中的ContentProviderConnection#unstableCount或者stableCount。ContentProviderConnection中的unstableCount或者stableCount值最大为1。当refContentProvider的unstableCount或者stableCount为0,那么ContentProviderConnection中的unstableCount或者stableCount值也变为0。当refContentProvider的unstableCount或者stableCount>=1时, ContentProviderConnection中的unstableCount或者stableCount的值为1。
只有query同其他操作同时进行时,ContentProviderConnection的unstableCount和stableCount才会同时为1
在本地没有缓存IContentProvider时,从AMS中获取到IContentProvider后,会进行installProvider操作。installProvider 中会增加refCount,操作refCount的方法是ActivityThread#incProviderRefLocked()。
在目标CP进程死后,AMS会去调用removeDyingProviderLocked,其中会根据ContentProviderConnection的stableCount和unstableCount处理引用该CP的进程。如果stableCount不为0,则杀死该客户进程。如果stableCount为0,而unstableCount不为0,则通过ApplicationThread#unstableProviderDied通知客户进程,并从ContentProviderRecord中移除该ContentProviderConnection。
下面开始分析源码:
ContentResolver#query(...):
public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
//首先去使用unstable的方式获取IContentProvider。即向对应Connection的unstableRefCount加1
//如果有缓存就直接在缓存拿,如果是首次获取,则向AMS获取。
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 {
//通过binder通信直接与目标CP通信并获取Cursor
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
//如果目标CP所在进程已死,则抛这异常,此时将通过该方法处理这个缓存的Bp
unstableProviderDied(unstableProvider);
//通过stable的方式获取IContentProvider,即向对应的connection的stableRefCount加1
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object.
//最终还是要使用stable的方式去获取一次,即必须会对stableRefCount进行加1
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
//注意这里,那么下面则不会release这个stable的ref了,应该会在Cursor关闭之后才释放
stableProvider = null;
qCursor = null;//注意这里,提前置空,下面就不用close cursor了
return wrapper;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
if (qCursor != null) {//注意上面已置空了,不会执行此处
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
//每次对ContentProvider操作完都会马上release,即对refCount减1
if (unstableProvider != null) {//会被执行
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {//上面已置空,不会执行
releaseProvider(stableProvider);
}
}
}
ContextImpl$ApplicationContentResolver#acquireProvider,acquireUnstableProvider和acquireExistingProvider,都是直接调用ActivityThread的方法,其中acquireProvider,acquireUnstableProvider向AcitivityThread传递的参数的区别是stable参数分别是true和false:
@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);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
return mMainThread.acquireExistingProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
接着分析AcitivityThread#acquireProvider():
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
//首先去找缓存中是否已经有这个IContentProvider了,一般存储在ActivityThread
//ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;//如果有缓存在直接返回该provider
}
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
//向AMS获取,把stable参数一并传过去
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
Slog.d(TAG, "holder:" + holder + ", holder.provider:" + holder.provider);
// Install provider will increment the reference count for us, and break
// any ties in the race.
/// M: if provider is killed for some reasons when getContentProvider from AMS,
/// M: restart the provider one time @{
try {
//如果是客户进程的话,install到本地,很明显这是第一次获取时才会去install,如果不是第一次
//获取,那么必然会从缓存中获取到并直接返回。
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
} catch (SecurityException sex) {
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
}
/// M: @}
return holder.provider;
}
分析AMS#getContentProvider(...):
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord r = null;
if (caller != null) {
r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
}
}
boolean checkCrossUser = true;
checkTime(startTime, "getContentProviderImpl: getProviderByName");
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
/// M: To debug for get content provider process info
Slog.d(TAG, "getContentProviderImpl: from caller=" + caller + " (pid=" + Binder.getCallingPid() + ", userId=" + userId + ") to get content provider " + name + " cpr=" + cpr);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
if (cpr == null && userId != UserHandle.USER_OWNER) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
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_OWNER;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
boolean providerRunning = cpr != null;
//如果目标CP进程已经在运行了,进入这里
if (providerRunning) {
cpi = cpr.info;
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
if (r != null && cpr.canRunHere(r)) {
// This provider has been published or is in the process
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
Slog.d(TAG, "getContentProviderImpl: holder.provider = null");
holder.provider = null;
return holder;
}
final long origId = Binder.clearCallingIdentity();
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
// In this case the provider instance already exists, so we can
// return it right away.
//和refCount,stable参数相关的就只有这里了。该方法主要是创建一个ContentProviderConnection
//存到客户进程ProcessRecord和目标CP的ContentProviderRecord中,然后对该对象那个的refCount
//加1,其中也有stableCount和unstableCount。后面接着分析该方法
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
Slog.d(TAG, "getContentProviderImpl: updateLruProcessLocked cpr.proc=" + cpr.proc);
}
}
if (cpr.proc != null) {
if (false) {
if (cpr.name.flattenToShortString().equals(
"com.android.providers.calendar/.CalendarProvider2")) {
Slog.v(TAG, "****************** KILLING "
+ cpr.name.flattenToShortString());
Process.killProcess(cpr.proc.pid);
}
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
boolean success = updateOomAdjLocked(cpr.proc);
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
// the race is now smaller.
if (!success) {
// Uh oh... it looks like the provider's process
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
appDiedLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after appDied");
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;
}
/// M: Update cpr.proc's connProvider's process adj since it may have relation with A->B->C . @{
if (SystemProperties.get("ro.mtk_gmo_ram_optimize").equals("1")) {
if (success) {
for (int provi = cpr.proc.conProviders.size() - 1; provi >= 0 ; provi--) {
ContentProviderConnection proviConn = cpr.proc.conProviders.get(provi);
if (proviConn.stableCount > 0) {
if (proviConn.provider.proc != null && !proviConn.provider.proc.processName.equals("system")) {
Slog.e(TAG, "getContentProviderImpl: Update provider " + cpr.proc + " conProviers's adj. conProviders.provider.proc=" + proviConn.provider.proc + " stableCount=" + proviConn.stableCount);
updateOomAdjLocked(proviConn.provider.proc);
}
}
}
}
}
/// M: }@
}
/// M: cpr added to mProviderMap when start process, but cpr.proc will set until publish provider @{
/// We need to update provider adj if a provider process is acquired during launching
else {
if (SystemProperties.get("ro.mtk_gmo_ram_optimize").equals("1")) {
final int N = mLaunchingProviders.size();
int i;
ContentProviderRecord launchingCpr;
for (i = 0; i < N; i++) {
launchingCpr = mLaunchingProviders.get(i);
if (cpr == launchingCpr) {
Slog.i(TAG, "getContentProviderImpl: updateOomAdjLocked for cpr=" + cpr + " launchingApp=" + cpr.launchingApp);
updateOomAdjLocked(cpr.launchingApp);
break;
}
}
}
}
/// M: }@
Binder.restoreCallingIdentity(origId);
}
boolean singleton;
//如果目标CP进程还未运行,进入这里。没运行首先肯定是要先startProcessLocked
if (!providerRunning) {
try {
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
/// M: Debug for get content provider problem from PMS
Log.v(TAG, "getContentProviderImpl: resolveContentProvider() exception " + ex.getMessage(), ex);
}
if (cpi == null) {
/// M: Debug for get content provider problem from PMS
Log.v(TAG, "getContentProviderImpl: can't get cpi from packagemanager");
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
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
// If this content provider does not run in the system
// process, and the system is not yet ready to run other
// processes, then fail fast instead of hanging.
throw new IllegalArgumentException(
"Attempt to launch content provider before system ready");
}
// Make sure that the user who owns this provider is running. If not,
// we don't want to allow it to run.
if (!isUserRunningLocked(userId, false)) {
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);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
try {
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
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;
}
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);
}
}
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
if (r != null && cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr.newHolder(null);
}
if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+ (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+ cpr.info.name + " callers=" + Debug.getCallers(6));
// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
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 = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
/// M: Add pubProviders check for schedule install to avoid init
/// content provider twice
/// (It may run schedule install while process launching)
if (DEBUG_PROVIDER || true) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
checkTime(startTime, "getContentProviderImpl: before start process");
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
checkTime(startTime, "getContentProviderImpl: after start process");
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;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
checkTime(startTime, "getContentProviderImpl: updating data structures");
// Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
checkTime(startTime, "getContentProviderImpl: done!");
}
// Wait for the provider to be published...
synchronized (cpr) {
while (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");
EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
return null;
}
try {
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
+ " launchingApp=" + cpr.launchingApp);
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;
}
分析AMS#incProviderCountLocked(...):
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (r != null) {
for (int i=0; i<r.conProviders.size(); i++) {//循环查看ProcessRecord
ContentProviderConnection conn = r.conProviders.get(i);
if (conn.provider == cpr) {//如果该进程有跟目标CP的connection,就直接加1
if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
"Adding provider requested by "
+ r.processName + " from process "
+ cpr.info.processName + ": " + cpr.name.flattenToShortString()
+ " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
//增加引用
if (stable) {
conn.stableCount++;
conn.numStableIncs++;
} else {
conn.unstableCount++;
conn.numUnstableIncs++;
}
return conn;//如果该进程有跟目标CP的connection,直接返回
}
}
//如果客户Process没有与目标CP的connection,则创建一个
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);//加到目标CP的ContentProviderRecord中
r.conProviders.add(conn);//加到客户进程的ProcessRecord中
startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);//这个不清楚干什么用,暂时先不研究
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken);
return null;
}
分析ActivityThread#installProvider(...):
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
//这里在目标CP进程中才会进入,因为客户进程中holder不为空,目标CP进程在此创建CP实例的
if (holder == null || holder.provider == null) {
if (DEBUG_PROVIDER || noisy) {
Slog.d(TAG, "Loading provider " + info.authority + ": "
+ info.name);
}
Context c = null;
ApplicationInfo ai = info.applicationInfo;
Slog.d(TAG, "installProvider: context.getPackageName()=" + context.getPackageName());
if (context.getPackageName().equals(ai.packageName)) {
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
if (c == null) {
Slog.w(TAG, "Unable to get context for package " +
ai.packageName +
" while loading content provider " +
info.name);
return null;
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// 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);
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
IBinder jBinder = provider.asBinder();
//如果是目标CP进程这里就会成立
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 IActivityManager.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) {//因为是首次查询,一般都没有缓存,所以直接跳到else
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 {
ActivityManagerNative.getDefault().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 {
//创建时根据stable参数初始化。即分别对stableCount和unstableCount初始化
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
//把一个跟ref相关的对象存起来,以Bp端作为key。installProvider除了创建ref相关对象,还会把一个
//ProviderClientRecord放到ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
分析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()) {
// The hosting process of the provider has died; we can't
// use this one.
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// Only increment the ref count if we have one. If we don't then the
// provider is not reference counted and never needs to be released.
//在installProvider方法中分析过,在向AMS获取provider时,会创建一个ProviderRefCount
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//对缓存中provider引用加1,那么是对stableCount还是unstableCount加1,那就看acquire时传入的参
//数了
incProviderRefLocked(prc, stable);
}
return provider;
}
}
分析ActivityThread#incProviderRefLocked:
private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
if (stable) {//如果是stable方式获取,则进入这里
//每次都会对本地的refCount加1
prc.stableCount += 1;
//在加1后等于1,即这是首次对该Provider做stable引用
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.
if (DEBUG_PROVIDER) {
Slog.v(TAG, "incProviderRef: stable "
+ "snatched provider from the jaws of death");
}
prc.removePending = false;
// There is a race! It fails to remove the message, which
// will be handled in completeRemoveProvider().
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
unstableDelta = 0;
}
try {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "incProviderRef Now stable - "
+ prc.holder.info.name + ": unstableDelta="
+ unstableDelta);
}
//首次stable引用才会触发AMS#refContentProvider方法,第二次对同一provider做stable引用
//则只在本地增加引用数
ActivityManagerNative.getDefault().refContentProvider(
prc.holder.connection, 1, unstableDelta);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {//如果是unstable方式获取则进入这里
//每次都会对本地的refCount加1
prc.unstableCount += 1;
//在加1后等于1,即这是首次对该Provider做unstable引用。和stable类似的属性
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.
if (DEBUG_PROVIDER) {
Slog.v(TAG, "incProviderRef: unstable "
+ "snatched provider from the jaws of death");
}
prc.removePending = false;
mH.removeMessages(H.REMOVE_PROVIDER, prc);
} else {
// First unstable ref, increment our count in the
// activity manager.
try {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "incProviderRef: Now unstable - "
+ prc.holder.info.name);
}
//首次unstable引用才会触发AMS#refContentProvider方法,第二次对同一provider做unstable引用
//则只在本地增加引用数
ActivityManagerNative.getDefault().refContentProvider(
prc.holder.connection, 0, 1);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
}
}
}
由上面的分析可以得知,每次acquireProvider,无论是去本地缓存取,还是去AMS获取,都会对本地的ProviderRefCount加1,而只有首次对Provider进行stable或者首次unstable引用才会去触发AMS中和refCount有关的方法。当然AMS#getContentProvider()中就有和refCount有关的重要逻辑。
分析AMS#refContentProvider(...):
public 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");
}
synchronized (this) {
if (stable > 0) {
conn.numStableIncs += stable;
}
stable = conn.stableCount + stable;
if (stable < 0) {
throw new IllegalStateException("stableCount < 0: " + stable);
}
if (unstable > 0) {
conn.numUnstableIncs += unstable;
}
unstable = conn.unstableCount + unstable;
if (unstable < 0) {
throw new IllegalStateException("unstableCount < 0: " + unstable);
}
if ((stable+unstable) <= 0) {
throw new IllegalStateException("ref counts can't go to zero here: stable="
+ stable + " unstable=" + unstable);
}
conn.stableCount = stable;
conn.unstableCount = unstable;
return !conn.dead;
}
}
看这方法也没干什么,只是对传过来的ContentProviderConnection的Bp端的字段变量进行赋值。而没有将该Bp端存起来
下面分析releaseProvider相关和AMS#removeDyingProviderLocked,前面分析了创建一个对引用加1,下面的是对引用减一和销毁,还有研究目标CP所在进程死后,stable参数对AMS处理和目标CP关联的客户进程的影响。
那么这个stableCount