Android之本进程ContentProvider启动流程分析

1、ContentProvider介绍

ContentProvider主要用于向外部提供数据
1、自己应用进程提供数据

2、其它app进程的提供数据

这里分析本进程的ContentProvider的启动过程


 
2、ContentProvider启动分析

1、我们知道Android程序入口在ActivityThread.java文件的main函数里面,如下代码

        public static void main(String[] args) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
            SamplingProfilerIntegration.start();
     
            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);
     
            Environment.initForCurrentUser();
     
            // Set the reporter for event logging in libcore
            EventLogger.setReporter(new EventLoggingReporter());
     
            AndroidKeyStoreProvider.install();
     
            // Make sure TrustedCertificateStore looks in the right place for CA certificates
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
     
            Process.setArgV0("<pre-initialized>");
     
            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();
     
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }


 

2、我们这里可以看到有关键函数thread.attach(false)方法,我们跟踪进去,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("<pre-initialized>",
                                                        UserHandle.myUserId());
                RuntimeInit.setApplicationObject(mAppThread.asBinder());
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                try {
                    mgr.attachApplication(mAppThread);
                } catch (RemoteException ex) {
                    // Ignore
                }
                // Watch for getting close to heap limit.
                BinderInternal.addGcWatcher(new Runnable() {
                    @Override public void run() {
                        if (!mSomeActivitiesChanged) {
                            return;
                        }
                        Runtime runtime = Runtime.getRuntime();
                        long dalvikMax = runtime.maxMemory();
                        long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                        if (dalvikUsed > ((3*dalvikMax)/4)) {
                            if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                    + " total=" + (runtime.totalMemory()/1024)
                                    + " used=" + (dalvikUsed/1024));
                            mSomeActivitiesChanged = false;
                            try {
                                mgr.releaseSomeActivities(mAppThread);
                            } catch (RemoteException e) {
                            }
                        }
                    }
                });
    *******


 

3、这里有个关键方法,mgr.attachApplication(mAppThread),我们看下这个方法ActivityManagerService.java文件里面的实现

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

 
 

4、我们再看关键函数attachApplicationLocked函数部分实现

        private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid) {
            *******
            boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
            List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
     
            *******
                thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                        profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                        app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(mConfiguration), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked());
                updateLruProcessLocked(app, false, null);
                app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();

 


5、这里又调用了generateApplicationProvidersLocked(app)函数,这个函数返回了一个ProviderInfo对象的集合,我们跟踪这个函数看是如何得到这个集合的。

     private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
            List<ProviderInfo> providers = null;
            try {
                ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().
                    queryContentProviders(app.processName, app.uid,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
                providers = slice != null ? slice.getList() : null;
            } catch (RemoteException ex) {
            }
            if (DEBUG_MU) Slog.v(TAG_MU,
                    "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
            int userId = app.userId;
            if (providers != null) {
                int N = providers.size();
                app.pubProviders.ensureCapacity(N + app.pubProviders.size());
                for (int i=0; i<N; i++) {
                    ProviderInfo cpi =
                        (ProviderInfo)providers.get(i);
                    boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                            cpi.name, cpi.flags);
                    if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
                        providers.remove(i);
                        N--;
                        i--;
                        continue;
                    }
                    ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                    ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                    if (cpr == null) {
                        cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                        mProviderMap.putProviderByClass(comp, cpr);
                    }
                    if (DEBUG_MU) Slog.v(TAG_MU,
                            "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
                    app.pubProviders.put(cpi.name, cpr);
                    if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
                        app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                                mProcessStats);
                    }
                    ensurePackageDexOpt(cpi.applicationInfo.packageName);
                }
            }
            return providers;
        }

 

这里很明显是查询ContentProvider通过app进程名字和app的uid,然后得到一个ProviderInfo的集合,就是这里的providers,然后我们遍历这个集合,通过每个ProviderInfo的packageName和name属性构建ComponentName这个对象,然后再去构建ContentProviderRecord对象,key为ComponentName,value为ContentProviderRecord添加到这个ProviderMap对象里面,也就是这行代码

mProviderMap.putProviderByClass(comp, cpr);

然后把返回的providers作为参数,传递给了bindApplication函数。

 


