每日一题:Android app进程是怎么启动的?
在android面试中,我们常会遇到Framework面试相关问题,而今天要分享的就是Android app进程是怎么启动的?
其主要考察的是程序员对app进程的创建和启动流程。
问题正解:
分析app如何被fork出来,然后,讲解app启动过程中的重要细节,我们首先分析app启动的方案,然后再重点讲解相关的启动流程。
什么是冷启动和热启动
- 冷启动 当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动,也就是先实例化Application。
- 热启动 当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,也就是直接从进程中启动,不需要重新创建Application,这个方式叫热启动。
由于热启动是从已有的后台进程中启动,所以热启动并不会走Application这步,它一般是直接走MainActivity,所以热启动过程只需要创建和初始化一个MainActivity即可,不必创建和初始化Application。
冷启动的启动流程分析
1)启动APP进程
当我们点击Launcher桌面程序的APP图标时,Launcher程序会调用startActivity()函数,通过Binder跨进程通信,发送消息给system_server进程中的AMS。在system_server进程中,由AMS通过socket通信告知Zygote进程fork出一个子进程(APP进程)。
对上面流程中需要进行几点说明:1) AMS不是一个独立的进程,它只是system_server进程的一个服务;2)Launcher进程要启动另外一个app就必须发消息给AMS,由AMS发送App进程创建的命令;3)Launcher是通过去ServiceManager进程中获取AMS的Binder的方案得到AMS的Binder,然后通过这个Binder调用AMS的服务;4)当AMS收到Launcher启动进程的事件后,会在AMS体系中进行各种检测和判断,最终发现被启动的App进程还未创建;5)此时AMS会给Zygote发送一个 socket消息,而zygote中的socket服务器会接收到这个消息,然后会执行Zygote 的fork,并产生一个子进程,这个子进程就是APP进程。
具体流程如下图所示:
1)launcher进程不能直接去启动app进程,所以它会调用SM拿到ATMS的代理对象ActivityTaskManagerProxy,然后执行ActivityTaskManagerProxy的startActivity方法。
2)ActivityTaskManager收到执行startActivity方法的请求后会执行将请求转交给AMS,然后AMS会去判断当前Activity所对于的Application进程是否存在,如果进程存在,那么就是热启动,如果进程不存在那么就是冷启动。在冷启动的时候,AMS将发送socket请求给到Zygote进程,通知zygote去创建app进程。
3)Zygote进程收到socket请求就会去执行fork函数,fork会产生一个子进程,这个进程就是需要启动的app进程了。这个子进程同时就具备了Zygote进程的一切,这个 说明在zygote相关的内容中有详细介绍。
4)开启APP主线程
APP进程启动后,会实例化一个ActivityThread,并在native层面通过反射执行其main函数,同时触发执行attach函数,同时会创建ApplicationThread、Looper、Handler对象,开启主线程消息循环Looper.loop()。
对于上面流程的需要进行几点说明:
1)App进程创建后,Zygote会执行反射相关的代码,通过反射执行ActivityThread的main函数,此时代码进入ActivityThread类,并完成了ActivityThread的初始化。
2)ActivityThread执行main函数的代码如下所示:
public static void main(String[] args) {
...
//核心代码1
Looper.prepareMainLooper();
...
//核心代码2
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
//核心代码3
Looper.loop();
...
}
首先,创建了主线程的Looper,并且开启了主线程的Looper.loop(),对线程开始执行消息循环。这样的设计可以让android所有的主线程的事务都封装成为Message,然后通过MessageQueue的循环来完成消息轮询和执行。
其次,核心代码2中创建了ActivityThread对象,同时调用了thread.attach()函数,这个函数会获取AMS服务的binder,然后调用AMS的attachApplication()方法,这个方法会将App的 IApplicationThread 对象传递给AMS,AMS这时候就持有了App的Binder对象,当AMS需要向App进行通信的时候就能够非常的便利了。
5)创建并初始化Application和Activity
ActivityThread的main函数通过调用attach方法进行 Binder 通信,通知system_server进程执行AMS的attachApplication方法。在attachApplication方法中,AMS分别通过bindApplication、scheduleLaunchActivity方法,并且将这些操作封装成Message并通知APP进程的主线程Handler,对APP进程的Application和Activity进行初始化,并执行Application、Activity的生命周期。最后在Activity的生命周期中执行UI的创建和显示。
至此,应用启动流程完成,这里对源码细节不做过多分析。
今日分享到此结束,下期更精彩~
关注公众号:Android老皮 解锁 《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版
内容如下:
1.Android车载应用开发系统学习指南(附项目实战) 2.Android Framework学习指南,助力成为系统级开发高手 3.2023最新Android中高级面试题汇总+解析,告别零offer 4.企业级Android音视频开发学习路线+项目实战(附源码) 5.Android Jetpack从入门到精通,构建高质量UI界面 6.Flutter技术解析与实战,跨平台首要之选 7.Kotlin从入门到实战,全方面提升架构基础 8.高级Android插件化与组件化(含实战教程和源码) 9.Android 性能优化实战+360°全方面性能调优 10.Android零基础入门到精通,高手进阶之路
敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔
转载自:https://juejin.cn/post/7252171148757106743