前言

2022年的第一篇分享文章,整整一周,利用晚上下班时间梳理了桌面点击APP到打开的流程,可以说看似简简单单的一个操作,里边的过程相当复杂,各种进程间通信等等,下面我们一起看看整个流程是怎么样的。

正文

我们先通过一张图来看整个流程的一个概览:

startActivity

桌面点击app到打开,涉及了三个进程,分别如下:

Launcher进程:它是一个Activity,可以把桌面看成是一个app,里边有多个啊、其他app的入口,当点击app图标时,就会去启动对应的app,并且跳转至页面。

SystemServer进程:在Android系统中有着重要的作用,由Zygote进程fork出来,许多重要的服务,都是在此进程开启的,例如ActivityManagerService、InputManagerService和WindowManagerService等等。

APP进程:我们要启动的app的进程。

startActivity

首先我们从startActivity开始,startActivity最终会调用startActivityForResult:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);//...} else {//...}
}

在这里我们先了解一下Instrumentation,每个Activity都会持有一个Instrumentation引用,整个进程只会有一个Instrumentation的实例,它主要是完成对Application和Activity初始化和生命周期的工具类。

我们可以看到,里边调用了mInstrumentation的execStartActivity方法,其中的核心代码如下:

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {//...try {//...int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(), who.getAttributionTag(), intent,      intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;
}

ActivityTaskManager.getService()返回的是一个ActivityManagerProxy,它就是用来与AMS进行通信的,AMS是运行在system_server进程中的,这一次的调用,实际是通过Binder的方式,调用到了AMS的startActivity方法。

fork创建新进程

调用了ActivityManagerService的startActivity方法后,经过一系列的调用,来到了startProcesslocked方法,然后会通过Process.start()方法,这次使用的是socket通信方式向zygote进程发送一个创建新进程的请求,也就是请求Zygote去创建App进程。

Zygote进程监听到有创建新进程的请求后,便会fork新的进程,并返回对应的pid。新进程创建后,然后会执行ActivityThread的main()方法。

这里说一下Zygote进程:由init进程fork出来的,当创建app进程时,都是由zygote进程fork而来的。

不知你会不会有两个疑问:

为什么SystemServer进程与Zegote进程通信不是使用Binder而是使用Socket?下面整理了网友的几点回答。

  • zegote比serviceManager先启动,这点从先后顺序看,没有serviceManager可以注册,没法用Binder。
  • 假设它们谁先启动这个顺序不确定,但是如果serviceManager先启动,但没法保证它先初始化完。
  • 在安全性上,socket的所有者是root,group是system,只有系统权限用户才能进行读写。

为什么APP进程需要由Zegote进程fork出来?

我们知道每个APP都运行在独立的Dalvik虚拟机中,如果每启动一个APP就得去单独启动跟初始化,那么是比较耗时的。Zegote进程会把已经加载好的虚拟机代码和内存信息共享,通过它fork会起到一个预加载作用,加快了app的启动。

绑定Application

创建线程后,便会执行ActivityThread的main函数,main函数里边会启动主线程的Looper。在我们初学Java的时候可以知道,main函数是一个应用程序的入口。

main函数里边会调用ActivityThread的attach方法。

//由于在main方法里边调用传进来的system为false,所以我们只看第一个分支。
private void attach(boolean system, long startSeq) {//...if (!system) {final IActivityManager mgr = ActivityManager.getService();try {mgr.attachApplication(mAppThread, startSeq);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}} else {//...}
}

attach方法中,会远程调用ActivityManagerService的attachApplication方法,ActivityManagerService最后会通过远程调用ActivityThread的bindApplication,bindApplication会发送一个BIND_APPLICATION的消息,

public final void bindApplication(String processName, ApplicationInfo appInfo,ProviderInfoList providerList, ComponentName instrumentationName,/*省略n个参数*/) {
//...sendMessage(H.BIND_APPLICATION, data);
}

接收到此消息后,通过handleBindApplication方法进行处理,然后调用LoadedApk的makeApplication方法,由Instrumentation加载Application实例出来,

public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {if (mApplication != null) {return mApplication;}//...Application app = null;//...try {final java.lang.ClassLoader cl = getClassLoader();//...app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {//...}//...mApplication = app;if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {//...}}return app;
}

newApplication方法里边会去加载出Application对象,并且调用它的attach方法。

