Android四大组件 ContentProvider原理

一 概述

ContentProvider 用于提供数据的统一访问格式,封装底层的具体实现。对于数据使用者来说,无需知晓数据的来源是数据库、文件,或者网络,只需简单地使用 ContentProvider 提供的数据操作接口:增(insert)、删(delete)、改(update)、查(query) 即可,非常方便。

在 Android 系统中通讯录或者短信的数据,都是以 ContentProvider 的形式提供的,ContentProvider 本质上就是把数据存储在 SQLite 数据库中,另外 ContentProvider 读取数据时使用了匿名共享内存(ASM),ASM 实质上也是通过 Binder 通信的。

  • ContentProvider 的 onCreate 先于 Application 的 onCreate 启动,在应用启动的时候,会通过 ActivityThread 的 attach 方法,通过远程调用 AMS 的 attachApplication 来将 ApplicationThread 传递给 AMS,同时在该方法中会调用 ApplicationThread 的 bindApplication 方法,同样也是跨进程的。该方法最终跳转到 ActivityThread 中运行,具体为 handleBindApplication,进而调用 installContentProviders 完成 ContentProvider 的加载
  • 外界无法直接访问 ContentProvider,只能通过 AMS 根据 URI 来获取对应的 ContentProvider 的 Binder 接口 IContentProvider,然后再访问相应数据

ContentProvider 可以做成多实例,通过属性控制,但是现实中很少采用因为浪费开销。外界访问其增删改查的任何一个方法都会导致 ContentProvider 的创建,并且拉起进程。

比如通过 query 方法启动 ContentProvider:

  1. 通过 acquireProvider 来获取 IContentProvider 对象
  2. 先检查本端 ActivityThread 中是否存在 ContentProvider,如果存在就直接返回(返回的是 IContentProvider 客户端接口对象)。如果没有,就调用远程 AMS.getContentProvider 方法
  3. ContentProvider 的启动伴随着进程的启动,启动进程靠的是 AMS 的 startProcessLocked,新进程启动后其入口方法为 ActivityThread.main() 方法,然后在 attach 方法中通过 attachApplication 方法将 ApplicationThread 作为参数传递给 AMS
  4. AMS 的方法中又调用了ApplicationThread.bindApplication
  5. ActivityThread 的 bindApplication 发送 BIND_APPLICATION 消息给 mH 使得 ActivityThread 完成一系列工作,包括(按步骤顺序):
  • 创建 ContextImpl 和 instrumrent
  • 创建 Application 对象
  • 启动当前进程的 ContentProvider 并调用其 onCreate 方法,将创建好的 Contentprovider 保存在 AMS 中的 providerMap 中,这样外部调用者就能直接从 AMS 中获取 ContentProvider 了,然后调用其 onCreate 方法
  • 调用 Application 的 onCreate 方法

上述四个步骤之后,外部就能在 AMS 中拿到 ContentProvider 访问其接口了,但拿到的其实是 Binder 类型对象 IContentProvider。其具体实现是 ContentProvider.Transport,所以外界调用 query 方法时候,是通过调用 ContentProvider.Transport 中的 query 方法,其远程调用 ContentProvider.query 方法,结果通过 Binder 返回给调用者,其它方法调用类似。

1.1 ContentProvider

ContentProvider 作为 Android 四大组件之一,并没有 Activity 那样复杂的生命周期,只有简单的 onCreate 过程。

ContentProvider 是一个抽象类,当要实现自己的 ContentProvider 类时,需继承于 ContentProvider,并且实现以下六个 abstract 方法即可:

  • insert(Uri, ContentValues):插入新数据
  • delete(Uri, String, String[]):删除已有数据
  • update(Uri, ContentValues, String, String[]):更新数据
  • query(Uri, String[], String, String[], String):查询数据
  • onCreate():执行初始化工作
  • getType(Uri):获取数据 MIME 类型

1.2 类图

1.3 重要成员变量

类名    成员变量    含义
AMS    CONTENT_PROVIDER_PUBLISH_TIMEOUT    默认值为10s
AMS    mProviderMap    记录所有 contentProvider
AMS    mLaunchingProviders    记录存在客户端等待 publish 的 ContentProviderRecord
ProcessRecord    pubProviders    该进程创建的 ContentProviderRecord
ProcessRecord    conProviders    该进程使用的 ContentProviderConnection
ActivityThread    mLocalProviders    记录所有本地的 ContentProvider,以 IBinder 以 key
ActivityThread    mLocalProvidersByName    记录所有本地的 ContentProvider,以组件名为 key
ActivityThread    mProviderMap    记录该进程的 contentProvider
ActivityThread    mProviderRefCountMap    记录所有对其他进程中的 ContentProvider 的引用计数

  • CONTENT_PROVIDER_PUBLISH_TIMEOUT:provider 所在进程发布其 ContentProvider 的超时时长为 10s,超过 10s 则会被系统所杀
  • mProviderMap: AMS 和 ActivityThread 都有的一个同名的成员变量,AMS 的数据类型为 ProviderMap,而 AT 则是以 ProviderKey 为 key 的 ArrayMap 类型
  • mLaunchingProviders:ArrayList 的每一项是一个 ContentProviderRecord 对象,所有的存在 client 等待其发布完成的 contentProvider 列表,一旦发布完成则相应的 contentProvider 便会从该列表中移除
  • mLocalProviders 和 mLocalProvidersByName:都是用于记录所有本地的 ContentProvider,不同的只是 key

二 发布ContentProvider

通过 ContentProvider 共享数据时,需要编写一个类继承 ContentProvier,创建数据库,并在 AndroidManifest 声明该 Provider,这样其他的进程才可以通过 ContentResolver 去查询其共享的信息。

