【转】 Android是怎么样启动应用程序的,从点击启动图标到显示视图到底做了什么操作

转载自 https://juejin.im/post/5b0d0a0cf265da091f105858

本文阐述了用户点击启动图标后,Android 系统是怎么启动你的应用程序,将应用视图显示在移动设备上,Android 系统在背后做了很多操作,本文通过重点介绍将一些重要信息以及他们的顺序来阐述应用的启动过程。 首先说一下 Android 应用程序的两个特点

  1. 多入口,和只有一个 main 方法的应用程序不同,Android 应用程序有四大组件构成 ( Activity , Service ) ,每个组件都是一个入口,所以说 Android 应用是多入口的应用。
  2. 每个 Android 应用运行在一个 独立的 linux 进程拥有自己的 dalvik vm,并且分配唯一的的用户 ID。

那么什么时候会启动应用的进程呢,答案就是什么时候用到应用程序就启动,这种 ‘ 懒汉模式 ‘。

当用户或者其他应用程序用到了属于你的应用程序的组件,比如 ( Activity ,Service ) Android 就会为你的应用程序启动一个新的进程(你的应用进程不存在当前 Android 系统中时),启动的应用进程会伴随着整个 Android 系统,直到 Android 杀掉你应用进程(内存不足或者被用户清除)。

每个应用都有独立的进程,默认情况下,每个应用程序都运行在自己的进程,并且启动一个主线程工作。当你的应用程序 需要打开相册功能就会打开系统的相册应用,因为你的应用和相册应用都有自己独立的应用进程,通过启动相册的操作,在一个进程中启动另外一个进程,这适用于其他应用程序里面的每一个组件。

Android 开机过程 Android 开机的过程加载内核和 init 进程 然后 init 进程又会产生很多守护进程 比如 usb 进程 debug 调试进程 ,这些守护进程一般是处理底层硬件接口。 然后 init 进程又会启动一个 zygote 进程 ,zygote 进程他会创建一个原始 dalvik 虚拟机 然后继承系统资源,和 Android 应用程序框架,然后进入监听状态,随时准备复制一份,当系统请求 zygote 就会 fork出一份新的进程,这个进程就有了 dalvik 虚拟机和系统的资源了。

然后 init 进程还会启动系统服务进程 SystemServer,SystemServer 去创建系统服务类比如 ActivityManagerService (AMS)。再去启动 launcher 应用(桌面启动器)。

所以当在桌面点击 启动 logo 就会通过 binder接口 以ipc的形式,通知 ams 会发起一个startactivity 然后通过 packagemanager.resolveIntent 来获取 activity的信息,并且保存起来,下次就拿来用。 然后调用 geturipermissionlocked 判断有没有权限执行这个操作,然后 ams 检查 activity 在哪个应用栈列里面,然后再判断 activity 所在的 应用进程是否存在,如果 ams 检测到 activity 所在进程为空会去 通知 zygnote 去fork 一个进程,执行 activitythread 的 main 方法 实例化 looper 消息队列,调用 looper。loop去循环消息队列。,然后进程和 ams 绑定在一起,下次就不会创建该activty了。

启动应用程序可以分为三个步骤

  1. 创建一个进程
  2. 绑定应用程序
  3. 启动一个 Activity

163aee65e35936d8.png

创建一个进程

ams 会通过 startprocessLocked 方法向 zygote 请求一个新的进程,通过 socket 的方法 向 zygote 传递参数,zygote fork了一份 调用 zygoteInit.main 方法 ,然后实例化 Activitythread 对象 并返回进程的 id。

每一个进程都有一个主线程,主线程的有一个looper实例来处理消息队列里面的,在遍历里面的消息队列时,run 方法 会调用 looper.loop 方法。 activitythread 也会调用 looper.prepareLoop 和looper.loop 来启动消息循环。详细如图:

163aef7f73aef0d3.png

进程绑定应用程序

