【源码解析】ContentProvider的启动过程

一、引言

ContentProvider作为Android的四大组件之一,其主要的作用是通过Binder向其他组件或者其他应用提供数据。它的底层实现方式也是Binder,但是它的使用方法又比较简单。原因是系统为我们做了封装,而我们无须关心底层细节就能轻松的实现进程间的通信。

ContentProvider的应用还是挺广泛的,比如我们应用中获取通讯录、获取短信、获取手机通话记录等,都是通过ContentProvider来进行的。

既然ContentProvider这么重要,我们有必要从源码的角度深挖一下ContentProvider的启动过程。

二、源码分析

1、ContentProvider的创建与初始化

在具体分析源码之前,我们大致看一下ContentProvider的整个启动过程的示意图,如下所示:


ContentProvider的启动过程

App启动后,会调用ActivityThread的main方法,接着在main方法中创建了ActivityThread对象,并调用了它的attach方法。在attach方法中远程调用AMS的attachApplication方法,该方法中又远程调用PMS的queryContentProviders方法获取应用注册的Provider信息,然后调用ApplicationThread的bindApplication方法将Provider信息传递过去。在ApplicationThread中通过makeApplication生成Application对象,并调用installContentProviders方法初始化并加载ContentProvider,然后调用Application对象的onCreate方法,应用就这样跑起来了。

下面我们具体分析上述的每一个步骤。

首先是App启动,调用了ActivityThread的main方法,如下所示:

public static void main(String[] args) {
    ...省略

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();
}

main方法中,创建了ActivityThread对象,然后调用了该对象的attach方法,如下所示:

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        ...省略
    } else {
        ...省略
    }
    ...省略
}

系统的应用我们不作分析,而对于非系统应用,ActivityManager.getService()获取到一个IActivityManager对象,它是一个Binder对象,通过它调用attachApplication方法实际上就是远程调用了ActivityManagerService的attachApplication方法,如下所示:

public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

attachApplication方法又调用了attachApplicationLocked方法,如下所示:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {

    ...省略

    EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

    app.makeActive(thread, mProcessStats);
    app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
    app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
    app.forcingToImportant = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;
    app.killed = false;

    app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

    mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    //获取应用中注册的ContentProvider数据
    List providers = normalMode ? generateApplicationProvidersLocked(app) : null;

    if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
        Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
        msg.obj = app;
        mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
    }

    checkTime(startTime, "attachApplicationLocked: before bindApplication");
    try {
        ...省略

        // If we were asked to attach an agent on startup, do so now, before we're binding
        // application code.
        if (agent != null) {
            thread.attachAgent(agent);
        }

        checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
        mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
        if (app.instr != null) {
            thread.bindApplication(processName, appInfo, providers,
                    app.instr.mClass,
                    profilerInfo, app.instr.mArguments,
                    app.instr.mWatcher,
                    app.instr.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        } else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial);
        }

        checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
        updateLruProcessLocked(app, false, null);
        checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        ...省略
    }

    ...省略

    return true;
}

在attachApplicationLocked方法中,主要流程分为两步:

  • 在正常模式下,调用了generateApplicationProvidersLocked方法获取注册的ContentProvider信息。
  • 将上一步中的ContentProvider信息作为参数,远程调用了ApplicationThread的bindApplication方法。

我们首先看第一步,generateApplicationProvidersLocked方法如下所示:

private final List generateApplicationProvidersLocked(ProcessRecord app) {
    List providers = null;
    try {
        //远程调用PMS获取应用中注册的ContentProvider信息
        providers = AppGlobals.getPackageManager()
                .queryContentProviders(app.processName, app.uid,
                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
                                | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
                .getList();
    } catch (RemoteException ex) {
    }
    int userId = app.userId;
    ...省略
    return providers;
}

在上述方法中,AppGlobals.getPackageManager()方法返回的是IPackageManager,调用了它的queryContentProviders方法。这是一个Binder对象,其实际调用的是PackageManagerService的queryContentProviders方法,如下所示:

public @NonNull ParceledListSlice queryContentProviders(String processName,
        int uid, int flags, String metaDataKey) {
    final int callingUid = Binder.getCallingUid();
    final int userId = processName != null ? UserHandle.getUserId(uid)
            : UserHandle.getCallingUserId();
    if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
    flags = updateFlagsForComponent(flags, userId, processName);
    ArrayList finalList = null;
    // reader
    synchronized (mPackages) {
        final Iterator i = mProviders.mProviders.values().iterator();
        while (i.hasNext()) {
            final PackageParser.Provider p = i.next();
            PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
            if (ps != null && p.info.authority != null
                    && (processName == null
                            || (p.info.processName.equals(processName)
                                    && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
                    && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {

                // See PM.queryContentProviders()'s javadoc for why we have the metaData
                // parameter.
                if (metaDataKey != null
                        && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
                    continue;
                }
                final ComponentName component =
                        new ComponentName(p.info.packageName, p.info.name);
                if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
                    continue;
                }
                if (finalList == null) {
                    finalList = new ArrayList(3);
                }
                ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
                        ps.readUserState(userId), userId);
                if (info != null) {
                    finalList.add(info);
                }
            }
        }
    }

    if (finalList != null) {
        Collections.sort(finalList, mProviderInitOrderSorter);
        return new ParceledListSlice(finalList);
    }

    return ParceledListSlice.emptyList();
}

queryContentProviders方法很长,但是其主要做的事情是,遍历了mProviders.mProviders中的值,而mProviders.mProviders的一个ArrayMap,value为PackageParse.Provider对象。所以,我们需要知道mProviders.mProviders是在哪里被赋值的,最后找到了PackageManagerService.ProviderIntentResolver的addProvider方法,如下所示:

public final void addProvider(PackageParser.Provider p) {
    if (mProviders.containsKey(p.getComponentName())) {
        Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
        return;
    }

    mProviders.put(p.getComponentName(), p);
    if (DEBUG_SHOW_INFO) {
        Log.v(TAG, "  "
                + (p.info.nonLocalizedLabel != null
                        ? p.info.nonLocalizedLabel : p.info.name) + ":");
        Log.v(TAG, "    Class=" + p.info.name);
    }
    final int NI = p.intents.size();
    int j;
    for (j = 0; j < NI; j++) {
        PackageParser.ProviderIntentInfo intent = p.intents.get(j);
        if (DEBUG_SHOW_INFO) {
            Log.v(TAG, "    IntentFilter:");
            intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
        }
        if (!intent.debugCheck()) {
            Log.w(TAG, "==> For Provider " + p.info.name);
        }
        addFilter(intent);
    }
}

该方法中,将参数中的PackageParser.Provider对象put了进来,而PackageParser.Provider对象存储的就是每一个ContentProvider的信息。在PackageManagerService的commitPackageSettings方法中调用了上述方法,commitPackageSettings方法如下所示:

private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
        UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
    ...省略
    //存储ContentProvider的信息
    int N = pkg.providers.size();
    StringBuilder r = null;
    int i;
    for (i=0; i

可以看到,commitPackageSettings方法中不仅仅存储了ContentProvider的信息,还存储了Service、BroadcastReceiver、Activity等信息,而PackageParser.Provider对象是遍历PackageParser.Package的providers获取的,而PackageParser.Package的providers就是通过解析AndroidManifest.xml得到的。PackageParser的parseBaseApplication方法就是解析方法,如下所示:

private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
    ...省略
    
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
                        true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.receivers.add(a);

            } else if (tagName.equals("service")) {
                Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.providers.add(p);

            } else {
                if (!RIGID_PARSER) {
                    Slog.w(TAG, "Unknown element under : " + tagName
                            + " at " + mArchiveSourcePath + " "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else {
                    outError[0] = "Bad element under : " + tagName;
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
            }
    }
    ...省略

    return true;
}

可以看到对于AndroidManifest中的tagName为provider,则解析其中的信息并生成PackageParser.Provider对象。

通过PMS获取ContentProvider列表信息的流程到此结束,通过上述分析,我们也验证了自定义的ContentProvider必须在AndroidManifest中注册这样的一个结论。

我们继续回到AMS的attachApplicationLocked方法中,在拿到了应用注册的ContentProvider信息后,远程调用了ApplicationThread的bindApplication方法,如下所示:

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List providers, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial) {

    if (services != null) {
        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    data.instrumentationName = instrumentationName;
    data.instrumentationArgs = instrumentationArgs;
    data.instrumentationWatcher = instrumentationWatcher;
    data.instrumentationUiAutomationConnection = instrumentationUiConnection;
    data.debugMode = debugMode;
    data.enableBinderTracking = enableBinderTracking;
    data.trackAllocation = trackAllocation;
    data.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    data.buildSerial = buildSerial;
    sendMessage(H.BIND_APPLICATION, data);
}

注意:参数中的上述的providers就是从PMS中获取的ContentProvider信息。

该方法发送了一个消息,消息ID是H.BIND_APPLICATION。在mH对象的handleMessage方法中处理该消息,并调用handleBindApplication方法,如下所示:

private void handleBindApplication(AppBindData data) {
    ...省略

    Application app;
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
    try {
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        if (!data.restrictedBackupMode) {
             //ContentProvider列表不为空
            if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers); //初始化并加载ContentProvider
                // 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);
            }
        }

        try {
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) {
            throw new RuntimeException(
                "Exception thrown in onCreate() of "
                + data.instrumentationName + ": " + e.toString(), e);
        }
        //调用Application的onCreate方法
        try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                  "Unable to create application " + app.getClass().getName()
                  + ": " + e.toString(), e);
            }
        }
    } finally {
        // If the app targets < O-MR1, or doesn't change the thread policy
        // during startup, clobber the policy to maintain behavior of b/36951662
        if (data.appInfo.targetSdkVersion <= Build.VERSION_CODES.O
                || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }

    ...省略
}