先来看一下应用是如何发布 ContentProvider,提供给其它应用使用的。ContentProvider 一般是在应用进程启动的时候启动,是四大组件中最早启动的。

发布 ContentProvider 分两种情况:Provider 进程未启动,Provider 进程已经启动但未发布。

  • Provider 进程未启动

        如果发现 provider 进程已经存在且 attach 到 system_server,但对应的 provider 还没有发布,则通过 binder 机制到 provider 进程执行scheduleInstallProvider 方法,见2.7节

  • Provider 进程已经启动但未发布

        如果发现 provider 进程已经存在且 attach 到 system_server,但对应的 provider 还没有发布,则通过 binder 机制到 provider 进程执行scheduleInstallProvider 方法,见2.7节

这两种情况最后都会走到 installProvider 这个方法。

2.1 Provider进程未启动

2.1.1 ApplicationThread.bindApplication

ActivityThread.java#ApplicationThread

public final void bindApplication(String processName, ApplicationInfo appInfo,
              List<ProviderInfo> providers, ComponentName instrumentationName,
              ProfilerInfo profilerInfo, ......) {
              
          AppBindData data = new AppBindData();
          data.processName = processName;
          data.appInfo = appInfo;
          // provider
          data.providers = providers;
          ...
          sendMessage(H.BIND_APPLICATION, data);
}

发送 BIND_APPLICATION 消息到主线程。

需要注意的是参数 providers,这个是从 AMS 传递过来的,是本进程注册的 ContentProvider 信息,其中 AMS 是通过 PKMS 得到这些注册在 AndroidManifest.xml 文件中的 ContentProvider 信息的。

2.1.2 ActivityThread.handleMessage

ActivityThread.java

public void handleMessage(Message msg) {
           if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
           switch (msg.what) {
               case BIND_APPLICATION:
                   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                   AppBindData data = (AppBindData)msg.obj;
                   handleBindApplication(data);
                   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                   break;
               }
               ...
  }

主线程收到 BIND_APPLICATION 后,执行 handleBindApplication 方法。

2.1.3 ActivityThread.handleBindApplication

ActivityThread.java

private void handleBindApplication(AppBindData data) {
       ......
       Application app;
       final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
       final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
       try {
           // 实例化 Application,会调用 attachBaseContext 方法
           app = data.info.makeApplication(data.restrictedBackupMode, null);
           
           // Propagate autofill compat state
           app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
           mInitialApplication = app;
           // 不是限制备份模式
           // don't bring up providers in restricted mode; they may depend on the
           // app's custom Application class
           if (!data.restrictedBackupMode) {
               if (!ArrayUtils.isEmpty(data.providers)) {
                   // 安装 ContentProvider,见2.4节
                   installContentProviders(app, data.providers);
               }
           }
           try {
               // 调用 Application 的 onCreate 方法
               mInstrumentation.callApplicationOnCreate(app);
           } catch (Exception e) {
               ......
           }
       } 
       ......
   }
2.1.4 ActivityThread.installContentProviders

ActivityThread.java

@UnsupportedAppUsage
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();

        for (ProviderInfo cpi : providers) {
            ......
            //安装 provider,见2.1.5节
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
            //发布 provider 见2.2.1节
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
}
2.1.5 ActivityThread.installProvider

ActivityThread.java

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) { // 这里 holder 为空
          ......
          Context c = null;
          ApplicationInfo ai = info.applicationInfo;
          // 初始化并赋值 context
          ......
          try {
              final java.lang.ClassLoader cl = c.getClassLoader();
              LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
              ......
              // 通过反射,创建目标 ContentProvider 对象
              localProvider = packageInfo.getAppFactory()
                      .instantiateProvider(cl, info.name);
              //获取 contentprovider        
              provider = localProvider.getIContentProvider();
              if (provider == null) {
                  ......
                  return null;
              }
              ......
              // XXX Need to create the correct context for this provider.
              // 回调目标 ContentProvider.this.onCreate() 方法
              localProvider.attachInfo(c, info);
          } catch (java.lang.Exception e) {
              ......
              return null;
          }
      } else {
          provider = holder.provider;
          if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                  + info.name);
      }
      
      // retHolder 赋值,用于将 contentProvider 放入缓存
      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 {
              ......
          }
      }
      return retHolder;
  }

这里主要是通过反射生成 ContentProvider,并回调其 onCreate 方法,然后生成 ProviderClientRecord 对象,并把这个对象添加到 mLocalProviders 和 mLocalProvidersByName 中,最后对 ContentProviderHolder 进行赋值并返回。

2.1.6 AMS.publishContentProviders

ActivityManagerService.java

public final void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) {
        ......
        synchronized (this) {
            final ProcessRecord r = getRecordForAppLocked(caller);
            ......
            final int N = providers.size();
            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 (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
                if (dst != null) {
                    ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                    // 将该 provider 添加到 mProviderMap
                    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;
                    boolean wasInLaunchingProviders = false;
                    for (j = 0; j < launchingCount; j++) {
                        if (mLaunchingProviders.get(j) == dst) {
                        // 从 mLaunchingProviders 中移除
                            mLaunchingProviders.remove(j);
                            wasInLaunchingProviders = true;
                            j--;
                            launchingCount--;
                        }
                    }
                    if (wasInLaunchingProviders) {
                        // 移除超时消息
                        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                    }
                    synchronized (dst) {
                        dst.provider = src.provider;
                        dst.proc = r;
                        // 唤醒客户端的 wait 等待方法
                        dst.notifyAll();
                    }
                    // 更新 adj
                    updateOomAdjLocked(r, true);
                    maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                            src.info.authority);
                }
            }

            Binder.restoreCallingIdentity(origId);
        }
    }

