Android Framework

Android本质就是在标准的Linux系统上增加了Java虚拟机Dalvik/ART,并在Dalvik/ART虚拟机上搭建了一个JAVA的application framework,所有的应用程序都是基于JAVA的application framework之上。

Android系统由linux内核,函数库,android runtime,应用程序框架以及应用程序组成。

android分为四层

  • 应用程序层,提供了一些核心程序包,例如电子邮件,短信,浏览器等
  • 应用程序框架层(Java Framework),为开发人员提供了可以开发应用程序所需要的api
  • 系统运行库层,包括C/C++程序库(C/C++程序库可以被android系统的不同组件所使用)和Android运行时库(分为核心库和art/dalvik,核心库提供了java语言核心库的大多数功能,dalvik专门为移动设备而定制,允许在有限的内存中同时运行多个虚拟机的实例)
  • Linux内核层,Android的核心系统服务基于LInux内核,在此基础上添加了部分Android专用的驱动,系统的安全性,内存管理,进程管理,网络协议栈和驱动模型等都依赖于Linux内核

Android文件格式

  • apk,安卓的安装包格式,包含android应用的所有代码和资源,包括AndroidManifest.xml,META-INF(保存apk的签名信息),classes.dex(程序的可执行代码)以及资源文件夹res
  • class,编写的代码是java文件,jvm运行的是class文件,需要jdk工具将java文件转化为class文件
  • jar,编译后的java代码的class文件的集合
  • aar.android studio全新的库文件格式,包含代码,资源数据
  • dex,android虚拟机的可执行字节码文件,java文件首先通过javac编译为class文件,然后再通过dx根据处理生成dex文件,dex文件主要包含四个部分,dex文件头,索引结构区,data数据区,静态链接数据区
  • odex和oat,优化程序执行的文件,dalvik在执行dex前会把dex优化后生成odex(在第一次安装时优化),然后把dex删除,可以加快软件启动,减少ram占用等,再dalvik中是odex,再art中是oat,在应用首次安装时dex2oat就会把classes.dex文件编译为机器码,生成elf格式的oat文件

Android启动流程

按下开机键后,引导芯片从固化的rom处执行预设的代码,将bootloader加载到RAM中,bootloader设置硬件参数,检查RAM,将操作系统映像文件拷贝到RAM然后跳转到入口处执行,linux内核启动,加载各种驱动和数据结构,开始启动android系统,创建第一个内核进程idle进程,最终会创建第一个用户进程init,init进程创建zygote进程

init进程

第一阶段

挂载以及创建基本的文件系统,设置访问权限,挂载system,cache,data等系统分区,加载.rc文件

第二阶段

selinux初始化完成后使用execv函数重新执行main方法,初始化和启动属性服务,解析init.rc文件

init进程在解析完init.rc文件后依次执行on early-init=>init=>late-init,late-init触发时就会启动zygote

Zygote

zygote进程是所有android进程的父进程,包括SystemServer和各种应用进程都是从zygote进程fork出来的

zygote进程有linux进程的init进程启动,即init进程=>Zygote进程=>SystemServer=>各种应用进程

zygote进程

  1. 初始化DDMS,通过registerZygoteSocket函数注册Server端的Socket。当Zygote进程将SystemServer进程启动后,就会在这个服务端的Socket上来等待ActivityManagerService请求Zygote进程来创建新的应用程序进程。
  2. 预加载类和资源(perloadClasses(),perloadShareLibrareis()等)
  3. 启动SystemServer进程
  4. 监听Socket,启动应用进程

应用启动

  • Launcher进程请求AMS
  • AMS发送创建应用进程请求
  • Zygote进程接收请求并孵化应用进程
  • 应用进程启动ActivityThread

PMS,开机后遍历data/app目录,找到apk,解压apk,通过dom解析最后找到包含Launcher对应的Activity,然后存放在Package缓存中(得到应用程序的相关信息,如应用程序的组件Package,Activity,Service等),保存到PMS的mPackages,mActivities等成员变量(HashMap类型)

AMS 加载Activity并且管理 Activity
当我们要启动一个应用的时候,需要加载Activity,还需要PMS提供对应的信息。

Launcher启动

Android应用程序安装Android系统在启动的过程中zygote进程启动SystemServer进程,SystemServer启动PackageManagerService(PMS),PMS扫描data/app目录找到apk并解析,得到应用的相关信息,完成安装。此时应用程序相当于在PMS服务中注册好了,还需要一个Home应用程序(Android中默认为Launcher)才能在桌面上看到这个应用程序。

当点击桌面上的应用程序时会调用Launcher的startActivitySafely方法,之后会调用Instrucmentation的execStartActivity方法,这个方法会调用ActivityManagerNative的getDefault方法(Binder机制)来获取ActivityManagerService(AMS)的代理对象,然后调用它的startActivity方法启动一个Activity,AMS时Launcher栈最顶端的Activity进入onPause状态,AMS通知Process使用Socket和zygote进程通信,请求创建一个新进程,zygote收到socket请求后fork出一个进程,调用ActivityThread main方法,ActivityThread通过Binder通知AMS启动应用程序,AMS通知ActivityStackSupervisor真正的启动Activity,ActivityStackSupervisor通知ApplicationThread启动Activity,ApplicationThread发消息给ActivityThread,需要启动一个Activity,ActivityThread又通知LoadedApk创建Application,并调用其onCreate方法,ActivityThread装载目标Activity类,调用Activity.attach(),ActivityThread通知Instrumentation调用Activity.onCreate(),Instrumentation调用Activity.perfoemCreate(),在该方法中调用自身onCreate()方法

