Android启动流程、app启动原理

从头分析整理学习底层知识。

Android 众多基于Linux内核的系统类似, 启动系统时, bootloader启动内核和init进程. init进程分裂出更多名为"daemons(守护进程)"的底层的Linux进程, 诸如android debug deamon, USB deamon等. 这些守护进程处理底层硬件相关的接口.随后, init进程会启动一个非常有意思的进程---"Zygote". 顾名思义, 这是一个Android平台的非常基础的进程. 这个进程初始化了第一个VM, 并且预加载了framework和众多App所需要的通用资源. 然后它开启一个Socket接口来监听请求, 根据请求孵化出新的VM来管理新的App进程. 一旦收到新的请求, Zygote会基于自身预先加载的VM来孵化出一个新的VM创建一个新的进程.

启动Zygote之后, init进程会启动runtime进程. Zygote会孵化出一个超级管理进程---System Server. SystemServer会启动所有系统核心服务, 例如Activity Manager Service, 硬件相关的Service等. 到此, 系统准备好启动它的第一个App进程---Home进程了.

Zygote 进程

Zygote 的中文意思是受精卵,从这个意思里也可以看出 Zygote 进程是用来分裂复制(fork)的,实际上所有的 App 进程都是通过对 Zygote 进程的 Fork 得来的。当 app_process 启动 Zygote 时,Zygote 会在其启动后,预加载必要的 Java Classes(相关列表查看 预加载文件) 和 Resources,并启动 System Server ,并打开 /dev/socket/zygote socket 去监听启动应用程序的请求,日后。在下面的代码中,显示了 Zygote 进程如何启动,和加载 System Server 的。

Android进程与Linux进程一样. 默认情况下, 每个apk运行在自己的Linux进程中. 另外, 默认一个进程里面只有一个线程---主线程. 这个主线程中有一个Looper实例, 通过调用Looper.loop()从Message队列里面取出Message来做相应的处理.

那么, 这个进程何时启动的呢?

简单的说, 进程在其需要的时候被启动. 任意时候, 当用户或者其他组件调取你的apk中的任意组件时, 如果你的apk没有运行, 系统会为其创建一个新的进程并启动. 通常, 这个进程会持续运行直到被系统杀死. 关键是: 进程是在被需要的时候才创建的.

点击图标 启动应用
Android启动流程、app启动原理_第1张图片
app launch.png

Click事件会调用startActivity(Intent), 会通过Binder IPC机制, 最终调用到ActivityManagerService. 该Service会执行如下操作:

第一步通过PackageManager的resolveIntent()收集这个intent对象的指向信息.
指向信息被存储在一个intent对象中.
下面重要的一步是通过grantUriPermissionLocked()方法来验证用户是否有足够的权限去调用该intent对象指向的Activity.
如果有权限, ActivityManagerService会检查并在新的task中启动目标activity.
现在, 是时候检查这个进程的ProcessRecord是否存在了.
如果ProcessRecord是null, ActivityManagerService会创建新的进程来实例化目标activity.

ActivityManager 架构

在我们编程过程中,涉及到许多 Activity 跳转的事情,在 Launcher 中点击 Icon 进行跳转也是同样的道理,调用 context.startActivity(intent) 方法。Launcher 出于一个线程,而启动的 App 则运行在另一个进程中,在这其中势必牵涉到跨进程 (IPC) 调用,这样复杂的过程显然需要一种中介者,或者一个系统来进行中转和管理,而这个服务就是 ActivityManagerService。

ActivityManagerService 作为一个守护进程运行在 Android Framework 中,如果让开发者直接接触这个类的话,就需要开发者自行处理 IPC 调用的问题,且这有不利于 Android 系统进行安全校验等工作。因而 Android 系统实现了 ActivityManager,通过这个 ActivityManager 作为一个入口,变相地和 ActivityManagerService 打交道。

App安装过程

Dalvik和ART是什么,有啥区别?
Davlivk

Dalvik是Google公司自己设计用于Android平台的虚拟机。支持已转换为** .dex格式**的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。
Dalvik 经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
很长时间以来,Dalvik虚拟机一直被用户指责为拖慢安卓系统运行速度不如IOS的根源。
2014年6月25日,Android L 正式亮相于召开的谷歌I/O大会,Android L 改动幅度较大,谷歌将直接删除Dalvik,代替它的是传闻已久的ART。

ART

即Android Runtime
ART 的机制与 Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器(just in time ,JIT)转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(AOT,Ahead-Of-Time)。这样的话,应用的启动(首次)和执行都会变得更加快速。

区别:

