ContentProvider总结(上)

简介

ContentProvider是一种内容共享型组件,底层通过Binder和其他进程进行通信。ContentProvider一般是运行在独立的进程中的,每一个Content Provider在系统中只有一个实例存在,其它应用程序首先要找到这个实例,然后才能访问它的数据。ContentProvider采取懒加载的形式,即安装的时候并不会把ContentProvider加载到内存中来,而是会等到第一次使用的时候才加载,第二次使用的时候就直接返回了。

过程分析

要访问ContentProvider的数据,首先需要调用Context的getContentResolver()方法获取ContentResolver对象,从这里入手,我们找到ContextImpl的getContentResolver()方法实现如下:

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

追溯到ContentResolver 的初始化过程如下:

mContentResolver = new ApplicationContentResolver(this, mainThread, user);

通过跟踪代码知道,ContentResolver是一个抽象类,我们使用的ApplicationContentResolver是这个抽象类的一个实现类。其中一个参数mainThread是是ActivityThread的一个实例。
  一个应用启动时,入口方法为ActivityThread的main方法,该方法是一个static方法,其中创建了ActivityThread的实例并创建了主线程的消息队列,而且调用了ActivityThread的attach方法。

        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        AsyncTask.init();
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Looper.loop();

ActivityThread的attach()方法远程调用了AMS的 attachApplication()方法。参数mAppThread是一个ApplicationThread对象(Binder对象),该对象主要用于ActivityThread和AMS之间的通信。

           //AMS继承的ActivityManagerNative实现了IActivityManager 接口
           IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }

AMS的attachApplication()方法跨进程调用了ApplicationThread的bindApplication方法。

     thread.bindApplication(processName, appInfo, providers,
     app.instrumentationClass, profileFile, profileFd,               profileAutoStop,
                    app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                    mCoreSettingsObserver.getCoreSettingsLocked());

ApplicationThread是ActivityThread的一个内部类。bindApplication最终会通过H类的实例mH切换到ActivityThread中去执行。

 sendMessage(H.BIND_APPLICATION, data);
            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;

在handleBindApplication中,ActivityThread会创建Application对象并加载ContentProvider。由以下代码可知,ActivityThread是先加载ContentProvider,然后再调用Application的onCreate方法。

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                List providers = data.providers;
                if (providers != null) {
                    installContentProviders(app, providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }

            // Do this after providers, since instrumentation tests generally start their
            // test thread at this point, and we don't want that racing.
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                throw new RuntimeException(
                    "Exception thrown in onCreate() of "
                    + data.instrumentationName + ": " + e.toString(), e);
            }

            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {

以上为ContentProvider的启动过程,启动后,外界就可以通过增删改查接口来操纵ContentProvider的数据。
当ContentProvider所在的进程未启动时,第一次访问它时会触发ContentProvider的创建,同时会拉起ContentProvider所在的进程。下面从调用ContentResolver的query入手分析:

   //ContentResolver.java
   IContentProvider unstableProvider = acquireUnstableProvider(uri);
   ......
   qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
      //ApplicationContentResolver.java 
      @Override
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
        }

ApplicationContentResolver的acquireUnstableProvider自己不做任何事情,最终交由ActivityThread的acquireProvider处理。

 //ActivityThread
  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;
        }

        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        IActivityManager.ContentProviderHolder holder = null;
        try {
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            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;
    }

ActivityThread 会先通过acquireExistingProvider查询IContentProvider 是否存在,存在则直接返回。acquireExistingProvider源码如下:

            final ProviderKey key = new ProviderKey(auth, userId);
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                return null;
            }

            IContentProvider provider = pr.mProvider;

如果目标ContentProvider未启动,ActivityThread会通过进程间通信让AMS启动ContentProvider。启动ContentProvider,需要先通过AMS的startProcessLocked启动其所在的进程。startProcessLocked最终会调用到Process.start,最后任务交由Zygote处理。

  // Use existing process if already started
                        ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);
                        if (proc != null && proc.thread != null) {
                            if (DEBUG_PROVIDER) {
                                Slog.d(TAG, "Installing in existing process " + proc);
                            }
                            proc.pubProviders.put(cpi.name, cpr);
                            try {
                                proc.thread.scheduleInstallProvider(cpi);
                            } catch (RemoteException e) {
                            }
                        } else {
                            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;
                            }
                        }
                        cpr.launchingApp = proc;
                        mLaunchingProviders.add(cpr);
                   Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);
       public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
         }
     }

进程启动后,入口为ActivityThread的main方法。

你可能感兴趣的:(ContentProvider总结(上))