当前位置:   article > 正文

Android ContenProvider 机制完整剖析_android contextprovider

android contextprovider

请支持原创~~~

相关博文:

Android ContenProvider 机制完整剖析

android 中的 ContentObserver 应用举例

android 中的 ContentObserver 原理详解

android 中的Uri

Android基础总结之八:ContentProvider

基于版本:Android R

0. 前言

很早以前分析过service(Android 中service 详解) 和broadcast receiver(android 中的 Broadcast 机制详解) 的机制,最近在回顾的时候发现少了ContentProvider 和 Activity 的流程,抽些时间补充。这一篇主要分析ContentProvider 的原理。

Android基础总结之八:ContentProvider》中举例说明ContentProvider 的调用流程,涉及到的接口比较多,我们这里以query 为入口进行剖析。

1. 入口--ContentResolver

调用接口类似:

  1. ContentResolver cr = mContext.getContentResolver();
  2. cr.query(...);

使用ContentResolver的原因:

  • ContentResolver 是不同的应用与不同或相同的ContentProvider 交互的枢纽;
  • ContentResolver 不但管理ContentProvider 状态的notify,也管理应用端ContentObserver的转接;
  • 让架构更清晰,应用端只需要与ContentResolver 交互,ContentProvider只需要负责数据维护、数据状态更新;
  • ContentProvider 为单独的进程,作为通信的server 端,ContentResolver 是应用为了交互使用,作为通信的Client 端;

1.1 getContentResolver

frameworks/base/core/java/android/app/ContextImpl.java

  1. @Override
  2. public ContentResolver getContentResolver() {
  3. return mContentResolver;
  4. }
  1. private ContextImpl(...) {
  2. ...
  3. mContentResolver = new ApplicationContentResolver(this, mainThread);
  4. }
  1. private static final class ApplicationContentResolver extends ContentResolver {
  2. @UnsupportedAppUsage
  3. private final ActivityThread mMainThread;
  4. public ApplicationContentResolver(Context context, ActivityThread mainThread) {
  5. super(context);
  6. mMainThread = Objects.requireNonNull(mainThread);
  7. }
  8. ...
  9. }

ContentResolver的源头是ApplicationContentResolver,继承自ContentResolver。

ApplicationContentResolver中记录这App 的context 和mainThread。

1.2 ContentResolver 中重要的接口

frameworks/base/core/java/android/content/ContentResolver.java

  1. public abstract class ContentResolver implements ContentInterface {
  2. ...
  3. public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
  4. @Nullable String[] projection, @Nullable String selection,
  5. @Nullable String[] selectionArgs, @Nullable String sortOrder) {
  6. ...
  7. }
  8. public final @Nullable String getType(@NonNull Uri url) {
  9. ...
  10. }
  11. public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
  12. @Nullable ContentValues values) {
  13. ...
  14. }
  15. public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
  16. @Nullable String[] selectionArgs) {
  17. ...
  18. }
  19. public final int update(@RequiresPermission.Write @NonNull Uri uri,
  20. @Nullable ContentValues values, @Nullable String where,
  21. @Nullable String[] selectionArgs) {
  22. ...
  23. }
  24. public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
  25. ContentObserver observer, @UserIdInt int userHandle) {
  26. ...
  27. }
  28. public final void unregisterContentObserver(@NonNull ContentObserver observer) {
  29. ...
  30. }
  31. }

 这里没有细列举,应为ContentResolver和ContentProvider 都是继承自interface ContentInterface,所以,query/insert/delete/update/getType 等接口都是需要实现的。在此基础上ContentResolver还负责ContentObserver的register 和unRegister 工作。

