Android 浅析 ContentProvider (四) 启动原理

前言

Linus Benedict Torvalds : RTFSC – Read The Fucking Source Code

ContentProvider下文将会简称CP。
ContentResolver下文将会简称CR。

CP 启动原理

安装APK的时候,并不会把相应的Content Provider加载到内存中来,系统采取的是懒加载的机制,等到第一次使用这个Content Provider的时候,系统才会把它加载到内存中来,下次再要使用这个Content Provider的时候,就可以直接从内存读取了。

ContentProvider 的启动原理从startProcessLocked开始,也就是Android的应用程序启动原理。

Step1.ActivityManagerService.startProcessLocked
Step2.Process.start
Step3.ActivityThread.main
Step4.ActivityThread.attach
Step5.ActivityManagerService.attachApplication

所以我们从attachApplication开始浅析

ActivityManagerService

Step 1.attachApplicationLocked

private final boolean attachApplicationLocked(    IApplicationThread thread, int pid) {    ProcessRecord app;    if (pid != MY_PID && pid >= 0) {        synchronized (mPidsSelfLocked) {            app = mPidsSelfLocked.get(pid);        }    }    ...    app.makeActive(thread, mProcessStats);    app.curAdj = app.setAdj = -100;    app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;    app.forcingToForeground = null;    updateProcessForegroundLocked(app, false, false);    app.hasShownUi = false;    app.debugging = false;    app.cached = false;    app.killedByAm = false;    ...    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);    List providers = normalMode ? generateApplicationProvidersLocked(app) : null;    ...    try {          ...         thread.bindApplication(processName, app.instrumentationInfo != null ? app.instrumentationInfo : app.info, providers,  app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, mConfiguration, getCommonServicesLocked());          ...     }}private final List generateApplicationProvidersLocked(ProcessRecord app) {    List providers = null;    providers = AppGlobals.getPackageManager().        queryContentProviders(app.processName, app.uid,        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);    int userId = app.userId;    if (providers != null) {        int N = providers.size();        app.pubProviders.ensureCapacity(N + app.pubProviders.size());        for (int i=0; i

这里首先根据传进来的进程ID找到相应的进程记录块,然后对这个进程记录块做一些初倾始化的工作。接下来通过调用generateApplicationProvidersLocked获得需要在这个过程中加载的Content Provider列表,最后调用从参数传进来的IApplicationThread对象thread的bindApplication函数来执行一些应用程序初始化工作。

ActivityThread

Step 2.bindApplication

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

bindApplication把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息最终是是在ActivityThread类的handleBindApplication函数中进行处理的。

Step 3.handleBindApplication

private final void handleBindApplication(AppBindData data) {      ...     List providers = data.providers;      if (providers != null) {          installContentProviders(app, providers);          ...     }      ...  }  

这个函数有很多内容,其中对于Provider就是调用installContentProviders函数来在本地安装Content Providers信息。

Step 4.installContentProviders

private void installContentProviders(        Context context, List providers) {    final ArrayList results =        new ArrayList();    for (ProviderInfo cpi : providers) {        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);        if (cph != null) {            cph.noReleaseNeeded = true;            results.add(cph);        }    }    ActivityManagerNative.getDefault().publishContentProviders(        getApplicationThread(), results);}

installContentProviders做了两件事,第一件是调用installProvider来在本地安装每一个Content Proivder的信息,并且为每一个Content Provider创建一个ContentProviderHolder对象来保存相关的信息。第二件就是调用ActivityManagerService服务的publishContentProviders函数来通知ActivityManagerService服务,这个进程中所要加载的Content Provider,都已经准备完毕。

Step 5.installProvider

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) {        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 {            c = context.createPackageContext(ai.packageName,                    Context.CONTEXT_INCLUDE_CODE);        }        final java.lang.ClassLoader cl = c.getClassLoader();        localProvider = (ContentProvider)cl.            loadClass(info.name).newInstance();        provider = localProvider.getIContentProvider();        localProvider.attachInfo(c, info);    } else {        provider = holder.provider;    }    IActivityManager.ContentProviderHolder retHolder;    synchronized (mProviderMap) {        IBinder jBinder = provider.asBinder();        if (localProvider != null) {            ComponentName cname = new ComponentName(info.packageName, info.name);            ProviderClientRecord pr = mLocalProvidersByName.get(cname);            if (pr != null) {                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 (!noReleaseNeeded) {                    incProviderRefLocked(prc, stable);                    ActivityManagerNative.getDefault().removeContentProvider(holder.connection, stable);                }            } 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;}

installProvider主要是在应用程序进程中把相应的Content Provider类加载进来。

先来看下其中的localProvider.getIContentProvider()函数,它是从ContentProvider中返回该对象的。

ContentProvider

Step 6.getIContentProvider

public abstract class ContentProvider implements ComponentCallbacks {      ...    private Transport mTransport = new Transport();      ...    class Transport extends ContentProviderNative {          ...    }      public IContentProvider getIContentProvider() {          return mTransport;      }      ...}

ContentProvider类和Transport类的关系就类似于ActivityThread和ApplicationThread的关系,其它应用程序不是直接调用ContentProvider接口来访问它的数据,而是通过调用它的内部对象mTransport来间接调用ContentProvider的接口。

接着我们来看localProvider.attachInfo(c, info)函数,通过它可以开始初始化Provider。

Step 7.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();    }}

