Android面试题(31)-App启动流程

先贴个链接,总结的挺全面

在看这篇文章之前,希望先看完我的之前的博客 android面试(6)-Binder机制,因为关于App启动流程设计很多Binder通信;

先将“三个进程”,“六个大类”进行介绍:

三个进程:

Launcher进程:整个App启动流程的起点,负责接收用户点击屏幕事件,它其实就是一个Activity,里面实现了点击事件,长按事件,触摸等事件,可以这么理解,把Launcher想象成一个总的Activity,屏幕上各种App的Icon就是这个Activity的button,当点击Icon时,会从Launcher跳转到其他页面;

SystemServer进程:这个进程在整个的Android进程中是非常重要的一个,地位和Zygote等同,它是属于Application Framework层的,Android中的所有服务,例如AMS, WindowsManager, PackageManagerService等等都是由这个SystemServer fork出来的。所以它的地位可见一斑

App进程:你要启动的App所运行的进程;

六个大类:

ActivityManagerService:(AMS)AMS是Android中最核心的服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要,它本身也是一个Binder的实现类。

Instrumentation:监控应用程序和系统的交互;

ActivityThread:应用的入口类,通过调用main方法,开启消息循环队列。ActivityThread所在的线程被称为主线程;

ApplicationThread:ApplicationThread提供Binder通讯接口,AMS则通过代理调用此App进程的本地方法

ActivityManagerProxy:AMS服务在当前进程的代理类,负责与AMS通信。

ApplicationThreadProxy:ApplicationThread在AMS服务中的代理类,负责与ApplicationThread通信。

可以说,启动的流程就是通过这六个大类在这三个进程之间不断通信的过程;

我先简单的梳理一下app的启动的步骤:

(1)启动的起点发生在Launcher活动中,启动一个app说简单点就是启动一个Activity,那么我们说过所有组件的启动,切换,调度都由AMS来负责的,所以第一步就是Launcher响应了用户的点击事件,然后通知AMS

(2)AMS得到Launcher的通知,就需要响应这个通知,主要就是新建一个Task去准备启动Activity,并且告诉Launcher你可以休息了(Paused);

(3)Launcher得到AMS让自己“休息”的消息,那么就直接挂起,并告诉AMS我已经Paused了;

(4)AMS知道了Launcher已经挂起之后,就可以放心的为新的Activity准备启动工作了,首先,APP肯定需要一个新的进程去进行运行,所以需要创建一个新进程,这个过程是需要Zygote参与的,AMS通过Socket去和Zygote协商,如果需要创建进程,那么就会fork自身,创建一个线程,新的进程会导入ActivityThread类,这就是每一个应用程序都有一个ActivityThread与之对应的原因;

(5)进程创建好了,通过调用上述的ActivityThread的main方法,这是应用程序的入口,在这里开启消息循环队列,这也是主线程默认绑定Looper的原因;

(6)这时候,App还没有启动完,要永远记住,四大组建的启动都需要AMS去启动,将上述的应用进程信息注册到AMS中,AMS再在堆栈顶部取得要启动的Activity,通过一系列链式调用去完成App启动;

下面这张图很好的描述了上面的六大步:

Android面试题(31)-App启动流程

接下来看看详细看看这几个步骤:

(1)Launcher响应用户点击,通知AMS