2. query

  1. public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
  2. @Nullable String[] projection, @Nullable Bundle queryArgs,
  3. @Nullable CancellationSignal cancellationSignal) {
  4. Objects.requireNonNull(uri, "uri");
  5. ...
  6. IContentProvider unstableProvider = acquireUnstableProvider(uri);
  7. if (unstableProvider == null) {
  8. return null;
  9. }
  10. IContentProvider stableProvider = null;
  11. Cursor qCursor = null;
  12. try {
  13. long startTime = SystemClock.uptimeMillis();
  14. ...
  15. try {
  16. qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
  17. queryArgs, remoteCancellationSignal);
  18. } catch (DeadObjectException e) {
  19. // The remote process has died... but we only hold an unstable
  20. // reference though, so we might recover!!! Let's try!!!!
  21. // This is exciting!!1!!1!!!!1
  22. unstableProviderDied(unstableProvider);
  23. stableProvider = acquireProvider(uri);
  24. if (stableProvider == null) {
  25. return null;
  26. }
  27. qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
  28. queryArgs, remoteCancellationSignal);
  29. }
  30. if (qCursor == null) {
  31. return null;
  32. }
  33. // Force query execution. Might fail and throw a runtime exception here.
  34. qCursor.getCount();
  35. long durationMillis = SystemClock.uptimeMillis() - startTime;
  36. maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
  37. // Wrap the cursor object into CursorWrapperInner object.
  38. final IContentProvider provider = (stableProvider != null) ? stableProvider
  39. : acquireProvider(uri);
  40. final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
  41. stableProvider = null;
  42. qCursor = null;
  43. return wrapper;
  44. } catch (RemoteException e) {
  45. ...
  46. } finally {
  47. ...
  48. }
  49. }

 代码比较长,大概可以分以下几个部分:

  • acquireUnstableProvider 获取ContentProvider 的proxy;
  • 通过ContentProvider 的proxy 调用query 接口进行查询;
  • 如果查询中unstable provider 出现dead,应用会尝试再拉一次;
  • 实例CursorWrapperInner 并返回;

2.1 acquireUnstableProvider

  1. public final IContentProvider acquireUnstableProvider(Uri uri) {
  2. if (!SCHEME_CONTENT.equals(uri.getScheme())) {
  3. return null;
  4. }
  5. String auth = uri.getAuthority();
  6. if (auth != null) {
  7. return acquireUnstableProvider(mContext, uri.getAuthority());
  8. }
  9. return null;
  10. }

acquireUnstableProvider 是个抽象函数,实现在ApplicationContentResolver中:

frameworks/base/core/java/android/app/ContextImpl.java#ApplicationContentResolver

  1. protected IContentProvider acquireUnstableProvider(Context c, String auth) {
  2. return mMainThread.acquireProvider(c,
  3. ContentProvider.getAuthorityWithoutUserId(auth),
  4. resolveUserIdFromAuthority(auth), false);
  5. }

 最终调用的是ActivityThread.acquireProvider。

2.1.1 acquireProvider

frameworks/base/core/java/android/app/ActivityThread.java

  1. public final IContentProvider acquireProvider(
  2. Context c, String auth, int userId, boolean stable) {
  3. final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
  4. if (provider != null) {
  5. return provider;
  6. }
  7. try {
  8. synchronized (getGetProviderLock(auth, userId)) {
  9. holder = ActivityManager.getService().getContentProvider(
  10. getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
  11. }
  12. } catch (RemoteException ex) {
  13. throw ex.rethrowFromSystemServer();
  14. }
  15. if (holder == null) {
  16. ...
  17. return null;
  18. }
  19. // Install provider will increment the reference count for us, and break
  20. // any ties in the race.
  21. holder = installProvider(c, holder, holder.info,
  22. true /*noisy*/, holder.noReleaseNeeded, stable);
  23. return holder.provider;
  24. }

 大概分三部分:

  • acquireExistingProvider 函数用于确认是否ActivithThread 中已经存有provider,如果存有则直接返回,防止反复去AMS 中acquire;
  • 通过AMS.getContentProvider 函数获取符合auth 和userId的 provider proxy;
  • 通过installProvider 让ActivityThread 持有provider;

这里的AMS.getContentProvider 以单独的一节讲解,详细请看第 3 节。

这里的installProvider 关注3.4.4节;

另外,最终获取到的provider proxy 是通过getIContentProvider 接口而来,或者的流程详细见3.4.4节,getIContentProvider 接口讲解看第 4 节。

3. AMS.getContentProvider

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  1. public final ContentProviderHolder getContentProvider(
  2. IApplicationThread caller, String callingPackage, String name, int userId,
  3. boolean stable) {
  4. ...
  5. return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
  6. null, stable, userId);
  7. }

getContentProviderImpl 代码比较长,这里分开剖析。