ContentProviders 一旦 publish 成功,则会移除超时发布的消息,并调用 notifyAll 来唤醒所有等待 client 端进程。

2.2 Provider 进程启动但未发布

2.2.1 ApplicationThread.scheduleInstallProvider

ActivityThread.java#ApplicationThread

@Override
public void scheduleInstallProvider(ProviderInfo provider) {
    sendMessage(H.INSTALL_PROVIDER, provider);
}

public void handleMessage(Message msg) {
      ......
      case INSTALL_PROVIDER:
            handleInstallProvider((ProviderInfo) msg.obj);
            break;
      ......
}

ContentResolver#query 分为2个主要步骤:获取 Provider 和 query 查询。

2.2.2 ActivityThread.handleInstallProvider
public void handleInstallProvider(ProviderInfo info) {
       final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
       try {
           installContentProviders(mInitialApplication, Arrays.asList(info));
       } finally {
           StrictMode.setThreadPolicy(oldPolicy);
       }
}

这个方法之后就是 2.1.4 节的流程 installContentProviders

三 查询 ContentResolver

一般使用 ContentProvider 的时候,会先得到 ContentResolver,之后通过 uri 可以获取相应的信息,下面就从查询方法开始,分析这个过程的源码流程。

ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.skytoby.articles/android/1");
Cursor cursor = contentResolver.query(uri, null, null, null, null);

 query时序图:

3.1 ContextImpl.getContentResolver

ContextImpl.java

@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}

private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
        @NonNull LoadedApk packageInfo, @Nullable String splitName,
        @Nullable IBinder activityToken, @Nullable UserHandle user, int flags,
        @Nullable ClassLoader classLoader) {
    ......
    mContentResolver = new ApplicationContentResolver(this, mainThread);
}

 Context 中调用 getContentResolver,经过层层调用到 ContextImpl,返回的 mContentResolver 是在 ContextImpl 对象创建过程中完成赋值的,是一个 ApplicationContentResolver 对象,它继承自 ContentResolver。下面看下查询的操作。

3.2 ContentResolver.query

ContentResolver.java

public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
        @Nullable String[] projection, @Nullable String selection,
        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
        @Nullable String[] projection, @Nullable Bundle queryArgs,
        @Nullable CancellationSignal cancellationSignal) {
    Preconditions.checkNotNull(uri, "uri");
    // 获取 unstableProvider 见 3.3 节
    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, 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
            // 远程进程死亡,处理 unstableProvider 死亡过程
            unstableProviderDied(unstableProvider);
            // unstable 类型死亡后,再创建 stable 类型的 provider,见3.5节
            stableProvider = acquireProvider(uri);
            if (stableProvider == null) {
                return null;
            }
            // 再次执行查询操作
            qCursor = stableProvider.query(
                    mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
        }
        if (qCursor == null) {
            return null;
        }
        // 强制执行操作,可能会失败并抛出 RuntimeException
        // Force query execution.  Might fail and throw a runtime exception here.
        qCursor.getCount();
        long durationMillis = SystemClock.uptimeMillis() - startTime;
        maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
      
        // 创建 CursorWrapperInner 对象
        // 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) {
        return null;
    } finally {
        // 资源释放
        ......
    }
}

一般获取 unstable 的 Provider:调用 acquireUnstableProvider,尝试获取 unstable 的 ContentProvider;然后执行 query 操作,当执行 query 操作过程中抛出 DeadObjectException,即 ContentProvider 所在的进程死亡,则尝试获取 stable 的 ContentProvider:

  1. 先调用 unstableProviderDied,清理刚创建的 unstable 的 ContentProvider
  2. 调用 acquireProvider,尝试获取 stable 的 ContentProvider,此时当 ContentProvider 进程死亡,则会杀掉该 ContentProvider 的客户端进程
  3. 执行 query 操作

stable 和 unstable 区别:

  • 采用 unstable 类型的 ContentProvider 的应用不会因为远程 ContentProvider 进程的死亡而被杀
  • 采用 stable 类型的 ContentProvider 的应用会因为远程 ContentProvider 进程的死亡而被杀

对于应用无法决定创建的 ContentProvider 是 stable 还是 unstable 的,也无法知道自己的进程是否依赖于远程进程的生死。

3.3 ContentResolver.acquireUnstableProvider

ContentResolver.java

   public final IContentProvider acquireUnstableProvider(Uri uri) {
       if (!SCHEME_CONTENT.equals(uri.getScheme())) {
           return null;
       }
       String auth = uri.getAuthority();
       if (auth != null) {
           //获取 UnstableProvider,见3.4节
           return acquireUnstableProvider(mContext, uri.getAuthority());
       }
       return null;
   }

3.4 ApplicationContentResolver.acquireUnstableProvider

ContextImpl.java::ApplicationContentResolver

private static final class ApplicationContentResolver extends ContentResolver {
     ...
    private static final class ApplicationContentResolver extends ContentResolver {
        @UnsupportedAppUsage
        private final ActivityThread mMainThread;
        ......
        // stable provider
        @Override
        @UnsupportedAppUsage
        protected IContentProvider acquireProvider(Context context, String auth) {
            return mMainThread.acquireProvider(context,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), true);
        }
        // unstable provider
        @Override
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), false);
        }
    }
}

从上面可以看出,无论是 acquireProvider 还是 acquireUnstableProvider 方法,最后调用的都是 ActivityThread 的同一个方法的 acquireProvider。getAuthorityWithoutUserId 是字符截断过程,即去掉 auth 中的 userid 信息,比如 com.skytoby.article@666,经过该方法则变成了 com.skytoby.article。

3.5 ActivityThread.acquireProvider

