6.8 KiB
目录
- Activity
- Service
- BroadcastReceiver
- ContentProvider
Activity 的启动流程
当我们在桌面点击一个应用程序的快捷图标时,Launcher 组件的成员函数 startActivitySafely 就会被调用来启动这个应用程序根 Activity。其中要启动的 MainActivity 信息就包含在 Intent 中。
Launcher 组件是如何获取这些信息的呢?其实是在系统启动时,PackageManagerService 在安装每一个应用程序的过程中,都会去解析其 Manifest 文件,找到 ACTION_MAIN 和 Category 为 LAUNCHER 的 Activity 组件,最后为这个 Acivity 创建一个快捷图标,当点击这个图标时,就会启动这个应用程序的入口 Activity。
回到 Launcher 的 startActivitySafely 函数中,它会调用其父类的 startActivityForResult 方法,实际上是调用 Instrumentation 的 execStartActivity 方法,这是一个插件化的 Hook 点。在这个方法中会传递三个重要的参数,ApplicationThread、mToken、Intent。ApplicationThread 是一个 Binder 本地对象,AMS 接下来就可以通过它来通知 Launcher 组件进入 Pause 状态,mToken 是一个 Binder 代理对象,它指向 AMS 中的一个 ActivityRecord 的 Binder 本地对象,每一个已经启动的 Activity 组件在 AMS 中都有一个对应的 ActivityRecord 对象,用来维护对应的 Activity 组件的运行状态及信息,这样 AMS 就可以获取 Launcher 组件的详细信息了。
在 Instrumentation 的 execStartActivity 中,通过 ActivityManagerNative 的 getDefault 获取 AMS 的一个代理对象,实际上就是调用 ServiceManager 的 getService,获取的是一个 IActivityManager 接口,这也是一个 Hook 点。然后就调到了它的实现类 ActivityManagerProxy 中的 startActivity 方法,在这个方法中,就会往 AMS tranact 一个 START_ACTIVITY_TRANSACTION 的请求。
在 AMS 收到这个请求时,就会让 ActivityStack 去处理。它首先根据上面传递过来的 ApplicationThread 去通知 Launcher 所在的应用程序进程去暂停 Launcher 组件,也就是回调到 ActivityThread 的内部类 ApplicationThread 的 schedulePauseActivity,往主线程发送一个 PAUSE_ACTIVITY 消息,mH 进行处理执行 handlePauseActivity。这个方法先调用 Activity 的 onPause 函数,然后执行 QueuedWork 里面的一些数据写入操作,SharedPreferences 的 apply 就会丢在这执行,如果数据量毕竟大的话可能会造成 ANR 的。最后就是通知 AMS Launcher 组件已经暂停完成了。
再回到 AMS 中,就开始真正的去启动 MainActivity 了,首先检查这个 Activity 对应的 ActivityRecord 对象所在的应用程序进程是否已经存在,如果存在就直接执行 realStartActivityLocked,如果不存在就先 startProcessLocked 去创建一个应用程序进程。创建应用程序进程即调用 Porcess start 函数,并指定该进程的入口函数为 ActivityThread,这一步其实是请求 Zygote fork 出一个应用程序进程。在 ActivityThread 的 main 函数中,创建消息循环,并且调用 attachApplication 把当前的 ApplicationThread 对象传递给 AMS,AMS 有了它就可以去通知应用程序去执行 MainActivity 的 onCreate 方法了。同上述执行 Launcher 的 onPause 函数一样,也是发一个消息给主线程,调用 handleLauncherActivity。
在 handleLauncherActivity 中,通过 Instrumentation 的 newActivity 去创建这个 Activity,然后创建 Application 对象以及 ContextImpl ,最后调用 Activity 的 attach 函数,这个函数里面会 new 一个 PhoneWindow 并关联 WindowManager,也就是 Activity 显示流程的入口函数了。最最后会调用到 Activity 的 onCreate 函数。
至此,Activity 的启动流程讲完了。如果是非根 Activity 的启动呢,只需要去掉创建应用程序进程那一步即可。
Service 的启动过程
首先说一下非绑定 Service 的启动过程。
在我们调用 Context 的 startService 方法时,是调用了 ContextImpl 的 startService,这个方法同样是获取 AMS 的代理对象,然后向 AMS transact 一个 START_SERVICE 请求。在 AMS 的 startServiceLocked 去处理这个请求。在 AMS 中,每一个 Service 组件都是用一个 ServiceRecord 对象来描述,就像每一个 Activity 组件都使用一个 ActivityRecord 对象来描述一样。
在 startServiceLocked 中,会首先向 AMS 中查找是否存在与参数 Intent 对应的一个 ServiceRecord 对象,如果不存在,就会到 PKMS 中去获取这个 Intent 对应的 Service 组件的信息,然后封装成一个 ServiceRecord 对象,最后调用 bringUpServiceLocked 来启动这个 Service。
在 bringUpServiceLocked 中,同 Activity 的启动一样,都会去首先判断该 Service 组件所在的应用程序进程是否已经存在,如果不存在就会先去创建应用程序进程,创建完成之后会把 ApplicationThread 传递给 AMS,以便 AMS 可以和这个新创建的应用程序进程通信。接着,就是 realStartServiceLocked,这个方法无非就是通过 ApplicationThread 向应用程序进程发送一个 CREATE_SERVICE 进程间通信请求,在应用程序进程是如何处理的呢?其实还是老样子,往主线程 Handler 发现一个消息,然后调用 handleCreateService。
在 handleCreateService 中,会通过 LoadedApk 的 ClassLoader 去加载这个 Service 类,然后在创建一个 ContextImpl,最后调用 Service 的 attach 和 onCreate 函数。
至此,非绑定 Service 组件的启动流程就讲完了。下面再来说说绑定服务的启动流程。
bindService 的流程要比 startService 流程复杂很多,不过核心就是把 ServiceConnection 对象传递给 Activity 组件,在应用程序进程会执行 handleCreateService 和 handleBindService,前者就是 startService 的流程,后者即是多出来的 bind 流程。
在 ContextImpl 的 bindService 中,会首先把 ServiceConnection 通过 getServiceDispatcher 调用转化成一个 IServiceConnection 接口,这个 IServiceConnection 是一个 Binder 对象,所以就可以跨进程传递给 Activity 了。然后就是获取 AMS 的代理对象,去执行 bindService 调用。这个方法会传入 AppplicationThread、ActivityToken 以及 Intent。在 AMS 成功将 Service 组件启动起来之后,就会把这个 Binder 对象封装成一个消息,发送给 Activity 组件所运行的应用程序的主线程消息队列中,最后在分发给 Activity 组件内部的成员变量 ServiceConnection 的 onServiceConnected 来处理。Activity 组件获得了 Service 组件的访问接口之后,就可以调用其相关服务了。
至此,绑定服务的流程就讲完了,虽然省略了很多,但是大致流程还是很清楚地嘛~