3.1 getRecordForAppLocked

  1. private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
  2. String name, IBinder token, int callingUid, String callingPackage, String callingTag,
  3. boolean stable, int userId) {
  4. ...
  5. synchronized(this) {
  6. ...
  7. ProcessRecord r = null;
  8. if (caller != null) {
  9. r = getRecordForAppLocked(caller);
  10. if (r == null) {
  11. throw new SecurityException(
  12. "Unable to find app for caller " + caller
  13. + " (pid=" + Binder.getCallingPid()
  14. + ") when getting content provider " + name);
  15. }
  16. }

根据传入的caller,类型为IApplicationThread,获得调用者App 的ProcessRecord,要求App 必须是存在的。

3.2 确认provider 是否已经存在

  1. // First check if this content provider has been published...
  2. cpr = mProviderMap.getProviderByName(name, userId);

下面的代码主要是根据provider 是否已经发布进行分段,主要分下面几个部分:

  • 如果provider 已经running;
  • 如果 provider 尚未running;
    • 如果provider 已经启动,当未发布;
    • 如果provider 没有启动;
  • 等待provider 发布;

3.3 如果provider已经running

  1. if (providerRunning) {
  2. cpi = cpr.info;
  3. String msg;
  4. //当允许运行在调用者进程且已发布,则直接返回
  5. if (r != null && cpr.canRunHere(r)) {
  6. // 检查权限
  7. ...
  8. ContentProviderHolder holder = cpr.newHolder(null);
  9. holder.provider = null; //注意这里的provider 为null,详细见3.4.4
  10. return holder;
  11. }
  12. //如果provider不是在caller进程中,需要继续检查caller 的权限
  13. ...
  14. //权限检查ok,则返回已经存在的provider 的connection,并增加引用计数
  15. conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
  16. stable);
  17. if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
  18. if (cpr.proc != null
  19. && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
  20. //更新进程LRU队列updateLruProcess");
  21. mProcessList.updateLruProcessLocked(cpr.proc, false, null);
  22. }
  23. }
  24. //更新进程adj
  25. final int verifiedAdj = cpr.proc.verifiedAdj;
  26. boolean success = updateOomAdjLocked(cpr.proc, true,
  27. OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
  28. if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
  29. success = false;
  30. }
  31. ...
  32. if (!success) {//如果失败了,provider进程已经被kill,减少引用计数
  33. boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
  34. if (!lastRef) {
  35. // This wasn't the last ref our process had on
  36. // the provider... we will be killed during cleaning up, bail.
  37. return null;
  38. }
  39. // We'll just start a new process to host the content provider
  40. providerRunning = false;
  41. conn = null;
  42. dyingProc = cpr.proc;
  43. } else {
  44. cpr.proc.verifiedAdj = cpr.proc.setAdj;
  45. }
  46. ...
  47. }

如果ContentProvider 所在进程已经存在时:

  • 权限检查;
  • 当允许运行在调用者进程,直接返回;
  • 增加引用计数;
  • 更新进程LRU队列;
  • 更新进程adj;
  • 当provider被kill时,减少引用计数并调用appDiedLocked,且设置ContentProvider为未running状态,并记录dyingProc;

注意:当允许运行在发布者的进程中时,holder.provider 为null,installProvider 函数中需要重新创建provider,详细见3.4.4节。

