赞
踩
请支持原创~~~
相关博文:
android 中的 ContentObserver 应用举例
android 中的 ContentObserver 原理详解
基于版本:Android R
很早以前分析过service(Android 中service 详解) 和broadcast receiver(android 中的 Broadcast 机制详解) 的机制,最近在回顾的时候发现少了ContentProvider 和 Activity 的流程,抽些时间补充。这一篇主要分析ContentProvider 的原理。
《Android基础总结之八:ContentProvider》中举例说明ContentProvider 的调用流程,涉及到的接口比较多,我们这里以query 为入口进行剖析。
调用接口类似:
- ContentResolver cr = mContext.getContentResolver();
- cr.query(...);
使用ContentResolver的原因:
frameworks/base/core/java/android/app/ContextImpl.java
- @Override
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
- private ContextImpl(...) {
- ...
- mContentResolver = new ApplicationContentResolver(this, mainThread);
- }
- private static final class ApplicationContentResolver extends ContentResolver {
- @UnsupportedAppUsage
- private final ActivityThread mMainThread;
-
- public ApplicationContentResolver(Context context, ActivityThread mainThread) {
- super(context);
- mMainThread = Objects.requireNonNull(mainThread);
- }
-
- ...
- }
ContentResolver的源头是ApplicationContentResolver,继承自ContentResolver。
ApplicationContentResolver中记录这App 的context 和mainThread。
frameworks/base/core/java/android/content/ContentResolver.java
- public abstract class ContentResolver implements ContentInterface {
- ...
-
- public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
- @Nullable String[] projection, @Nullable String selection,
- @Nullable String[] selectionArgs, @Nullable String sortOrder) {
- ...
- }
-
- public final @Nullable String getType(@NonNull Uri url) {
- ...
- }
-
- public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
- @Nullable ContentValues values) {
- ...
- }
-
- public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
- @Nullable String[] selectionArgs) {
- ...
- }
-
- public final int update(@RequiresPermission.Write @NonNull Uri uri,
- @Nullable ContentValues values, @Nullable String where,
- @Nullable String[] selectionArgs) {
- ...
- }
-
- public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
- ContentObserver observer, @UserIdInt int userHandle) {
- ...
- }
-
- public final void unregisterContentObserver(@NonNull ContentObserver observer) {
- ...
- }
- }

这里没有细列举,应为ContentResolver和ContentProvider 都是继承自interface ContentInterface,所以,query/insert/delete/update/getType 等接口都是需要实现的。在此基础上ContentResolver还负责ContentObserver的register 和unRegister 工作。
- public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
- @Nullable String[] projection, @Nullable Bundle queryArgs,
- @Nullable CancellationSignal cancellationSignal) {
- Objects.requireNonNull(uri, "uri");
-
- ...
-
- IContentProvider unstableProvider = acquireUnstableProvider(uri);
- if (unstableProvider == null) {
- return null;
- }
- IContentProvider stableProvider = null;
- Cursor qCursor = null;
- try {
- long startTime = SystemClock.uptimeMillis();
-
- ...
-
- try {
- qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
- queryArgs, remoteCancellationSignal);
- } catch (DeadObjectException e) {
- // The remote process has died... but we only hold an unstable
- // reference though, so we might recover!!! Let's try!!!!
- // This is exciting!!1!!1!!!!1
- unstableProviderDied(unstableProvider);
- stableProvider = acquireProvider(uri);
- if (stableProvider == null) {
- return null;
- }
- qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
- queryArgs, remoteCancellationSignal);
- }
- if (qCursor == null) {
- return null;
- }
-
- // Force query execution. Might fail and throw a runtime exception here.
- qCursor.getCount();
- long durationMillis = SystemClock.uptimeMillis() - startTime;
- maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
-
- // Wrap the cursor object into CursorWrapperInner object.
- final IContentProvider provider = (stableProvider != null) ? stableProvider
- : acquireProvider(uri);
- final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
- stableProvider = null;
- qCursor = null;
- return wrapper;
- } catch (RemoteException e) {
- ...
- } finally {
- ...
- }
- }

