Android应用启动流程分析(1),读完我这份《Android开发核心源码精编解析》面试至少多要3K

  • 启动ServiceManager,它是Binder服务管理器,管理所有Android系统服务
  1. 在系统启动后init进程会fork Zygote进程,Zygote作为孵化器进程,它的main函数会创建好自己的环境准备孵化子进程,并开始等待孵化请求:
  • 创建一个server端的socket, name为zynote,用于和客户端进程通信
  • 预加载类和资源,提高应用启动速度
  • 启动SystemServer进程
  • 监听socket,当有一个应用程序启动时,就会向它发出请求,然后zygote进程fock自己来创建的一个新的子进程。
  1. Zygote进程首先会fork自己孵化出SystemServer进程,它的main函数主要负责:
  • 启动binder线程池,这是SystemServer与其他进程通信的基础
  • 初始化Looper
  • 创建了SystemServiceManager对象,它会启动Android中的各种服务。包括AMS、PMS、WMS
  • 启动桌面进程,这样才能让用户见到手机的界面。
  • 开启loop循环,开启消息循环,SystemServer进程一直运行,保障其他应用程序的正常运行。
  1. 当系统里面的zygote进程运行之后,后续启动APP,就相当于开启一个新的进程。而Android为了实现资源共用和更快的启动速度,子进程都是通过zygote进程fork出来的。所以说,除了init进程fork出来的第一个进程zygote,其他应用进程都是zygote的子进程,也不难理解为何这个孵化器进程的英文名叫zygote(受精卵),因为所有的应用进程都是由它孵化诞生。

3.2 SystemServer进程

SystemServer是由zygote进程fork出来的第一个进程,SystemServer和Zygote是Android Framework最重要的2个进程。 系统里面重要的服务都是在这个进程里面开启的,比如ActivityManagerService、PackageManagerService、WindowManagerService。

应用启动流程基本是围绕着ActivityManagerService和ActivityThread展开。

3.3 Android系统里的Client/Server模式

平时我们所熟知的前端(Web\Android\iOS)通过网络与服务器通信是客户端-服务端模式的体现,而在Android Framework中,四大组件的创建、生命周期也是通过这样的模式进行通信:

  1. 服务器端(server)指的就是SystemServer进程,这个进程提供了很多服务 比如AMS、PMS、WMS等等,所有的App进程都可以与其通信。
  2. 客户端(client)指的就是各个独立的App进程。

Android开发者都应该知道,通过包名和Activity类名就可以打开一个APP。实际上,项目里的业务代码startActivity()方法并不是直接创建进程、拉起APP的。而是通过一系列的调用,把请求传递给SystemServer的AMS。AMS收到来自客户端的请求后,再通知zygote进程来fork一个新进程,来开启我们的目标App的。 这就像是在浏览器里打开一个网页,浏览器把url和参数发送到服务器,然后还是服务器处理请求,并返回相应的html并展示在浏览器上。

这个过程涉及到3个进程:App进程、AMS(SystemServer进程)、zygote进程。

  1. App进程与AMS通过Binder机制进行跨进程通信
  2. AMS(SystemServer进程)与zygote通过Socket进行跨进程通信。

在Android系统中,任何一个Activity的启动都是由AMS和App进程(主要是ActivityThread)相互配合来完成的。AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属的进程具体来完成。

3.4 Android Binder机制

我们知道AMS与ActivityThread的交互主要是通过进程间通信 (IPC) 。跨进程通信的机制就是将方法调用及其数据分解至操作系统可识别的程度,并将其从本地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行该调用。 Android 提供了执行这些 IPC 事务的方案——Binder机制,因此我们只需关心接口定义和实现 RPC 编程接口。

而App进程与SystemServer进程也是通过Binder机制进行进程间通信,Android为此设计了两个Binder接口:

  1. IApplicationThread: 作为系统进程请求应用进程的接口;
  2. IActivityManager: 作为应用进程请求系统进程的接口。

对于一个Binder接口,在客户端和服务端各有一个实现:Proxy和Native,它们之间的通信主要是通过transact和onTransact触发。一般从命名上可以区分:xxxNative是在本进程内的Binder代理类,xxxProxy是在对方进程的Binder代理类。

多说一句,这些Binder都由ServiceManager统一管理:

  1. ServiceManager管理所有的Android系统服务,有人把ServiceManager比喻成Binder机制中的DNS服务器,client端应用如果要使用系统服务,调用getSystemService接口,ServiceManager就会通过字符串形式的Binder名称找到并返回对应的服务的Binder对象。
  2. 它是一个系统服务进程,在native层启动,它在system/core/rootdir/init.rc脚本中描述并由init进程启动。
  3. ServiceManager启动后,会通过循环等待来处理Client进程的通信请求。

