当前位置:   article > 正文

ContentProvider--stable参数_contentprovider stable

contentprovider stable

先总结一下,在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(...):

  1. public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
  2. @Nullable String selection, @Nullable String[] selectionArgs,
  3. @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
  4. Preconditions.checkNotNull(uri, "uri");
  5. //首先去使用unstable的方式获取IContentProvider。即向对应Connection的unstableRefCount加1
  6. //如果有缓存就直接在缓存拿,如果是首次获取,则向AMS获取。
  7. IContentProvider unstableProvider = acquireUnstableProvider(uri);
  8. if (unstableProvider == null) {
  9. return null;
  10. }
  11. IContentProvider stableProvider = null;
  12. Cursor qCursor = null;
  13. try {
  14. long startTime = SystemClock.uptimeMillis();
  15. ICancellationSignal remoteCancellationSignal = null;
  16. if (cancellationSignal != null) {
  17. cancellationSignal.throwIfCanceled();
  18. remoteCancellationSignal = unstableProvider.createCancellationSignal();
  19. cancellationSignal.setRemote(remoteCancellationSignal);
  20. }
  21. try {
  22. //通过binder通信直接与目标CP通信并获取Cursor
  23. qCursor = unstableProvider.query(mPackageName, uri, projection,
  24. selection, selectionArgs, sortOrder, remoteCancellationSignal);
  25. } catch (DeadObjectException e) {
  26. // The remote process has died... but we only hold an unstable
  27. // reference though, so we might recover!!! Let's try!!!!
  28. // This is exciting!!1!!1!!!!1
  29. //如果目标CP所在进程已死,则抛这异常,此时将通过该方法处理这个缓存的Bp
  30. unstableProviderDied(unstableProvider);
  31. //通过stable的方式获取IContentProvider,即向对应的connection的stableRefCount加1
  32. stableProvider = acquireProvider(uri);
  33. if (stableProvider == null) {
  34. return null;
  35. }
  36. qCursor = stableProvider.query(mPackageName, uri, projection,
  37. selection, selectionArgs, sortOrder, remoteCancellationSignal);
  38. }
  39. if (qCursor == null) {
  40. return null;
  41. }
  42. // Force query execution. Might fail and throw a runtime exception here.
  43. qCursor.getCount();
  44. long durationMillis = SystemClock.uptimeMillis() - startTime;
  45. maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
  46. // Wrap the cursor object into CursorWrapperInner object.
  47. //最终还是要使用stable的方式去获取一次,即必须会对stableRefCount进行加1
  48. CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
  49. stableProvider != null ? stableProvider : acquireProvider(uri));
  50. //注意这里,那么下面则不会release这个stable的ref了,应该会在Cursor关闭之后才释放
  51. stableProvider = null;
  52. qCursor = null;//注意这里,提前置空,下面就不用close cursor了
  53. return wrapper;
  54. } catch (RemoteException e) {
  55. // Arbitrary and not worth documenting, as Activity
  56. // Manager will kill this process shortly anyway.
  57. return null;
  58. } finally {
  59. if (qCursor != null) {//注意上面已置空了,不会执行此处
  60. qCursor.close();
  61. }
  62. if (cancellationSignal != null) {
  63. cancellationSignal.setRemote(null);
  64. }
  65. //每次对ContentProvider操作完都会马上release,即对refCount减1
  66. if (unstableProvider != null) {//会被执行
  67. releaseUnstableProvider(unstableProvider);
  68. }
  69. if (stableProvider != null) {//上面已置空,不会执行
  70. releaseProvider(stableProvider);
  71. }
  72. }
  73. }

ContextImpl$ApplicationContentResolver#acquireProvider,acquireUnstableProvider和acquireExistingProvider,都是直接调用ActivityThread的方法,其中acquireProvider,acquireUnstableProvider向AcitivityThread传递的参数的区别是stable参数分别是true和false:

  1. @Override
  2. protected IContentProvider acquireProvider(Context context, String auth) {
  3. return mMainThread.acquireProvider(context,
  4. ContentProvider.getAuthorityWithoutUserId(auth),
  5. resolveUserIdFromAuthority(auth), true);
  6. }
  7. @Override
  8. protected IContentProvider acquireUnstableProvider(Context c, String auth) {
  9. return mMainThread.acquireProvider(c,
  10. ContentProvider.getAuthorityWithoutUserId(auth),
  11. resolveUserIdFromAuthority(auth), false);
  12. }
  13. @Override
  14. protected IContentProvider acquireExistingProvider(Context context, String auth) {
  15. return mMainThread.acquireExistingProvider(context,
  16. ContentProvider.getAuthorityWithoutUserId(auth),
  17. resolveUserIdFromAuthority(auth), true);
  18. }