在handleBindApplication方法中,判断如果ContentProvider列表不为空,则调用installContentProviders方法,如下所示:

private void installContentProviders(
        Context context, List providers) {
    final ArrayList 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();
    }
}

对于传递过来的ContentProvider列表,遍历该列表,取出每一个ProviderInfo对象,并调用installProvider方法(第二个参数传过来的是null)。如下所示:

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 { 
            //通过类生成器生成了ContentProvider对象
            final java.lang.ClassLoader cl = c.getClassLoader();
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            provider = localProvider.getIContentProvider();
            ...省略
            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 {
        ...省略
    }

    ...省略
    return retHolder;
}

由于上一个方法中传递进来的holder为null,则走holder == null的逻辑,其中通过类生成器生成了ContentProvider对象,并且调用了ContentProviderProvider对象的attachInfo方法,attachInfo方法调用了另一个attachInfo重载方法,如下所示:

private void attachInfo(Context context, ProviderInfo info, boolean testing) {
    mNoPerms = testing;
    
    if (mContext == null) {
        mContext = context;
        if (context != null) {
            mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                    Context.APP_OPS_SERVICE);
        }
        mMyUid = Process.myUid();
        if (info != null) {
            setReadPermission(info.readPermission);
            setWritePermission(info.writePermission);
            setPathPermissions(info.pathPermissions);
            mExported = info.exported;
            mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
            setAuthorities(info.authority);
        }
        ContentProvider.this.onCreate();
    }
}

在该方法中执行了ContentProvider对象的onCreate方法。这也证明了一个结论:ContentProvider的onCreate方法是在UI线程执行的。

小结:通过上述的源码分析,我们知道了ContentProvider是在AndroidManifest中注册,并且在App启动时通过反射的形式创建的,创建后并且调用了每一个ContentProvider对象的onCreate方法。然后调用了Application对象的onCreate方法,整个App就这样运行起来了。

2、ContentProvider的调用

上面分析了ContentProvider对象是如何创建和初始化的,承接上面的内容,我们继续分析外部应用是如何调用ContentProvider的CRUD方法来和ContentProvider交互的。