public Application newApplication(ClassLoader cl, String className, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {Application app = getFactory(context.getPackageName()).instantiateApplication(cl, className);app.attach(context);return app;
}

创建完之后,回到ActivityThread的handleBindApplication方法,会通过Instrumentation去调用Application的onCreate方法。

try {mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {//...
}

到这里Application的创建就完成了。

启动Activity

经过一连串的调用,最后会向H发送一个消息,这里的H是一个Handler,由于版本不同,所以这里会有不一样,它们最终都会调用到handleLaunchActivity方法:

public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {//...final Activity a = performLaunchActivity(r, customIntent);//...return a;
}

performLaunchActivity方法里边会创建Activity,并且走onCreate

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//...ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);//...} catch (Exception e) {//...}try {//...设置一些参数等,还有attach进Applicationif (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}//...}r.setState(ON_CREATE);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {//...}return activity;
}

可以看到,又有Instrumentation的身影,此方法里边通过mInstrumentation去创建Activity,然后设置参数、校验等操作后,再继续调用callActivityOnCreate方法,里边会去调用Activity的onCreate方法,至此,Activity被创建好了。

接下来就是继续通过Handler,然后去调用Activity的onStart、onResume,到这里,Activity就可见了。

小结

最后我们回顾一下整个流程:

  1. 在桌面点击app图标,Launcher响应点击事件,然后经过调用,通过Binder的方式告诉在system_server进程中的ActivityManagerService去startActivity
  2. ActivityManagerService收到调用后,便会去请求创建一个新的进程,它通过Socket的方式,告诉Zygote进程去启动一个新的进程。
  3. 新的进程启动后,会执行ActivityThread的main方法,这是程序的入口,并且会开始Looper。
  4. 在main中,会去请求ActivityManagerService进行attach Application,再经过一系列的调用,会回到app进程,创建Application,并且让Application进行attach。
  5. Application创建绑定完,便开始创建Activity,由AMS告诉APP进程去scheduleLaunchActivity,APP进程会发送一个Handler的消息,收到这个消息后由Instrumentation去创建Activity,接着继续去调用Activity的onCreate、onStart和onResume的生命周期,至此,从桌面点击APP的图标到APP启动至可见已完成。

结语

到这里我们便把APP的启动流程过了一遍,看似很简单的一个操作,实际上系统帮我们做了很多的事情。当然在源码上不同版本会存在不一样,但它们的流程基本是一样的,只是一些方法或者细节做了改变。

APP的启动流程梳理相关推荐

  1. 高通SDX12平台:启动流程梳理

    高通SDX12平台 启动流程梳理 1. 高通平台CPU类型介绍 通常我们所说的CPU如高通平台MSM8998.苹果A12, 华为海思平台(麒麟980.990)等,这些我们虽然叫CPU,但并不是只有一个 ...

  2. (四十四)Android O WiFi启动流程梳理

    前言:最近又重新拿起来WiFi模块,从WiFi 各个流程梳理开始复习一下. 参考博客:https://blog.csdn.net/csdn_of_coder/article/details/51541 ...

  3. (七十)Android O Service启动流程梳理——bindService

    前言:最近在处理anr问题的时候迫切需要搞清楚service的启动流程,抽时间梳理一下. 1.service启动简述 service启动分三种,比较简单的就是startService,Android ...

  4. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  5. App 启动流程与 Activity 启动流程梳理

    目录 前言 流程图 启动流程 第一阶段(Launcher 向 AMS 发送启动请求) 第二阶段(AMS 启动 Activity, 并告知 Launcher pasue) 第三阶段 (App 进程的 A ...

  6. Andorid App程序启动流程

    Native进程的运行过程 一般程序的启动步骤,可以用下图描述.程序由内核加载分析,使用linker链接需要的共享库,然后从c运行库的入口开始执行. 通常,native进程是由shell或者init启 ...

  7. Oracle11g RAC 启动流程梳理(二)OHASD简析和启停实验

    简单说明: 11gRAC启动分为四个层次,第一个层次是OHASD和子代理进程启动: init-->init.ohasd-->ohasd-->agent子进程启动 即: OS启动--& ...

  8. Kernel 启动流程梳理

    内核生命周期 uboot 打印完 Starting kernel . . .,就完成了自己的使命,控制权便交给了 kernel 的第一条指令,也就是下面这个函数 init/main.c asmlink ...

  9. QCM6490启动流程梳理

    前言: 高通平台启动过程简述 PBL-SBL 01.如何修改borad-id 并且修改加载dtbo 注意修改这里可以打印加载的是哪个dtbo: bootable/bootloader/edk2/Qco ...

最新文章

  1. 《C#精彩实例教程》小组阅读09 -- C#数组与集合
  2. Dijkstra 最短路径算法详解 无向图
  3. Automatic Reference Counting
  4. 20220227:力扣第282场周赛(上)
  5. Linux 文件操作
  6. 关于switchhosts的一些问题
  7. 数据结构(C语言版清华严蔚敏)
  8. 大规模电生理网络动力学
  9. 嵌入式软件开发到底是干什么的?
  10. C语言标识符之——“~“
  11. 后端利用MultipartFIle类型参数接受文件上传
  12. Java 类详解 9章
  13. js-视频播放插件Video.js简单使用
  14. python神经网络编程 豆瓣,用python构建神经网络
  15. 强化学习:DDPG到MADDPG
  16. oracle无法删除em,Oracle 11g EM删除重建的方法
  17. Chronic/iPhone Dev Team联合发布iOS 5.0.1完美越狱
  18. oracle planning bom,OracleERP表结构--BOM模块
  19. 正则表达式-问号的四种用法
  20. optimized out参考解决方法

热门文章

  1. Java深度历险(四)——Java垃圾回收机制与引用类型
  2. Unity人工智能编程精粹学习笔记 AI角色的复杂决策——行为树
  3. 图片拼图微信小程序源码_支持多模板制作和流量主
  4. 写在“华为伙伴暨开发者大会”前夕:给昇腾AI划三个重点
  5. 经纪业务部负责人是什么工作
  6. mysql单表查询详解
  7. HSB/HSV/HSL区别
  8. 已解决 vmware 虚拟机安装后没有虚拟网卡问题
  9. STM32G473CBT6关于ADC采集的总结
  10. 如何用css实现左右翻页效果图,如何利用CSS3实现3D翻书效果