Android ContentProvider原理分析
目录
- ContentProvider概述
- 类图
- 时序图
- 源码解析
- installProvider
- ContentResolver中的CURD
- acquireProvider
- 到AMS获取ContentProvider
- publishContentProvider
- removeDyingProvider
- 总结
1. ContentProvider概述
ContentProvider作为Android四大组件之一,重要性肯定是不言而喻的,顾名思义,内容提供者,其最重要的作用就在于提供了一种跨进程获取数据的方式,provider组件不仅可以自己的进程使用,还可以提供给其他的进程使用,大大方便了不同进程之间的数据交换,本文将详细介绍provider运行的原理。
注:本文基于Android 8.1
2. 类图
看起来涉及到的类非常多,一下有种不知道从何看起的感觉,所以这里对于其中的重点关注部分加上了颜色:
白色:provider运行过程中涉及到的内部类或私有类,一般APP开发过程中不太会涉及
蓝色:APP开发过程中经常会接触到的类
紫色:在system server
进程中provider相关的类
3. 时序图
其中白色部分:发起获取provider的client进程
红色部分:systemserver进程
蓝色部分:提供provider的server进程
时序图解读:
- 1~4流程是在APP自己的进程(进程A)中,一般来讲APP在进程启动之后初始化时,就会installProvider(流程7~10),如果APP请求的provider在自己进程,那么到4就能获取到。
- 如果请求的provider另外一个进程(进程B)中,则会触发进程5~6
- 如果进程B不存在则先启动进程B并installprovider(7~10),告诉AMS之后,由AMS返回给进程A对方的provider信息(此过程中由进程A发起的请求provider的线程会一直等待)
- 如果进程B存在则AMS直接返回给进程A对方的provider信息
- 查询到provider信息之后,如果需要跨进程调用,则通过ContentProviderProxy发起binder call到对端进程执行query
在这其中,AMS充当一个中间管理员的角色,每个进程在启动之后需要把自己应该install的providerinstall之后告诉AMS,这样后面有其他进程请求这个provider的话,AMS可以告诉你所请求的对端的信息。
4. 源码解析
4.1 ActivityThread.installProvider
installProvider,顾名思义就是安装provider,说的通俗一点就是把APP进程中的provider组件封装成对象保存起来,方便使用
在APP的进程启动的时候,handleBindApplication中会触发installProvider:
private void installContentProviders( Context context, List providers) { // 此处的provider信息是在AMS启动进程时 // 从manifest收集到的需要install的provider信息 final ArrayList results = new ArrayList<>(); for (ProviderInfo cpi : providers) { // 执行installProvider,注意此处的stable参数默认为true ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } try { // install完成之后,要告诉AMS ActivityManager.getService().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } }
进一步看一下ActivityThread.installProvider的具体实现
private ContentProviderHolder installProvider(Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; IContentProvider provider; // holder为null表示还没有install过 if (holder == null || holder.provider == null) { Context c = null; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { c = mInitialApplication; } else { try { // 创建context c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } } ... try { final java.lang.ClassLoader cl = c.getClassLoader(); // 通过反射创建provider对象 localProvider = (ContentProvider)cl. loadClass(info.name).newInstance(); // 获取IContentProvider对象,用于跨进程binder call provider = localProvider.getIContentProvider(); if (provider == null) { Slog.e(TAG, "Failed to instantiate class " + info.name + " from sourceDir " + info.applicationInfo.sourceDir); return null; } // provider的attach,其中最重要的是会执行provider的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 { provider = holder.provider; } // 到这里,provider的对象创建好了,那么接下来需要做的就是数据结构的封装 // 把provider相关信息保存起来 ContentProviderHolder retHolder; // mProviderMap的key时providerKey,value是ProviderClientReocrd // 这两个类主要是封装了一些provider的基本信息,可以到上面看一下类图 synchronized (mProviderMap) { IBinder jBinder = provider.asBinder(); if (localProvider != null) { ComponentName cname = new ComponentName(info.packageName, info.name); // mLocalProvidersByName的key是component信息,value是对应的ProviderClientReocrd ProviderClientRecord pr = mLocalProvidersByName.get(cname); if (pr != null) { // 不为空代表install过 provider = pr.mProvider; } else { // 对于新创建的provider,创建其对应的ContentProviderHolder对象 holder = new ContentProviderHolder(info); holder.provider = provider; holder.noReleaseNeeded = true; // install Authorities pr = installProviderAuthoritiesLocked(provider, localProvider, holder); // mLocalProviders的key是IContentProvider的binder对象,value是ProviderClientRecord // 将封装好的provider放入map中 mLocalProviders.put(jBinder, pr); mLocalProvidersByName.put(cname, pr); } retHolder = pr.mHolder; } else { // mProviderRefCountMap的key是binder对象,value是ProviderRefCount // ProviderRefCount中记录了这个provider的stable和unstable的数量 ProviderRefCount prc = mProviderRefCountMap.get(jBinder); if (prc != null) { if (!noReleaseNeeded) { incProviderRefLocked(prc, stable); try { ActivityManager.getService().removeContentProvider( holder.connection, stable); } catch (RemoteException e) { } } } else { ProviderClientRecord client = installProviderAuthoritiesLocked( provider, localProvider, holder); if (noReleaseNeeded) { // 创建ProviderRefCount prc = new ProviderRefCount(holder, client, 1000, 1000); } else { // 根据参数中的stable和unstable创建对象 prc = stable ? new ProviderRefCount(holder, client, 1, 0) : new ProviderRefCount(holder, client, 0, 1); } // 放入map mProviderRefCountMap.put(jBinder, prc); } retHolder = prc.holder; } } return retHolder; }
这里需要提一下其中的getIContentProvider:
返回的是一个Transport对象,而这又是ContentProviderNative的子类,主要作用就是用来binder通信的
它的创建:在ContentProvider类中
private Transport mTransport = new Transport();
也就是说在对象创建的时候就默认创建了
然后是ActivityThread.installProviderAuthoritiesLocked
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, ContentProvider localProvider, ContentProviderHolder holder) { final String auths[] = holder.info.authority.split(";"); final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid); if (provider != null) { for (String auth : auths) { // 对于一些特殊的auth,允许跨进程binder call // Binder.allowBlocking代表允许执行同步的binder call switch (auth) { case ContactsContract.AUTHORITY: case CallLog.AUTHORITY: case CallLog.SHADOW_AUTHORITY: case BlockedNumberContract.AUTHORITY: case CalendarContract.AUTHORITY: case Downloads.Impl.AUTHORITY: case "telephony": Binder.allowBlocking(provider.asBinder()); } } } // 创建ProviderClientRecord final ProviderClientRecord pcr = new ProviderClientRecord( auths, provider, localProvider, holder); for (String auth : auths) { // 根据auth和userId创建ProviderKey,放入mProviderMap final ProviderKey key = new ProviderKey(auth, userId); final ProviderClientRecord existing = mProviderMap.get(key); if (existing != null) { Slog.w(TAG, "Content provider " + pcr.mHolder.info.name + " already published as " + auth); } else { mProviderMap.put(key, pcr); } } return pcr; }
小结:
- 创建了provider对象,其中也创建了IContentProvider对象(Transport)
- 创建ContentProviderHolder
- 创建ProviderKey
- 创建ProviderClientRecord,这是一个provider在client进程中对应的对象
- 分别放入
mProviderMap
/mLocalProviders
/mLocalProvidersByName
- 创建ProviderRefCount,放入
mProviderRefCountMap
这里先说一下
stable
和unstable
:
- 代表的是client和server的链接,主要取决于获取provider的传参,默认情况下,insert/update/delete建立的链接都是stable,而query则是unstable,不过在query的时候如果失败,还会重新创建stable
- stable和unstable最重大的差别在于unstable的情况下,即使对端挂掉了,client也没关系,但是stable的话,如果对端进程挂掉了,client也会被跟着级联kill掉。(后面会介绍)
4.2 ContentResolver中的CURD
4.2.1 ContentResolver.insert
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, @Nullable ContentValues values) { Preconditions.checkNotNull(url, "url"); // 请求provider,经过调用之后,最终传参获取的是stable类型provider IContentProvider provider = acquireProvider(url); if (provider == null) { throw new IllegalArgumentException("Unknown URL " + url); } try { long startTime = SystemClock.uptimeMillis(); // 执行通过IContentProvider执行insert,其实是发起了binder call到了provider所在进程执行 Uri createdRow = provider.insert(mPackageName, url, values); long durationMillis = SystemClock.uptimeMillis() - startTime; maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); return createdRow; } catch (RemoteException e) { return null; } finally { releaseProvider(provider); } }
ContentResolver.delete
:执行provider的delete
ContentResolver.update
:执行provider的update
ContentResolver.call
:执行provider的call,这个比较灵活,传递的参数比较多,不固定于某一个
这三个方法的实现都跟instert基本类似,此处不再罗列
下面需要重点说一下query
:
4.2.2 query
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { Preconditions.checkNotNull(uri, "uri"); // 这里执行的方法是acquireUnstableProvider // 也就是说建立的链接是unstable类型 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 { // 执行query qCursor = unstableProvider.query(mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } catch (DeadObjectException e) { // 如果query失败 // 因为unstable类型,失败代表对端挂掉了,那么重新请求stable类型链接 unstableProviderDied(unstableProvider); stableProvider = acquireProvider(uri); if (stableProvider == null) { return null; } // 再次query qCursor = stableProvider.query( mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } if (qCursor == null) { return null; } qCursor.getCount(); long durationMillis = SystemClock.uptimeMillis() - startTime; final IContentProvider provider = (stableProvider != null) ? stableProvider : acquireProvider(uri); final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); stableProvider = null; qCursor = null; return wrapper; } catch (RemoteException e) { ... } }
- query的时候先建立的unstable链接,然后发起了binder call
- 如果catchRemoteException,那说明对段进程挂了,此时重新请求stable类型链接把对方进程拉起来,再执行query
4.3 ActivityThread.acquireProvider
public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { // 如果已经存在则直接返回 final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } ContentProviderHolder holder = null; // 如果不存在则需要向AMS查询 try { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); return null; } // 在本进程中installProvider holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider; }
到这里可能有有一些迷糊,前面已经installProvider过了,为什么acquireProvider的时候需要再install一次呢?
答案是因为这是两个不同的进程
- 在bindApplication的时候执行的installProvider是提供provider的进程,也就是server进程
- 而在此处查询的则是需要获取provider的进程,也就是client进程
- server进程installProvider的作用是为了自己进程内使用的话在
acquireExistingProvider
的时候就能查到了,不需要在跨进程到AMS去查询 - client进程installProvider的作用是经过了一次向AMS的查询之后,客户端就可以缓存起来,这样就不用每次都向AMS查询
4.3.1 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()) { // 对端进程挂掉了 handleUnstableProviderDiedLocked(jBinder, true); return null; } ProviderRefCount prc = mProviderRefCountMap.get(jBinder); if (prc != null) { // 增加引用计数 incProviderRefLocked(prc, stable); } return provider; } }
4.4 ActivityManagerService.getContentProvider
public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { enforceNotIsolatedCaller("getContentProvider"); if (caller == null) { String msg = "null IApplicationThread when getting content provider " + name; Slog.w(TAG, msg); throw new SecurityException(msg); } return getContentProviderImpl(caller, name, null, stable, userId); }
简单对caller进行了判断,重点在getContentProviderImpl
4.4.1 getContentProviderImpl
方法比较长,删除了其中一些无用的log以及checkTime
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; ProviderInfo cpi = null; synchronized(this) { // 对caller判断 boolean checkCrossUser = true; // 在AMS的providermap中先看看是不是已经存在了 cpr = mProviderMap.getProviderByName(name, userId); // 如果不存在且system,校验Singleton,也就是只能有一个 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.uid, cpi.applicationInfo.uid)) { userId = UserHandle.USER_SYSTEM; checkCrossUser = false; } else { cpr = null; cpi = null; } } } // 看看这个provider当前是不是已经在运行了 boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed; // 如果已经在运行了,也就说明各个数据结构都已经添加过了,进程也都已经存在了 if (providerRunning) { cpi = cpr.info; if (r != null && cpr.canRunHere(r)) { // canRunHere主要针对自己请求的provider在自己进程中的情况,一般不会遇到 ContentProviderHolder holder = cpr.newHolder(null); holder.provider = null; return holder; } ... final long origId = Binder.clearCallingIdentity(); // 建立provider之间的链接 conn = incProviderCountLocked(r, cpr, token, stable); // 需要更新lru队列 if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { updateLruProcessLocked(cpr.proc, false, null); } } final int verifiedAdj = cpr.proc.verifiedAdj; // 更新进程优先级 boolean success = updateOomAdjLocked(cpr.proc, true); if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) { success = false; } // 记录usageStates maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name); if (!success) { // 更新lru失败代表那个进程挂掉了 boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); // 需要处理进程挂掉的流程 // 并且标志provider当前不在运行状态,这样会走进下面的provider不在运行的流程中 appDiedLocked(cpr.proc); if (!lastRef) { return null; } providerRunning = false; conn = null; } else { cpr.proc.verifiedAdj = cpr.proc.setAdj; } Binder.restoreCallingIdentity(origId); } // 如果provider当前不在运行 if (!providerRunning) { try { // 先从packageManager那边查询到相关的信息 cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); } catch (RemoteException ex) { } // 没查到的话那就说明这个是一个无效的provider if (cpi == null) { return null; } boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid); if (singleton) { userId = UserHandle.USER_SYSTEM; } // 获取applicationInfo cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); String msg; if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) != null) { throw new SecurityException(msg); } // 在system启动之前不允许非system的进程获取provider if (!mProcessesReady && !cpi.processName.equals("system")) { throw new IllegalArgumentException( "Attempt to launch content provider before system ready"); } // 校验user是否正在运行中 if (!mUserController.isUserRunningLocked(userId, 0)) { 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); // 从getProviderByClass中获取,看看这个provider是不是AMS这边已经有保存了 // 如果没有,代表这个provider从来没有向AMS注册过 // 此时需要创建一个新的ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId); final boolean firstClass = cpr == null; if (firstClass) { final long ident = Binder.clearCallingIdentity(); if (mPermissionReviewRequired) { if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) { return null; } } try { ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId); 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); } } ... // 看看当前请求的provider是不是在mLaunchingProviders // 如果一个 provider被请求过,但是因为对方进程没有启动没有publishProvider // 则会加入mLaunchingProviders中 final int N = mLaunchingProviders.size(); int i; for (i = 0; i < N; i++) { if (mLaunchingProviders.get(i) == cpr) { break; } } // launching中没有 if (i >= N) { final long origId = Binder.clearCallingIdentity(); try { try { AppGlobals.getPackageManager().setPackageStoppedState( cpr.appInfo.packageName, false, userId); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + cpr.appInfo.packageName + ": " + e); } // 看看这个进程是不是存在 ProcessRecord proc = getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false); if (proc != null && proc.thread != null && !proc.killed) { // 如果进程已经存在,那么就让这个进程去installProvider即可 if (!proc.pubProviders.containsKey(cpi.name)) { proc.pubProviders.put(cpi.name, cpr); try { proc.thread.scheduleInstallProvider(cpi); } catch (RemoteException e) { } } } else { // 如果进程不存在,那就得先启动进程 // 因为provider必然运行在某一个进程中,对端进程不在肯定无法获取provider proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false); if (proc == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": process is bad"); return null; } } // 因为需要启动进程,记录这个provider的launchingApp // 并把这个provider加入到mLaunchingProviders中,等待对方publish之后 // 再从mLaunchingProviders中移除 cpr.launchingApp = proc; mLaunchingProviders.add(cpr); } finally { Binder.restoreCallingIdentity(origId); } } // 如果是第一次创建的provider,还需要放入mProviderMap if (firstClass) { mProviderMap.putProviderByClass(comp, cpr); } mProviderMap.putProviderByName(name, cpr); // 建立privier之间的链接 conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null) { conn.waiting = true; } } grantEphemeralAccessLocked(userId, null /*intent*/, cpi.applicationInfo.uid, UserHandle.getAppId(Binder.getCallingUid())); } // 代码执行到这里就说明当前的provider不存在,需要等待对端publish synchronized (cpr) { while (cpr.provider == null) { ... try { if (conn != null) { conn.waiting = true; } // 在需要获取的provider上wait // 直到对端provider被publish之后,方可notify cpr.wait(); } catch (InterruptedException ex) { } finally { if (conn != null) { conn.waiting = false; } } } } return cpr != null ? cpr.newHolder(conn) : null; }
这段逻辑比较长,总结来说流程如下:
- 校验caller/权限等
- 如果provider已经在运行,那么建立连接
- 更新进程优先级,如果更新失败则代表进程被kill了,标记provider不在运行状态
- provider不在运行状态,则需要看一下provider是否mProviderMap中曾经有记录
- 如果没有需要创建新的ContentProviderRecord对象,并加到mProviderMap
- 判断进程是否存在
- 如果进程存在则直接调度进程installProvider
- 如果进程不存在则需要先启动进程
- 添加mProviderMap以及mLaunchingProviders
- 在需要获取的provider上等待对方notify
4.4.2 incProviderCountLocked
ContentProviderConnection incProviderCountLocked(ProcessRecord r, final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) { if (r != null) { for (int i=0; i
这个方法相对简单,所以没有写太多注释,就是根绝provider是否存在以及是否stable,记录stable和unstable的数量
4.5 ActivityManagerService.publishContentProviders
上面的流程中多次提到进程启动的时候会installProvider以及publishContentProviders
,接下来就来看一下到底是怎么回事,在前面4.1
节中也有提到,在installProvider之后,会通过binder call告诉AMS,publishContentProvider:
public final void publishContentProviders(IApplicationThread caller, List providers) { if (providers == null) { return; } enforceNotIsolatedCaller("publishContentProviders"); synchronized (this) { final ProcessRecord r = getRecordForAppLocked(caller); if (r == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when publishing content providers"); } final long origId = Binder.clearCallingIdentity(); final int N = providers.size(); // 遍历所有已经安装的provider for (int i = 0; i < N; i++) { ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null) { continue; } ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (dst != null) { // 将这个providerRecord放入到mProviderMap中 ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); mProviderMap.putProviderByClass(comp, dst); String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.putProviderByName(names[j], dst); } int launchingCount = mLaunchingProviders.size(); int j; // 从mLaunchingProviders中移除 boolean wasInLaunchingProviders = false; for (j = 0; j < launchingCount; j++) { if (mLaunchingProviders.get(j) == dst) { mLaunchingProviders.remove(j); wasInLaunchingProviders = true; j--; launchingCount--; } } if (wasInLaunchingProviders) { mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); } // notify当前正在等待这个provider呗publish的所有的binder线程 synchronized (dst) { dst.provider = src.provider; dst.proc = r; dst.notifyAll(); } // 更新进程优先级 updateOomAdjLocked(r, true); maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority); } } Binder.restoreCallingIdentity(origId); } }
- 把所有的已经install的Provider放入到mProviderMap,简而言之相当于是注册,让AMS知道这个provider已经在运行了
- 把provider从从mLaunchingProviders中移除
- 通知等待在这个provider上的binder线程,那些binder线程就可以拿到provider信息返回各自进程继续干活了
4.6 removeDyingProvider
前面多次说了stable与unstable,而且前面基本都是在操作计数,那么到底什么时候会用到这个计数呢?
重点就在这个removeDyingProviderLocked
,这个方法作用是当一个进程死亡之后,把其中的所有的provider也remove掉:
private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) { final boolean inLaunching = mLaunchingProviders.contains(cpr); // 如果这个provider还在等待launching就被remove了 // 需要把当前等待这个provider的线程都notifyAll,否则就再也没有机会notify了 if (!inLaunching || always) { synchronized (cpr) { cpr.launchingApp = null; cpr.notifyAll(); } // 从mProviderMap中移除 mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid)); String names[] = cpr.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid)); } } // 判断这个provider上的所有链接 for (int i = cpr.connections.size() - 1; i >= 0; i--) { ContentProviderConnection conn = cpr.connections.get(i); if (conn.waiting) { if (inLaunching && !always) { continue; } } ProcessRecord capp = conn.client; conn.dead = true; // 如果stableCount大于0,也就是说存在stable的链接 // server挂掉了,那么就会把client也给kill掉 // 这正是我们前面提到的stable和unstable的重大区别 if (conn.stableCount > 0) { if (!capp.persistent && capp.thread != null && capp.pid != 0 && capp.pid != MY_PID) { capp.kill("depends on provider " + cpr.name.flattenToShortString() + " in dying proc " + (proc != null ? proc.processName : "??") + " (adj " + (proc != null ? proc.setAdj : "??") + ")", true); } } else if (capp.thread != null && conn.provider.provider != null) { try { capp.thread.unstableProviderDied(conn.provider.provider.asBinder()); } catch (RemoteException e) { } cpr.connections.remove(i); if (conn.client.conProviders.remove(conn)) { stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name); } } } if (inLaunching && always) { mLaunchingProviders.remove(cpr); } return inLaunching; }
5. 总结
经过上面的解读,主要需要了解到的有以下几点:
- application初始化的时候会installProvider
- 向AMS请求provider的时候如果对端进程不存在则请求的那个线程需要一直等待
- 当对方的进程启动之后并publish之后,请求provider的线程才可返回,所以尽量不要在主线程请求provider
- 请求provider分为stable以及unsbale,stable类型链接在server进程挂掉之后,client进程会跟着被株连kill
insert/delete/update
默认建立stable链接,query默认建立unstable链接,如果失败会重新建立stable链接- AMS作为一个中间管理员的身份,所有的provider会向它注册
- 向AMS请求到provider之后,就可以在client和server之间自行binder通信,不需要再经过systemserver
更多相关文章
- android超链接
- android中将静态库链接进动态库成功的例子
- 在android中获取系统正在运行的进程
- Android Audio代码分析21 - 创建AudioEffect对象
- Android Training精要(六)如何防止Bitmap对象出现OOM
- android textView加载html 解决a标签链接无效
- android 获取当前运行进程的名称
- 《Android开发艺术探索》读书笔记--part2 IPC进程间通信机制