ActivityThread.java

public final IContentProvider acquireProvider(
          Context c, String auth, int userId, boolean stable) {
      // 获取已经存在的 provider    
      final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
      if (provider != null) {
          //成功则返回
          return provider;
      }
      
      ContentProviderHolder holder = null;
      try {
          synchronized (getGetProviderLock(auth, userId)) {
              //见3.6节
              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;
      }
      
      // 安装 provider 将会增加引用计数,见 3.8 节
      // 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;
}

主要过程:

  • 获取已经存在的 provider,如果存在则返回,否则继续执行
  • 通过 AMS 获取 provider,无法获取则返回,否则继续执行
  • 通过 installProvider 方法安装 provider,并增加该 provider 的引用计数
3.5.1 ActivityThread.acquireExistingProvider

 ActivityThread.java

@UnsupportedAppUsage
public final IContentProvider acquireExistingProvider(
        Context c, String auth, int userId, boolean stable) {
    synchronized (mProviderMap) {
        final ProviderKey key = new ProviderKey(auth, userId);
        //从 mProviderMap 中查询是否存在,在 2.1.6 节发布时将 provider 添加到了 mProviderMap
        final ProviderClientRecord pr = mProviderMap.get(key);
        if (pr == null) {
            return null;
        }

        IContentProvider provider = pr.mProvider;
        IBinder jBinder = provider.asBinder();
        if (!jBinder.isBinderAlive()) {
            Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                    + ": existing object's process dead");
            // 当 provider 所在的进程已经死亡则返回        
            handleUnstableProviderDiedLocked(jBinder, true);
            return null;
        }
        // Only increment the ref count if we have one.  If we don't then the
        // provider is not reference counted and never needs to be released.
        ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
        if (prc != null) {
            //增加引用计数
            incProviderRefLocked(prc, stable);
        }
        return provider;
    }
}

查询 mProviderMap 是否存在 provider,如果不存在则直接返回。如果存在判断 provider 的进程是否死亡,死亡则返回 null。如果 provider 所在的进程还在,则增加引用计数。

3.6 AMS.getContentProvider

ActivityManagerService.java

@Override
   public final ContentProviderHolder getContentProvider(
           IApplicationThread caller, String name, int userId, boolean stable) {
       enforceNotIsolatedCaller("getContentProvider");
       ......
       return getContentProviderImpl(caller, name, null, stable, userId);
}

3.7 AMS.getContentProviderImpl

ActivityManagerService.java

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
          String name, IBinder token, boolean stable, int userId) {
      ContentProviderRecord cpr;
      ContentProviderConnection conn = null;
      ProviderInfo cpi = null;
      boolean providerRunning = false;

      synchronized(this) {
          long startTime = SystemClock.uptimeMillis();

          ProcessRecord r = null;
          if (caller != null) {
              // 获取调用者的进程记录
              r = getRecordForAppLocked(caller);
              ......
          }
          ......          
          // 从 mProviderMap 中获取 ContentProviderRecord
          // First check if this content provider has been published...
          cpr = mProviderMap.getProviderByName(name, userId);
          // If that didn't work, check if it exists for user 0 and then
          // verify that it's a singleton provider before using it.
          if (cpr == null && userId != UserHandle.USER_SYSTEM) {
              // 从 USER_SYSTEM 获取,这里的 name 是 componentName
              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;
                  }
              }
          }

          if (cpr != null && cpr.proc != null) {
              providerRunning = !cpr.proc.killed;
              // 目标 provider 进程死亡
              if (cpr.proc.killed && cpr.proc.killedByAm) {
                  checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)");
                  final long iden = Binder.clearCallingIdentity();
                  try {
                      appDiedLocked(cpr.proc);
                  } finally {
                      Binder.restoreCallingIdentity(iden);
                  }
                  checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)");
              }
          }
         // 目标 provider 存在的情况,见3.7.1
         if (providerRunning) {
            ....
         }
         // 目标 provider 不存在的情况,见3.7.2
         if (!providerRunning) {
            ....
         }
        // 循环等待 provider 发布完成,见3.7.3
         synchronized (cpr) {
             while (cpr.provider == null) {
                 ....
              }
         }
   }
     return super.onTransact(code, data, reply, flags);
}

这个方法比较长,主要分为三个部分:

  • 目标 provider 存在的情况
  • 目标 provider 不存在的情况
  • 循环等待目标 provider 发布完成
3.7.1 目标provider存在
if (providerRunning) {
           cpi = cpr.info;
           String msg;
           ......
           if (r != null && cpr.canRunHere(r)) {
               // 当允许运行在调用者进程,且已经发布,则直接返回
               // This provider has been published or is in the process
               // of being published...  but it is also allowed to run
               // in the caller's process, so don't make a connection
               // and just let the caller instantiate its own instance.
               ContentProviderHolder holder = cpr.newHolder(null);
               // don't give caller the provider object, it needs
               // to make its own.
               holder.provider = null;
               return holder;
           }
           ......
           final long origId = Binder.clearCallingIdentity();

           checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
           // 增加引用计数,见 3.8.1 节
           // In this case the provider instance already exists, so we can
           // return it right away.
           conn = incProviderCountLocked(r, cpr, token, stable);
           if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
               if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                   // 更新进程 LRU 队列
                   checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
                   updateLruProcessLocked(cpr.proc, false, null);
                   checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
               }
           }

           checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
           final int verifiedAdj = cpr.proc.verifiedAdj;
           // 更新进程 adj
           boolean success = updateOomAdjLocked(cpr.proc, true);
           // XXX things have changed so updateOomAdjLocked doesn't actually tell us
           // if the process has been successfully adjusted.  So to reduce races with
           // it, we will check whether the process still exists.  Note that this doesn't
           // completely get rid of races with LMK killing the process, but should make
           // them much smaller.
           if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
               success = false;
           }
           maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
           checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
           if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
           // NOTE: there is still a race here where a signal could be
           // pending on the process even though we managed to update its
           // adj level.  Not sure what to do about this, but at least
           // the race is now smaller.
           if (!success) {
               // provider 进程被杀死,则减少应用计数,见3.8.3节
               // Uh oh...  it looks like the provider's process
               // has been killed on us.  We need to wait for a new
               // process to be started, and make sure its death
               // doesn't kill our process.
               Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                       + " is crashing; detaching " + r);
               boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
               checkTime(startTime, "getContentProviderImpl: before appDied");
               appDiedLocked(cpr.proc);
               checkTime(startTime, "getContentProviderImpl: after appDied");
               if (!lastRef) {
                   // This wasn't the last ref our process had on
                   // the provider...  we have now been killed, bail.
                   return null;
               }
               providerRunning = false;
               conn = null;
           } else {
               cpr.proc.verifiedAdj = cpr.proc.setAdj;
           }

           Binder.restoreCallingIdentity(origId);
}