Dalvik与Art

在Android4.4之前使用的是Dalvik虚拟机,之后则是Art虚拟机,Art虚拟机能够向下兼容,提供了对Dalvik可执行格式以及字节码规范的支持。

Dalvik的特点

  • 体积小,占用内存小
  • 专有的dex文件体积小,执行速度快
  • 常量池采用32位索引值,对类方法名,字段名,常量的寻址速度快
  • 基于寄存器架构,拥有完整的一套指令系统
  • 提供了对象生命周期管理,堆栈管理,线程管理,安全和异常管理以及垃圾回收等重要功能
  • 所有的android程序都运行在Android系统进程中,每个进程都和一个Dalvik虚拟机实例对应

与Java虚拟机的区别

  • 运行的字节码不同,JVM运行的是java字节码,Dalvik运行的是Dalvik字节码,Java程序=>java字节码=>保存至class文件=>jvm解码class来运行程序,而Dalvik是Java字节码=>dalvik字节码=>打包到dex=>dalvik解释dex文件来执行字节码
  • dakvik的可执行文件体积更小,dx工具在将java字节码转换为dalvik字节码时会消除在类文件中出现的冗余信息,通过共享常量池的方法(java中有多个方法签名,引用方法时签名也会被复制,所以会有很多冗余信息)
  • 架构不同,jvm基于栈架构,cpu资源耗费大(对栈频繁的读写,指令分配,内存访问),dalvik基于寄存器架构,数据的访问在寄存器之间传递

Dalvik和Art的区别

  • art虚拟机执行的是本地机器码采用的是AOT(ahead-of-time)编译,应用在第一次安装时就会预先编译成机器码,app运行时就不用解释字节码了
  • dalvik采用的是JIT(just-in-time)编译,运行时先把dex文件解释翻译为机器码之后才能运行,因此art应用启动速度快,运行快,电池续航高,但是占用空间大

Binder

binder是一种进程间通信机制(IPC),用于在不同进程间的通信和数据交换,底层实现是通过内存共享,数据传输和读取的速度更快。

核心概念

  • binder驱动,binder机制的实现依赖于linux内核中的binder驱动,负责处理进程间通信的底层细节,包括进程注册,线程创建,消息传递等
  • binder服务,是在一个进程中提供服务的组件,可以被其他进程通过binder机制调用,每个binder服务有一个唯一的标识符(binder对象的引用)用于进行跨进程通信
  • binder代理,是在客户端进程中的一个中间组件,用于处理客户端和服务端之间的通信,负责将客户端的请求转发给服务端,并将服务端的响应返回给客户端
  • binder通信,通过跨进程的消息传递进行,客户端通过向服务端发送请求消息,服务端接收并处理请求,然后将响应返回给客户端

工作流程

  1. 客户端获取服务端的binder引用(通过binder引用获取服务端的接口)
  2. 客户端发送请求消息
  3. 服务端接收请求消息
  4. 服务端处理请求并发送响应消息
  5. 客户端接收响应消息

Android的签名机制

签名的作用

  • 发送者的身份认证 由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不同的包不被替换
  • 保证应用的完整性,签名对于包中的每个文件进行处理,确保包中的内容不被替换
  • 应用升级校验,当应用需要升级时,系统会检查新版本的签名是否和旧版本一致
  • 权限授予,某些系统级权限的授予会基于apk的签名

APK签名的机制和原理

  • 数字签名技术,开发者使用私钥对apk进行签名,生成签名文件(META-INF目录下),当android系统或其他设备需要验证apk时,会使用公钥来验证签名文件
  • android的安全机制,在安装apk时,系统会检查签名文件的完整性和有效性,如果缺失或无效,系统会拒绝安装该应用,同时还会记录每个应用的签名信息用于后续的应用升级和权限校验

签名检测

SELinux

SELinux核心概念

  • 安全上下文,每个进程,文件,设备和网络套接字都有一个唯一的安全上下文呢,有用户标识符UID,角色标识符RID和类型标识符TID组成
  • 策略规则,通过策略规则来定义和强制访问控制
  • 强制访问控制
  • 上下文转换,进程需要切换不同的安全上下文时需要进行上下文转换

SELinux工作原理

  • 在系统引导过程SELinux加载策略文件并初始化
  • 当进程,文件,设备或网络套接字被创建时,SELinux为其分配唯一的安全上下文
  • 当进程试图访问受限资源时,SELinux会根据策略规则进行决策
  • 当进程需要切换不同的安全上下文时需要进行上下文转换

Android app可访问文件的路径

  • 应用程序内部存储(Internal Storage),每个应用都有自己的私有目录,可以创建和访问应用所私有的文件(/data/data/
  • 外部存储(External Storage),设备共享媒体文件等数据的存储位置(storage/emulated/0/)
  • 缓存目录(Cache Directory),临时缓存文件,系统在需要释放空间时可能会去除该目录的文件(/data/data//cache/)
  • SD卡目录(SD Card Directory),(/mnt/sdcad/或/storage/sdcard/)

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3049155267@qq.com

💰

×

Help us with donation