接着分析AcitivityThread#acquireProvider():

  1. public final IContentProvider acquireProvider(
  2. Context c, String auth, int userId, boolean stable) {
  3. //首先去找缓存中是否已经有这个IContentProvider了,一般存储在ActivityThread
  4. //ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
  5. final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
  6. if (provider != null) {
  7. return provider;//如果有缓存在直接返回该provider
  8. }
  9. // There is a possible race here. Another thread may try to acquire
  10. // the same provider at the same time. When this happens, we want to ensure
  11. // that the first one wins.
  12. // Note that we cannot hold the lock while acquiring and installing the
  13. // provider since it might take a long time to run and it could also potentially
  14. // be re-entrant in the case where the provider is in the same process.
  15. IActivityManager.ContentProviderHolder holder = null;
  16. try {
  17. //向AMS获取,把stable参数一并传过去
  18. holder = ActivityManagerNative.getDefault().getContentProvider(
  19. getApplicationThread(), auth, userId, stable);
  20. } catch (RemoteException ex) {
  21. }
  22. if (holder == null) {
  23. Slog.e(TAG, "Failed to find provider info for " + auth);
  24. return null;
  25. }
  26. Slog.d(TAG, "holder:" + holder + ", holder.provider:" + holder.provider);
  27. // Install provider will increment the reference count for us, and break
  28. // any ties in the race.
  29. /// M: if provider is killed for some reasons when getContentProvider from AMS,
  30. /// M: restart the provider one time @{
  31. try {
  32. //如果是客户进程的话,install到本地,很明显这是第一次获取时才会去install,如果不是第一次
  33. //获取,那么必然会从缓存中获取到并直接返回。
  34. holder = installProvider(c, holder, holder.info,
  35. true /*noisy*/, holder.noReleaseNeeded, stable);
  36. } catch (SecurityException sex) {
  37. try {
  38. holder = ActivityManagerNative.getDefault().getContentProvider(
  39. getApplicationThread(), auth, userId, stable);
  40. } catch (RemoteException ex) {
  41. }
  42. if (holder == null) {
  43. Slog.e(TAG, "Failed to find provider info for " + auth);
  44. return null;
  45. }
  46. holder = installProvider(c, holder, holder.info,
  47. true /*noisy*/, holder.noReleaseNeeded, stable);
  48. }
  49. /// M: @}
  50. return holder.provider;
  51. }