当 ContentProvider 所在的进程已经存在:

  • 检查权限
  • 当允许运行在调用者进程且已经发布,则直接返回
  • 增加引用计数
  • 更新进程LRU队列
  • 更新adj
  • 当 provider 进程被杀时,则减少引用计数并调用 appDiedLocked,设置 provider 为未发布状态
3.7.2 目标 provider 不存在
if (!providerRunning) {
        try {
            checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
            // 获取 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;
        }
        // provider 是否是单例
        // If the provider is a singleton AND
        // (it's a call within the same user || the provider is a
        // privileged app)
        // Then allow connecting to the singleton provider
        boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                cpi.name, cpi.flags)
                && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
        if (singleton) {
            userId = UserHandle.USER_SYSTEM;
        }
        cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
        checkTime(startTime, "getContentProviderImpl: got app info for user");

        String msg;
        checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
        // 权限检查
        if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                != null) {
            throw new SecurityException(msg);
        }
        checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
        ......        
        // 拥有该 provider 的用户没有运行,则直接返回
        // Make sure that the user who owns this provider is running.  If not,
        // we don't want to allow it to run.
        if (!mUserController.isUserRunning(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);
        checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
        cpr = mProviderMap.getProviderByClass(comp, userId);
        checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
        final boolean firstClass = cpr == null;
        if (firstClass) {
            final long ident = Binder.clearCallingIdentity();

            // If permissions need a review before any of the app components can run,
            // we return no provider and launch a review activity if the calling app
            // is in the foreground.
            if (mPermissionReviewRequired) {
                if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
                    return null;
                }
            }

            try {
                checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
                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);
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
        // 见 3.7.4 节
        if (r != null && cpr.canRunHere(r)) {
            // If this is a multiprocess provider, then just return its
            // info and allow the caller to instantiate it.  Only do
            // this if the provider is the same user as the caller's
            // process, or can run as root (so can be in any process).
            return cpr.newHolder(null);
        }

        if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
                    + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
                    + cpr.info.name + " callers=" + Debug.getCallers(6));
        
        // 从 mLaunchingProviders 中查询
        // This is single process, and our app is now connecting to it.
        // See if we are already in the process of launching this
        // provider.
        final int N = mLaunchingProviders.size();
        int i;
        for (i = 0; i < N; i++) {
            if (mLaunchingProviders.get(i) == cpr) {
                break;
            }
        }

       // 如果 mLaunchingProviders 中没有该 provider,则启动它
        // If the provider is not already being launched, then get it
        // started.
        if (i >= N) {
            final long origId = Binder.clearCallingIdentity();

            try {
                // Content provider is now in use, its package can't be stopped.
                try {
                    checkTime(startTime, "getContentProviderImpl: before set stopped state");
                    AppGlobals.getPackageManager().setPackageStoppedState(
                            cpr.appInfo.packageName, false, userId);
                    checkTime(startTime, "getContentProviderImpl: after set stopped state");
                } catch (RemoteException e) {
                } catch (IllegalArgumentException e) {
                    Slog.w(TAG, "Failed trying to unstop package "
                            + cpr.appInfo.packageName + ": " + e);
                }

                // Use existing process if already started
                checkTime(startTime, "getContentProviderImpl: looking for process record");
                // 查询进程记录
                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)) {
                        checkTime(startTime, "getContentProviderImpl: scheduling install");
                        proc.pubProviders.put(cpi.name, cpr);
                        try {
                             // 发布 provider,见2.2.1节
                            proc.thread.scheduleInstallProvider(cpi);
                        } catch (RemoteException e) {
                        }
                    }
                } else {
                    checkTime(startTime, "getContentProviderImpl: before start process");
                    // 启动进程
                    proc = startProcessLocked(cpi.processName,
                            cpr.appInfo, false, 0, "content provider",
                            new ComponentName(cpi.applicationInfo.packageName,
                                    cpi.name), 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 = proc;
                // 将 cpr 添加到 mLaunchingProviders
                mLaunchingProviders.add(cpr);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }

        checkTime(startTime, "getContentProviderImpl: updating data structures");

        // 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, stable);
        if (conn != null) {
            conn.waiting = true;
        }
    }
    checkTime(startTime, "getContentProviderImpl: done!");

    grantEphemeralAccessLocked(userId, null /*intent*/,
            cpi.applicationInfo.uid, UserHandle.getAppId(Binder.getCallingUid()));
}

