【艺术探索笔记】 第 9 章 四大组件的工作过程

第 9 章 四大组件的工作过程

对四大组件的运行状态和工作方式做概括描述
分析四大组件工作过程


9.1 四大组件的运行状态

除了 BroadcastReceiver 外,其他三种组件都必须在 AndroidManifest 中注册。
BroadcastReceiver 既可以在清单文件注册,也可以通过代码注册。

调用方式上,ContentProvider 无需借助 Intent,其他三种需要借助 Intent

  1. Activity 是一个展示型组件,用于向用户展示一个界面,接收用户输入信息进行交互

    • 对用户来说 Activity 就是一个 Android 应用的全部(其他三大组件对用户来说都是不可感知的)
    • 启动由 Intent 触发。Intent 分为 显式(明确的指向一个 Activity) 和 隐式(指向一个或多个目标 Activity,也可能 0 个)。
    • 具有特定启动模式
    • 可以停止(调用 finish() 方法)
    • 主要作用:展示一个界面与用户交互,扮演前台界面
  2. Service 是计算型组件,用于在后台执行计算任务。

    • 用户无法直接感知
    • 两种运行状态:启动状态、绑定状态。启动状态不需要和外界交互;绑定状态外界可以方便与 Service 通信。
    • Service 本身运行在主线程,耗时操作需要单独开个线程去做
    • 它可以停止,稍复杂,需灵活采用 stopService 和 unBindService 方法
  3. BroadcastReceiver 是消息型组件,在不同的组件或者不同应用间传递消息

    • 用户无法感知(工作在系统内部)
    • 两种注册方式:静态注册和动态注册。静态注册指在清单文件注册,应用安装时会被系统解析,不需要 app 启动就能收到广播;动态注册通过 Context.registerReceiver() 来实现,不需要的时候用 Context.unRegisterReceiver() 来解除广播,必须 app 启动才能注册并接收广播
    • 实际开发中通过 Context 的一系列 send 方法发送广播,然后系统发送给相应的广播接收者。发送和接受的匹配通过广播接收者的<intent-filter>描述
  4. ContentProvider 是数据共享型组件,向其他组件或其他应用共享数据

    • 用户无法直接感知
    • 内部实现增删改查操作
    • 内部维护一份数据集合。可以是数据库,也可以用任何类型实现,比如 List、Map
    • 增删改查需处理线程同步(因为是在 Binder 线程池中被调用的)
    • 不需要手动停止

9.2 Activity 的工作过程(基于 api 27 重新分析了一波)

api 27 中,启动流程的调用链跟书中的稍微有点不一样

启动一个新的 Activity 示例:

    val intent = Intent(this, SecondActivity::class.java)
    startActivity(intent)
  • Activity 的 startActivity 最终会调用 startActivityForResult,它的实现如下:

    image

    • mParent 代表 ActivityGroup。它最开始被用来在一个页面中嵌入多个子 Activity,(api 13 之后被废弃,推荐用 fragment)
    • mMainThread.getApplicationThread() 参数,类型是 ApplicationThread(ActivityThread 的内部类)。ApplicationThreadActivityThread 在 Activity 的启动过程中发挥着重要作用
  • InstrumentationexecStartActivity 方法:

    image

    • 由上可看出,启动 Activity 真正的实现由 ActivityManager.getService() 的 startActivity 方法来完成。 ActivityManagerService(下面简称 AMS)继承自 IActivityManager 这个 Binder 接口,因此 AMS 也是个 Binder,它是 IActivityManager 的具体实现。
    • AMS 这个 Binder 对象采用单例模式对外提供:

          public static IActivityManager getService() {
              return IActivityManagerSingleton.get();
          }
      
          private static final Singleton<IActivityManager> IActivityManagerSingleton =
                  new Singleton<IActivityManager>() {
                      @Override
                      protected IActivityManager create() {
                          final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                          final IActivityManager am = IActivityManager.Stub.asInterface(b);
                          return am;
                      }
                  };
    • checkStartActivityResult 检查启动 Activity 的结果
  • Activity 的启动过程又转移到了 AMS 中,下边看 AMS 的 startActivity 方法:

    image

    • 可以看到 Activity 的启动过程又转移到了 ActivityStarterstartActivityMayWait 方法中了
    • startActivityMayWait 中又调用了 startActivityLocked 方法;然后 startActivityLocked 方法中又调用了 startActivity 22 参数 方法;然后 startActivity 22 参数方法中又调用了 startActivity 9 参数 方法;然后 startActivity 9 参数方法中又调用了 startActivityUnchecked 方法;接着 startActivityUnchecked 方法又调用了 ActivityStackSupervisorresumeFocusedStackTopActivityLocked 方法。
    • 这个时候启动过程已经从 ActivityStarter 到 ActivityStackSupervisor 中去了
  • 接着分析 ActivityStackSupervisorresumeFocusedStackTopActivityLocked 方法

    image

    • 看上边代码,此时启动流程又从 ActivityStackSupervisor 转移到 ActivityStack 中了
  • 分析 ActivityStackresumeTopActivityUncheckedLocked 方法:

    image

    • resumeTopActivityUncheckedLocked 调用了 resumeTopActivityInnerLocked 方法,resumeTopActivityInnerLocked 内部又调用了 ActivityStackSupervisorstartSpecificActivityLocked 方法
    • 此时启动流程又从 ActivityStack 转移到 ActivityStackSupervisor
  • 分析 ActivityStackSupervisorstartSpecificActivityLocked 方法:

    image

    • 方法内部调用了 realStartActivityLocked
  • 接着看 ActivityStackSupervisor # realStartActivityLocked 方法,里边有如下一段重要的代码:

    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, !andResume,
                        mService.isNextTransitionForward(), profilerInfo);
    • app.thread 的类型是 IApplicationThread(Binder 接口),它的实现是 ActivityThread 的内部类 ApplicationThread