代码比较长,大概可以分以下几个部分:
- public final IContentProvider acquireUnstableProvider(Uri uri) {
- if (!SCHEME_CONTENT.equals(uri.getScheme())) {
- return null;
- }
- String auth = uri.getAuthority();
- if (auth != null) {
- return acquireUnstableProvider(mContext, uri.getAuthority());
- }
- return null;
- }
acquireUnstableProvider 是个抽象函数,实现在ApplicationContentResolver中:
frameworks/base/core/java/android/app/ContextImpl.java#ApplicationContentResolver
- protected IContentProvider acquireUnstableProvider(Context c, String auth) {
- return mMainThread.acquireProvider(c,
- ContentProvider.getAuthorityWithoutUserId(auth),
- resolveUserIdFromAuthority(auth), false);
- }
最终调用的是ActivityThread.acquireProvider。
frameworks/base/core/java/android/app/ActivityThread.java
- 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;
- }
-
- try {
- synchronized (getGetProviderLock(auth, userId)) {
- holder = ActivityManager.getService().getContentProvider(
- getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
- }
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- if (holder == null) {
- ...
- return null;
- }
-
- // Install provider will increment the reference count for us, and break
- // any ties in the race.
- holder = installProvider(c, holder, holder.info,
- true /*noisy*/, holder.noReleaseNeeded, stable);
- return holder.provider;
- }

大概分三部分:
这里的AMS.getContentProvider 以单独的一节讲解,详细请看第 3 节。
这里的installProvider 关注3.4.4节;
另外,最终获取到的provider proxy 是通过getIContentProvider 接口而来,或者的流程详细见3.4.4节,getIContentProvider 接口讲解看第 4 节。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- public final ContentProviderHolder getContentProvider(
- IApplicationThread caller, String callingPackage, String name, int userId,
- boolean stable) {
- ...
- return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
- null, stable, userId);
- }
-
getContentProviderImpl 代码比较长,这里分开剖析。
- private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token, int callingUid, String callingPackage, String callingTag,
- boolean stable, int userId) {
- ...
-
- synchronized(this) {
- ...
- ProcessRecord r = null;
- if (caller != null) {
- r = getRecordForAppLocked(caller);
- if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when getting content provider " + name);
- }
- }

根据传入的caller,类型为IApplicationThread,获得调用者App 的ProcessRecord,要求App 必须是存在的。
- // First check if this content provider has been published...
- cpr = mProviderMap.getProviderByName(name, userId);
下面的代码主要是根据provider 是否已经发布进行分段,主要分下面几个部分:
- if (providerRunning) {
- cpi = cpr.info;
- String msg;
-
- //当允许运行在调用者进程且已发布,则直接返回
- if (r != null && cpr.canRunHere(r)) {
- // 检查权限
- ...
-
- ContentProviderHolder holder = cpr.newHolder(null);
- holder.provider = null; //注意这里的provider 为null,详细见3.4.4
- return holder;
- }
-
- //如果provider不是在caller进程中,需要继续检查caller 的权限
- ...
-
- //权限检查ok,则返回已经存在的provider 的connection,并增加引用计数
- 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) {
- //更新进程LRU队列updateLruProcess");
- mProcessList.updateLruProcessLocked(cpr.proc, false, null);
- }
- }
-
-
- //更新进程adj
- final int verifiedAdj = cpr.proc.verifiedAdj;
- boolean success = updateOomAdjLocked(cpr.proc, true,
- OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
-
- if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
- success = false;
- }
- ...
- if (!success) {//如果失败了,provider进程已经被kill,减少引用计数
- boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- if (!lastRef) {
- // This wasn't the last ref our process had on
- // the provider... we will be killed during cleaning up, bail.
- return null;
- }
- // We'll just start a new process to host the content provider
- providerRunning = false;
- conn = null;
- dyingProc = cpr.proc;
- } else {
- cpr.proc.verifiedAdj = cpr.proc.setAdj;
- }
-
- ...
- }

