1. 概述
ContentProvider
(内容提供器)是Android四大组件之一,提供对数据访问的统一格式,封装具体的实现。使用方无需知道底层数据的组织形式(例如数据库、文件、网络等),只需要使用ContentProvider
提供的数据操作接口,即可实现增删改查操作。ContentProvider
是抽象类,ContentProvider
实现方需要实现下列方法
onCreate
:用于初始化ContentProviderquery
:查询操作,用于返回数据给调用方insert
:插入操作,用于向ContentProvider插入新的数据update
:更新操作,用于更新ContentProvider现有的数据delete
:删除操作,用于删除ContentProvider中对应的数据getType
:返回数据的MIME类型
2. 类继承关系
ContentProvider
相关类的继承关系如上图所示,我们在编写ContentProvider
提供者的时候,都会继承ContentProvider
基类,ContentProvider
实现在Android框架中,ContentProvider
内部有一个mTransport
成员,其类型是Transport
。Transport
继承了ContentProviderNative
,通过类名大概可以了解到ContentProvderNative
和ContentProviderProxy
是Binder通信的双方,通过这种方式最终实现跨进程的数据访问。
3. 以query调用为例
ContentProvider
的适用方会通过如下的代码进行调用,所以下面就按照这个调用的逻辑来做简单分析
1 2 3 4 5 6 7 |
private void queryAll() { Cursor cursor = context.getContentResolver().query(CourseProviders.COURSE_URI, null, null, null, null); if (cursor == null) { return; } .............. |
3.1 getContentResolver
老套路,Context
只是定义了接口,具体的实现还是在ContextImpl
中
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@UnsupportedAppUsage private final ApplicationContentResolver mContentResolver; @Override public ContentResolver getContentResolver() { return mContentResolver; } private ContextImpl(@Nullable ContextImpl container, ...............) { .......... mContentResolver = new ApplicationContentResolver(this, mainThread); } |
从上到下,根据摘取的代码可以知道,getContentResolver
最后返回的是ApplicationContentResolver
实例对象。
3.2 ApplicationContentResolver query调用流程
ApplicationContentResolver
继承了ContentResolver
,query实现在ContentResolver
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Override public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { ......... //调用acquireUnstableProvider函数,参数为uri,函数也由ContentResolver实现 IContentProvider unstableProvider = acquireUnstableProvider(uri); if (unstableProvider == null) { return null; } // 剩余的代码就是基于上面获取到的IContentProvider对象进行query调用 // 后面有机会在进行分析 .................. |
这里acquireUnstableProvider
最后会调用到父类ApplicationContentResolver
的acquireUnstableProvider
,细心的同学应该还会注意到,ContentResolver
内部还有一个acquireProvider
方法。unstableProvider
与stableProvider
在ActivityThread
和 AMS 都有各自独立的引用计数,区别在于使用unstableProvider
的客户端进程不会受到ContentProvider
服务端进程死亡的牵连,而使用stableProvider
,服务端死亡将导致客户端进程也被杀死。
1 2 3 4 5 6 7 8 9 |
@Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { // mMainThread指向代表应用进程主线程的ActivityThread对象, // 每个应用进程只有一个ActivityThread对象 return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); } |
acquireProvider(Uri)
方法的情况与acquireUnstableProvider
的情况相似,唯一要注意的是调用ActivityThread.acquireProvider
方法时最后一个参数为 true 而非 false。这里因为我们调用的是acquireUnstableProvider
,所以最后传递的参数为false。接下来就看ActivityThread
中具体的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { // 尝试调用 acquireExistingProvider 获取已有的 ContentProvider,如果成功则直接返回; // 方法内部通过查询mProviderMap是否存在provider,如果不存在则直接返回。 // 如果存在判断provider的进程是否死亡,死亡则返回null。如果provider所在的进程还在,则增加引用计数。 final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } ContentProviderHolder holder = null; try { synchronized (getGetProviderLock(auth, userId)) { // 如果上述判断系统中尚未存在对应的ContentProvider,就要通过AMS进行查询 holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable); } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } if (holder == null) { if (UserManager.get(c).isUserUnlocked(userId)) { Slog.e(TAG, "Failed to find provider info for " + auth); } else { Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)"); } return null; } // 使用 installProvider 方法安装内容提供程序 holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider; } |
-
- 第一步是在查询当前进程中是否已经安装过该
ContentProvider
,需要注意的是运行当前代码的仍是ContentProvider
的使用方
- 第一步是在查询当前进程中是否已经安装过该
-
- 如果第一步没有在本进程中查询到
ContentProvider
,就需要和AMS交互进行查询
- 如果第一步没有在本进程中查询到
-
- 最后会通过
installProvider
安装内容提供器,这个方法我们先记住,在后面还会遇到,我们在后面做进一步分析
- 最后会通过
第三步的installProvider
我们在后面还会继续做分析的,所以这里我们可以先暂时越过。现在我们假设需要使用的内容提供器还没有运行,接下来看看AMS是如何处理的。
3.3 AMS getContentProvider处理
AMS中实现的getContentProvider
的主要工作还是以来于getContentProviderImpl
来进行,所以我们下面直接看getContentProviderImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingPackage, String callingTag, boolean stable, int userId) { .............. synchronized(this) { long startTime = SystemClock.uptimeMillis(); ProcessRecord r = null; if (caller != null) { // 下面几句代码表示查询调用者信息 // 如果无法获取到调用者信息,就抛出SecurityException r = getRecordForAppLocked(caller); if (r == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when getting content provider " + name); } } ............... // 检查请求的ContentProvider是否已经发布并记录在mProviderMap中 cpr = mProviderMap.getProviderByName(name, userId); // 接着如果在当前用户中没有发布所请求的ContentProvider // 则在USER_SYSTEM用户中查询请求的ContentProvider是否已经发布 if (cpr == null && userId != UserHandle.USER_SYSTEM) { cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM); if (cpr != null) { cpi = cpr.info; if (isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) { userId = UserHandle.USER_SYSTEM; checkCrossUser = false; } else { cpr = null; cpi = null; } } } ProcessRecord dyingProc = null; if (cpr != null && cpr.proc != null) { providerRunning = !cpr.proc.killed; } .................... if (providerRunning) { cpi = cpr.info; String msg; if (r != null && cpr.canRunHere(r)) { ...............// 做权限检查 // 判断这个ContentProvider能够在调用者的进程中直接运行, // 就不建立调用者和当前运行进程的连接,而是使调用者启动自己的 // ContentProvider 实例(通过设置 holder.provider = null),向调用者返回 ContentProviderHolder。 ContentProviderHolder holder = cpr.newHolder(null); holder.provider = null; return holder; } ............// 权限检查 final long origId = Binder.clearCallingIdentity(); checkTime(startTime, "getContentProviderImpl: incProviderCountLocked"); // 不能在调用者进程运行,需要连接到服务端进程,就获取一个 ContentProviderConnection, // 同时增加提供程序的引用计数。如果这个连接的总引用计数为 1 // 需要更新 LruProcess 列表。最后还要调整 OOM Adj。 conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, stable); if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { if (cpr.proc != null && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { checkTime(startTime, "getContentProviderImpl: before updateLruProcess"); mProcessList.updateLruProcessLocked(cpr.proc, false, null); checkTime(startTime, "getContentProviderImpl: after updateLruProcess"); } } .................. // 之后的代码更多的是进行OOMAdj或者LRU的调整,各位同学可自行分析 } // 如果ContentProvider进程没有运行 if (!providerRunning) { try { checkTime(startTime, "getContentProviderImpl: before resolveContentProvider"); // 查询PMS,得到指定的ProviderInfo信息 cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); checkTime(startTime, "getContentProviderImpl: after resolveContentProvider"); } catch (RemoteException ex) { } if (cpi == null) { return null; } // 判断ContentProvider是否为单例 boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r == null ? callingUid : r.uid, cpi.applicationInfo.uid); if (singleton) { userId = UserHandle.USER_SYSTEM; } ...............// 各种权限检查 ComponentName comp = new ComponentName(cpi.packageName, cpi.name); checkTime(startTime, "getContentProviderImpl: before getProviderByClass"); cpr = mProviderMap.getProviderByClass(comp, userId); checkTime(startTime, "getContentProviderImpl: after getProviderByClass"); boolean firstClass = cpr == null; // 初次启动ContentProvider,firstClass为true if (firstClass) { final long ident = Binder.clearCallingIdentity(); ...............// 权限检查 try { checkTime(startTime, "getContentProviderImpl: before getApplicationInfo"); // 通过PMS获取ContentProvider 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); } ................ } checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord"); // 与前一段代码类似,判断ContentProvider是否可以直接运行在调用者的进程 if (r != null && cpr.canRunHere(r)) { return cpr.newHolder(null); } // 遍历mLaunchingProviders,检查之前是否已经安排启动该ContentProvider final int N = mLaunchingProviders.size(); int i; for (i = 0; i < N; i++) { if (mLaunchingProviders.get(i) == cpr) { break; } } // 如果没有找到则尝试启动它 if (i >= N) { final long origId = Binder.clearCallingIdentity(); try { try { checkTime(startTime, "getContentProviderImpl: before set stopped state"); // 通过PMS,调用 PackageManager.setStoppedState 方法,使应用不能被停止; AppGlobals.getPackageManager().setPackageStoppedState( cpr.appInfo.packageName, false, userId); checkTime(startTime, "getContentProviderImpl: after set stopped state"); } ............ // 尝试获取应用的ProcessRecord,如果获取成功, // 调用其 ActivityThread.scheduleInstallProvider 方法; ProcessRecord proc = getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false); if (proc != null && proc.thread != null && !proc.killed) { if (!proc.pubProviders.containsKey(cpi.name)) { checkTime(startTime, "getContentProviderImpl: scheduling install"); proc.pubProviders.put(cpi.name, cpr); try { // 获取成功,调用scheduleInstallProvider方法 proc.thread.scheduleInstallProvider(cpi); } catch (RemoteException e) { } } } else { checkTime(startTime, "getContentProviderImpl: before start process"); // 如果获取失败,说明应用进程没有启动,调用 AMS的 startProcessLocked 方法启动该进程 proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, new HostingRecord("content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name)), ZYGOTE_POLICY_FLAG_EMPTY, 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 变量,将其加入到 mLaunchingProviders 中。 cpr.launchingApp = proc; mLaunchingProviders.add(cpr); } finally { Binder.restoreCallingIdentity(origId); } } ................. // 如果是首次启动,向 mProviderMap 添加 ComponentName 记录; if (firstClass) { mProviderMap.putProviderByClass(comp, cpr); } // 向 mProviderMap 添加 authorities 的记录; mProviderMap.putProviderByName(name, cpr); // 尝试获取 ContentProviderConnection,设定其 waiting 标志为 true。 conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, stable); if (conn != null) { conn.waiting = true; } } checkTime(startTime, "getContentProviderImpl: done!"); grantImplicitAccess(userId, null /*intent*/, callingUid, UserHandle.getAppId(cpi.applicationInfo.uid)); } // 等待内容提供程序启动完成并发布。当前设置的超时时间 // CONTENT_PROVIDER_WAIT_TIMEOUT = 20000,单位毫秒,也就是 20 秒。 final long timeout = SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS; boolean timedOut = false; synchronized (cpr) { while (cpr.provider == null) { // 判断前面设置启动是否顺利,如果出错了,直接返回null if (cpr.launchingApp == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": launching app became null"); EventLogTags.writeAmProviderLostProcess( UserHandle.getUserId(cpi.applicationInfo.uid), cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name); return null; } try { // cpr 将等待 cpr.provider 就绪,直到超时时间已过或 publishContentProviders 方法调用 notify 唤醒线程。 // 如果超时时间已过,就返回 null。 final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis()); if (DEBUG_MU) Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms"); if (conn != null) { conn.waiting = true; } // 等待ContentProvider就绪 cpr.wait(wait); if (cpr.provider == null) { timedOut = true; break; } } catch (InterruptedException ex) { } finally { if (conn != null) { conn.waiting = false; } } } } if (timedOut) { ............. // 超时处理 } return cpr.newHolder(conn); } } |
好了,getContentProviderImpl
方法的内容非常的多,建议同学们详细的多看几次就好了。getContentProviderImpl
方法的内容虽然很多,但是我们记下来关注的地方是两个,一个是如果此前该ContentProvider
已经尝试启动了,则调用scheduleInstallProvider
来等待其启动。如果之前ContentProvider
还没有尝试启动,则调用startProcessLocked
进行进程的创建和启动
scheduleInstallProvider方法分析
上一节说到,在获取ContentProvider
的过程中会先尝试获取应用的ProcessRecord,如果获取成功,调用其 ActivityThread.scheduleInstallProvider
方法,接下来我们就简要分析下这个scheduleInstallProvider
方法,该方法是现在ActivityThread.java
文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
public void scheduleInstallProvider(ProviderInfo provider) { sendMessage(H.INSTALL_PROVIDER, provider); } public void handleMessage(Message msg) { ................ case INSTALL_PROVIDER: handleInstallProvider((ProviderInfo) msg.obj); break; ................ } public void handleInstallProvider(ProviderInfo info) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { installContentProviders(mInitialApplication, Arrays.asList(info)); } finally { StrictMode.setThreadPolicy(oldPolicy); } } private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<ContentProviderHolder> results = new ArrayList<>(); for (ProviderInfo cpi : providers) { if (DEBUG_PROVIDER) { StringBuilder buf = new StringBuilder(128); buf.append("Pub "); buf.append(cpi.authority); buf.append(": "); buf.append(cpi.name); Log.i(TAG, buf.toString()); } ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } try { ActivityManager.getService().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } |
调用的流程如上,可以看到最后也是调用installProvider
来进行ContentProvider的安装,这个方法我们在前面分析acquireProvider
的时候有看到过,这个也一样留到最后做分析。只是要注意的是,当前调用installProvider
的第二个参数传递的是null,而在acquireProvider
中是有传递ContentProviderHolder
对象参数的。
startProcessLocked简要分析
startProcessLocked
是启动新进程会调用的一个流程,整个流程比较复杂,中间有很多流程是和我们分析ContentProvider没有太多关联的,所以就只给出startProcessLocked
过程中的调用流程,总体流程可以参考下面的调用流程图做分析:
上面之分析到Zygote
fork部分,到最后就和Zygote
启动新进程的流程一样了,这部分网上教程也比较多,可以参考下图二(之前从网上保存的图,原出处找不到了),因为startProcessLocked
过程中会传递参数android.app.ActivityThread
,如下图一,在后续通过反射创建ActivityThread
。所以下面的流程图(如图二)就从`ActivityThread开始了
在Zygote启动进程的过程中,会进行ContentProvider
的安装,从流程图可以看到最后也是会调用到installContentProviders
。在scheduleInstallProvider
一节我们可以看到,installContentProviders
最后也还是会调用到installProvider
来进行的,所以这几个地方最后最后都是会跑到installProvider
方法来执行。
installProvider分析
终于来到installProvider
方法了,这个方法在前面已经出现过三次了
- 第一次是在
acquireProvider
过程中,最后会通过installProvider
安装内容提供器,此第二个参数传递的是ContentProviderHolder
实例对象,此时代码运行在调用着进程中 - 第二次是在
scheduleInstallProvider
调用过程中,此时第二个参数传递的是null - 第三次是在
startProcessLocked
调用过程中,此时第二个参数传递的也是null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
private ContentProviderHolder installProvider(Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; IContentProvider provider; // 如果holder为null,对应上述后面两种情况 if (holder == null || holder.provider == null) { ........... Context c = null; ApplicationInfo ai = info.applicationInfo; // 下面这个if判断的作用就是为该ContentProvider找到对应的Application。 // 在AndroidManifest.xml中,ContentProvider是Application的子标签,所以 // ContentProvider和Application有一种对应关系。 if (context.getPackageName().equals(ai.packageName)) { c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { c = mInitialApplication; } else { try { // 创建Context,指向对应的APK c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } } .............. try { // 为什么一定要找到对应的Context呢?除了ContentProvider和Application的 // 对应关系外,还有一个决定性原因:即只有对应的Context才能加载对应APK的Java字节码, // 从而可通过反射机制生成ContentProvider实例 final java.lang.ClassLoader cl = c.getClassLoader(); LoadedApk packageInfo = peekPackageInfo(ai.packageName, true); if (packageInfo == null) { // System startup case. packageInfo = getSystemContext().mPackageInfo; } // instantiateProvider方法内部通过Java反射机制得到真正的ContentProvider localProvider = packageInfo.getAppFactory() .instantiateProvider(cl, info.name); // 从ContentProvider中取出其mTransport成员 provider = localProvider.getIContentProvider(); if (provider == null) { ............. return null; } // 初始化该ContentProvider,attachInfo内部会调用其onCreate函数 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 { // 如果holder不为null,对应上述第一种情况 // 直接从ContentProviderHolder中取出provider provider = holder.provider; if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": " + info.name); } ContentProviderHolder retHolder; synchronized (mProviderMap) { if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider + " / " + info.name); IBinder jBinder = provider.asBinder(); // localProvider != null,说明之前走了 holder.provider == null 的分支 // 获取了本地的 ContentProvider 实例 if (localProvider != null) { // 尝试从 mLocalProvidersByName 查询对应的 ProviderClientRecord ComponentName cname = new ComponentName(info.packageName, info.name); ProviderClientRecord pr = mLocalProvidersByName.get(cname); // 如果找到ProviderClientRecord对象,则直接返回其 mProvider 成员; if (pr != null) { if (DEBUG_PROVIDER) { Slog.v(TAG, "installProvider: lost the race, " + "using existing local provider"); } provider = pr.mProvider; } else { // 如果没有找到ProviderClientRecord对象,创建新的 ContentProviderHolder 对象, // 存入所需信息,调用installProviderAuthoritiesLocked 注册; holder = new 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说明引用了已有的 ContentProvider: } else { // 尝试从 mProviderRefCountMap 查询对应的 ProviderRefCount ProviderRefCount prc = mProviderRefCountMap.get(jBinder); // 如果找到ProviderRefCount对象,更新其引用计数 if (prc != null) { if (DEBUG_PROVIDER) { Slog.v(TAG, "installProvider: lost the race, updating ref count"); } if (!noReleaseNeeded) { incProviderRefLocked(prc, stable); try { ActivityManager.getService().removeContentProvider( holder.connection, stable); } catch (RemoteException e) { //do nothing content provider object is dead any way } } // 如果没有找到ProviderRefCount对象,调用 installProviderAuthoritiesLocked 注册 // 创建新的引用计数,存入 mProviderRefCountMap; } else { ProviderClientRecord client = installProviderAuthoritiesLocked( provider, localProvider, holder); if (noReleaseNeeded) { prc = new ProviderRefCount(holder, client, 1000, 1000); } else { prc = stable ? new ProviderRefCount(holder, client, 1, 0) : new ProviderRefCount(holder, client, 0, 1); } mProviderRefCountMap.put(jBinder, prc); } // 使用ProviderRefCount 的 holder 成员作为返回的对象 retHolder = prc.holder; } } return retHolder; } |
installProvider
的内容比较简单,方法最后返回获取的 ContentProviderHolder
对象,其中详细的情况同学们可以看上述代码中的注释。
OK,关于获取ContentProvider的获取流程就到这里结束了。