3.4 如果provider没有running

  1. if (!providerRunning) {
  2. try {
  3. //根据authority,获取ProviderInfo对象
  4. cpi = AppGlobals.getPackageManager().
  5. resolveContentProvider(name,
  6. STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
  7. } catch (RemoteException ex) {
  8. }
  9. if (cpi == null) {//不存在这个provider,则返回null
  10. return null;
  11. }
  12. //provider是否为system,或者是PHONE_UID或者是persistent app
  13. boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
  14. cpi.name, cpi.flags)
  15. && isValidSingletonCall(r == null ? callingUid : r.uid,
  16. cpi.applicationInfo.uid);
  17. if (singleton) {//如果是标记UID 为system
  18. userId = UserHandle.USER_SYSTEM;
  19. }
  20. cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
  21. //check caller的权限
  22. ...
  23. ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
  24. cpr = mProviderMap.getProviderByClass(comp, userId);
  25. boolean firstClass = cpr == null;
  26. if (firstClass) {
  27. final long ident = Binder.clearCallingIdentity();
  28. ...
  29. try {
  30. ApplicationInfo ai =
  31. AppGlobals.getPackageManager().
  32. getApplicationInfo(
  33. cpi.applicationInfo.packageName,
  34. STOCK_PM_FLAGS, userId);
  35. if (ai == null) {
  36. Slog.w(TAG, "No package info for content provider "
  37. + cpi.name);
  38. return null;
  39. }
  40. ai = getAppInfoForUser(ai, userId);
  41. //创建对象ContentProviderRecord
  42. cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
  43. } catch (RemoteException ex) {
  44. // pm is in same process, this will never happen.
  45. } finally {
  46. Binder.restoreCallingIdentity(ident);
  47. }
  48. } else if (dyingProc == cpr.proc && dyingProc != null) {
  49. cpr = new ContentProviderRecord(cpr);
  50. // This is sort of "firstClass"
  51. firstClass = true;
  52. }
  53. if (r != null && cpr.canRunHere(r)) {
  54. //可以运行在caller 进程中,详细见3.4.4节
  55. return cpr.newHolder(null);
  56. }
  57. //从mLaunchingProviders中查询是否存在该cpr
  58. final int N = mLaunchingProviders.size();
  59. int i;
  60. for (i = 0; i < N; i++) {
  61. if (mLaunchingProviders.get(i) == cpr) {
  62. break;
  63. }
  64. }
  65. //当provider并没有处于mLaunchingProviders队列,则启动它
  66. if (i >= N) {
  67. final long origId = Binder.clearCallingIdentity();
  68. try {
  69. // Content provider is now in use, its package can't be stopped.
  70. try {
  71. AppGlobals.getPackageManager().setPackageStoppedState(
  72. cpr.appInfo.packageName, false, userId);
  73. } catch (RemoteException e) {
  74. } catch (IllegalArgumentException e) {
  75. Slog.w(TAG, "Failed trying to unstop package "
  76. + cpr.appInfo.packageName + ": " + e);
  77. }
  78. //查询进程记录ProcessRecord
  79. ProcessRecord proc = getProcessRecordLocked(
  80. cpi.processName, cpr.appInfo.uid, false);
  81. if (proc != null && proc.thread != null && !proc.killed) {
  82. if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
  83. "Installing in existing process " + proc);
  84. if (!proc.pubProviders.containsKey(cpi.name)) {
  85. proc.pubProviders.put(cpi.name, cpr);
  86. try {
  87. //provider进程启动,发布provider
  88. proc.thread.scheduleInstallProvider(cpi);
  89. } catch (RemoteException e) {
  90. }
  91. }
  92. } else {
  93. proc = startProcessLocked(cpi.processName,
  94. cpr.appInfo, false, 0,
  95. new HostingRecord("content provider",
  96. new ComponentName(cpi.applicationInfo.packageName,
  97. cpi.name)),
  98. ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
  99. ...
  100. }
  101. cpr.launchingApp = proc;
  102. //将cpr添加到mLaunchingProviders
  103. mLaunchingProviders.add(cpr);
  104. } finally {
  105. Binder.restoreCallingIdentity(origId);
  106. }
  107. }
  108. // Make sure the provider is published (the same provider class
  109. // may be published under multiple names).
  110. if (firstClass) {
  111. mProviderMap.putProviderByClass(comp, cpr);
  112. }
  113. mProviderMap.putProviderByName(name, cpr);
  114. conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
  115. stable);
  116. if (conn != null) {
  117. conn.waiting = true;
  118. }
  119. }

如果ContentProvider 所在进程没有存在或被kill时:

  • 根据auth 获取ProviderInfo;
  • 权限检查;
  • 当provider 不是运行在system 进程,且系统未准备好,则抛出异常;
  • 当拥有该provider 的用户并没有运行,则直接返回;
  • 根据ComponentName,从AMS.mProviderMap中查询相应的ContentProviderRecord;
  • 当没有添加ContentProviderRecord 时,表示为首次调用,则创建ContentProviderRecord;
  • 当允许运行在调用者的进程中,且ProcessRecord 不为空,则直接返回
  • 当provider 并没有处于LaunchingProviders队列,则启动provider process;
  • 增加引用计数