分析AMS#getContentProvider(...):

  1. private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
  2. String name, IBinder token, boolean stable, int userId) {
  3. ContentProviderRecord cpr;
  4. ContentProviderConnection conn = null;
  5. ProviderInfo cpi = null;
  6. synchronized(this) {
  7. long startTime = SystemClock.elapsedRealtime();
  8. ProcessRecord r = null;
  9. if (caller != null) {
  10. r = getRecordForAppLocked(caller);
  11. if (r == null) {
  12. throw new SecurityException(
  13. "Unable to find app for caller " + caller
  14. + " (pid=" + Binder.getCallingPid()
  15. + ") when getting content provider " + name);
  16. }
  17. }
  18. boolean checkCrossUser = true;
  19. checkTime(startTime, "getContentProviderImpl: getProviderByName");
  20. // First check if this content provider has been published...
  21. cpr = mProviderMap.getProviderByName(name, userId);
  22. /// M: To debug for get content provider process info
  23. Slog.d(TAG, "getContentProviderImpl: from caller=" + caller + " (pid=" + Binder.getCallingPid() + ", userId=" + userId + ") to get content provider " + name + " cpr=" + cpr);
  24. // If that didn't work, check if it exists for user 0 and then
  25. // verify that it's a singleton provider before using it.
  26. if (cpr == null && userId != UserHandle.USER_OWNER) {
  27. cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
  28. if (cpr != null) {
  29. cpi = cpr.info;
  30. if (isSingleton(cpi.processName, cpi.applicationInfo,
  31. cpi.name, cpi.flags)
  32. && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
  33. userId = UserHandle.USER_OWNER;
  34. checkCrossUser = false;
  35. } else {
  36. cpr = null;
  37. cpi = null;
  38. }
  39. }
  40. }
  41. boolean providerRunning = cpr != null;
  42. //如果目标CP进程已经在运行了,进入这里
  43. if (providerRunning) {
  44. cpi = cpr.info;
  45. String msg;
  46. checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
  47. if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
  48. != null) {
  49. throw new SecurityException(msg);
  50. }
  51. checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
  52. if (r != null && cpr.canRunHere(r)) {
  53. // This provider has been published or is in the process
  54. // of being published... but it is also allowed to run
  55. // in the caller's process, so don't make a connection
  56. // and just let the caller instantiate its own instance.
  57. ContentProviderHolder holder = cpr.newHolder(null);
  58. // don't give caller the provider object, it needs
  59. // to make its own.
  60. Slog.d(TAG, "getContentProviderImpl: holder.provider = null");
  61. holder.provider = null;
  62. return holder;
  63. }
  64. final long origId = Binder.clearCallingIdentity();
  65. checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
  66. // In this case the provider instance already exists, so we can
  67. // return it right away.
  68. //和refCount,stable参数相关的就只有这里了。该方法主要是创建一个ContentProviderConnection
  69. //存到客户进程ProcessRecord和目标CP的ContentProviderRecord中,然后对该对象那个的refCount
  70. //加1,其中也有stableCount和unstableCount。后面接着分析该方法
  71. conn = incProviderCountLocked(r, cpr, token, stable);
  72. if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
  73. if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
  74. // If this is a perceptible app accessing the provider,
  75. // make sure to count it as being accessed and thus
  76. // back up on the LRU list. This is good because
  77. // content providers are often expensive to start.
  78. checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
  79. updateLruProcessLocked(cpr.proc, false, null);
  80. checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
  81. Slog.d(TAG, "getContentProviderImpl: updateLruProcessLocked cpr.proc=" + cpr.proc);
  82. }
  83. }
  84. if (cpr.proc != null) {
  85. if (false) {
  86. if (cpr.name.flattenToShortString().equals(
  87. "com.android.providers.calendar/.CalendarProvider2")) {
  88. Slog.v(TAG, "****************** KILLING "
  89. + cpr.name.flattenToShortString());
  90. Process.killProcess(cpr.proc.pid);
  91. }
  92. }
  93. checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
  94. boolean success = updateOomAdjLocked(cpr.proc);
  95. maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
  96. checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
  97. if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
  98. // NOTE: there is still a race here where a signal could be
  99. // pending on the process even though we managed to update its
  100. // adj level. Not sure what to do about this, but at least
  101. // the race is now smaller.
  102. if (!success) {
  103. // Uh oh... it looks like the provider's process
  104. // has been killed on us. We need to wait for a new
  105. // process to be started, and make sure its death
  106. // doesn't kill our process.
  107. Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
  108. + " is crashing; detaching " + r);
  109. boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
  110. checkTime(startTime, "getContentProviderImpl: before appDied");
  111. appDiedLocked(cpr.proc);
  112. checkTime(startTime, "getContentProviderImpl: after appDied");
  113. if (!lastRef) {
  114. // This wasn't the last ref our process had on
  115. // the provider... we have now been killed, bail.
  116. return null;
  117. }
  118. providerRunning = false;
  119. conn = null;
  120. }
  121. /// M: Update cpr.proc's connProvider's process adj since it may have relation with A->B->C . @{
  122. if (SystemProperties.get("ro.mtk_gmo_ram_optimize").equals("1")) {
  123. if (success) {
  124. for (int provi = cpr.proc.conProviders.size() - 1; provi >= 0 ; provi--) {
  125. ContentProviderConnection proviConn = cpr.proc.conProviders.get(provi);
  126. if (proviConn.stableCount > 0) {
  127. if (proviConn.provider.proc != null && !proviConn.provider.proc.processName.equals("system")) {
  128. Slog.e(TAG, "getContentProviderImpl: Update provider " + cpr.proc + " conProviers's adj. conProviders.provider.proc=" + proviConn.provider.proc + " stableCount=" + proviConn.stableCount);
  129. updateOomAdjLocked(proviConn.provider.proc);
  130. }
  131. }
  132. }
  133. }
  134. }
  135. /// M: }@
  136. }
  137. /// M: cpr added to mProviderMap when start process, but cpr.proc will set until publish provider @{
  138. /// We need to update provider adj if a provider process is acquired during launching
  139. else {
  140. if (SystemProperties.get("ro.mtk_gmo_ram_optimize").equals("1")) {
  141. final int N = mLaunchingProviders.size();
  142. int i;
  143. ContentProviderRecord launchingCpr;
  144. for (i = 0; i < N; i++) {
  145. launchingCpr = mLaunchingProviders.get(i);
  146. if (cpr == launchingCpr) {
  147. Slog.i(TAG, "getContentProviderImpl: updateOomAdjLocked for cpr=" + cpr + " launchingApp=" + cpr.launchingApp);
  148. updateOomAdjLocked(cpr.launchingApp);
  149. break;
  150. }
  151. }
  152. }
  153. }
  154. /// M: }@
  155. Binder.restoreCallingIdentity(origId);
  156. }
  157. boolean singleton;
  158. //如果目标CP进程还未运行,进入这里。没运行首先肯定是要先startProcessLocked
  159. if (!providerRunning) {
  160. try {
  161. checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
  162. cpi = AppGlobals.getPackageManager().
  163. resolveContentProvider(name,
  164. STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
  165. checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
  166. } catch (RemoteException ex) {
  167. /// M: Debug for get content provider problem from PMS
  168. Log.v(TAG, "getContentProviderImpl: resolveContentProvider() exception " + ex.getMessage(), ex);
  169. }
  170. if (cpi == null) {
  171. /// M: Debug for get content provider problem from PMS
  172. Log.v(TAG, "getContentProviderImpl: can't get cpi from packagemanager");
  173. return null;
  174. }
  175. // If the provider is a singleton AND
  176. // (it's a call within the same user || the provider is a
  177. // privileged app)
  178. // Then allow connecting to the singleton provider
  179. singleton = isSingleton(cpi.processName, cpi.applicationInfo,
  180. cpi.name, cpi.flags)
  181. && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
  182. if (singleton) {
  183. userId = UserHandle.USER_OWNER;
  184. }
  185. cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
  186. checkTime(startTime, "getContentProviderImpl: got app info for user");
  187. String msg;
  188. checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
  189. if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
  190. != null) {
  191. throw new SecurityException(msg);
  192. }
  193. checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
  194. if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
  195. && !cpi.processName.equals("system")) {
  196. // If this content provider does not run in the system
  197. // process, and the system is not yet ready to run other
  198. // processes, then fail fast instead of hanging.
  199. throw new IllegalArgumentException(
  200. "Attempt to launch content provider before system ready");
  201. }
  202. // Make sure that the user who owns this provider is running. If not,
  203. // we don't want to allow it to run.
  204. if (!isUserRunningLocked(userId, false)) {
  205. Slog.w(TAG, "Unable to launch app "
  206. + cpi.applicationInfo.packageName + "/"
  207. + cpi.applicationInfo.uid + " for provider "
  208. + name + ": user " + userId + " is stopped");
  209. return null;
  210. }
  211. ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
  212. checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
  213. cpr = mProviderMap.getProviderByClass(comp, userId);
  214. checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
  215. final boolean firstClass = cpr == null;
  216. if (firstClass) {
  217. final long ident = Binder.clearCallingIdentity();
  218. try {
  219. checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
  220. ApplicationInfo ai =
  221. AppGlobals.getPackageManager().
  222. getApplicationInfo(
  223. cpi.applicationInfo.packageName,
  224. STOCK_PM_FLAGS, userId);
  225. checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
  226. if (ai == null) {
  227. Slog.w(TAG, "No package info for content provider "
  228. + cpi.name);
  229. return null;
  230. }
  231. ai = getAppInfoForUser(ai, userId);
  232. cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
  233. } catch (RemoteException ex) {
  234. // pm is in same process, this will never happen.
  235. } finally {
  236. Binder.restoreCallingIdentity(ident);
  237. }
  238. }
  239. checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
  240. if (r != null && cpr.canRunHere(r)) {
  241. // If this is a multiprocess provider, then just return its
  242. // info and allow the caller to instantiate it. Only do
  243. // this if the provider is the same user as the caller's
  244. // process, or can run as root (so can be in any process).
  245. return cpr.newHolder(null);
  246. }
  247. if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
  248. + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
  249. + cpr.info.name + " callers=" + Debug.getCallers(6));
  250. // This is single process, and our app is now connecting to it.
  251. // See if we are already in the process of launching this
  252. // provider.
  253. final int N = mLaunchingProviders.size();
  254. int i;
  255. for (i = 0; i < N; i++) {
  256. if (mLaunchingProviders.get(i) == cpr) {
  257. break;
  258. }
  259. }
  260. // If the provider is not already being launched, then get it
  261. // started.
  262. if (i >= N) {
  263. final long origId = Binder.clearCallingIdentity();
  264. try {
  265. // Content provider is now in use, its package can't be stopped.
  266. try {
  267. checkTime(startTime, "getContentProviderImpl: before set stopped state");
  268. AppGlobals.getPackageManager().setPackageStoppedState(
  269. cpr.appInfo.packageName, false, userId);
  270. checkTime(startTime, "getContentProviderImpl: after set stopped state");
  271. } catch (RemoteException e) {
  272. } catch (IllegalArgumentException e) {
  273. Slog.w(TAG, "Failed trying to unstop package "
  274. + cpr.appInfo.packageName + ": " + e);
  275. }
  276. // Use existing process if already started
  277. checkTime(startTime, "getContentProviderImpl: looking for process record");
  278. ProcessRecord proc = getProcessRecordLocked(
  279. cpi.processName, cpr.appInfo.uid, false);
  280. if (proc != null && proc.thread != null) {
  281. /// M: Add pubProviders check for schedule install to avoid init
  282. /// content provider twice
  283. /// (It may run schedule install while process launching)
  284. if (DEBUG_PROVIDER || true) Slog.d(TAG_PROVIDER,
  285. "Installing in existing process " + proc);
  286. if (!proc.pubProviders.containsKey(cpi.name)) {
  287. checkTime(startTime, "getContentProviderImpl: scheduling install");
  288. proc.pubProviders.put(cpi.name, cpr);
  289. try {
  290. proc.thread.scheduleInstallProvider(cpi);
  291. } catch (RemoteException e) {
  292. }
  293. }
  294. } else {
  295. checkTime(startTime, "getContentProviderImpl: before start process");
  296. proc = startProcessLocked(cpi.processName,
  297. cpr.appInfo, false, 0, "content provider",
  298. new ComponentName(cpi.applicationInfo.packageName,
  299. cpi.name), false, false, false);
  300. checkTime(startTime, "getContentProviderImpl: after start process");
  301. if (proc == null) {
  302. Slog.w(TAG, "Unable to launch app "
  303. + cpi.applicationInfo.packageName + "/"
  304. + cpi.applicationInfo.uid + " for provider "
  305. + name + ": process is bad");
  306. return null;
  307. }
  308. }
  309. cpr.launchingApp = proc;
  310. mLaunchingProviders.add(cpr);
  311. } finally {
  312. Binder.restoreCallingIdentity(origId);
  313. }
  314. }
  315. checkTime(startTime, "getContentProviderImpl: updating data structures");
  316. // Make sure the provider is published (the same provider class
  317. // may be published under multiple names).
  318. if (firstClass) {
  319. mProviderMap.putProviderByClass(comp, cpr);
  320. }
  321. mProviderMap.putProviderByName(name, cpr);
  322. conn = incProviderCountLocked(r, cpr, token, stable);
  323. if (conn != null) {
  324. conn.waiting = true;
  325. }
  326. }
  327. checkTime(startTime, "getContentProviderImpl: done!");
  328. }
  329. // Wait for the provider to be published...
  330. synchronized (cpr) {
  331. while (cpr.provider == null) {
  332. if (cpr.launchingApp == null) {
  333. Slog.w(TAG, "Unable to launch app "
  334. + cpi.applicationInfo.packageName + "/"
  335. + cpi.applicationInfo.uid + " for provider "
  336. + name + ": launching app became null");
  337. EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
  338. UserHandle.getUserId(cpi.applicationInfo.uid),
  339. cpi.applicationInfo.packageName,
  340. cpi.applicationInfo.uid, name);
  341. return null;
  342. }
  343. try {
  344. if (DEBUG_MU) Slog.v(TAG_MU,
  345. "Waiting to start provider " + cpr
  346. + " launchingApp=" + cpr.launchingApp);
  347. if (conn != null) {
  348. conn.waiting = true;
  349. }
  350. cpr.wait();
  351. } catch (InterruptedException ex) {
  352. } finally {
  353. if (conn != null) {
  354. conn.waiting = false;
  355. }
  356. }
  357. }
  358. }
  359. return cpr != null ? cpr.newHolder(conn) : null;
  360. }