如果ContentProvider 所在进程已经存在时:
注意:当允许运行在发布者的进程中时,holder.provider 为null,installProvider 函数中需要重新创建provider,详细见3.4.4节。
- if (!providerRunning) {
- try {
- //根据authority,获取ProviderInfo对象
- cpi = AppGlobals.getPackageManager().
- resolveContentProvider(name,
- STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
- } catch (RemoteException ex) {
- }
- if (cpi == null) {//不存在这个provider,则返回null
- return null;
- }
-
- //provider是否为system,或者是PHONE_UID或者是persistent app
- boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags)
- && isValidSingletonCall(r == null ? callingUid : r.uid,
- cpi.applicationInfo.uid);
- if (singleton) {//如果是标记UID 为system
- userId = UserHandle.USER_SYSTEM;
- }
- cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
-
- //check caller的权限
- ...
-
-
- ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
- cpr = mProviderMap.getProviderByClass(comp, userId);
- boolean firstClass = cpr == null;
- if (firstClass) {
- final long ident = Binder.clearCallingIdentity();
-
- ...
-
- 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);
- //创建对象ContentProviderRecord
- cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
- } catch (RemoteException ex) {
- // pm is in same process, this will never happen.
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- } else if (dyingProc == cpr.proc && dyingProc != null) {
- cpr = new ContentProviderRecord(cpr);
- // This is sort of "firstClass"
- firstClass = true;
- }
-
- if (r != null && cpr.canRunHere(r)) {
- //可以运行在caller 进程中,详细见3.4.4节
- return cpr.newHolder(null);
- }
-
- //从mLaunchingProviders中查询是否存在该cpr
- final int N = mLaunchingProviders.size();
- int i;
- for (i = 0; i < N; i++) {
- if (mLaunchingProviders.get(i) == cpr) {
- break;
- }
- }
-
- //当provider并没有处于mLaunchingProviders队列,则启动它
- if (i >= N) {
- final long origId = Binder.clearCallingIdentity();
-
- try {
- // Content provider is now in use, its package can't be stopped.
- 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
- ProcessRecord proc = getProcessRecordLocked(
- cpi.processName, cpr.appInfo.uid, false);
- if (proc != null && proc.thread != null && !proc.killed) {
- if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
- "Installing in existing process " + proc);
- if (!proc.pubProviders.containsKey(cpi.name)) {
- proc.pubProviders.put(cpi.name, cpr);
- try {
- //provider进程启动,发布provider
- proc.thread.scheduleInstallProvider(cpi);
- } catch (RemoteException e) {
- }
- }
- } else {
- 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);
- ...
- }
- cpr.launchingApp = proc;
- //将cpr添加到mLaunchingProviders
- mLaunchingProviders.add(cpr);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- // Make sure the provider is published (the same provider class
- // may be published under multiple names).
- if (firstClass) {
- mProviderMap.putProviderByClass(comp, cpr);
- }
-
- mProviderMap.putProviderByName(name, cpr);
- conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
- stable);
- if (conn != null) {
- conn.waiting = true;
- }
- }