当 ContentProvider 所在的进程不存在:

  • 根据 authority 获取 ProviderInfo 对象
  • 权限检查
  • 当系统不是运行在 system 进程,且系统未准备好,则抛出异常
  • 当拥有该 provider 的用户没有运行,则直接返回
  • 当允许运行在调用者进程且 ProcessRecord 不为空,则直接返回
  • 当 provider 并没有在 mLaunchingProviders 队列,则启动它
  • 当 ProcessRecord 不为空,则直接加入到 pubProviders 队列,并安装 provider
  • 当 ProcessRecord 为空,则启动进程
  • 增加引用计数
3.7.3 等待目标 provider 发布

ActivityManagerService.java

static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
// Wait for the provider to be published...
final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
synchronized (cpr) {
    //
    while (cpr.provider == null) {
        ......
        try {
            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;
            }
            cpr.wait(wait);
            ......
        } catch (InterruptedException ex) {
        } finally {
            if (conn != null) {
                conn.waiting = false;
            }
        }
    }
}
return cpr != null ? cpr.newHolder(conn) : null;

循环等待 20s,直到发布完成才退出。

3.7.4 ContentProviderRecord.canRunHere

ContentProviderRecord.java

public boolean canRunHere(ProcessRecord app) {
      return (info.multiprocess || info.processName.equals(app.processName))
              && uid == app.info.uid;
}


ContentProvider 是否能运行在调用者所在的进程需要满足以下条件

  • ContentProvider 在 AndroidManifest.xml 文件配置中 multiprocess=true;或者调用者进程和 ContentProvider 在同一进程
  • ContentProvider 进程跟调用者所在的进程是同一个 uid

3.8 ActivityThread.installProvider

ActivityThread.java

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) {
            //从packageInfo中获取provider
            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
                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) {
                        // 增加引用计数,通过 AMS,见3.8.4
                        incProviderRefLocked(prc, stable);
                        try {
                            
                            ActivityManager.getService().removeContentProvider(
                                    holder.connection, stable);
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                } else {
                    //见3.8.5节
                    ProviderClientRecord client = installProviderAuthoritiesLocked(
                            provider, localProvider, holder);
                    if (noReleaseNeeded) {
                       //见3.8.6节
                        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;
    }
3.8.1 AMS.incProviderCountLocked

ActivityManagerService.java

ContentProviderConnection incProviderCountLocked(ProcessRecord r,
           final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
       if (r != null) {
           for (int i=0; i<r.conProviders.size(); i++) {
               // 从当前进程所使用的 provider 中查询与目标 provider 一致的信息
               ContentProviderConnection conn = r.conProviders.get(i);
               if (conn.provider == cpr) {
                   if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                           "Adding provider requested by "
                           + r.processName + " from process "
                           + cpr.info.processName + ": " + cpr.name.flattenToShortString()
                           + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
                   if (stable) {
                       conn.stableCount++;
                       conn.numStableIncs++;
                   } else {
                       conn.unstableCount++;
                       conn.numUnstableIncs++;
                   }
                   return conn;
               }
           }
           // 查不到则新建 provider 连接对象
           ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
           if (stable) {
               conn.stableCount = 1;
               conn.numStableIncs = 1;
           } else {
               conn.unstableCount = 1;
               conn.numUnstableIncs = 1;
           }
           cpr.connections.add(conn);
           r.conProviders.add(conn);
           startAssociationLocked(r.uid, r.processName, r.curProcState,
                   cpr.uid, cpr.name, cpr.info.processName);
           return conn;
       }
       cpr.addExternalProcessHandleLocked(externalProcessToken);
       return null;
   }
3.8.2 AMS.removeContentProvider

ActivityManagerService.java

/**
    * Drop a content provider from a ProcessRecord's bookkeeping
    */
   public void removeContentProvider(IBinder connection, boolean stable) {
       enforceNotIsolatedCaller("removeContentProvider");
       long ident = Binder.clearCallingIdentity();
       try {
           synchronized (this) {
               ContentProviderConnection conn;
               try {
                   conn = (ContentProviderConnection)connection;
               } catch (ClassCastException e) {
                   String msg ="removeContentProvider: " + connection
                           + " not a ContentProviderConnection";
                   Slog.w(TAG, msg);
                   throw new IllegalArgumentException(msg);
               }
               if (conn == null) {
                   throw new NullPointerException("connection is null");
               }
               // 见 3.8.3 节
               if (decProviderCountLocked(conn, null, null, stable)) {
                   updateOomAdjLocked();
               }
           }
       } finally {
           Binder.restoreCallingIdentity(ident);
       }
}
3.8.3 AMS.decProviderCountLocked
boolean decProviderCountLocked(ContentProviderConnection conn,
            ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
        if (conn != null) {
            cpr = conn.provider;
            if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                    "Removing provider requested by "
                    + conn.client.processName + " from process "
                    + cpr.info.processName + ": " + cpr.name.flattenToShortString()
                    + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
            if (stable) {
                conn.stableCount--;
            } else {
                conn.unstableCount--;
            }
            // 当 provider 连接的 stable 和 unstable 的引用次数为 0 时,则移除连接对象信息
            if (conn.stableCount == 0 && conn.unstableCount == 0) {
                cpr.connections.remove(conn);
                conn.client.conProviders.remove(conn);
                if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                    // The client is more important than last activity -- note the time this
                    // is happening, so we keep the old provider process around a bit as last
                    // activity to avoid thrashing it.
                    if (cpr.proc != null) {
                        cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
                    }
                }
                stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
                return true;
            }
            return false;
        }
        cpr.removeExternalProcessHandleLocked(externalProcessToken);
        return false;
    }
3.8.4 ActivityThread.incProviderRefLocked

ActivityThread.java

private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
       //stable provider
       if (stable) {
           prc.stableCount += 1;
           if (prc.stableCount == 1) {
               // 数量为1,状态为 removePending,发送 REMOVE_PROVIDER 信息
               // We are acquiring a new stable reference on the provider.
               int unstableDelta;
               if (prc.removePending) {
                   // We have a pending remove operation, which is holding the
                   // last unstable reference.  At this point we are converting
                   // that unstable reference to our new stable reference.
                   unstableDelta = -1;
                   // Cancel the removal of the provider.
                   if (DEBUG_PROVIDER) {
                       Slog.v(TAG, "incProviderRef: stable "
                               + "snatched provider from the jaws of death");
                   }
                   prc.removePending = false;
                   // There is a race! It fails to remove the message, which
                   // will be handled in completeRemoveProvider().
                   mH.removeMessages(H.REMOVE_PROVIDER, prc);
               } else {
                   unstableDelta = 0;
               }
               try {
                   if (DEBUG_PROVIDER) {
                       Slog.v(TAG, "incProviderRef Now stable - "
                               + prc.holder.info.name + ": unstableDelta="
                               + unstableDelta);
                   }
                   // 调用 AMS 方法
                   ActivityManager.getService().refContentProvider(
                           prc.holder.connection, 1, unstableDelta);
               } catch (RemoteException e) {
                   //do nothing content provider object is dead any way
               }
           }
       } else {
           prc.unstableCount += 1;
           if (prc.unstableCount == 1) {
               // We are acquiring a new unstable reference on the provider.
               if (prc.removePending) {
                   // Oh look, we actually have a remove pending for the
                   // provider, which is still holding the last unstable
                   // reference.  We just need to cancel that to take new
                   // ownership of the reference.
                   if (DEBUG_PROVIDER) {
                       Slog.v(TAG, "incProviderRef: unstable "
                               + "snatched provider from the jaws of death");
                   }
                   prc.removePending = false;
                   mH.removeMessages(H.REMOVE_PROVIDER, prc);
               } else {
                   // First unstable ref, increment our count in the
                   // activity manager.
                   try {
                       if (DEBUG_PROVIDER) {
                           Slog.v(TAG, "incProviderRef: Now unstable - "
                                   + prc.holder.info.name);
                       }
                       ActivityManager.getService().refContentProvider(
                               prc.holder.connection, 0, 1);
                   } catch (RemoteException e) {
                       //do nothing content provider object is dead any way
                   }
               }
           }
       }
   }