分析AMS#incProviderCountLocked(...):

  1. ContentProviderConnection incProviderCountLocked(ProcessRecord r,
  2. final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
  3. if (r != null) {
  4. for (int i=0; i<r.conProviders.size(); i++) {//循环查看ProcessRecord
  5. ContentProviderConnection conn = r.conProviders.get(i);
  6. if (conn.provider == cpr) {//如果该进程有跟目标CP的connection,就直接加1
  7. if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
  8. "Adding provider requested by "
  9. + r.processName + " from process "
  10. + cpr.info.processName + ": " + cpr.name.flattenToShortString()
  11. + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
  12. //增加引用
  13. if (stable) {
  14. conn.stableCount++;
  15. conn.numStableIncs++;
  16. } else {
  17. conn.unstableCount++;
  18. conn.numUnstableIncs++;
  19. }
  20. return conn;//如果该进程有跟目标CP的connection,直接返回
  21. }
  22. }
  23. //如果客户Process没有与目标CP的connection,则创建一个
  24. ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
  25. if (stable) {//增加引用
  26. conn.stableCount = 1;
  27. conn.numStableIncs = 1;
  28. } else {
  29. conn.unstableCount = 1;
  30. conn.numUnstableIncs = 1;
  31. }
  32. cpr.connections.add(conn);//加到目标CP的ContentProviderRecord中
  33. r.conProviders.add(conn);//加到客户进程的ProcessRecord中
  34. startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);//这个不清楚干什么用,暂时先不研究
  35. return conn;
  36. }
  37. cpr.addExternalProcessHandleLocked(externalProcessToken);
  38. return null;
  39. }