Dalvik是基于寄存器的,而JVM是基于栈的。
Dalvik运行dex文件,而JVM运行java字节码
自Android 2.2开始,Dalvik支持JIT(just-in-time,即时编译技术)。
优化后的Dalvik较其他标准虚拟机存在一些不同特性: 
1.占用更少空间 
2.为简化翻译,常量池只使用32位索引  
3.标准Java字节码实行8位堆栈指令,Dalvik使用16位指令集直接作用于局部变量。局部变量通常来自4位的“虚拟寄存器”区。这样减少了Dalvik的指令计数,提高了翻译速度。 
 当Android启动时,Dalvik VM 监视所有的程序(APK),并且创建依存关系树,为每个程序优化代码并存储在Dalvik缓存中。Dalvik第一次加载后会生成Cache文件,以提供下次快速加载,所以第一次会很慢。
 Dalvik解释器采用预先算好的Goto地址,每个指令对内存的访问都在64字节边界上对齐。这样可以节省一个指令后进行查表的时间。为了强化功能, Dalvik还提供了快速翻译器(Fast Interpreter)。

对比

ART有什么优缺点呢?

优点:
1、系统性能的显著提升。
2、应用启动更快、运行更快、体验更流畅、触感反馈更及时。
3、更长的电池续航能力。
4、支持更低的硬件。
缺点:
1.机器码占用的存储空间更大,字节码变为机器码之后,可能会增加10%-20%
2.应用的安装时间会变长

安装过程

Android应用安装有如下四种方式
1.系统应用安装――开机时完成,没有安装界面
2.网络下载应用安装――通过market应用完成,没有安装界面
3.ADB工具安装――没有安装界面。
4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。

应用安装的流程及路径
应用安装涉及到如下几个目录:
system/app
系统自带的应用程序,无法删除

data/app
用户程序安装的目录,有删除权限。
安装时把apk文件复制到此目录

data/data
存放应用程序的数据

Data/dalvik-cache
将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)

   安装过程:复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。
   卸载过程:删除安装过程中在上述三个目录下创建的文件及目录。 

把APK安装包保存在SD卡中,从手机里访问SD卡中的APK安装包,点击就可以启动安装界面,系统应用Packageinstaller.apk处理这种方式下的安装及卸载界面流程,如下图:

PackageInstallerActivity负责解析包,判断是否是可用的Apk文件
创建临时安装文件/data/data/com.android.packageinstaller/files/ApiDemos.apk
并启动安装确认界面startInstallConfirm,列出解析得到的该应用基本信息。如果手机上已安装有同名应用,则需要用户确认是否要替换安装(校验签名)。
确认安装后,启动InstallAppProgress,调用安装接口完成安装。
pm.installPackage(mPackageURI,observer, installFlags);

具体步骤

  1. 将apk文件copy至data/app目录

1.1 installPackageAsUser 这个方法主要是判断安装来源,包括adb,shell,all_user,然后向PMS的mHandler发送INIT_COPY的消息,这个mHandler运行在一个HandlerThread中。


Android启动流程、app启动原理_第2张图片
image.png

1.2handleMessage(INIT_COPY)&handleMessage(MCS_BOUND)
INIT_COPY主要是确保DefaultContainerService已bound,DefaultContainerService是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作。而MCS_BOUND中则执行了


Android启动流程、app启动原理_第3张图片
image.png

params.startCopy()这句,也是最关键的开始copy文件。
1.3handleStartCopy()handleStartCopy的核心就是copyApk,其他的都是些存储空间检查,权限检查等等安全校验
2 .解析apk信息

完成apk copy到data/app目录的操作后,下一步就到了 handleReturnCode,这个方法又跳转到processPendingInstall()方法,
解析了package包,然后做了大量签名和权限校验的工作,最终会走到
覆盖安装和安装新应用对应的具体执行.

  if (replace) {
        replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                installerPackageName, res);
    } else {
        installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                args.user, installerPackageName, res);
    }

scanPackageLI负责安装,而updateSettingLI则是完成安装后的设置信息更新

dexopt操作

Apk文件其实只是一个归档zip压缩包,而我们编写的代码最终都编译成了.dex文件,但为了提高运行性能,android系统并不会直接执行.dex,而是会在安装过程中执行dexopt操作来优化.dex文件,最终android系统执行的时优化后的'odex'文件(注意:这个odex文件的后缀也是.dex,其路径在data/dalvik-cache)。对于dalvik虚拟机,dexopt就是优化操作,而对于art虚拟机,dexopt执行的则是dex2oat操作,既将.dex文件翻译成oat文件。

dexopt操作执行完后,installNewPackageLI()方法就会走到updateSettingsLI()来更新设置信息,而更新设置信息主要是权限信息,所以直接来看updatePermissionsLPw();

最终会发送Intent.ACTION_PACKAGE_ADDED广播,apk的安装就到到此结束了。

todo 待完善 2018年3月28日 17:20:54
其它:

  1. PackageManagerService.java的内部类AppDirObserver实现了监听app目录的功能:当把某个APK拖到app目录下时,可以直接调用scanPackageLI完成安装。
    2.手机数据区目录“data/system/packages.xml”文件中,包含了手机上所有已安装

参考整理链接:
https://www.jianshu.com/p/a5532ecc8377
https://www.jianshu.com/p/594e338e5fd3
https://www.jianshu.com/p/58f817d176b7
https://www.jianshu.com/p/953475cea991

你可能感兴趣的:(Android)