如果ContentProvider 所在进程没有存在或被kill时:
发布ContentProvider 分两种情况:
对于此场景,system_server 进程调用startProcessLocked 创建provider进程,且attach 到system_server 后,通过binder call 到provider 进程执行ActivityThread.bindApplication 进行发布;
对于此场景,provider 进程已存在且attach 到system_server,但所对应的provider 还没有发布,通过binder call 到provider进程执行ActivityThread.scheduleInstallProvider 进行发布;
frameworks/base/core/java/android/app/ActivityThread.java
注意,这里是Provider 进程
- public void scheduleInstallProvider(ProviderInfo provider) {
- sendMessage(H.INSTALL_PROVIDER, provider);
- }
消息INSTALL_PROVIDER最终的处理函数为handleInstallProvider:
- public void handleInstallProvider(ProviderInfo info) {
- final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- installContentProviders(mInitialApplication, Arrays.asList(info));
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
frameworks/base/core/java/android/app/ActivityThread.java
注意,这里是provider进程
- private void handleBindApplication(AppBindData data) {
- ...
-
- try {
- ...
- if (!data.restrictedBackupMode) {
- if (!ArrayUtils.isEmpty(data.providers)) {
- installContentProviders(app, data.providers);
- }
- }
- ...
注意bindApplication 是从attachApplicationLocked 中触发,而对于provider 在attach函数中埋下了ANR 的炸弹:
- if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
- Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg,
- ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
- }
消息为 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
timeout 为ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS(10s)
这个ANR 的炸弹需要在3.4.3 和之下的函数中拆除,详细看3.4.5节。
3.4.1和3.4.2 两小节就是在provider没有运行下的两种场景,但最终调用的都是installContentProvider:
- private void installContentProviders(
- Context context, List<ProviderInfo> providers) {
- final ArrayList<ContentProviderHolder> results = new ArrayList<>();
-
- for (ProviderInfo cpi : providers) {
- ...
- 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();
- }
- }

主要两件事:
- private ContentProviderHolder installProvider(Context context,
- ContentProviderHolder holder, ProviderInfo info,
- boolean noisy, boolean noReleaseNeeded, boolean stable) {
- ContentProvider localProvider = null;
- IContentProvider provider;
- if (holder == null || holder.provider == null) {
- if (DEBUG_PROVIDER || noisy) {
- Slog.d(TAG, "Loading provider " + info.authority + ": "
- + info.name);
- }
- Context c = null;
- ApplicationInfo ai = info.applicationInfo;
- if (context.getPackageName().equals(ai.packageName)) {
- c = context;
- } else if (mInitialApplication != null &&
- mInitialApplication.getPackageName().equals(ai.packageName)) {
- c = mInitialApplication;
- } else {
- try {
- c = context.createPackageContext(ai.packageName,
- Context.CONTEXT_INCLUDE_CODE);
- } catch (PackageManager.NameNotFoundException e) {
- // Ignore
- }
- }
- if (c == null) {
- Slog.w(TAG, "Unable to get context for package " +
- ai.packageName +
- " while loading content provider " +
- info.name);
- return null;
- }
-
- if (info.splitName != null) {
- try {
- c = c.createContextForSplit(info.splitName);
- } catch (NameNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-
- try {
- final java.lang.ClassLoader cl = c.getClassLoader();
- LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
- if (packageInfo == null) {
- // System startup case.
- packageInfo = getSystemContext().mPackageInfo;
- }
- localProvider = packageInfo.getAppFactory()
- .instantiateProvider(cl, info.name);
- provider = localProvider.getIContentProvider();
- if (provider == null) {
- Slog.e(TAG, "Failed to instantiate class " +
- info.name + " from sourceDir " +
- info.applicationInfo.sourceDir);
- return null;
- }
- if (DEBUG_PROVIDER) Slog.v(
- TAG, "Instantiating local provider " + info.name);
- // XXX Need to create the correct context for this provider.
- localProvider.attachInfo(c, info);
- } catch (java.lang.Exception e) {
- if (!mInstrumentation.onException(null, e)) {
- throw new RuntimeException(
- "Unable to get provider " + info.name
- + ": " + e.toString(), e);
- }
- return null;
- }
- } else {
- provider = holder.provider;
- if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
- + info.name);
- }
-
- ContentProviderHolder retHolder;
-
- synchronized (mProviderMap) {
- if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
- + " / " + info.name);
- IBinder jBinder = provider.asBinder();
- if (localProvider != null) {
- ComponentName cname = new ComponentName(info.packageName, info.name);
- ProviderClientRecord pr = mLocalProvidersByName.get(cname);
- if (pr != null) {
- if (DEBUG_PROVIDER) {
- Slog.v(TAG, "installProvider: lost the race, "
- + "using existing local provider");
- }
- provider = pr.mProvider;
- } else {
- holder = new ContentProviderHolder(info);
- holder.provider = provider;
- holder.noReleaseNeeded = true;
- pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
- mLocalProviders.put(jBinder, pr);
- mLocalProvidersByName.put(cname, pr);
- }
- retHolder = pr.mHolder;
- } else {
- ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
- if (prc != null) {
- if (DEBUG_PROVIDER) {
- Slog.v(TAG, "installProvider: lost the race, updating ref count");
- }
- // We need to transfer our new reference to the existing
- // ref count, releasing the old one... but only if
- // release is needed (that is, it is not running in the
- // system process).
- if (!noReleaseNeeded) {
- incProviderRefLocked(prc, stable);
- try {
- ActivityManager.getService().removeContentProvider(
- holder.connection, stable);
- } catch (RemoteException e) {
- //do nothing content provider object is dead any way
- }
- }
- } else {
- ProviderClientRecord client = installProviderAuthoritiesLocked(
- provider, localProvider, holder);
- if (noReleaseNeeded) {
- prc = new ProviderRefCount(holder, client, 1000, 1000);
- } else {
- prc = stable
- ? new ProviderRefCount(holder, client, 1, 0)
- : new ProviderRefCount(holder, client, 0, 1);
- }
- mProviderRefCountMap.put(jBinder, prc);
- }
- retHolder = prc.holder;
- }
- }
- return retHolder;
- }

代码比较长,逻辑大概分下面几部分:
当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节。
代码比较多,这里不列举,主要做如下:
- if (wasInLaunchingProviders) {
- mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
- }
- synchronized (dst) {
- dst.provider = src.provider;
- dst.setProcess(r);
- dst.notifyAll();
- }
- synchronized (cpr) {
- while (cpr.provider == null) {
- ...
- try {
- final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
-
- if (conn != null) {
- conn.waiting = true;
- }
- cpr.wait(wait);
- if (cpr.provider == null) {
- timedOut = true;
- break;
- }
- } catch (InterruptedException ex) {
- } finally {
- if (conn != null) {
- conn.waiting = false;
- }
- }
- }
- }

如3.4 节中讲到的,如果provider 没有publish,则会进入startProcessLocked 和scheduleInstallProvider,provider 在publish 完成后会notify,唤醒这里的等待。
至此,AMS.getContentProviderImpl 分析基本完成。
这个函数是在3.4.4 节中触发,在调用query / insert 等接口前首先要通过acquire 获取到provider proxy,最终就是通过getIContentProvider 而来:
frameworks/base/core/java/android/content/ContentProvider.java
- public IContentProvider getIContentProvider() {
- return mTransport;
- }
private Transport mTransport = new Transport();
AMS 中在启动provider之后都将provider proxy 存放到ContentProviderRecord 中,并保存在AMS 的providerMap 中。
class Transport extends ContentProviderNative {
- abstract public class ContentProviderNative extends Binder implements IContentProvider {
- ...
- }
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
- public class ContentProviderHolder implements Parcelable {
- ...
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- info.writeToParcel(dest, 0);
- if (provider != null) {
- dest.writeStrongBinder(provider.asBinder());
- } else {
- dest.writeStrongBinder(null);
- }
- dest.writeStrongBinder(connection);
- dest.writeInt(noReleaseNeeded ? 1 : 0);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ContentProviderHolder> CREATOR
- = new Parcelable.Creator<ContentProviderHolder>() {
- @Override
- public ContentProviderHolder createFromParcel(Parcel source) {
- return new ContentProviderHolder(source);
- }
-
- @Override
- public ContentProviderHolder[] newArray(int size) {
- return new ContentProviderHolder[size];
- }
- };
-
- @UnsupportedAppUsage
- private ContentProviderHolder(Parcel source) {
- info = ProviderInfo.CREATOR.createFromParcel(source);
- provider = ContentProviderNative.asInterface(
- source.readStrongBinder());
- connection = source.readStrongBinder();
- noReleaseNeeded = source.readInt() != 0;
- }
- }

(1)ContentProviderHolder 为一个Parcelable,用以binder间数据传递;
(2)ContentProviderHolder.writeToParcel 是将provider.asBinder 写入data;
dest.writeStrongBinder(provider.asBinder());
若,provider 为Bn provier,即为ContentProviderNative,asBinder为自身,即remote 端。
- public IBinder asBinder()
- {
- return this;
- }
若,provider 为Bp provider,即为ContentProviderProxy(为什么是这个,后面讲),asBinder 为:
- public IBinder asBinder()
- {
- return mRemote;
- }
即,无论provider是Bn provider,还是Bp provider,只要以ContentProviderHolder 传递,就会将Bn provider 作为数据写入。
(3)通过CREATOR读取provider
- provider = ContentProviderNative.asInterface(
- source.readStrongBinder());
- static public IContentProvider asInterface(IBinder obj)
- {
- if (obj == null) {
- return null;
- }
- IContentProvider in =
- (IContentProvider)obj.queryLocalInterface(descriptor);
- if (in != null) {
- return in;
- }
-
- return new ContentProviderProxy(obj);
- }
总结,如果ContentProviderHolder 作为参数传递,对端永远是ContentProviderProxy。即,provider 进程在创建后,无论是AMS 还是APP 拿到的provider 都是ContentProviderProxy,即都是用proxy 进行通信。
ok,终于解惑了provider 的产生和传递,回到第 2节query 接口,通过acquireUnstableProvider 获取到的provider 就是ContentProviderProxy。剩下来的就都是binder通信的问题啦,最终调用的肯定是Bn provider 中的query ,也就是Transport 中的query 接口,最终调用的当然是ContentProvider 中的query 接口。。。。。
至此,ContentProvider 机制就完整的剖析完了,中间可能过程还有些省略,如果有什么问题,可以留言!
下面做一些总结,大体分:
如果provider在publish完成之后, 这时再次请求该provider,那就便没有的最右侧的这个过程,直接在AMS.getContentProviderImpl之后便进入AT.installProvider的过程,而不会再次进入wait()过程.
ContentObserver 这里没有细列举,详细可以看:
android 中的 ContentObserver 应用举例
android 中的 ContentObserver 原理详解
在3.4.2 节已经说明在启动provider 进程时最终会调用attachApplicationLocked,并埋下ANR 炸弹。timeout 为:
ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS(10s)
在3.4.5 节中通过publish 接口拆除炸弹。其实这个时间都在AMS 和provider ActivityThread 的流程中,我们能做的就是onCreate()时尽可能的少做耗时操作。
OVER~~
参考:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。