这一步的作用就是将进程绑定到应用程序上, ams 调用 bindApplicaiton,让线程发送一个 message 给消息队列,最后在 handler 的 handlemessage 方法调用 hanldebindapplicaiton 方法,接着调用 makeApplicaiton ,将应用程序的类加载到内存上。如图:

163aefd430ac7121.png

启动一个 Activity

上面两步为你创建了进程和加载资源类到进程的内存里面,这一步为了 ams 调用 realstartactiivtyLocked 来启动 activity ,然后调用 schedulelauncheractivity 方法 ,让 Activitythread 发送LAUNCH_ACTIVITY 的标识,然后在 handleMessage 方法调用 handlelaunchActivity 和 performLaunchActivity ,通过 newActivity 传入 classloader,classname 和 intent 来创建对应的 activity 最后调用 oncreate 加载视图方法 setcontentview。最后视图显示在手机上。 如图:

image

总结

当你启动一个 activity 的时候 ,你当前的进程通过 binder 接口 以 ipc 的方式 startactivity 请求 AMS , AMS 判断用户有没有权限请求这个actiivty 再根据应用栈来确定新 activity 的 task ,最后请求 zygote 创建 dalvik 虚拟机 以及加载系统资源类 ,来创建新的进程,调用新进程的 activitythread 类的 main 方法 创建 looper 调用 loop 方法来遍历消息队列。然后 zygote 返回新进程 pid 给 AMS 。 AMS 绑定这个进程到应用上,加载类到进程的内存上,最后调用 handlelaunchActivity 和 performlaunchactivity 启动这个 activity。最后执行 activity 的 oncreate 方法加载视图,执行 onstart 方法使视图可见。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Angular&服务

mac安装nvm

如果没有.bash_profile文件需要自行touch .bash_profile哦

1163
来自专栏鸿的学习笔记

日志采集技术笔记

使用Linux的rename机制保证文件写入要么成功,要么失败,绝对不能出现写了一半的情况。

3965
来自专栏技术博文

LNMP源码编译安装(centos7+nginx1.9+mysql5.6+php7)

1.准备工作: 1)把所有的软件安装在/Data/apps/,源码包放在/Data/tgz/,数据放在/Data/data,日志文件放在/Data/logs,项...

4316
来自专栏架构技术

使用docker+consul+nginx集成分布式的服务发现与注册架构

consul-Server 是运行在docker里的consul实例的server模式,可以通过DNS或者HTTP接口使服务注册并对容器进行健康状态检查,con...

1163
来自专栏我的博客

window安装memcache

memcache 下载(这个是64位的) 1.解压到 D:\memcached 2.进入cmd image.png 依次执行 memcached.exe -d...

3274
来自专栏Pythonista

Linux之文档与目录结构

Linux目录结构的组织形式和Windows有很大的不同。首先Linux没有“盘(C盘、D盘、E盘)”的概念。已经建立文件系统的硬盘分区被挂载到某一个目录下,用...

1743
来自专栏云计算教程系列

如何在CentOS 7上使用Etckeeper进行版本控制管理/ etc

在Linux生态系统中,必须定期安装,维护和升级软件。但是,仍然需要跟踪对本地配置文件所做的更改。与在进行更改之前制作配置文件副本的旧备用数据库相反,etcke...

1741
来自专栏章鱼的慢慢技术路

Linux中的环境变量PATH

2472
来自专栏前端小叙

windows mongodb最常用命令简单归纳

在windows安装好了windows,首先记得要把mongodb bin目录路径放在 系统环境变量的path中,确定之后即配置好了mongo的环境变量,在do...

3896
来自专栏程序小工

【Linux】系统学习Crontab定时任务

crontab 是一个用于设置周期性执行任务的工具。目前服务器端的运行环境大多数为 Linux,在日常的运营和维护中会有很多需要定期执行的操作,其中有些操作是可...

1802

扫码关注云+社区

领取腾讯云代金券