6、我们看下bindApplication函数的实现,在ActivityThread.java文件里面看下实现

           public final void bindApplication(String processName, ApplicationInfo appInfo,
                    List<ProviderInfo> providers, ComponentName instrumentationName,
                    ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                    IInstrumentationWatcher instrumentationWatcher,
                    IUiAutomationConnection instrumentationUiConnection, int debugMode,
                    boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                    Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                    Bundle 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.enableOpenGlTrace = enableOpenGlTrace;
                data.restrictedBackupMode = isRestrictedBackupMode;
                data.persistent = persistent;
                data.config = config;
                data.compatInfo = compatInfo;
                data.initProfilerInfo = profilerInfo;
                sendMessage(H.BIND_APPLICATION, data);
            }

我们可以看到发了一个携带providers数据的消息,消息是H.BIND_APPLICATION,handler类里面的handleMessage方法里面的收到消息处理如下

                    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(data)方法。

 


7、我们看下handleBindApplication(data)方法部分实现

           try {
                // If the app is being launched for full backup or restore, bring it up in
                // a restricted environment with the base application class.
                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<ProviderInfo> 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) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            } finally {
                StrictMode.setThreadPolicy(savedPolicy);
            }

这里为什么我要说明下面这行函数呢?因为我们可以跟踪makeApplication函数里面去会调用我们平时代码里面继承了Application类的attachBaseContext函数,这是我们一般app的Application类首先执行的函数

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

我们来跟踪下makeApplication函数,传递的第二个参数是null,也就是Instrumentation传递进去是null,这里的data.info对象是LoadedApk对象,所以我们需要到这个LoadedApk.java文件里面来看这个函数的部分实现如下

     public Application makeApplication(boolean forceDefaultAppClass,
                Instrumentation instrumentation) {
            if (mApplication != null) {
                return mApplication;
            }
     
            Application app = null;
     
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
     
            try {
                java.lang.ClassLoader cl = getClassLoader();
                if (!mPackageName.equals("android")) {
                    initializeJavaContextClassLoader();
                }
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
                appContext.setOuterContext(app);
            } catch (Exception e) {
                if (!mActivityThread.mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate application " + appClass
                        + ": " + e.toString(), e);
                }
            }
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
     
            if (instrumentation != null) {
                try {
                    instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!instrumentation.onException(app, e)) {
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            }

因为Instrumentation传递进去的是null,所以我们不会执行 instrumentation.callApplicationOnCreate(app)方法,也就是不会执行Application里面的onCreate方法,我们再看下mActivityThread.mInstrumentation.newApplication这个方法,在Instrumentation.java文件看这个函数实现

        public Application newApplication(ClassLoader cl, String className, Context context)
                throws InstantiationException, IllegalAccessException,
                ClassNotFoundException {
            return newApplication(cl.loadClass(className), context);
        }

接着看newApplication函数实现如下

        static public Application newApplication(Class<?> clazz, Context context)
                throws InstantiationException, IllegalAccessException,
                ClassNotFoundException {
            Application app = (Application)clazz.newInstance();
            app.attach(context);
            return app;
        }

然后再看这个Application的attach函数如下

     /* package */ final void attach(Context context) {
            attachBaseContext(context);
            mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
        }

我们发现这里已经调用了我们平时见得很多在Application里面的attachBaseContext(context)方法

 


8、再来分析ContentProvider的调用,我们看下这个installContentProviders(app, providers)这个函数,这里providers是携带过来的数据,方法实现如下

        private void installContentProviders(
                Context context, List<ProviderInfo> providers) {
            final ArrayList<IActivityManager.ContentProviderHolder> results =
                new ArrayList<IActivityManager.ContentProviderHolder>();
     
            for (ProviderInfo cpi : providers) {
                if (DEBUG_PROVIDER) {
                    StringBuilder buf = new StringBuilder(128);
                    buf.append("Pub ");
                    buf.append(cpi.authority);
                    buf.append(": ");
                    buf.append(cpi.name);
                    Log.i(TAG, buf.toString());
                }
                IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                        false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
                if (cph != null) {
                    cph.noReleaseNeeded = true;
                    results.add(cph);
                }
            }
     
            try {
                ActivityManagerNative.getDefault().publishContentProviders(
                    getApplicationThread(), results);
            } catch (RemoteException ex) {
            }
        }

我们可以看到这里调用了installProvider函数,我们看下这个函数的调用,在ActivityThread.java文件里面

        private IActivityManager.ContentProviderHolder installProvider(Context context,
                IActivityManager.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;
                }
                try {
                    final java.lang.ClassLoader cl = c.getClassLoader();
                    localProvider = (ContentProvider)cl.
                        loadClass(info.name).newInstance();
                    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);
            }