3.8.5 ActivityThread.installProviderAuthoritiesLocked

ActivityThread.java

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) {
           // If this provider is hosted by the core OS and cannot be upgraded,
           // then I guess we're okay doing blocking calls to it.
           for (String auth : auths) {
               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());
               }
           }
       }

       final ProviderClientRecord pcr = new ProviderClientRecord(
               auths, provider, localProvider, holder);
       for (String auth : auths) {
           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;
   }
3.8.6 ProviderRefCount

ActivityThread.java::ProviderRefCount

private static final class ProviderRefCount {
      public final ContentProviderHolder holder;
      public final ProviderClientRecord client;
      public int stableCount;
      public int unstableCount;
      
      //当该标记设置时,stableCount和unstableCount引用都会设置为0
      // When this is set, the stable and unstable ref counts are 0 and
      // we have a pending operation scheduled to remove the ref count
      // from the activity manager.  On the activity manager we are still
      // holding an unstable ref, though it is not reflected in the counts
      // here.
      public boolean removePending;

      ProviderRefCount(ContentProviderHolder inHolder,
              ProviderClientRecord inClient, int sCount, int uCount) {
          holder = inHolder;
          client = inClient;
          stableCount = sCount;
          unstableCount = uCount;
      }
  }

获取到 Provider 后,就可以进行查询操作了。

3.9 ContentProviderNative.query

ContentProviderNative.java::ContentProviderProxy

@Override
  public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
          @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
          throws RemoteException {
      BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
      Parcel data = Parcel.obtain();
      Parcel reply = Parcel.obtain();
      try {
          data.writeInterfaceToken(IContentProvider.descriptor);

          data.writeString(callingPkg);
          url.writeToParcel(data, 0);
          int length = 0;
          if (projection != null) {
              length = projection.length;
          }
          data.writeInt(length);
          for (int i = 0; i < length; i++) {
              data.writeString(projection[i]);
          }
          data.writeBundle(queryArgs);
          data.writeStrongBinder(adaptor.getObserver().asBinder());
          data.writeStrongBinder(
                  cancellationSignal != null ? cancellationSignal.asBinder() : null);
          //发送给binder服务
          mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);

          DatabaseUtils.readExceptionFromParcel(reply);

          if (reply.readInt() != 0) {
              BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
              Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
              adaptor.initialize(d);
          } else {
              adaptor.close();
              adaptor = null;
          }
          return adaptor;
      } catch (RemoteException ex) {
          adaptor.close();
          throw ex;
      } catch (RuntimeException ex) {
          adaptor.close();
          throw ex;
      } finally {
          data.recycle();
          reply.recycle();
      }
  }

3.10 ContentProviderNative.onTransact

ContentProviderNative.java