Activity 的启动过程在 ActivityStarter、ActivityStackSupervisor 和 ActivityStack 之间的传递顺序(api-27):

这里写图片描述

绕了一大圈,Activity 的启动过程最终回到了 ApplicationThread 中。

  • 接着上边流程,继续看 ApplicationThread 的 scheduleLaunchActivity 方法:

    image

    • 上边方法逻辑很简单,主要是发送一个启动 Activity 的消息交由 Handler 处理。这个 Handler 的名字是 H
  • 接着看 sendMessage 方法的最终实现:

    image

  • 接下来看 Handler H 对消息的处理:

    image

  • 接着调用了 handleLaunchActivity 方法:

    image

    • 上边代码可看出,performLaunchActivity 方法最终完成了 Activity 对象的创建和启动过程,并且 ActivityThread 通过 handleResumeActivity 方法来调用被启动的 Activity 的 onResume 这一生命周期方法。

performLaunchActivity 主要完成了如下几件事

  1. 从 ActivityClientRecord 中获取待启动的 Activity 的组建信息

    image

  2. 创建 ContextImpl 对象,通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象

    image

    • ContextImpl 是一个很重要的数据结构,它是 Context 的具体实现,Context 中的大部分逻辑都是由 ContextImpl 来完成的。
  3. 通过 LoadedApk 的 makeApplication 方法城市创建 Application 对象

    image

    • 上边方法可以看出,如果 Application 已经被创建过了,就不会再重复创建了,这意味着一个应用只有一个 Application 对象。
    • Application 对象的创建也是通过 Instrumentation 来完成的(通过类加载器)
    • Application 创建完成后,系统会通过 Instrumentation 的 callActivityOnCreate 来调用 Application 的 onCarete 方法
  4. 通过 Activity 的 attach 方法来完成一些重要数据的初始化

    activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    • ContextImpl 是通过 Activity 的 attach 方法来和 Activity 建立关联的
    • 在 attach 方法中还会完成 Window 的创建并建立 Activity 和 Window 的关联。这样当 Window 接收到外部输入事件后就可以传递给 Activity
  5. 调用 Activity 的 onCreate 方法

    mInstrumentation.callActivityOnCreate(activity, r.state);,到这里,算是分析完 Activity 的整个启动过程了。


9.3 Service 的工作过程

  • 启动状态:主要用于执行后台计算
  • 绑定状态:主要用于其他组件和 Service 的交互
  • 两种状态可以共存。可以同时处于启动状态和绑定状态

9.3.1 Service 的 启动过程

启动 Service 的示例代码:

    val intent = Intent(this, MyService::class.java)
    startService(intent)
下面是从 startService 开始追踪的调用链流程图(api-27):

这里写图片描述