我们拿其中的一个方法query进行分析,其他方法的流程与之类似,就不再重复分析了。

我们知道,在客户端应用中,调用ContentProvider的query方法是通过Context的getContentResolver().query方法来实现的,而Context的实现者对象是ContextImpl,其getContentResolver方法如下所示:

public ContentResolver getContentResolver() {
      return mContentResolver;
 }

很简单的返回了一个ContentResolver对象,而上面的mContenResolver实际类型是ApplicationContentResolver,所以getContentResolver().query方法实际上执行的是ApplicationContentResolver.query方法,而ApplicationContentResolver并没有重写query方法,所以query方法还是在ContentResolver中实现,如下所示:

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
        @Nullable String[] projection, @Nullable Bundle queryArgs,
        @Nullable CancellationSignal cancellationSignal) {
    Preconditions.checkNotNull(uri, "uri");
    IContentProvider unstableProvider = acquireUnstableProvider(uri);
    if (unstableProvider == null) {
        return null;
    }
    IContentProvider stableProvider = null;
    Cursor qCursor = null;
    try {
        long startTime = SystemClock.uptimeMillis();

        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = unstableProvider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        try {
            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
            unstableProviderDied(unstableProvider);
            stableProvider = acquireProvider(uri);
            if (stableProvider == null) {
                return null;
            }
            qCursor = stableProvider.query(
                    mPackageName, 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;
    } 
    ...省略
}

query方法中,获取数据的步骤主要有以下两步:

  • 通过acquireUnstableProvider方法获取IContentProvider,这是Binder对象。
  • 通过该Binder对象远程调用ContentProvider的query方法得到Cursor对象。

我们先来看第一步,acquireUnstableProvider方法如下所示:

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

一上来就判断了Uri的合法性,如果Uri的Scheme没有以SCHEME_CONTENT开头,则返回null。SCHEME_CONTENT的值是"content",说明了和ContentProvider交互的Uri必须以"content"作为scheme。然后调用了acquireUnstableProvider方法,acquireUnstableProvider在子类中实现,即在ApplicationContentResolver中实现,如下所示:

protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}

acquireUnstableProvider方法又调用了ActivityThread的acquireProvider方法,如下所示:

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
    //如果缓存中有,则从缓存中返回
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
        return provider;
    }

    ContentProviderHolder holder = null;
    try {
        //缓存中没有,远程调用AMS的getContentProvider方法返回IContentProvider对象
        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;
    }

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

如果缓存中有IContentProvider对象,则从缓存中获取;否则从远程调用AMS获取IContentProvider对象。

小结:这里说明了和ContentProvider交互是进程间的通信,而中间桥梁就是AMS。

通过AMS拿到了服务端应用的ContentProvider的代理对象IContentProvider,返回到上面的query方法,通过IContentProvider对象调用其query方法返回了Cursor对象给到客户端调用者。

我们知道,IContentProvider对象的实现者是ContentProvider.Transport。因此客户端通过IContentProvider远程调用query方法,实际上调用的是ContentProvider.Transport的query方法,如下所示:

public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
        @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
    validateIncomingUri(uri);
    uri = maybeGetUriWithoutUserId(uri);
    if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
        if (projection != null) {
            return new MatrixCursor(projection, 0);
        }

        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 {
        return ContentProvider.this.query(
                uri, projection, queryArgs,
                CancellationSignal.fromTransport(cancellationSignal));
    } finally {
        setCallingPackage(original);
    }
}

可以看到,ContentProvider.Transport的query方法最终调用了ContentProvider对象的query方法,最终的结果再通过Binder返回给客户端调用者。这样就完成了客户端远程调用ContentProvider的query方法的整个过程。

三、总结

客户端应用和服务端应用的ContentProvider交互是进程间的通信,其底层是通过Binder实现的。
ContentProvider对象在App启动时会创建并初始化,其onCreate方法是运行在服务端的主进程的;外部应用调用ContentProvider的CRUD方法是进程间的调用,是运行在系统的Binder进程的。

你可能感兴趣的:(【源码解析】ContentProvider的启动过程)