@Override
 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
         throws RemoteException {
     try {
         switch (code) {
             case QUERY_TRANSACTION:
             {
                 data.enforceInterface(IContentProvider.descriptor);

                 String callingPkg = data.readString();
                 Uri url = Uri.CREATOR.createFromParcel(data);

                 // String[] projection
                 int num = data.readInt();
                 String[] projection = null;
                 if (num > 0) {
                     projection = new String[num];
                     for (int i = 0; i < num; i++) {
                         projection[i] = data.readString();
                     }
                 }

                 Bundle queryArgs = data.readBundle();
                 IContentObserver observer = IContentObserver.Stub.asInterface(
                         data.readStrongBinder());
                 ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                         data.readStrongBinder());
                 //见3.11节      
                 Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
                 if (cursor != null) {
                     CursorToBulkCursorAdaptor adaptor = null;

                     try {
                         adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                 getProviderName());
                         cursor = null;

                         BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
                         adaptor = null;

                         reply.writeNoException();
                         reply.writeInt(1);
                         d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     } finally {
                         // Close cursor if an exception was thrown while constructing the adaptor.
                         if (adaptor != null) {
                             adaptor.close();
                         }
                         if (cursor != null) {
                             cursor.close();
                         }
                     }
                 } else {
                     reply.writeNoException();
                     reply.writeInt(0);
                 }

                 return true;
             }

             case GET_TYPE_TRANSACTION:
             case INSERT_TRANSACTION:
             case BULK_INSERT_TRANSACTION: 
             case APPLY_BATCH_TRANSACTION:
             case DELETE_TRANSACTION:
             case UPDATE_TRANSACTION:
             ...
         }
     } catch (Exception e) {
         DatabaseUtils.writeExceptionToParcel(reply, e);
         return true;
     }

3.11 Transport.query

ContentProvider.java::Transport

public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
              @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
          uri = validateIncomingUri(uri);
          uri = maybeGetUriWithoutUserId(uri);
          if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
              // The caller has no access to the data, so return an empty cursor with
              // the columns in the requested order. The caller may ask for an invalid
              // column and we would not catch that but this is not a problem in practice.
              // We do not call ContentProvider#query with a modified where clause since
              // the implementation is not guaranteed to be backed by a SQL database, hence
              // it may not handle properly the tautology where clause we would have created.
              if (projection != null) {
                  return new MatrixCursor(projection, 0);
              }

              // Null projection means all columns but we have no idea which they are.
              // However, the caller may be expecting to access them my index. Hence,
              // we have to execute the query as if allowed to get a cursor with the
              // columns. We then use the column names to return an empty cursor.
              Cursor cursor = ContentProvider.this.query(
                      uri, projection, queryArgs,
                      CancellationSignal.fromTransport(cancellationSignal));
              if (cursor == null) {
                  return null;
              }

              // Return an empty cursor for all columns.
              return new MatrixCursor(cursor.getColumnNames(), 0);
          }
          final String original = setCallingPackage(callingPkg);
          try {
              //调用目标provider的query方法
              return ContentProvider.this.query(
                      uri, projection, queryArgs,
                      CancellationSignal.fromTransport(cancellationSignal));
          } finally {
              setCallingPackage(original);
          }
      }

四 总结

本文分析了发布 ContentProvider 的过程,并分析了 query 过程,先获取 provider,再安装 provider 信息,最后才查询。而查询操作主要分为两种情况:

4.1 进程未启动

provider 进程不存在,需要创建进程并发布相关的 provider

 

  • client 进程:通过 Binder 向 systemserver 进程请求相应的 provider
  • systemserver 进程:如果目标进程未启动,则调用 startProcessLocked 启动进程,当启动完成,当 cpr.provider ==null,则 systemserver 进入 wait 阶段,等待目标 provider 发布
  • provider 进程:进程启动后执行 attach 到 systemserver,而后 bindApplication,在这个过程会 installProvider 和 PublishContentProviders,再 binder 到 systemserver 进程
  • systemserver 进程:回到 systemserver 发布 provider 信息,并且通过 notify 机制唤醒当前处于 wait 状态的 binder 线程,并将结果返回给 client 进程
  • client 进程:回到 client 进程,执行 installProvider 操作,安装 provider

关于 CONTENT_PROVIDER_PUBLISH_TIMEOUT 超时机制所统计的时机区间是指在 startProcessLocked 之后会调用 AMS.attachApplicationLocked 为起点,一直到 AMS.publishContentProviders 的过程。

4.2 进程已启动

provider 进程已启动但未发布,需要发布相关的 provider

  • Client 进程:获取 provider 发现 cpr 为空,则调用 scheduleInstallProvider 来向 provider 所在的进程发出一个 oneway 的 binder 请求,进入 wait 状态
  • provider进程:安装完成 provider 信息后,通过 notify 机制唤醒当前处于 wait 状态的 binder 线程

如果 provider 在 publish 之后,这是在请求 provider 则没用最右边的过程,直接 AMS.getContentProvierImpl 之后便进入 AT.installProvider 的过程,而不会再进入 wait 过程。

4.3 引用计数

provider 分为 stable provider 和 unstable provider,主要在于引用计数的不同。

provider 引用计数的增加与减少关系,removePending 是指即将被移除的引用,lastRef 表示当前引用为0。

方法    stableCount    unstableCount    条件
acquireProvider    +1    0    removePending=false
acquireProvider    +1    -1    removePending=true
acquireUnstableProvider    0    +1    removePending=false
acquireUnstableProvider    0    0    removePending=true
releaseProvider    -1    0    lastRef=false
releaseProvider    -1    1    lastRef=true
releaseUnstableProvider    0    -1    lastRef=false
releaseUnstableProvider    0    0    lastRef=true

当 Client 进程存在对某个 provider 的引用时,Provider 进程死亡则会根据 provider 类型进行不同的处理:

  • 对于 stable provider,会杀掉所有和该 provider 建立 stable 连接的非 persistent 进程
  • 对于 unstable provider,不会导致 client 进程被级联所杀,会回调 unstableProviderDied 来清理相关信息

当 stable 和 unstable 引用计数都为 0 则移除 connection 信息

  • AMS.removeContentProvider 过程移除 connection 相关所有信息

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值