调用链流程中的源代码的分析:
  • ContextWrapper#startService()

    image

    • 上面代码的 mBase 类型是 ContextImpl ,Activity 被创建时通过 attach 方法将一个 ContextImpl 对象关联起来,这个 ContextImpl 就是 mBase。
    • ContextWrapper 的实现大部分都是通过 ContextImpl 来实现的,在设计模式中这种叫桥接模式
  • ContextImpl#startService()ContextImpl#startServiceCommon()

    image

    • startService 方法调用 startServiceCommon 方法
    • startServiceCommon 方法内部调用 AMS 的 startService 方法(IPC通信)
  • ActivityManagerService#startService()

    image

    • AMS 通过 mServices 这个对象来完成 Service 后续的启动流程。
    • mServices 类型是 ActiveServices。ActiveServices是辅助 AMS 进行 Service 管理的类。包括启动、绑定、停止等
    • startServiceLocked 方法尾部会调用 startServiceInnerLocked 方法
  • ActiveServices#startServiceInnerLocked()

    image

    • ServiceRecord 描述的是一个 Service 记录,它一直贯穿着整个 Service 的启动过程
    • startServiceInnerLocked 又调用 bringUpServiceLocked 方法处理启动工作。在 bringUpServiceLocked 方法中又调用 realStartServiceLocked 方法。
  • ActiveServices#realStartServiceLocked()

    image

    • 先通过 app.thread 的 scheduleCreateService 方法创建 Service 并调用其 onCreate。(IPC)
    • 接着通过 sendServiceArgsLocked 调用 Service 的其他方法。如 onStartCommand。(IPC)
    • app.thread 就是 ActivityThread 的内部类 ApplicationThread
  • ApplicationThread#scheduleCreateService()

            public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
                updateProcessState(processState, false);
                CreateServiceData s = new CreateServiceData();
                s.token = token;
                s.info = info;
                s.compatInfo = compatInfo;
    
                sendMessage(H.CREATE_SERVICE, s);
            }
    • 跟 Activity 的启动过程类似,都是通过发消息给 Handler H 来完成的。
    • H 接受 CREATE_SERVICE,并调用 ActivityThread#handleCreateService 来完成 Service 的最终启动
  • ActivityThread#handleCreateService()

    image

    1. 通过类加载器创建 Service 的实例
    2. 创建 ContextImpl对象
    3. 尝试创建 Application 对象并调用 onCreate。(Application 一个 app 只有一个)
    4. 调用 Service 的 attach 方法,建立与 ContextImpl 的连接以及一些其他操作
    5. 调用 Service 的 onCreate 方法,并将 Service 对象存储到 ActivityThread 的一个列表中。

到此 Service 的启动过程就结束了

ActivityThread 中还会通过 handleServiceArgs 方法调用 Service 的 onStartCommand 方法:

image

9.3.2 Service 的绑定过程