我们可以看到返回对象是IActivityManager.ContentProviderHolder,然后这里先获取相应的Context上下文信息,然后ClassLoader加载对应的ContentProvider类,并创建该类的对象,然后我们调用了如下函数,参数是上下文,和函数传递进来的

ProviderInfo.

localProvider.attachInfo(c, info);

然后我们跟踪这个函数到里面去,(在ContentProvider类文件里面)代码如下,

        public void attachInfo(Context context, ProviderInfo info) {
            attachInfo(context, info, false);
        }

继续跟踪这个函数attachInfo函数

        private void attachInfo(Context context, ProviderInfo info, boolean testing) {
            mNoPerms = testing;
     
            /*
             * Only allow it to be set once, so after the content service gives
             * this to us clients can't change it.
             */
            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函数,这里ContentProvider就创建完了。

然后installProvider方法还有部分如下

            IActivityManager.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 IActivityManager.ContentProviderHolder(info);
                        holder.provider = provider;
                        holder.noReleaseNeeded = true;
                        pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                        mLocalProviders.put(jBinder, pr);
                        mLocalProvidersByName.put(cname, pr);
                    }
                    retHolder = pr.mHolder;
                } else {
                    ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                    if (prc != null) {
                        if (DEBUG_PROVIDER) {
                            Slog.v(TAG, "installProvider: lost the race, updating ref count");
                        }
                        // We need to transfer our new reference to the existing
                        // ref count, releasing the old one...  but only if
                        // release is needed (that is, it is not running in the
                        // system process).
                        if (!noReleaseNeeded) {
                            incProviderRefLocked(prc, stable);
                            try {
                                ActivityManagerNative.getDefault().removeContentProvider(
                                        holder.connection, stable);
                            } catch (RemoteException e) {
                                //do nothing content provider object is dead any way
                            }
                        }
                    } else {
                        ProviderClientRecord client = installProviderAuthoritiesLocked(
                                provider, localProvider, holder);
                        if (noReleaseNeeded) {
                            prc = new ProviderRefCount(holder, client, 1000, 1000);
                        } else {
                            prc = stable
                                    ? new ProviderRefCount(holder, client, 1, 0)
                                    : new ProviderRefCount(holder, client, 0, 1);
                        }
                        mProviderRefCountMap.put(jBinder, prc);
                    }
                    retHolder = prc.holder;
                }
            }
     
            return retHolder;
        }

获取ContetProvider的IContentProvider赋值给provider变量,然后调用

IBinder jBinder = provider.asBinder();

IContentProvider可以理解为ContentProvider客户端和服务端通信的接口,这里根据ProviderInfo的信息和Binder类型IContentProvider对象,创建一个ContentProviderHolder对象,它里边封装了这个ContentProvider的ProviderInfo和IContentProvider信息,然后又调用了下面的方法,我们跟踪进去

        private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
                ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
            final String auths[] = holder.info.authority.split(";");
            final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
     
            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;
        }

然后这里根据Provider的信息构造了ProviderClientRecord对象,authority是一个多属性值,变量这个Provider对应的所有authority,每个authority属性为key,保存这个ProviderClientReocrd到mProviderMap的HashMap中

我们可以看下这个地方本地声明的缓存存储信息,在ActivityThread.java这个类文件中

        // The lock of mProviderMap protects the following variables.
        final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
            = new ArrayMap<ProviderKey, ProviderClientRecord>();
        final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
            = new ArrayMap<IBinder, ProviderRefCount>();
        final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
            = new ArrayMap<IBinder, ProviderClientRecord>();
        final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
                = new ArrayMap<ComponentName, ProviderClientRecord>();

通过不同的key,来存储,然后构建不同的map对象,分别是以authority为key、IBinder文key、ComponentName为key.

代码后面还按照其它方式保存到内存

                        mLocalProviders.put(jBinder, pr);
                        mLocalProvidersByName.put(cname, pr);

按照不同的存储类型分别保存不同的ContentProvider集合中。