分析ActivityThread#installProvider(...):

  1. private IActivityManager.ContentProviderHolder installProvider(Context context,
  2. IActivityManager.ContentProviderHolder holder, ProviderInfo info,
  3. boolean noisy, boolean noReleaseNeeded, boolean stable) {
  4. ContentProvider localProvider = null;
  5. IContentProvider provider;
  6. //这里在目标CP进程中才会进入,因为客户进程中holder不为空,目标CP进程在此创建CP实例的
  7. if (holder == null || holder.provider == null) {
  8. if (DEBUG_PROVIDER || noisy) {
  9. Slog.d(TAG, "Loading provider " + info.authority + ": "
  10. + info.name);
  11. }
  12. Context c = null;
  13. ApplicationInfo ai = info.applicationInfo;
  14. Slog.d(TAG, "installProvider: context.getPackageName()=" + context.getPackageName());
  15. if (context.getPackageName().equals(ai.packageName)) {
  16. c = context;
  17. } else if (mInitialApplication != null &&
  18. mInitialApplication.getPackageName().equals(ai.packageName)) {
  19. c = mInitialApplication;
  20. } else {
  21. try {
  22. c = context.createPackageContext(ai.packageName,
  23. Context.CONTEXT_INCLUDE_CODE);
  24. } catch (PackageManager.NameNotFoundException e) {
  25. // Ignore
  26. }
  27. }
  28. if (c == null) {
  29. Slog.w(TAG, "Unable to get context for package " +
  30. ai.packageName +
  31. " while loading content provider " +
  32. info.name);
  33. return null;
  34. }
  35. try {
  36. final java.lang.ClassLoader cl = c.getClassLoader();
  37. localProvider = (ContentProvider)cl.
  38. loadClass(info.name).newInstance();
  39. provider = localProvider.getIContentProvider();
  40. if (provider == null) {
  41. Slog.e(TAG, "Failed to instantiate class " +
  42. info.name + " from sourceDir " +
  43. info.applicationInfo.sourceDir);
  44. return null;
  45. }
  46. if (DEBUG_PROVIDER) Slog.v(
  47. TAG, "Instantiating local provider " + info.name);
  48. // XXX Need to create the correct context for this provider.
  49. localProvider.attachInfo(c, info);
  50. } catch (java.lang.Exception e) {
  51. if (!mInstrumentation.onException(null, e)) {
  52. throw new RuntimeException(
  53. "Unable to get provider " + info.name
  54. + ": " + e.toString(), e);
  55. }
  56. return null;
  57. }
  58. } else {
  59. provider = holder.provider;
  60. if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
  61. + info.name);
  62. }
  63. IActivityManager.ContentProviderHolder retHolder;
  64. synchronized (mProviderMap) {
  65. if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
  66. + " / " + info.name);
  67. IBinder jBinder = provider.asBinder();
  68. //如果是目标CP进程这里就会成立
  69. if (localProvider != null) {
  70. ComponentName cname = new ComponentName(info.packageName, info.name);
  71. ProviderClientRecord pr = mLocalProvidersByName.get(cname);
  72. if (pr != null) {
  73. if (DEBUG_PROVIDER) {
  74. Slog.v(TAG, "installProvider: lost the race, "
  75. + "using existing local provider");
  76. }
  77. provider = pr.mProvider;
  78. } else {
  79. holder = new IActivityManager.ContentProviderHolder(info);
  80. holder.provider = provider;
  81. holder.noReleaseNeeded = true;
  82. pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
  83. mLocalProviders.put(jBinder, pr);
  84. mLocalProvidersByName.put(cname, pr);
  85. }
  86. retHolder = pr.mHolder;
  87. } else {//客户进程进入这里
  88. ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
  89. if (prc != null) {//因为是首次查询,一般都没有缓存,所以直接跳到else
  90. if (DEBUG_PROVIDER) {
  91. Slog.v(TAG, "installProvider: lost the race, updating ref count");
  92. }
  93. // We need to transfer our new reference to the existing
  94. // ref count, releasing the old one... but only if
  95. // release is needed (that is, it is not running in the
  96. // system process).
  97. if (!noReleaseNeeded) {
  98. incProviderRefLocked(prc, stable);
  99. try {
  100. ActivityManagerNative.getDefault().removeContentProvider(
  101. holder.connection, stable);
  102. } catch (RemoteException e) {
  103. //do nothing content provider object is dead any way
  104. }
  105. }
  106. } else {//一般进入这里
  107. ProviderClientRecord client = installProviderAuthoritiesLocked(
  108. provider, localProvider, holder);
  109. if (noReleaseNeeded) {
  110. prc = new ProviderRefCount(holder, client, 1000, 1000);
  111. } else {
  112. //创建时根据stable参数初始化。即分别对stableCount和unstableCount初始化
  113. prc = stable
  114. ? new ProviderRefCount(holder, client, 1, 0)
  115. : new ProviderRefCount(holder, client, 0, 1);
  116. }
  117. //把一个跟ref相关的对象存起来,以Bp端作为key。installProvider除了创建ref相关对象,还会把一个
  118. //ProviderClientRecord放到ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
  119. mProviderRefCountMap.put(jBinder, prc);
  120. }
  121. retHolder = prc.holder;
  122. }
  123. }
  124. return retHolder;
  125. }