也是从 ContextWrapper 开始的

  • ContextWrapper#bindService()

        @Override
        public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
            return mBase.bindService(service, conn, flags);
        }
    • 过程和 Service 启动过程类似。ContextImpl#bindService 最终调用 bindServiceCommon 方法
  • ContextImpl#bindServiceCommon

    image

    主要完成两件事:

    1. 将客户端 ServiceConnection 对象转化成 ServiceDispatcher.InnerConnection 对象

      • 因为服务的绑定可能是跨进程的,ServiceConnection 必须借助 Binder 才能让远程服务端回调自己的方法。而 ServiceDispatcher.InnerConnection 刚好充当 Binder 角色
      • ServiceDispatcher 起着连接 ServiceConnection 和 InnerConnection 的作用
      • 看 LoadedApk 的 getServiceDispatcher 方法:
          public final IServiceConnection getServiceDispatcher(ServiceConnection c,
          Context context, Handler handler, int flags) {
              synchronized (mServices) {
                  LoadedApk.ServiceDispatcher sd = null;
                  ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
                  if (map != null) {
                      if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                      sd = map.get(c);
                  }
                  if (sd == null) {
                      sd = new ServiceDispatcher(c, context, handler, flags);
                      if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                      if (map == null) {
                          map = new ArrayMap<>();
                          mServices.put(context, map);
                      }
                      map.put(c, sd);
                  } else {
                      sd.validate(context, handler);
                  }
                  return sd.getIServiceConnection();
              }
          }

      mService 是一个 ArrayMap,存着应用当前活动的 ServiceConnection 和 ServiceDispatcher 的映射关系,定义如下:

          private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
          = new ArrayMap<>();

      getServiceDispatcher 方法里,系统先查找是否有相同的 ServiceConnection,如果不存在就重新创建并保存在 mServices 中对应的当前应用的活动 Map 中。映射关系 key 是 ServiceConnection、value 是 ServiceDispatcher。

      ServiceDispatcher 内部又保存了 ServiceConnection 和 InnerConnection 对象。

      当 Service 和客户端建立连接后,系统会通过 InnerConnection 调用 ServiceConnection 的 onServiceConnected 方法,这个过程有可能跨进程

    2. 通过 AMS 来完成 Service 的具体绑定过程

  • ActivityManagerService#bindService()

    image

    AMS 会调用 ActivityServices 的 bindServiceLocked 方法,bindServiceLocked 再调用 bringUpServiceLocked,到这里就跟 Service 启动流程重合了。

    和启动流程不同的是,Service 的绑定过程会调用 app.thread 的 scheduleBindService 方法,这个过程的实现在 ActiveServices 的 requestServiceBindingLocked 方法中。现在再来看一下 ActiveServices 的 realStartServiceLocked 方法:

    image

  • ActiveServices#requestServiceBindingLocked()

    image

    调用了 ApplicationThread 的 scheduleBindService 方法(IPC),然后 ApplicationThread 通过 Handler H 再调用 ActivityThread 的 handleBindService 方法。

  • ActivityThread#handleBindService()

    image

    1. 根据 Service 的 token 取出 Service 对象
    2. 调用 Service 的 onBind 方法,返回一个 Binder 对象给客户端使用
    3. onBind 调用后已经处于绑定状态了,但这时候客户端不知道已经连接成功了,所以必须调用客户端的 ServiceConnection 的 onServiceConnected。这个过程由 AMS 的 publishService 完成
  • ActivityManagerService#publishService()

    image

  • ActiveServices#publishServiceLocked()

    image

    其中 c 的类型是 ConnectionRecord,c.conn de类型是 ServiceDispatcher.InnerConnection,service 就是 onBind 方法返回的 Binder对象。

  • InnerConnection#connected()

    image

    在这里调用了 ServiceDispatcher 的 connected 方法。

  • ServiceDispatcher#connected()

    image

    对于 Service 绑定过程来说,ServiceDispatcher 的 mActivityThread 是一个 Handler,其实它就是 ActivityThread 中的 H。分析得知 mActivityThread 不会为 null。所以 RunConnection 就可以运行在主线程中,由此可知客户端 ServiceConnection 中的方法在主线程被回调的。

  • ServiceDispatcher#doConnected()

    image

    由于 ServiceDispatcher 内部保存了客户端的 ServiceConnection 对象,因此可以很方便的调用它的 onServiceConnected 方法


9.4 BroadcastReceiver 的工作过程

  • 注册过程
  • 发送和接收过程

广播接收者实现示例:

  1. 定义广播接收者

image

  1. 注册广播接收者

    • 静态注册

    image

    • 动态注册

    image

  2. 发送广播

    image

9.4.1 广播的注册过程

注册分为静态个动态。静态注册在应用安装时系统自动完成注册,具体来说是由 PMS(PackageManagerService) 来完成整个注册过程的。

除了广播以外其他三大组件也是应用安装时由 PMS 解析并注册的

广播动态注册源码调用链:

  1. ContextWrapper#registerReceiver()

    image

    这里 mBase 的类型是 ContextImpl(前边介绍过)

    ContextImpl 的 registerReceiver 方法调用了自己的 registerReceiverInternal 方法

  2. ContextImpl#registerReceiverInternal()

    image

    上边代码系统首先从 mPackageInfo 获取 IIntentReceiver 对象,然后再采用跨进程的方式向 AMS 发送广播注册请求。

    用 IIntentReceiver 而不用 BroadcastReceiver 是因为广播注册过程是跨进程通信。

    IIntentReceiver 必须是一个 Binder 接口,它的具体实现是 LoadedApk.ReceiverDispatcher.InnerReceiver,ReceiverDispatcher 的内部同时保存了 BroadcastReceiver 和 InnerReceiver,这样当接收到广播时,可以方便地调用 BroadcastReceiver 的 onReceive 方法。

    • LoadedApk#getReceiverDispatcher()

      image

      getReceiverDispatcher 方法重新创建了一个 ReceiverDispatcher 对象并将其保存的 InnerReceiver 对象作为返回值返回。

  3. ActivityManagerService#registerReceiver()

    image

    把远程的 InnerReceiver 对象以及 IntentFilter 对象存储起来。这样整个广播注册流程就完成了

9.4.2 广播的发送和接收过程

通过 send 方法发送广播时,AMS 会查找出匹配的广播接收者并将广播发送给他们处理。

广播的发送有几种类型:普通广播、有序广播、粘性广播。

