赞
踩
先总结一下,在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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。