发布ContentProvider 分两种情况:

  • provider 进程尚未启动;

    对于此场景,system_server 进程调用startProcessLocked 创建provider进程,且attach 到system_server 后,通过binder call 到provider 进程执行ActivityThread.bindApplication 进行发布;

  • provider 进程已启动,但未发布;

    对于此场景,provider 进程已存在且attach 到system_server,但所对应的provider 还没有发布,通过binder call 到provider进程执行ActivityThread.scheduleInstallProvider 进行发布;

3.4.1 scheduleInstallProvider

frameworks/base/core/java/android/app/ActivityThread.java

注意,这里是Provider 进程

  1. public void scheduleInstallProvider(ProviderInfo provider) {
  2. sendMessage(H.INSTALL_PROVIDER, provider);
  3. }

消息INSTALL_PROVIDER最终的处理函数为handleInstallProvider

  1. public void handleInstallProvider(ProviderInfo info) {
  2. final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
  3. try {
  4. installContentProviders(mInitialApplication, Arrays.asList(info));
  5. } finally {
  6. StrictMode.setThreadPolicy(oldPolicy);
  7. }
  8. }

3.4.2 bindApplication

frameworks/base/core/java/android/app/ActivityThread.java

注意,这里是provider进程

  1. private void handleBindApplication(AppBindData data) {
  2. ...
  3. try {
  4. ...
  5. if (!data.restrictedBackupMode) {
  6. if (!ArrayUtils.isEmpty(data.providers)) {
  7. installContentProviders(app, data.providers);
  8. }
  9. }
  10. ...

注意bindApplication 是从attachApplicationLocked 中触发,而对于provider 在attach函数中埋下了ANR 的炸弹:

  1. if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
  2. Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
  3. msg.obj = app;
  4. mHandler.sendMessageDelayed(msg,
  5. ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
  6. }

消息为 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG

timeout 为ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS(10s)

这个ANR 的炸弹需要在3.4.3 和之下的函数中拆除,详细看3.4.5节。

3.4.3 installContentProviders

3.4.13.4.2 两小节就是在provider没有运行下的两种场景,但最终调用的都是installContentProvider:

  1. private void installContentProviders(
  2. Context context, List<ProviderInfo> providers) {
  3. final ArrayList<ContentProviderHolder> results = new ArrayList<>();
  4. for (ProviderInfo cpi : providers) {
  5. ...
  6. ContentProviderHolder cph = installProvider(context, null, cpi,
  7. false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
  8. if (cph != null) {
  9. cph.noReleaseNeeded = true;
  10. results.add(cph);
  11. }
  12. }
  13. try {
  14. ActivityManager.getService().publishContentProviders(
  15. getApplicationThread(), results);
  16. } catch (RemoteException ex) {
  17. throw ex.rethrowFromSystemServer();
  18. }
  19. }

主要两件事:

  • installProvider
  • AMS.publishContentProviders

3.4.4 installProvider

  1. private ContentProviderHolder installProvider(Context context,
  2. ContentProviderHolder holder, ProviderInfo info,
  3. boolean noisy, boolean noReleaseNeeded, boolean stable) {
  4. ContentProvider localProvider = null;
  5. IContentProvider provider;
  6. if (holder == null || holder.provider == null) {
  7. if (DEBUG_PROVIDER || noisy) {
  8. Slog.d(TAG, "Loading provider " + info.authority + ": "
  9. + info.name);
  10. }
  11. Context c = null;
  12. ApplicationInfo ai = info.applicationInfo;
  13. if (context.getPackageName().equals(ai.packageName)) {
  14. c = context;
  15. } else if (mInitialApplication != null &&
  16. mInitialApplication.getPackageName().equals(ai.packageName)) {
  17. c = mInitialApplication;
  18. } else {
  19. try {
  20. c = context.createPackageContext(ai.packageName,
  21. Context.CONTEXT_INCLUDE_CODE);
  22. } catch (PackageManager.NameNotFoundException e) {
  23. // Ignore
  24. }
  25. }
  26. if (c == null) {
  27. Slog.w(TAG, "Unable to get context for package " +
  28. ai.packageName +
  29. " while loading content provider " +
  30. info.name);
  31. return null;
  32. }
  33. if (info.splitName != null) {
  34. try {
  35. c = c.createContextForSplit(info.splitName);
  36. } catch (NameNotFoundException e) {
  37. throw new RuntimeException(e);
  38. }
  39. }
  40. try {
  41. final java.lang.ClassLoader cl = c.getClassLoader();
  42. LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
  43. if (packageInfo == null) {
  44. // System startup case.
  45. packageInfo = getSystemContext().mPackageInfo;
  46. }
  47. localProvider = packageInfo.getAppFactory()
  48. .instantiateProvider(cl, info.name);
  49. provider = localProvider.getIContentProvider();
  50. if (provider == null) {
  51. Slog.e(TAG, "Failed to instantiate class " +
  52. info.name + " from sourceDir " +
  53. info.applicationInfo.sourceDir);
  54. return null;
  55. }
  56. if (DEBUG_PROVIDER) Slog.v(
  57. TAG, "Instantiating local provider " + info.name);
  58. // XXX Need to create the correct context for this provider.
  59. localProvider.attachInfo(c, info);
  60. } catch (java.lang.Exception e) {
  61. if (!mInstrumentation.onException(null, e)) {
  62. throw new RuntimeException(
  63. "Unable to get provider " + info.name
  64. + ": " + e.toString(), e);
  65. }
  66. return null;
  67. }
  68. } else {
  69. provider = holder.provider;
  70. if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
  71. + info.name);
  72. }
  73. ContentProviderHolder retHolder;
  74. synchronized (mProviderMap) {
  75. if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
  76. + " / " + info.name);
  77. IBinder jBinder = provider.asBinder();
  78. if (localProvider != null) {
  79. ComponentName cname = new ComponentName(info.packageName, info.name);
  80. ProviderClientRecord pr = mLocalProvidersByName.get(cname);
  81. if (pr != null) {
  82. if (DEBUG_PROVIDER) {
  83. Slog.v(TAG, "installProvider: lost the race, "
  84. + "using existing local provider");
  85. }
  86. provider = pr.mProvider;
  87. } else {
  88. holder = new ContentProviderHolder(info);
  89. holder.provider = provider;
  90. holder.noReleaseNeeded = true;
  91. pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
  92. mLocalProviders.put(jBinder, pr);
  93. mLocalProvidersByName.put(cname, pr);
  94. }
  95. retHolder = pr.mHolder;
  96. } else {
  97. ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
  98. if (prc != null) {
  99. if (DEBUG_PROVIDER) {
  100. Slog.v(TAG, "installProvider: lost the race, updating ref count");
  101. }
  102. // We need to transfer our new reference to the existing
  103. // ref count, releasing the old one... but only if
  104. // release is needed (that is, it is not running in the
  105. // system process).
  106. if (!noReleaseNeeded) {
  107. incProviderRefLocked(prc, stable);
  108. try {
  109. ActivityManager.getService().removeContentProvider(
  110. holder.connection, stable);
  111. } catch (RemoteException e) {
  112. //do nothing content provider object is dead any way
  113. }
  114. }
  115. } else {
  116. ProviderClientRecord client = installProviderAuthoritiesLocked(
  117. provider, localProvider, holder);
  118. if (noReleaseNeeded) {
  119. prc = new ProviderRefCount(holder, client, 1000, 1000);
  120. } else {
  121. prc = stable
  122. ? new ProviderRefCount(holder, client, 1, 0)
  123. : new ProviderRefCount(holder, client, 0, 1);
  124. }
  125. mProviderRefCountMap.put(jBinder, prc);
  126. }
  127. retHolder = prc.holder;
  128. }
  129. }
  130. return retHolder;
  131. }

代码比较长,逻辑大概分下面几部分:

  • 当holder 为null 或者holder.provider为null 时:
    • 当holder 为null时,是由于AMS.getContentProviderImpl 中一些条件限制;

    • 当holder.provider 为null时,是由于AMS.getContentProviderImpl 中确定provider 可以在调用者的进程中发布,此时holder 不为null;

    • 根据参数ProviderInfo 重新创建、init 一个localProvider(通过函数instantiateProvider)

    • 通过localProvider.getIContentProvider 获取provider 代理,详细见第4节;

    • 如果获取provider 成功,则调用localProvider.attachInfo,进入onCreate 流程

  • 当holder 或holder.provider 都不为null时,表示provider已经创建成功

  • 维护mLocalProvidersByName 和mProviderRefCountMap

attachInfo 这里暂时不分析了,代码比较简单,设置一些Provider 的权限和authority 并最终调用onCreate;

最终通过getIContentProvider 获取的provider 会存放在ContentProviderHolder 里面,这里很重要。可以接着看第4节。

3.4.5 AMS.publishContentProviders

代码比较多,这里不列举,主要做如下:

  • 拆除ANR 的炸弹:
  1. if (wasInLaunchingProviders) {
  2. mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
  3. }
  • 发布成功,notify 到3.5 节中的等待
  1. synchronized (dst) {
  2. dst.provider = src.provider;
  3. dst.setProcess(r);
  4. dst.notifyAll();
  5. }

3.5 等待provider 发布

  1. synchronized (cpr) {
  2. while (cpr.provider == null) {
  3. ...
  4. try {
  5. final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
  6. if (conn != null) {
  7. conn.waiting = true;
  8. }
  9. cpr.wait(wait);
  10. if (cpr.provider == null) {
  11. timedOut = true;
  12. break;
  13. }
  14. } catch (InterruptedException ex) {
  15. } finally {
  16. if (conn != null) {
  17. conn.waiting = false;
  18. }
  19. }
  20. }
  21. }

3.4 节中讲到的,如果provider 没有publish,则会进入startProcessLocked 和scheduleInstallProvider,provider 在publish 完成后会notify,唤醒这里的等待。

至此,AMS.getContentProviderImpl 分析基本完成。

4. getIContentProvider

这个函数是在3.4.4 节中触发,在调用query / insert 等接口前首先要通过acquire 获取到provider proxy,最终就是通过getIContentProvider 而来:

frameworks/base/core/java/android/content/ContentProvider.java

  1. public IContentProvider getIContentProvider() {
  2. return mTransport;
  3. }
    private Transport mTransport = new Transport();

AMS 中在启动provider之后都将provider proxy 存放到ContentProviderRecord 中,并保存在AMS 的providerMap 中。

4.1 Tansport

    class Transport extends ContentProviderNative {
  1. abstract public class ContentProviderNative extends Binder implements IContentProvider {
  2. ...
  3. }

Transport 是继承自ContentProviderNative,看完整个ContentProviderNative,会发现第 3.4.4 节中通过getIContentProvider 接口获取的provider 是Bn provider。即,在provider 的ActivityThread 中获取的provider 为Bn provider

但是,当经过3.4.4节provider 获取后,紧接着会调用3.4.5节进行publish,而在publish 中会将ContentProviderHolder 作为参数传递给AMS。

---->来看下ContentProviderHolder

frameworks/base/core/java/andriod/app/ContentProviderHolder.java

  1. public class ContentProviderHolder implements Parcelable {
  2. ...
  3. @Override
  4. public void writeToParcel(Parcel dest, int flags) {
  5. info.writeToParcel(dest, 0);
  6. if (provider != null) {
  7. dest.writeStrongBinder(provider.asBinder());
  8. } else {
  9. dest.writeStrongBinder(null);
  10. }
  11. dest.writeStrongBinder(connection);
  12. dest.writeInt(noReleaseNeeded ? 1 : 0);
  13. }
  14. public static final @android.annotation.NonNull Parcelable.Creator<ContentProviderHolder> CREATOR
  15. = new Parcelable.Creator<ContentProviderHolder>() {
  16. @Override
  17. public ContentProviderHolder createFromParcel(Parcel source) {
  18. return new ContentProviderHolder(source);
  19. }
  20. @Override
  21. public ContentProviderHolder[] newArray(int size) {
  22. return new ContentProviderHolder[size];
  23. }
  24. };
  25. @UnsupportedAppUsage
  26. private ContentProviderHolder(Parcel source) {
  27. info = ProviderInfo.CREATOR.createFromParcel(source);
  28. provider = ContentProviderNative.asInterface(
  29. source.readStrongBinder());
  30. connection = source.readStrongBinder();
  31. noReleaseNeeded = source.readInt() != 0;
  32. }
  33. }

(1)ContentProviderHolder 为一个Parcelable,用以binder间数据传递;

(2)ContentProviderHolder.writeToParcel 是将provider.asBinder 写入data;

dest.writeStrongBinder(provider.asBinder());

若,provider 为Bn provier,即为ContentProviderNative,asBinder为自身,即remote 端。

  1. public IBinder asBinder()
  2. {
  3. return this;
  4. }

若,provider 为Bp provider,即为ContentProviderProxy(为什么是这个,后面讲),asBinder 为:

  1. public IBinder asBinder()
  2. {
  3. return mRemote;
  4. }

即,无论provider是Bn provider,还是Bp provider,只要以ContentProviderHolder 传递,就会将Bn provider 作为数据写入。

(3)通过CREATOR读取provider

  1. provider = ContentProviderNative.asInterface(
  2. source.readStrongBinder());
  1. static public IContentProvider asInterface(IBinder obj)
  2. {
  3. if (obj == null) {
  4. return null;
  5. }
  6. IContentProvider in =
  7. (IContentProvider)obj.queryLocalInterface(descriptor);
  8. if (in != null) {
  9. return in;
  10. }
  11. return new ContentProviderProxy(obj);
  12. }

总结,如果ContentProviderHolder 作为参数传递,对端永远是ContentProviderProxy。即,provider 进程在创建后,无论是AMS 还是APP 拿到的provider 都是ContentProviderProxy,即都是用proxy 进行通信。

ok,终于解惑了provider 的产生和传递,回到第 2节query 接口,通过acquireUnstableProvider 获取到的provider 就是ContentProviderProxy。剩下来的就都是binder通信的问题啦,最终调用的肯定是Bn provider 中的query ,也就是Transport 中的query 接口,最终调用的当然是ContentProvider 中的query 接口。。。。。

5. 总结

至此,ContentProvider 机制就完整的剖析完了,中间可能过程还有些省略,如果有什么问题,可以留言!

下面做一些总结,大体分:

  • 针对3.3 节当provider 已经运行的场景;
  • 针对3.4节当provider 尚未运行的场景;
  • 整体的调用流程图;
  • ANR 炸弹埋下、拆除说明;

5.1 针对provider 已经运行的场景

  •  Client进程在获取provider的过程,发现cpr为空,则调用scheduleInstallProvider来向provider所在进程发出一个oneway的binder请求,并进入wait()状态.
  • provider进程安装完provider信息,则notifyAll()处于等待状态的进程/线程;

如果provider在publish完成之后, 这时再次请求该provider,那就便没有的最右侧的这个过程,直接在AMS.getContentProviderImpl之后便进入AT.installProvider的过程,而不会再次进入wait()过程.

5.2 针对provider 尚未运行的场景

  •  client进程:通过binder(调用AMS.getContentProviderImpl)向system_server进程请求相应的provider;
  • system进程:如果目标provider所对应的进程尚未启动,system_server会调用startProcessLocked来启动provider进程; 当进程启动完成,此时cpr.provider ==null,则system_server便会进入wait()状态,等待目标provider发布;
  • provider进程:进程启动后执行完attch到system_server,紧接着执行bindApplication;在这个过程会installProvider以及 publishContentProviders;再binder call到system_server进程;
  • system进程:再回到system_server,发布provider信息,并且通过notify机制,唤醒前面处于wait状态的binder线程;并将 getContentProvider的结果返回给client进程;
  • client进程:接着执行installProvider操作,安装provider的(包含对象记录,引用计数维护等工作);

5.3 整体调用流程

ContentObserver 这里没有细列举,详细可以看:

android 中的 ContentObserver 应用举例

android 中的 ContentObserver 原理详解

5.4 ANR

在3.4.2 节已经说明在启动provider 进程时最终会调用attachApplicationLocked,并埋下ANR 炸弹。timeout 为:

ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS(10s)

在3.4.5 节中通过publish 接口拆除炸弹。其实这个时间都在AMS 和provider ActivityThread 的流程中,我们能做的就是onCreate()时尽可能的少做耗时操作。

OVER~~

参考:

http://gityuan.com/2016/07/30/content-provider/

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

闽ICP备14008679号