这里只分析普通广播(无序广播)的实现

广播的发送和接收本质上是一个过程的两个阶段。从发送开始分析:

  1. ContextWrapper 的 sendBroadcast 方法,调用 ContextImpl#sendBroadcast()

    image

  2. ActivityManagerService#broadcastIntent()

    image

  3. ActivityManagerService#broadcastIntentLocked()

    在方法的最开始有如下一行:

        // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    表示在 api 27 里默认情况广播不会发给已经停止的应用,从 android 3.1 开始广播就已经有这种特性了。

    两个标记位用来表示广播是否要对停止状态的应用起作用:

    • FLAG_INCLUDE_STOPPED_PACKAGES

      表示包含已经停止的应用,广播会发送给已经停止的应用

    • FLAG_EXCLUDE_STOPPED_PACKAGES

      表示不包含已经停止的应用,广播不会发送给已经停止的应用

    应用的停止状态:

    1. 安装后未运行

    2. 被手动或其他应用强停了

    若要处在停止状态的应用接收到广播,再发广播的时候设置 FLAG_INCLUDE_STOPPED_PACKAGES 标记位就可以了。两种标记位共存时,以 FLAG_INCLUDE_STOPPED_PACKAGES 为准

    在 broadcastIntentLocked 方法内部会根据 intent-filter 查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到 BroadcastQueue 中,接着 BroadcastQueue 就会将广播发送给相应的广播接收者:

    image

  4. BroadcastQueue#scheduleBroadcastsLocked()

    image

    没有立即发送广播,而是发了一个 BROADCAST_INTENT_MSG 消息,BroadcastQueue 收到消息后调用 processNextBroadcast 方法

  5. BroadcastQueue#processNextBroadcast()

    这里只看对普通广播处理的这部分代码:

    image

    无需广播存储在 mParallelBroadcasts 中,系统会遍历 mParallelBroadcasts 并将其中的广播发送给它们所有的接收者。

    具体发送过程是通过 deliverToRegisteredReceiverLocked 方法实现的,它负责将一个广播发送给一个特定的接收者,它内部调用了 performReceiveLocked 来完成具体的发送过程

  6. BroadcastQueue#performReceiveLocked()

    image

    这里调用了 ApplicationThread 的 scheduleRegisteredReceiver 进行进一步处理

  7. ApplicationThread#scheduleRegisteredReceiver()

    image

    调用了 InnerReceiver 的 performReceive 方法,performReceive 方法又会调用 LoadedApk.ReceiverDispatcherperformReceive 方法

  8. LoadedApk.ReceiverDispatcher#performReceive()

    image

    上边代码创建一个 Args 对象并通过 mActivityThread 的 post 方法来执行 Args 中的逻辑。Args 实现了 Runnable 接口。

    mActivityThread 是 ActivityThread 中的 Handler H,这意味着 Args 里边的逻辑会在主线程执行,即 广播接收者的 onReceive 方法

  9. LoadedApk.ReceiverDispatcher.Args#getRunnable()

    关键代码:

    
        final BroadcastReceiver receiver = mReceiver;
    
        receiver.setPendingResult(this);
        receiver.onReceive(mContext, intent);
    

    这时候 BroadcastReceiver 的 onReceive 执行了,意味着应用已经收到广播了,流程结束


9.5 ContentProvider 的工作过程

是内容共享型组件,通过 Binder 向其他组件乃至其他应用提供数据。

当 ContentProvider 所在的进程启动时,ContentProvider 会同时启动并被发布到 AMS 中。