Launcher调用startActivity()方法,而startActivity()最终也是调用startActivityForResult();

 

  1. @Override
  2. public void startActivity(Intent intent, @Nullable Bundle options) {
  3. if (options != null) {
  4. startActivityForResult(intent, -1, options);
  5. } else {
  6. // Note we want to go through this call for compatibility with
  7. // applications that may have overridden the method.
  8. startActivityForResult(intent, -1);
  9. }
  10. }
  1. public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
  2. @Nullable Bundle options) {
  3. if (mParent == null) {
  4. options = transferSpringboardActivityOptions(options);
  5. Instrumentation.ActivityResult ar =
  6. mInstrumentation.execStartActivity(
  7. this, mMainThread.getApplicationThread(), mToken, this,
  8. intent, requestCode, options);
  9. if (ar != null) {
  10. mMainThread.sendActivityResult(
  11. mToken, mEmbeddedID, requestCode, ar.getResultCode(),
  12. ar.getResultData());
  13. }
  14. ......
  15. }

在其中调用了Instrumentation的execstartActivity方法:

 

  1. public ActivityResult execStartActivity(
  2. Context who, IBinder contextThread, IBinder token, Activity target,
  3. Intent intent, int requestCode, Bundle options) {
  4. .....
  5. try {
  6. intent.migrateExtraStreamToClipData();
  7. intent.prepareToLeaveProcess(who);
  8. int result = ActivityManager.getService()
  9. .startActivity(whoThread, who.getBasePackageName(), intent,
  10. intent.resolveTypeIfNeeded(who.getContentResolver()),
  11. token, target != null ? target.mEmbeddedID : null,
  12. requestCode, 0, null, options);
  13. checkStartActivityResult(result, intent);
  14. } catch (RemoteException e) {
  15. throw new RuntimeException("Failure from system", e);
  16. }
  17. return null;
  18. }

这里调用了ActivityManager.getService方法返回的就是ActivityManagerProxy,用于与AMS通信,这样通过这些一系列的方法调用,就把Launcher进程和AMS进程进行通信了一次;

(2)AMS响应Launcher进程请求

主要是通过ActivityStackSupervisor:startActivityUncheckedLocked去给Activity申请Task的;此方法经过intent的标志值设置,通过findTaskLocked函数来查找存不存这样的Task,这里返回的结果是null,即intentActivity为null,因此,需要创建一个新的Task来启动这个Activity。现在处理堆栈顶端的Activity是Launcher,与我们即将要启动的MainActivity不是同一个Activity,创建了一个新的Task里面来启动这个Activity。

经过栈顶检测,则需要将Launcher推入Paused状态,才可以启动新的Activity。后续则调用至ActivityStack:startPausingLocked;此方法里有prev.app.thread是一个ApplicationThread对象的远程接口,通过调用这个远程接口的schedulePauseActivity来通知Launcher进入Paused状态。至此,AMS对Launcher的请求已经响应,这是我们发现又通过Binder通信回调至Launcher进程;

(3)Launcher进程挂起Launcher,再次通知AMS

这部分Launcher的ActivityThread处理页面Paused并且再次通过ActivityManagerProxy通知AMS。

(4)AMS创建新的进程

创建新进程的时候,AMS会保存一个ProcessRecord信息,如果应用程序中的AndroidManifest.xml配置文件中,我们没有指定Application标签的process属性,系统就会默认使用package的名称。每一个应用程序都有自己的uid,因此,这里uid + process的组合就可以为每一个应用程序创建一个ProcessRecord。

这里主要是调用Process:start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数,这就是每一个应用程序都有一个ActivityThread实例来对应的原因。

 

先判断是否有相应的 ProcessRecord,如果不存在,就需要新建进程,这个进程就是相应的应用进程。ActivityManagerService 通过 Socket 通信的方式和 Zygote 进行协商,Zygote 在其监听的 /dev/socket/zygote socket 中发现有需要创建进程的请求后,会 fork 自身,并返回相应的 Process Id。这个 Process 会进行相应的初始化,使得其具备与系统服务进行 IPC 通信的能力;

(5)应用进程初始化

我们来看Activity的main函数,这里绑定了主线程的Looper,并进入消息循环,大家应该知道,整个Android系统是消息驱动的,这也是为什么主线程默认绑定Looper的原因:

 

  1. public static void main(String[] args) {
  2. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
  3. SamplingProfilerIntegration.start();
  4. // CloseGuard defaults to true and can be quite spammy. We
  5. // disable it here, but selectively enable it later (via
  6. // StrictMode) on debug builds, but using DropBox, not logs.
  7. CloseGuard.setEnabled(false);
  8. Environment.initForCurrentUser();
  9. // Set the reporter for event logging in libcore
  10. EventLogger.setReporter(new EventLoggingReporter());
  11. // Make sure TrustedCertificateStore looks in the right place for CA certificates
  12. final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
  13. TrustedCertificateStore.setDefaultUserDirectory(configDir);
  14. Process.setArgV0("<pre-initialized>");
  15. Looper.prepareMainLooper();
  16. ActivityThread thread = new ActivityThread();
  17. thread.attach(false);
  18. if (sMainThreadHandler == null) {
  19. sMainThreadHandler = thread.getHandler();
  20. }
  21. if (false) {
  22. Looper.myLooper().setMessageLogging(new
  23. LogPrinter(Log.DEBUG, "ActivityThread"));
  24. }
  25. // End of event ActivityThreadMain.
  26. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  27. Looper.loop();
  28. throw new RuntimeException("Main thread loop unexpectedly exited");
  29. }

attach函数最终调用了ActivityManagerService的远程接口ActivityManagerProxy的attachApplication函数,传入的参数是mAppThread,这是一个ApplicationThread类型的Binder对象,它的作用是AMS与应用进程进行进程间通信的。

(6)在AMS中注册应用进程,启动启动栈顶页面

前面我们提到了AMS负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,通过上一个流程我们知道应用进程创建后通过Binder驱动与AMS产生交互,此时AMS则将应用进程创建后的信息进行了一次注册,如果拿Windows系统程序注册到的注册表来理解这个过程,可能会更形象一些。

mMainStack.topRunningActivityLocked(null)从堆栈顶端取出要启动的Activity,并在realStartActivityLockedhan函数中通过ApplicationThreadProxy调回App进程启动页面。

此时在App进程,我们可以看到,经过一些列的调用链最终调用至MainActivity:onCreate函数,之后会调用至onResume,而后会通知AMS该MainActivity已经处于resume状态。至此,整个启动流程告一段落。

上面讲的是activity的启动流程,下面要说的是,android系统的启动流程,通俗来说,按下电源键,开机的过程系统做了些什么:

1.当系统引导程序启动Linux内核,内核会加载各种数据结构,和驱动程序,加载完毕之后,Android系统开始启动并加载第一个用户级别的进程:init(system/core/init/Init.c)

我们来看一看这个Init.c代码,看main函数

  1. int main(int argc, char **argv)
  2. {
  3. ...
  4. //执行Linux指令
  5. mkdir("/dev", 0755);
  6. mkdir("/proc", 0755);
  7. mkdir("/sys", 0755);
  8. ...
  9. //解析执行init.rc配置文件
  10. init_parse_config_file("/init.rc");
  11. ...
  12. }

主要创建了一些目录,并且加载执行了一个init.rc的文件,我们来看看这个init.rc

2.在system\core\rootdir\Init.rc中定义好的指令都会开始执行,其中执行了很多bin指令,启动系统服务

  1. //启动孵化器进程,此进程是Android系统启动关键服务的一个母进程
  2. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  3. socket zygote stream 666
  4. onrestart write /sys/android_power/request_state wake
  5. onrestart write /sys/power/state on
  6. onrestart restart media
  7. onrestart restart netd

里面启动了一个app_process,我们看看这是什么:

3.在appprocess文件夹下找到appmain.cpp,查看main函数,发现以下代码

  1. int main(int argc, const char* const argv[])
  2. {
  3. ...
  4. //启动一个系统服务:ZygoteInit
  5. runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
  6. ...
  7. }

仍然是为启动一个系统服务做准备,我们继续跟下去看看:

4.在ZygoteInit.java中,查看main方法

  1. public static void main(String argv[]) {
  2. ...
  3. //加载Android系统需要的类
  4. preloadClasses();
  5. ...
  6. if (argv[1].equals("true")) {
  7. //调用方法启动一个系统服务
  8. startSystemServer();
  9. }
  10. ...
  11. }

在这里主要是先加载了android系统所需要的类,然后启动系统服务,继续跟下去:

5.startSystemServer()方法的方法体

  1. String args[] = {
  2. "--setuid=1000",
  3. "--setgid=1000",
  4. "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
  5. "--capabilities=130104352,130104352",
  6. "--runtime-init",
  7. "--nice-name=system_server",
  8. "com.android.server.SystemServer",
  9. };
  10. ...
  11. //分叉启动上面字符串数组定义的服务
  12. pid = Zygote.forkSystemServer(
  13. parsedArgs.uid, parsedArgs.gid,
  14. parsedArgs.gids, debugFlags, null,
  15. parsedArgs.permittedCapabilities,
  16. parsedArgs.effectiveCapabilities);

 6.SystemServer服务被启动

  1. public static void main(String[] args) {
  2. ...
  3. //加载动态链接库
  4. System.loadLibrary("android_servers");
  5. //执行链接库里的init1方法
  6. init1(args);
  7. ...
  8. }

7.动态链接库文件和java类包名相同,找到com_android_server_SystemServer.cpp文件

在com_android_server_SystemServer.cpp文件中,找到了

  1. static JNINativeMethod gMethods[] = {
  2. /* name, signature, funcPtr */
  3. //给init1方法映射一个指针,调用system_init方法
  4. { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
  5. };

 8.android_server_SystemServer_init1方法体中调用了system_init(),system_init()没有方法体

在system_init.cpp文件中找到system_init()方法,方法体中 //执行了SystemServer.java的init2方法 runtime->callStatic("com/android/server/SystemServer", "init2");

回到SystemServer.java,在init2的方法体中

  1. //启动一个服务线程
  2. Thread thr = new ServerThread();
  3. thr.start();

 9.在ServerThread的run方法中

  1. //准备消息轮询器
  2. Looper.prepare();
  3. ...
  4. //启动大量的系统服务并把其逐一添加至ServiceManager
  5. ServiceManager.addService(Context.WINDOW_SERVICE, wm);
  6. ...
  7. //调用systemReady,准备创建第一个activity
  8. ((ActivityManagerService)ActivityManagerNative.getDefault())
  9. .systemReady(new Runnable(){
  10. ...
  11. });

10.在ActivityManagerService.java中,有systemReady方法,方法体里找到

  1. //检测任务栈中有没有activity,如果没有,创建Launcher
  2. mMainStack.resumeTopActivityLocked(null);

11.在ActivityStack.java中,方法resumeTopActivityLocked

  1. // Find the first activity that is not finishing.
  2. ActivityRecord next = topRunningActivityLocked(null);
  3. ...
  4. if (next == null) {
  5. // There are no more activities! Let's just start up the
  6. // Launcher...
  7. if (mMainStack) {
  8. return mService.startHomeActivityLocked();
  9. }
  10. }
  11. ...

 

转自:https://blog.****.net/pgg_cold/article/details/79491791