主要就是根据这个Content Provider的信息info来设置相应的读写权限,然后调用它的子类的onCreate函数来让子类执行一些初始化的工作。

接着回到Step 5.installProvider

ActivityThread

Step 8 ->Step 5.installProvider

在ActivityThread中,以Content Provider的authority为键值来把这个Content Provider的信息保存在mProviderMap成员变量中,因为一个Content Provider可以对应多个authority,因此这里用一个for循环来处理,同时又以这个Content Provider对应的Binder对象provider来键值来把这个Content Provider的信息保存在mLocalProviders成员变量中,表明这是一个在本地加载的Content Provider。

接着返回到Step 4 instalContentProviders

Step 9.publishContentProviders

public final void publishContentProviders(    IApplicationThread caller,    List providers) {    synchronized (this) {        final ProcessRecord r = getRecordForAppLocked(caller);        final long origId = Binder.clearCallingIdentity();        final int N = providers.size();        for (int i=0; i

此函数调用的作用就是通知ActivityMangerService,需要在这个进程中加载的Content Provider已经完加载完成。在这句函数最后执行了dst.notiryAll语句会通知之前加载的线程要被唤醒。

最后将会返回getProvider函数中执行接下来的installProvider()

Step 10 .installProvider

holder = installProvider(c, holder, holder.info,        true /*noisy*/, holder.noReleaseNeeded, stable);

与Step 5不同,这里传进来的参数provider是不为null的,因此,它不需要执行在本地加载Content Provider的工作,只需要把从ActivityMangerService中获得的Content Provider接口保存在成员变量mProviderMap中就可以了。

更多相关文章

  1. Android实现机制(二)——View绘制机制
  2. Android(安卓)Camera 三 CameraService 和 Client 链接到 HAL
  3. Android横竖屏切换重载问题与小结
  4. android --- Afianl框架里面的FinalBitmap加载网络图片
  5. setStreamMute无法Mute部分stream
  6. 三.如何创建窗口模式的Activity
  7. Android自定义Dialog二次调用报错解决方法:The specified child a
  8. Android(安卓)JsBridge源码学习
  9. Android类参考---Fragment

随机推荐

  1. Android:shape的使用详解(2)
  2. Android开发常用属性
  3. android编译过程详解(二)
  4. Qt on Android(安卓)核心编程
  5. Android高效加载大图、多图解决方案,有效
  6. 你不知道的Runnable接口,深度解析Runnable
  7. android一些基础知识
  8. Android(安卓)调试桥(adb)是多种用途的工
  9. Android简明开发教程二十三:发布应用
  10. Android――动画专题研究