ContentProvider 的 onCreate 要先于 Application 的 onCreate 而执行,这在四大组件中是少有现象。

  • 当一个应用启动时,入口方法为 ActivityThread 的 main 方法

    image

    创建 ActivityThread 的实例并调用它的 attach 方法;创建主线程的消息队列 sMainThreadHandler,其实是 Handler H。

  • ActivityThread#attach()

    image

    远程调用 AMS 的 attachApplication 方法并将 ApplicationThread 对象提供给 AMS。

    ApplicationThread 是一个 Binder 对象,它的 Binder 接口是 IApplicationThread,主要用于 ActivityThread 和 AMS 之间的通信。

  • ActivityManagerService#attachApplication()

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

    它内部会跨进程调用 ApplicationThread 的 bindApplication 方法,bindApplication 方法会通过 Handler H 切换到 ActivityThread 调用 handleBindApplication 方法

  • ActivityThread#handleBindApplication()

    image

    1. 创建 ContextImpl 和 Instrumentation;
    2. 调用 LoadedApk 的 makeApplication 方法创建 Application 对象;
    3. 调用 installContentProviders 方法加载 ContentProvider;

      installContentProviders 方法完成了 ContentProvider 的启动工作,它的实现如下所示:

      image

      上边代码遍历当前进程的 PeoviderInfo 的列表并一一调用 installProvider 方法来启动它们,接着将已经启动的 ContentProvider 发送到 AMS 中,AMS 会把它们存储在 ProviderMap 中,这样一来外部调用者就可以直接从 AMS 中获取 ContentProvider 了。

      installProvider 有这么一段代码:

      image

      类加载器完成了 ContentProvider 的创建;attachInfo 方法用来调用它的 onCreate 方法。

      image

      ContentProvider 已经被创建并且其 onCreate 也已经被调用,意味着启动流程结束了

    4. 通过 Instrumentation 的 callApplicationOnCreate 方法去调用 Applicaton 的 onCreate 方法。

流程图:

image

启动后,外界就可以通过它提供的增删改查接口去操作 ContentProvider 里边的数据源。这四个方法都是通过 Binder 来调用的。外界只能通过 AMS 根据 Uri 来获取它对应的 Binder 接口 IContentProvider(具体实现是 ContentProvider.Transport)。

一般 ContentProvider 都是单实例的。android:multiprocess 属性决定是否是单实例,默认是 false,即单实例。如果是多实例的话,每个调用者进程都存在一个 ContentProvider 对象。实际开发中没有多实例的应用场景,因此可以简单认为 ContentProvider 都是单实例的。

通过 ContentResolver 访问 ContentProvider 的流程

getContext().getContentResolver() 获取的是 ApplicationContentResolver 对象,ApplicationContentResolver 继承自 ContentResolver 并实现了它里边的抽象方法。

当 ContentProvider 未启动时,第一次访问它就会触发 ContentProvider 的创建,当然也伴随着 ContentProvider 所在进程的启动。

这里分析 query 方法访问 ContentProvider 的调用链

  • ContentResolver#query()

    image

    • 首先获取 IContentProvider 对象,不论是通过 acquireUnstableProvider 方法还是 acquireProvider 方法获取,最终都会调用 ActivityThread#acquireProvider() 方法。

      image

      • ActivityThread#acquireProvider()

        image

        如果 ActivityThread 存在目标 ContentProvider 了,就直接返回;如果目标 ContentProvider 没有启动,就通过 ActivityManagerService#getContentProvider() 请求启动目标 ContentProvider,最后再通过 installProvider 来修改引用计数。

        ContentProvider 启动时会伴随着进程的启动,在 AMS 中首先会启动 ContentProvider 所在的进程,然后再启动 ContentProvider。启动进程通过 AMS 的 startProcessLocked 方法来完成,内部主要通过 Process 的 start 方法来完成新进程启动,新进程启动后的入口方法为 ActivityThread 的 main 方法。ContentProvider 的启动流程前边已经分析过了,这里点到即止。

        个人有一个疑问,进程启动的细节到 ZygoteProcess 这个类之后就完全没头绪了。。以后查查

    • 再看一下 IContentProvider 调用了 query 方法,找一下 IContentProvider 的具体实现,在 ActivityThread#acquireProvider() 方法里,我们看到最后返回了 ContentProviderHolder$provider 这个对象;在 ActivityThread#installProvider 方法里有这样几行代码:

      ContentProvider localProvider = null;
      IContentProvider provider;
      
      final java.lang.ClassLoader cl = c.getClassLoader();
      localProvider = (ContentProvider)cl.
          loadClass(info.name).newInstance();
      
      provider = localProvider.getIContentProvider();
      
      holder = new ContentProviderHolder(info);
      holder.provider = provider;
      

      可以看出,ContentProvider#getIContentProvider() 方法返回了我们需要的 IContentProvider 对象,再看一下 ContentProvider#getIContentProvider() 方法的具体实现:

      
      public IContentProvider getIContentProvider() {
          return mTransport;
      }
      

      返回的 mTransport 类型是 Transport,所以 IContentProvider 这个 Binder 接口的具体实现是 Transport。看一下 Transport#query()

      image

      这里直接调用了 ContentProvider 的 query 方法,执行结果再通过 Binder 返回给调用者。到这里流程就全部结束了。


猜你喜欢

转载自blog.csdn.net/Captive_Rainbow_/article/details/81542070
今日推荐