App进程与SystemServer进程的Binder接口如下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.4.1 服务端 IActivityManager——ActivityManagerNative——ActivityManagerService

  1. ActivityManagerNative作为服务端的“桩(Stub)”,其主要职责就是对远程传递过来的数据进行”反序列化(unparcel)”;
  2. ActivityManagerProxy作为服务的“代理(Proxy)”,运行在客户端,其主要职责就是将数据进行“序列化(parcel)”,再传递给远程的“桩(Stub)”,App使用AMS提供的功能,比如startActivity,是通过AMS在客户端的代理ActivityManagerProxy发起的。
  3. 最下面一层是桩(Stub)的具体实现——AMS(ActivityManagerService),负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,非常复杂。

AMS是一个系统服务,在SystemServer进程启动后完成初始化。在应用启动流程中,充当着服务端的角色。 App中Activity的生命周期由AMS管理,它决定着什么时候该调用onCreate、onResume这些生命周期函数,把Activity放在哪个栈里,上下文之间的关系是怎样的等等。

比如:

  1. startActivity 最终调用了AMS的 startActivity 系列方法,实现了Activity的启动;Activity的生命周期回调,也在AMS中完成;
  2. startService,bindService 最终调用到AMS的startService和bindService方法;
  3. 动态广播的注册和接收在 AMS 中完成(静态广播在 PMS 中完成)
  4. getContentResolver 最终从 AMS 的 getContentProvider 获取到ContentProvider

3.4.2 客户端 IApplicationThread——ApplicationThreadNative——ActivityThread

  1. 桩(Stub):ApplicationThreadNative
  2. 代理(Proxy):ApplicationThreadProxy,App在客户端进程中实现了实例化Activity、调用onCreate等生命周期函数的功能,因为跨进程也不能被AMS直接调用,而是AMS通过客户端的代理ApplicationThreadProxy来处理。
  3. 最下面一层是桩(Stub)的具体实现——ApplicationThread,它是ActivityThread的一个内部类,ApplicationThread负责响应系统进程发起的请求,而实际触发的业务逻辑是在ActivityThread中。与一般的代理模式不同,它不是直接持有ActivityThead的一个引用,而是把处理的请求发到ActivityThread内部的一个Handler上。

和服务端的AMS相对应,ActivityThread在应用启动的Client/Server模式中,是作为客户端那一边的具体实现。它并不是一个线程,但它包含了一个应用进程的主线程运作的全部机制:

  1. 启动应用的主线程,并开启消息循环
  2. 提供了一个IActivityThread接口作为与AMS的通讯接口,通过该接口AMS可以将Activity的状态变化传递到客户端的Activity对象

3.5 启动一个Activity的通信过程

我们已经知道应用进程创建以后,App进程的ActivityThread与SystemServer进程的AMS通过Binder进行通信。 在文章前面【2 应用启动流程】提到,在ActivityThread的main方法中,调用 ActivityThread#attach(false)方法进行 Binder 通信,通知system_server进程执行 ActivityManagerService#attachApplication(mAppThread)方法,用于初始化Application和Activity。

可以结合源码流程,稍微总结一下这个通信过程。

3.5.1 Application的初始化

从应用进程到系统进程

在ActivityThread创建的时候,会将自己的ApplicationThread绑定到AMS中:

ActivityThread.main()
└── ActivityThread.attach()
└── IActivityManager.attachApplication(mAppThread)
└── Binder.transact()

应用进程作为客户端,通过IAcitivtyManager接口发起了跨进程调用,跨进程传递的参数mAppThread就是IApplicationThread的实例,执行流程从应用进程进入到系统进程:

ActivityManagerService.onTransact()
└── ActivityManagerService.attachApplication(IApplicationThread thread)

AMS作为IActivityManager接口的服务端实现,会响应客户端的请求,最终AMS.attachApplication()函数会被执行,该函数接收跨进程传递过来的IApplicationThread实例,将存在系统进程维护的ProcessRecord中。 具体细节可以看AMS的源码,我们只需要知道AMS中维护了所有进程运行时的信息(ProcessRecord),一旦发生了应用进程的绑定请求,ProcessRecord.thread就被赋值成应用进程的IApplicationThread实例,这样一来,在AMS中就能通过该IApplicationThread实例发起向应用进程的调用

从系统进程到应用进程

在AMS.attachApplication()的过程中,会有一些信息要传递给应用进程,以便应用进程的初始化,系统进程会发起如下函数调用:

ActivityManagerService.attachApplication()
└── ActivityManagerService.attachApplicationLocked()
└── IApplicationThread.bindApplication(processName, appInfo …)
└── Binder.transact()

此时,AMS会反转角色,即系统进程作为客户端,通过IApplicationThread接口向应用进程发起调用。

  1. AMS通过ProcessRecord来维护进程运行时的状态信息,需要将应用进程绑定到ProcessRecord才能开始一个Application的构建;
  2. AMS维护的ProcessRecord这个数据结构,包含了进程运行时的信息,譬如应用进程的名称processName、解析AndroidManifest.xml得到的数据结构ApplicationInfo等,其中,要传递给应用进程的数据都是Parcelable类型的实例。

应用进程响应请求的调用关系如下所示:

ApplicationThread.onTransact()
└── ApplicationThread.bindApplication()
└── ActivityThread.H.handleMessage(BIND_APPLICATION)
└── ActivityThread.handleBindApplication()
└── Application.onCreate()

