面试基础知识(5)—— 运行流程基本考点
本文主要介绍Android系统流程中的基本考点!
1.Android虚拟机的变化
JIT:
JIT即运行时编译策略,可以理解成一种运行时编译器,此时Android的虚拟机使用的是Dalvik,为了加快Dalvik虚拟机解释dex速度,运行时动态地将执行频率很高的dex字节码翻译成本地机器码
缺点:
(1)每次启动应用都需要重新编译
(2)运行时比较耗电,造成电池额外的开销

AOT:
AOT是一种运行前编译的策略
缺点:
(1)应用安装和系统升级之后的应用优化比较耗时
(2)优化后的文件会占用额外的存储空间
AOT与JIT区别:
JIT 是在运行时进行编译,是动态编译,并且每次运行程序的时候都需要对 odex 重新进行编译
AOT 是静态编译,应用在安装的时候会启动 dex2oat 过程把 dex 预编译成 ELF 文件,每次运行程序的时候不用重新编译,是真正意义上的本地应用
Android7.0后 安装时不会编译、运行时热点函数jit编译、休息时采用AOT预编译
JVM、Dalvik、ART区别
JVM:传统的Java虚拟机、基于栈、运行class文件
Dalvik:支持已转换成dex格式的android应用,基于寄存器,指令执行更快,加载的是odex(优化的dex)
ART:第一次安装时,将dex进行Aot(预编译),字节码预先编译成机器码,生成可执行oat文件(ELF文件)
dex、odex、oat、vdex文件区别
(1)dex文件:Android将所有的class文件打包形成一个dex文件,是Dalvik运行的程序
(2)odex文件:优化过的dex文件,Apk在安装时会进行验证和优化,通过dexopt生成odex文件,加快Apk的响应时间
(3)oat文件:Android私有ELF文件格式,有dex2oat处理生成,包含(原dex文件+dex翻译的本地机器指令),是ART虚拟机使用的文件,可以直接加载
(4)vdex文件:Android 8.0引入,包含APK的未压缩DEX代码,以及一些旨在加快验证速度的元数据
2.java反射机制
java反射机制指程序在运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息
反射的常用对象:
(1)Class
Class 类的实例表示正在运行的Java应用程序中的类和接口
(2)Constructor
类的单个构造方法的信息以及对它的动态访问权限
(3)Field
Field提供有关类或接口的单个字段信息以及动态访问权限
(4)Method
Method提供关于类或接口上单独某个方法的信息
执行流程:Animal.java文件——>Animal.class文件——>类加载器加载到JVM中,JVM加载到内存中——>Animal.class就会有个对象表示
先获取类对象:
第一种 使用Class.forName静态方法:知道类的全路径名
第二种,使用 .class 方法:适合在编译前知道操作的CLass:
第三种,使用类对象的getClass()
//获取方法引用
c.getFields() //取得所有public属性(包括父类继承)
c.getDeclaredFields();//取得所有声明的属性(私有+公有)
私有属性要设置权限
field.setAccessible(boolean);
//获取构造方法引用
//实例化方法对象
通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法
//调用对象方法
3.类加载双亲委派机制
双亲委派:
(1)加载.class文件时,以递归的形式逐级向上委托给父加载器ParentClassLoader加载,如果加载过了,就不用再加载一遍
(2)如果父加载器没有加载过,继续委托给父加载器去加载,一直到这条链路的顶级,顶级ClassLoader如果没有加载过,则尝试加载,加载失败,则逐级向下交还调用者加载

类加载器作用:
(1)BootClassLoader:Android平台上所有Android系统启动时会使用BootClassLoader来预加载常用的类
(2)BaseDexClassLoader:实际应用层类文件的加载,而真正的加载委托给pathList来完成
(3)DexClassLoader:可以加载dex文件以及包含dex的压缩文件(apk,dex,jar,zip),可以安装一个未安装的apk文件,一般为自定义类加载器
(4)PathClassLoader:可以加载系统类和应用程序的类,通常用来加载已安装的apk的dex文件
Class文件加载:
1.通过Class.forName()方法动态加载
2.通过ClassLoader.loadClass()方法动态加载
类的加载分为3个步骤:1.装载(Load),2.链接(Link),3.初始化(Intialize)
4.静态代理和动态代理
我们不希望或是不能直接访问对象 A,而是通过访问一个中介对象 B,由 B 去访问 A 达成目的,这种方式我们就称为代理。
代理模式就是我实现你的方法代替你去做某件事,主要是为了不去修改原有的代码,通过代理也可以访问这个对象而且可以进行扩展
代理分为静态代理和动态代理,主要用于我们不想修改原本的实现逻辑,却想再原本实现逻辑上做拓展
静态代理:
实现被代理类的接口,重新需要代理的方法,需要创建代理对象,并将代理类所有方法都写一遍
动态代理:
动态代理的特点是不需要提前创建代理对象,而是利用反射机制在运行时创建代理类,主要便是利用了java提供的Proxy类和InvocationHandler
静态代理和动态代理,根据加载被代理类的时机不同,将代理分为静态代理和动态代理
静态代理:编译时就确定了被代理的类是哪一个
动态代理:运行时才确定被代理的类是哪个
静态代理(传统代理模)的实现方式比较暴力直接,需要将所有被代理类的所有方法都写一遍,并且一个个的手动转发过去,麻烦并繁琐。所以我们要学习并使用动态代理
动态代理:
- 动态代理能够增加程序的灵活度,比如调用方法前后的逻辑处理
- 完美解决解耦问题,动态代理可以将调用层和实现层分离
- 动态代理不需要接口实现类
静态代理的使用:
静态代理(传统代理模)的实现方式比较暴力直接,需要将所有被代理类的所有方法都写一遍,并且一个个的手动转发过去
动态代理的使用:
(1)定义一个接口
(2)定义真实对象
(3)定义一个InvocationHandler,相当于一个代理处理器
(4)调用
5.Android系统运行流程

(1)引导层: 手机开机后,引导芯片启动,引导芯片开始从固化在ROM里的预设代码执行,加载引导程序到到RAM,BootLoader检查RAM,初始化硬件参数等功能;
(2)内核层: Kernel层主要加载一些硬件设备驱动,初始化进程管理等操作。在Kernel中首先启动swapper进程(pid=0),用于初始化进程管理、内管管理、加载Driver等操作,再启动kthread进程(pid=2),这些linux系统的内核进程,kthread是所有内核进程的鼻祖;
(3)Native层:启动初始化进程管理等操作会启动init进程 ,这些在Native层中,init进程是所有进程的鼻祖,解析执行init.rc,到app_process进程,然后app_process孵化zygote进程
(4)java框架层:zygote进程会加载虚拟机,启动System_Server进程
加载BootLoader --> 初始化内核 --> 启动init进程 --> init进程fork出Zygote进程 --> Zygote进程fork出SystemServer进程
6.App启动流程

SystemServer启动了一个更加重要的服务ActivityManagerService
,AMS其中很重要的一个作用就是启动Launcher
进程
(1)点击桌面APP图标时,Launcher的startActivity()方法,通过Binder通信,调用system_server进程中AMS服务的startActivity方法,发起启动请求
(2)system_server进程接收到请求后,向Zygote进程发送创建进程的请求
(3)Zygote进程fork出App进程,并执行ActivityThread的main方法,创建ActivityThread线程
(4)创建ActivityThread线程--->handlerbindapplication进程
初始化————>Application的构造函数————>Application.attachBaseContext()————>Application.onCreate()函数
最后才会进入MainActivity中的attachBaseContext函数、onCreate函数