然后我们在第8步开始的installContentProviders方法里面还有这个函数没有分析,publishContentProviders函数,代码实现如下

        public final void publishContentProviders(IApplicationThread caller,
                List<ContentProviderHolder> providers) {
            if (providers == null) {
                return;
            }
     
            enforceNotIsolatedCaller("publishContentProviders");
            synchronized (this) {
                final ProcessRecord r = getRecordForAppLocked(caller);
                if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
                if (r == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                          + " (pid=" + Binder.getCallingPid()
                          + ") when publishing content providers");
                }
     
                final long origId = Binder.clearCallingIdentity();
     
                final int N = providers.size();
                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);
                        mProviderMap.putProviderByClass(comp, dst);
                        String names[] = dst.info.authority.split(";");
                        for (int j = 0; j < names.length; j++) {
                            mProviderMap.putProviderByName(names[j], dst);
                        }
                        int NL = mLaunchingProviders.size();
                        int j;
                        for (j=0; j<NL; j++) {
                            if (mLaunchingProviders.get(j) == dst) {
                                mLaunchingProviders.remove(j);
                                j--;
                                NL--;
                            }
                        }
                        synchronized (dst) {
                            dst.provider = src.provider;
                            dst.proc = r;
                            dst.notifyAll();
                        }
                        updateOomAdjLocked(r);
                        maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                                src.info.authority);
                    }
                }
                Binder.restoreCallingIdentity(origId);
            }
        }

 

为每一个ContentProvider信息创建了一个ContentProviderRecord对象,保存到了ProviderMap集合中,启动的ContentProvider按照authority为key保存到ProviderMap中,这里工作主要就是将ContentProvider的信息保存到AMS服务中去。

AMS服务保存ContentProvider的信息主要是在类ProviderMap中,它里边有两种保存的Provider信息的集合
1. ProviderByClass

以ComponentName为key保存了ContentProviderRecord的信息

2. ProviderByName

 
 

以authority为key保存了ContentProviderRecord的信息

 
 

最后我们不是看到这个函数,

notifyAll()

 

不同进程间调用ContentProvider的时候,先会判断该ContentProvider所在的进程是否已经启动,如果有启动需要首先启动该进程,在该进程启动完成后这个ContentProvider也就启动起来了,比如在我们项目中,我们有2个进程,然后一个ContentProvider在一个进程里面,我们在自己app通过下面的方法拉起ContentProvider

 

getContentResolver().insert

如果没有启动的时候,AMS就会首先启动个进程及ContentProvider,并把这个ContentProviderRecord添加到等待队列mLaunchingProviders中去,如下声明

        final ArrayList<ContentProviderRecord> mLaunchingProviders
                = new ArrayList<ContentProviderRecord>();

然后等他它启动完成,此处代码就是新的进程及ContentProvider启动完成后,首先判断是否在等待进程中,如果有,就将该ContentProvider信息从等待队列中移除,并调用notifyAll来唤醒等待的工作。

 

9、最后分析handleBindApplication函数的最后一步

            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
            try {
                // If the app is being launched for full backup or restore, bring it up in
                // a restricted environment with the base application class.
                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<ProviderInfo> 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) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            } finally {
                StrictMode.setThreadPolicy(savedPolicy);
            }

当有触发ContentProvider启动完成的时候,我们可以看到才去执行

 mInstrumentation.callApplicationOnCreate(app);

这里跟踪进去也就是Application的onCreate方法,所以它是在ContentProvider的onCreate后面(前提是同时启动Appliation和ContentProvider)

 

 
3、总结

AMS服务保存ContentProvider的信息主要是在类ProviderMap中,它里边有两种保存的Provider信息的集合
1. ProviderByClass
以ComponentName为key保存了ContentProviderRecord的信息
2. ProviderByName

以authority为key保存了ContentProviderRecord的信息

3、如果Applicaton和ContentProvider都会起来,确保ContentProvider在本进程里面,不能单独开辟一个进程放ContentProvider,那么部分函数执行顺序如下

Application继承类的的attachBaseContext方法----->ContentProvider继承类的onCreate方法---->pplication继承类的onCreate函数

4、如果是Applicaton和ContentProvider不在同进程,不管是否在一个app里面的不同进程还是在另外一个app的进程,那么会先启动Application继承类的的attachBaseContext方法----->Application继承类的onCreate函数,如果有另外一个进程或者一个app触发ContentProvider,那么依然部分函数执行顺序如下

Application继承类的的attachBaseContext方法----->ContentProvider继承类的onCreate方法---->pplication继承类的onCreate函数,因为每个进程都有一个Application,所以会在ContentProvider里面再次启动一次Application

 


 


 



  作者:chen.yu
深信服三年半工作经验,目前就职游戏厂商,希望能和大家交流和学习,
微信公众号:编程入门到秃头 或扫描下面二维码
零基础入门进阶人工智能(链接)