ApplicationThread作为IApplicationThread接口的服务端实现,运行在应用进程中,然后ApplicationThread.bindApplication()会被执行,完成一些简单的数据封装(AppBindData)后,通过Handler抛出BIND_APPLICATION消息。这一抛,就抛到了主线程上,ActivityThread.handleBindApplication()会被执行,终于创建了Application 对象,然后调用 Application#attach(context) 来绑定 Context,并调用Application.onCreate()函数。历经应用进程和系统进程之间的一个来回,总算是创建了一个应用程序。

Android源码里有较统一的函数命名方式,在AMS中与Activity管理相关很多函数都会带有Locked后缀,表示这些函数的调用都需要多线程同步操作(synchronized),它们会读/写一些多线程共享的数据

3.5.2 Activity的初始化

前面提到在system_server进程中,ActivityManagerService#attachApplication(mAppThread)里依次初始化了Application和Activity,其中的mStackSupervisor#attachApplicationLocked(ProcessRecord)里进行了Activity的初始化。

  1. AMS通过ActivityRecord来维护Activity运行时的状态信息,需要将Activity绑定到AMS中的ActivityRecord能开始Activity的生命周期。
  2. 在Activity类中有一个IBinder类型的属性:private IBinder mToken;,IBinder类型表示这个属性是一个远程对象的引用,Token持有了一个ActivityRecord实例的弱引用。在创建一个ActivityRecord的时候,就会创建了一个Token类型的对象。

在启动一个新的Activity时,AMS会将ActivityRecord的Token传递给应用进程,调用关系如下所示:

ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, …)
└── IApplicationThread.scheduleLaunchActivity(…token, …)
// 将ActivityRecord的Token跨进程传递给应用进程
└── Binder.transact()

ActivityStackSupervisor.realStartActivityLocked()表示要启动一个Activity实例,ActivityRecord作为参数。从ActivityRecord中提取出Token对象,作为跨进程调用的参数,通过IApplicationThread.scheduleLaunchActivity()传递到应用进程。

在应用进程这一侧,会收到启动Activity的跨进程调用,触发以下函数的调用:

ApplicationThread.onTransact()
└── ApplicationThread.scheduleLaunchActivity(…token, …)
// token将被封装进ActivityClientRecord这个数据结构中
└── ActivityThread.H.handleMessage()
└── ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY)
└── ActivityThread.performLaunchActivity(ActivityClientRecord, …)
// 从ActivityRecord取出token
└── Activity.attch(…token, …)

标准的Binder服务端处理流程,收到AMS传递过来的Token对象,进行一下数据封装(ActivityClientRecord),然后通过Handler抛出一个LAUNCH_ACTIVITY消息。这个消息显然也是抛到了应用进程的主线程去执行,所以ActivityThread.performLaunchActivity()函数会在主线程上执行,该函数从封装的数据结构ActivityClientRecord中取出Token对象,调用Activity.attach()函数,将其绑定到Activity上,如此一来,就建立应用进程的Activity与系统进程中ActivityRecord的关联。

系统进程维护的是ActivityRecord,应用进程维护的是Activity,两者之间的映射关系就是利用Token来维系的。应用进程的Activity在创建的时候,就被赋予了一个Token,拿着这个Token才能完成后续与系统进程的通信。在发生Activity切换时,应用进程会将上一个Activity的Token(AMS.startActivity()的输入参数resultTo)传递给系统进程,系统进程会根据这个Token找到ActivityRecord,对其完成调度后,再通知应用进程:Activity状态发生了变化。

3.5.3 Instrumentation

每个Activity都持有Instrumentation对象的一个引用,但是整个应用程序进程只会存在一个Instrumentation对象。 Instrumentation可以理解为应用进程的管家,ActivityThread要创建或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作。

Instrumentation这个类就是完成对Application和Activity初始化和生命周期的工具类。

前面提到,App和AMS是通过Binder传递信息的,ActivityThread接受AMS的命令,然后就是通过Instrumentation真正地创建Activity以及调用Activity的生命周期函数。 比如ApplicationThread接受AMS命令创建Acitivity,最后执行到ActivityThread,通过Instrumentation创建Activity并调用onCreate()生命周期。

//
ActivityThread.performLaunchActivity()
└── mInstrumentation.newActivity(appContext.getClassLoader(), component.getClassName(), activityClientRecord.intent)
└── return (Activity)cl.loadClass(className).newInstance()

└── mInstrumentation.callActivityOnCreate(activity, r.state)
└── activity.performCreate()
└── activity.onCreate(Bundle)

4 Activity的管理方式

前面知道应用启动以及Activity启动是一个跨进程通信的过程,这是因为: 每个应用都是一个独立的进程,Activity的生命周期本来就会在不同进程之间互相影响,所以需要一个系统进程对所有Activity进行统一管理。 在一个应用程序安装时,系统会解析出APK中所有Activity的信息,当显示APK中的用户界面时,就需要调度Activity的生命周期函数了。 系统进程(SystemServer)中维护了所有Activity的状态,管理中枢就是ActivityManagerService。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值