You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
android-notes/blogs/Android/口水话/四大组件的启动流程口水话.md

44 lines
5.6 KiB

---
四大组件的启动流程口水话
---
#### 目录
1. Activity
2. Service
3. BroadcastReceiver
4. 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 组件的启动流程就讲完了。下面再来说说绑定服务的启动流程。