分析ActivityThread#acquireExistingProvider:

  1. public final IContentProvider acquireExistingProvider(
  2. Context c, String auth, int userId, boolean stable) {
  3. synchronized (mProviderMap) {
  4. final ProviderKey key = new ProviderKey(auth, userId);
  5. final ProviderClientRecord pr = mProviderMap.get(key);
  6. if (pr == null) {
  7. return null;
  8. }
  9. IContentProvider provider = pr.mProvider;
  10. IBinder jBinder = provider.asBinder();
  11. if (!jBinder.isBinderAlive()) {
  12. // The hosting process of the provider has died; we can't
  13. // use this one.
  14. Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
  15. + ": existing object's process dead");
  16. handleUnstableProviderDiedLocked(jBinder, true);
  17. return null;
  18. }
  19. // Only increment the ref count if we have one. If we don't then the
  20. // provider is not reference counted and never needs to be released.
  21. //在installProvider方法中分析过,在向AMS获取provider时,会创建一个ProviderRefCount
  22. ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
  23. if (prc != null) {
  24. //对缓存中provider引用加1,那么是对stableCount还是unstableCount加1,那就看acquire时传入的参
  25. //数了
  26. incProviderRefLocked(prc, stable);
  27. }
  28. return provider;
  29. }
  30. }

 分析ActivityThread#incProviderRefLocked:

  1. private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
  2. if (stable) {//如果是stable方式获取,则进入这里
  3. //每次都会对本地的refCount加1
  4. prc.stableCount += 1;
  5. //在加1后等于1,即这是首次对该Provider做stable引用
  6. if (prc.stableCount == 1) {
  7. // We are acquiring a new stable reference on the provider.
  8. int unstableDelta;
  9. if (prc.removePending) {
  10. // We have a pending remove operation, which is holding the
  11. // last unstable reference. At this point we are converting
  12. // that unstable reference to our new stable reference.
  13. unstableDelta = -1;
  14. // Cancel the removal of the provider.
  15. if (DEBUG_PROVIDER) {
  16. Slog.v(TAG, "incProviderRef: stable "
  17. + "snatched provider from the jaws of death");
  18. }
  19. prc.removePending = false;
  20. // There is a race! It fails to remove the message, which
  21. // will be handled in completeRemoveProvider().
  22. mH.removeMessages(H.REMOVE_PROVIDER, prc);
  23. } else {
  24. unstableDelta = 0;
  25. }
  26. try {
  27. if (DEBUG_PROVIDER) {
  28. Slog.v(TAG, "incProviderRef Now stable - "
  29. + prc.holder.info.name + ": unstableDelta="
  30. + unstableDelta);
  31. }
  32. //首次stable引用才会触发AMS#refContentProvider方法,第二次对同一provider做stable引用
  33. //则只在本地增加引用数
  34. ActivityManagerNative.getDefault().refContentProvider(
  35. prc.holder.connection, 1, unstableDelta);
  36. } catch (RemoteException e) {
  37. //do nothing content provider object is dead any way
  38. }
  39. }
  40. } else {//如果是unstable方式获取则进入这里
  41. //每次都会对本地的refCount加1
  42. prc.unstableCount += 1;
  43. //在加1后等于1,即这是首次对该Provider做unstable引用。和stable类似的属性
  44. if (prc.unstableCount == 1) {
  45. // We are acquiring a new unstable reference on the provider.
  46. if (prc.removePending) {
  47. // Oh look, we actually have a remove pending for the
  48. // provider, which is still holding the last unstable
  49. // reference. We just need to cancel that to take new
  50. // ownership of the reference.
  51. if (DEBUG_PROVIDER) {
  52. Slog.v(TAG, "incProviderRef: unstable "
  53. + "snatched provider from the jaws of death");
  54. }
  55. prc.removePending = false;
  56. mH.removeMessages(H.REMOVE_PROVIDER, prc);
  57. } else {
  58. // First unstable ref, increment our count in the
  59. // activity manager.
  60. try {
  61. if (DEBUG_PROVIDER) {
  62. Slog.v(TAG, "incProviderRef: Now unstable - "
  63. + prc.holder.info.name);
  64. }
  65. //首次unstable引用才会触发AMS#refContentProvider方法,第二次对同一provider做unstable引用
  66. //则只在本地增加引用数
  67. ActivityManagerNative.getDefault().refContentProvider(
  68. prc.holder.connection, 0, 1);
  69. } catch (RemoteException e) {
  70. //do nothing content provider object is dead any way
  71. }
  72. }
  73. }
  74. }
  75. }

 由上面的分析可以得知,每次acquireProvider,无论是去本地缓存取,还是去AMS获取,都会对本地的ProviderRefCount加1,而只有首次对Provider进行stable或者首次unstable引用才会去触发AMS中和refCount有关的方法。当然AMS#getContentProvider()中就有和refCount有关的重要逻辑。

