Framework -- 系统架构
一、前言
framework的学习,需要掌握到什么程度?
- App 的启动流程:整体的过程,具体到某些类在整个流程中所起的作用;
- 组件的设计模式,核心设计思想;
- 需要知晓目前已知的问题,以及解决方案。
二、Android系统架构
1.首先先看下Google官方提供的经典分层架构图:

- Linux内核层
- HAL层(硬件抽象层)
- 系统运行库层(系统Native库和Android运行时环境)
- Framwork层(Java框架层)
- Application层(包括Systema Apps和三方App)
2.从进程上划分
Loader 开机引导程序
由BootLoader引导开机
当手机处于关机状态时,长按电源进行开机。
原因:主板通电之后,开启引导烧录在存储器里的预设代码,然后加载引导程序到内存中,这个主要做一些内存检测以及硬件参数的初始化过程
linux kernel 硬件抽象层
开机引导程序执行完成之后,开始加载linux kernel 核心代码。
这层主要是加载一些硬件驱动,如相机驱动,视频驱动,显示屏驱动,输入驱动
上层应用想要调用这些硬件驱动的话,为了解决各大应用商提供的驱动不统一的问题,由硬件抽象层来适配,提供统一的api,
C++ FrameWork
硬件驱动加载完成之后会加载linux 中第一个用户进程 init 进程,还会孵化出adbd deme进程,以及log deme进程。
这就是为什么在运行时可以断点调试和输出日志的原因,就是因为这两个守护进程的存在
Android Framework
在ZygoteInit main方法里面还启动了SystemServer 系统服务进程
3.关键进程
init进程
是Linux系统中用户空间的第一个进程,进程号为1(pid=1),由于Android是基于Linux内核的,所以init也是Android系统中用户空间的第一个进程。
init进程的作用
- 孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程(守护进程一般以d结尾)
- 提供property service(属性服务)来管理Android系统的属性。
- 启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务
- 孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。
Zygote进程
Init进程启动后,最重要的一个进程就是Zygote进程,Zygote是所有应用的鼻祖。SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来。
Zygote进程由app_process启动,Zygote是一个C/S模型,Zygote进程作为服务端,其他进程作为客户端向它发出“孵化-fork”请求,而Zygote接收到这个请求后就“孵化-fork”出一个新的进程。
是一个承上启下,连接Java世界和Linux 世界,zygote 进程创建完成之后就进入Java世界了,会调用ZygoteInit java 类,在这个类的入口方法,会创建Android Framework 系统服务,System Server 进程,所有app的进程都是由Zygote 进程孵化而来的
app进程创建完成之后,都会由ZygoteInit 反射调用app进程的入口类,也就是ActivityThread这个类,从而使app得以启动
1. 我们知道Java调用C++可以通过JNI。那么C++是如何转到Java的,也就是说ZygoteInit.java这个类是如何被调用的?
在java中,class文件是由ClassLoader来加载的,但实际上,ClassLoader在加载java文件的过程中,也是通过C++来完成的(Bootstrp loader就是用C++写的,具体可以去看java类加载过程及机制,Java类加载器ClassLoader总结),所以C++如果想要访问java文件的话,是非常轻松的2. 进程间通信通常使用的是binder,为什么SystemServer和Zygote之间通信要采用Socket
UNIX上C++程序设计守则3:多线程程序里不准使用fork
Binder通讯是需要多线程操作的,代理对象对Binder的调用是在Binder线程,需要再通过Handler调用主线程来操作。
害怕父进程binder线程有锁,然后子进程的主线程一直在等其子线程(从父进程拷贝过来的子进程)的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁。
3.为什么一个java应用一个虚拟机?
android为每个程序提供一个vm,可以使每个app都运行在独立的运行环境,使稳定性提高。每个程序一个虚拟机,各个程序之间也不可以随意访问内存,所以此类木马病毒几乎没有。
4.什么是Zygote资源预加载?
预加载是指在zygote进程启动的时候就加载,这样系统只在zygote执行一次加载操作,所有APP用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中App共享的资源会被列为预加载资源。
zygote fork子进程时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。5. Zygote为什么要预加载
应用程序都从Zygote孵化出来,应用程序都会继承Zygote的所有内容。
如果在Zygote启动的时候加载这些类和资源,这些孵化的应用程序就继承Zygote的类和资源,这样启动引用程序的时候就不需要加载类和资源了,启动的速度就会快很多。
开机的次数不多,但是启动应用程序的次数非常多。6.Zygote预加载的原理是什么?
zygote进程启动后将资源读取出来,保存到Resources一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。
//1从classpath路径下搜索ZygoteInit这个类,并返回该类的Class对象,进程创建创建完成后会固定加载这个类
jClass clazz = (*env)->Findclass(env, "com/ android/internal/os/zygoteInit"):
//2获取类的默认构造方法ID
jmethodID mid_construct = (*env) ->GetMethodID (env, clazz,
"<init>" "(v");
//3创建该类的实例
jobject jobj = (*env)->NewObject(env, clazz,mid_construct);
//4查找实例方法的ID
jmethodID mid_instance = (wenv)->GetMethodID(env, clazz, "main", "(Ljava/lang/String; I
1/5调用对象的实例方法
A
jstring str_arg = (*env)->NewstringUTF(env,”我是实例方法");
(wenv) ->CallVoidMethod (env, jobj,mid_instance, str_arg, 200) ;
Zygoteinit main 方法里做了四件事情
- 资源的预加载,加载系统的class文件,资源文件动态库。上层应用会使用大量的系统资源,如果在app启动的时候再去加载的话,会造成app启动缓慢,预加载可以提高app启动速度,也能共享这些资源文件
- 通过main方法传入的args 数组,判断是否有包含start-system-server 这个参数,来来决定是否启动systemserver 进程,该进程是Android framework 的核心进程
- 创建一个socket 服务,用来接受AMS 进程创建请求的
- socket 服务创建完成之后,进入阻塞状态,等待客户端的连接
ZygoteInit-java
public static void main(String argv []){//1.预加载frameworks/base/preloaded-classes和framework_res.apk资源preloadClasses();preloadResources();preloadSharedLibraries();//2.启动system_server进程。该进程是framework的核心。if (argv [1].equals("start-system-server")) {startSystemServer();}//3.创建Socket服务registerZygoteSocket();//4.进入阻塞状态,等待连接,用以处理来自AMS申请进程创建的请求runSelectLoopMode();}
}
SystemService进程
在zygoteInit main 方法中启动了SystemService系统服务进程,这个进程创建成功之后
通过反射的方法启动SystemServer.java的main()方法
在他的main 方法里面会启动非常多的系统服务,比如 ActivityManagerService、PowerManagerService、DisplayManagerService、PackageManagerService、WindowManagerService、LauncherAppsService等多个核心系统服务
这些系统服务大致可分为三类
- 引导服务
- 核心服务
- 其他一般服务
这些系统服务构成了Android的framework层,为app日常开发和运行提供了保障
当这些服务启动完成之后;其中的ActivityManagerService最终会调用systemReady()方法。是时候去通知ActivityManager去启动第三方应用了
4.Android系统启动流程总结:
- 手机开机后,引导芯片启动,开启引导烧录在存储器里的预设代码,然后加载引导程序到内存中,BootLoader检查RAM,初始化硬件参数等功能
- 硬件参数初始化完成后,进入到Kernel层,Kernel层主要加载一些硬件设备驱动(如相机驱动,视频驱动,显示屏驱动,输入驱动),初始化进程管理等操作。在Kernel中首先启动swapper进程(pid=0),用于初始化进程管理、内管管理、加载Driver等操作,再启动kthread进程(pid=2),这些linux系统的内核进程,kthread是所有内核进程的鼻祖;
- Kernel层加载完毕后,硬件设备驱动与HAL层进行交互。初始化进程管理等操作会启动init进程 ,这些在Native层中;
- init进程(pid=1,init进程是所有进程的鼻祖,第一个启动)启动后,会启动adbd,logd等用户守护进程,并且会启动servicemanager(binder服务管家)等重要服务,同时孵化出zygote进程,这里属于C++ Framework,代码为C++程序;
- zygote进程是由init进程解析init.rc文件后fork生成,它会加载虚拟机,启动System Server(zygote孵化的第一个进程);SystemServer负责启动和管理整个Java Framework,包含ActivityManager,WindowManager,PackageManager,PowerManager等服务;
- zygote同时会启动相关的APP进程,它启动的第一个APP进程为Launcher,然后启动Email,SMS等进程,所有的APP进程都有zygote fork生成。
三、Launcher应用的启动流程
进程的入口类一般有两种:
- native 进程的入口类一般是init
- Java进程的入口类一般都是main 方法
总结:Zygote 进程创建成功之后,会进入到Java世界,第一个创建的是ZygoteInit 这个Java类,在它的入口方法里主要做了系统资源的预加载,以提高App 启动的响应速度,同时也是为了App 运行时能够共享系统的资源,其次它还会启动系统服务进程SystemService,这个进程的入口类是SystemService.java,而这个类里面一个启动了一百多个服务,共同为App 运行提供保障服务,当所有的服务启动完成之后,会通知ActivityManagerService去启动launcher应用
1.相关类介绍
ActivityManagerService
负责管理四大组件和进程,包括生命周期和状态切换。它的systemReady()方法,是Launcher应用启动的入口。
ActivityTaskManagerService
把原先在ActivityManagerService 对Activity生命周期管理和调度等工作全部转移到此,由它来管理Activity 的工作(Android10新增)。
RootActivityContainer
调用PackageManagerService去查询手机系统中已安装的所有的应用,哪一个是符合launcher标准,且得到一个Intent 对象,并交给ActivityStarter。
ActivityStater
得到这个Intent 对象之后交由ActivityStarter启动器进一步的启动,在它里面会做启动之前的各项检查,比如检查Activity 有没有在清单文件中注册,class文件是否存在,这个activity 是否有权限启动等。
ActivityRecord
在Activity 启动的时候就会涉及到进栈和出栈的操作,在Service端是无法拿到Activity 实例的,而ActivityRecrd 是在Service端对Activity 的一种映射,它里面记录和存储了Activity 所有的信息。
代表一个Activity。
TaskRecord
任务栈,记录一个或多个ActivityRecord 的实例。
Activity栈,内部维护一个ArrayList<ActivityRecord>。
ActivityStack
任务栈的管理者,应用在运行的时候会有一个或多个任务栈,这些任务栈会交给ActivityStack 来管理。
负责管理各个Activity栈,内部维护一个ArrayList<TaskRecord>。
ActivityStackSupervisor
由于手机在运行中会启动一个或多个应用,这个时候会产生一个或多个ActivityStack 对象,用来管理Launcher和非Launcher应用的ActivityStack实例。
内部持有一个ActivityStack,而ActivityStack内部也持有ActivityStackSupervisor,相当于ActivityStack的辅助管理类
ProcessList
职责是把原先在ActivityManagerService钟启动进程的工作转移到此(Android10新增)。
ZygoteProcess
建立起与Zygote 进程的socket 链接,并且把创建进程所需要的参数给发送过去,
Instrumentation
负责调用Activity和Application生命周期。
2.Activity任务栈之间的关系 (包含多个)
ActivityStackSupervisor -> ActivityStack -> TaskRecord -> ActivityRecord
3.Launcher启动流程分析
BootRom -> BootLoader -> Linux Kernel -> Init -> Zygote -> SystemServer -> Launcher
1. ActivityManagerService.java 调用 systemReady() 系统服务启动完毕后,launcher应用的入口
//启动HomeActivity(即Launcher应用的入口Activity):本意是在所有的屏幕上启动桌面应用
//因为Android10.0开始是支持多屏幕的,比如手机屏幕,虚拟投屏,外接屏幕
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
2. 这里的mAtmInternal是ActivityTaskManagerInternal,是一个抽象类。真正的实现类在ActivityTaskManagerService的内部类LocalService中,进而调用startHomeOnAllDisplays(),在这里会做一层转发,进而委托给RootActivityContainer
3. 在RootActivityContainer的startHomeOnAllDisplays()中调用PackageManagerService中去查询手机系统中已安装的所有的应用,哪一个符合launcher标准,且得到一个Intent对象,并交给ActivityStarter。
4. ActivityStarter中调用startActivityUnchecked() 进行清单文件校验,启动权限检查,根据启动模式和Intent.flag计算出该Activity所属的任务栈并加入,但此时并不会显示
5. ActivityTask中调用resumeTopActivityInnerLocked(),启动新的Activity之前会把当前可见的Activity暂停,计算待启动的Activity所属进程是否存在
6. 在ActivityStackSuperVisor.java类的startSpecificActivityLocked()去判断进程是否存在,如果存在,调用realStartActivityLocked去启动Activity,否则调用ActivityManagerIntenal::startProcess去创建进程
7. ActivityManagerService$LocalService.java中startProcess(),委派给ProcessList来负责进程的创建
8. ProcessList中调用startProcessLocked()
9. ProcessList中调用startProcess() 中 调用annovaote.getProcess().start()
10. ZygoteProcessor.java 中的attemptZygoteSendArgsAndGetResult()
11. ActivityThread.java 进入应用的进程
相关文章:

Framework -- 系统架构
一、前言 framework的学习,需要掌握到什么程度? App 的启动流程:整体的过程,具体到某些类在整个流程中所起的作用;组件的设计模式,核心设计思想;需要知晓目前已知的问题,以及解决方…...

1.1 计算机安全概念
思维导图: 前言: 第1章: 计算机与网络安全概念笔记 1. 学习目标 了解保密性、完整性和可用性的关键安全需求。了解OSI的X.800安全架构。识别和举例说明不同的安全威胁和攻击。掌握安全设计的基本准则。熟悉攻击面和攻击树的使用。了解与密码标准相关的…...
react中的函数柯里化
函数柯里化是一种将接受多个参数的函数转化为一系列接受单一参数的函数的技术。在React开发中,函数柯里化可以帮助我们更好地组织组件的代码,使其具有更好的可读性和可复用性。 一个简单的函数柯里化示例: function add(a) {return functio…...

Unity点乘的实战案例1
向量的点乘,也叫向量的内积、数量积,对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,点乘的结果是一个标量。点乘,也叫数量积。结果是一个向量在另一个向量方向上投影的长度,是一个标量。 • …...
Hive数据查询详解
本专栏案例数据集链接: https://download.csdn.net/download/shangjg03/88478038 1.数据准备 为了演示查询操作,这里需要预先创建三张表,并加载测试数据。 1.1 员工表 -- 建表语句CREATE TABLE emp(empno INT, -- 员工表编号ename STRING, -- 员工姓名...

人工智能基础_机器学习008_使用正规方程_损失函数进行计算_一元一次和二元一次方程演示_sklearn线性回归演示---人工智能工作笔记0048
自然界很多都是正态分布的,身高,年龄,体重...但是财富不是. 然后我们来看一下这个y = wx+b 线性回归方程. 然后我们用上面的代码演示. 可以看到首先import numpy as np 导入numby 数据计算库 import matplotlib.pyplot as plt 然后导入图形画的库 然后: X = np.linspace(0,…...

【详细】Java网络通信 TCP、UDP、InetAddress
一、网络程序设计基础 1.局域网与因特网 为了实现两台计算机的通信,必须用一个网络线路连接两台计算机(服务器<-->网络<-->客户机)。 服务器是指提供信息的计算机或程序,客户机是指请求信息的计算机或程序。网络用…...

Linux(Centos7)操作记录
1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误,并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…...

Vue全局事件总线实现任意组件间通信
一、安装全局事件总线 全局事件总线就像是一个工具,专门用于挂载自定义事件和。 想要所有的组件都能使用这个全局事件总线,就只有在Vue的原型身上添加一个能够绑定自定义事件的属性。 所以我们在创建Vue实例对象的时候就可以添加如下代码:…...
linux-tools-$(uname -r) linux-headers-$(uname -r)工具安装:
linux-tools-$(uname -r) linux-headers-$(uname -r)工具安装: ebpfebpf-virtual-machine:~$ sudo apt-get install linux-tools-$(uname -r) [sudo] ebpf 的密码: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 linux…...
hive sql,年月日 时分秒格式的数据,以15分钟为时间段,找出每一条数据所在时间段的上下界限时间值(15分钟分区)
获取当前的年月日 时分秒 select date_format(current_timestamp(), yyyy-MM-dd HH:mm:ss)date_format(时间字段, ‘yyyy-MM-dd HH:mm:ss’) 将时间字段转为 2023-10-18 18:14:16 这种格式 在指定时间上增加15分钟 select from_unixtime(unix_timestamp(current_timestamp(…...
C#学习系列之继承
C#学习系列之继承 啰嗦继承使用特殊基类隐藏方法实际使用总结 啰嗦 基础学习。 继承 一个类派生于另一个基类型,它拥有该基础类型的所有成员字段和函数。A派生于B,继承A的所有东西,同时可以增加自己的东西。 使用 public class parent {p…...
PyTorch入门学习(六):神经网络的基本骨架使用
目录 一、引言 二、创建神经网络骨架 三、执行前向传播 一、引言 神经网络是深度学习的基础。在PyTorch中,可以使用nn.Module类创建自定义神经网络模型。本文将演示如何创建一个简单的神经网络骨架并执行前向传播操作。 二、创建神经网络骨架 首先,…...

“体检报告健康解读技术传承人”授牌仪式圆满结束
2023年10月,全国卫生健康技术推广传承项目办公室将体检报告健康解读技术传承人证书授予中山大学麻醉学硕士、副主任医师、医说友道创始人许才燕医生。 10月13日,许才燕医生团队在广东佛山举行“解读体检报告 重构健康生态”体检报告健康解读技术传承人授…...

查询计算机GUID码
如何查询计算机GUID码(全局唯一标识符) 1.快键键WINR进入注册表 2.找到\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography路径 3.双击MachineGuid项即可显示计算机GUID码...
MediaPlayer+TextureView实现视频播放功能
前面写一些基础知识的学习,这篇写个小demo,实现视频循环播放功能。 1、xml代码: <TextureViewandroid:id"id/textureView"android:layout_width"600px"android:layout_height"400px"android:focusable&quo…...
webpack 优化
打包优化 webpack 优化1、依赖转化,兼容低版本浏览器2、生产环境关闭sourceMap3、打包输出目录名称修改和静态资源的存放4、修改图标5、修改webpack配置5-1、写在此处的配置可以覆盖掉脚手架本来就预设上有的配置5-2、写在此处的都是预设没有配置的,脚手…...
保障 Golang 项目安全的最佳实践
对任何项目来说,安全都是一个永恒的话题,本文详细讲解一下保障 Golang 项目的安全性需要遵循一些最佳实践。 对源代码和构建出的二进制文件做全面的安全扫描 定期对源代码和二进制文件进行全面的安全扫描,查找漏洞,以便及早识别…...
PG物理备份与恢复之pg_basebackup
PG物理备份与恢复之pg_basebackup 开启WAL日志归档pg_basebackup备份工具全库恢复:recovery.conf 🐘 数据库版本:PostgreSQL 10.4 开启WAL日志归档 通过数据库的全量备份和WAL日志,可以将数据库恢复到任意时间点。每个WAL日志文件…...

npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
1 bug描述 使用vscode执行npm run dev指令时出现 “npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次 “ 的错误提示,原因是系统里没有安装n…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...