分析AMS#refContentProvider(...):

  1. public boolean refContentProvider(IBinder connection, int stable, int unstable) {
  2. ContentProviderConnection conn;
  3. try {
  4. conn = (ContentProviderConnection)connection;
  5. } catch (ClassCastException e) {
  6. String msg ="refContentProvider: " + connection
  7. + " not a ContentProviderConnection";
  8. Slog.w(TAG, msg);
  9. throw new IllegalArgumentException(msg);
  10. }
  11. if (conn == null) {
  12. throw new NullPointerException("connection is null");
  13. }
  14. synchronized (this) {
  15. if (stable > 0) {
  16. conn.numStableIncs += stable;
  17. }
  18. stable = conn.stableCount + stable;
  19. if (stable < 0) {
  20. throw new IllegalStateException("stableCount < 0: " + stable);
  21. }
  22. if (unstable > 0) {
  23. conn.numUnstableIncs += unstable;
  24. }
  25. unstable = conn.unstableCount + unstable;
  26. if (unstable < 0) {
  27. throw new IllegalStateException("unstableCount < 0: " + unstable);
  28. }
  29. if ((stable+unstable) <= 0) {
  30. throw new IllegalStateException("ref counts can't go to zero here: stable="
  31. + stable + " unstable=" + unstable);
  32. }
  33. conn.stableCount = stable;
  34. conn.unstableCount = unstable;
  35. return !conn.dead;
  36. }
  37. }

看这方法也没干什么,只是对传过来的ContentProviderConnection的Bp端的字段变量进行赋值。而没有将该Bp端存起来

下面分析releaseProvider相关和AMS#removeDyingProviderLocked,前面分析了创建一个对引用加1,下面的是对引用减一和销毁,还有研究目标CP所在进程死后,stable参数对AMS处理和目标CP关联的客户进程的影响。

那么这个stableCount

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/426761
推荐阅读
相关标签
  

闽ICP备14008679号