Framework -- 系统架构

news2025/1/12 1:53:39

一、前言

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 方法里做了四件事情

  1. 资源的预加载,加载系统的class文件,资源文件动态库。上层应用会使用大量的系统资源,如果在app启动的时候再去加载的话,会造成app启动缓慢,预加载可以提高app启动速度,也能共享这些资源文件
  2. 通过main方法传入的args 数组,判断是否有包含start-system-server 这个参数,来来决定是否启动systemserver 进程,该进程是Android framework 的核心进程
  3. 创建一个socket 服务,用来接受AMS 进程创建请求的
  4. 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等多个核心系统服务

这些系统服务大致可分为三类

  1. 引导服务
  2. 核心服务
  3. 其他一般服务

这些系统服务构成了Android的framework层,为app日常开发和运行提供了保障

当这些服务启动完成之后;其中的ActivityManagerService最终会调用systemReady()方法。是时候去通知ActivityManager去启动第三方应用了

4.Android系统启动流程总结:

  1. 手机开机后,引导芯片启动,开启引导烧录在存储器里的预设代码,然后加载引导程序到内存中,BootLoader检查RAM,初始化硬件参数等功能
  2. 硬件参数初始化完成后,进入到Kernel层,Kernel层主要加载一些硬件设备驱动(如相机驱动,视频驱动,显示屏驱动,输入驱动),初始化进程管理等操作。在Kernel中首先启动swapper进程(pid=0),用于初始化进程管理、内管管理、加载Driver等操作,再启动kthread进程(pid=2),这些linux系统的内核进程,kthread是所有内核进程的鼻祖;
  3. Kernel层加载完毕后,硬件设备驱动与HAL层进行交互。初始化进程管理等操作会启动init进程 ,这些在Native层中;
  4. init进程(pid=1,init进程是所有进程的鼻祖,第一个启动)启动后,会启动adbd,logd等用户守护进程,并且会启动servicemanager(binder服务管家)等重要服务,同时孵化出zygote进程,这里属于C++ Framework,代码为C++程序;
  5. zygote进程是由init进程解析init.rc文件后fork生成,它会加载虚拟机,启动System Server(zygote孵化的第一个进程);SystemServer负责启动和管理整个Java Framework,包含ActivityManager,WindowManager,PackageManager,PowerManager等服务;
  6. 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.javastartProcess(),委派给ProcessList来负责进程的创建

8. ProcessList中调用startProcessLocked() 

9. ProcessList中调用startProcess() 中 调用annovaote.getProcess().start()

10. ZygoteProcessor.java 中的attemptZygoteSendArgsAndGetResult()

11. ActivityThread.java 进入应用的进程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1137508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

定档11月2日,YashanDB 2023年度发布会完整议程公布

数据库作为支撑核心业务的关键技术&#xff0c;对数字经济的发展有着重要的支撑作用&#xff0c;随着云计算、AI等技术的迅猛发展和数据量的爆发式增长&#xff0c;推动着数据库技术的加速创新。 为了应对用户日益复杂的数据管理需求&#xff0c;赋能行业国产化建设和数字化转型…

python 线程池/AIO(异步非阻塞)调用接口示例

分别测试了 多线程、线程池、aio 等模式 线程受CPU调度限制&#xff0c;大请求量下 AIO 效率最高&#xff0c;详见代码 注释中有详细说明&#xff0c;main 方法中是程序入口 """ python 各种方式发起 http 请求对比 参考&#xff1a; https://plainenglish.io…

“第五十一天”

无符号整数&#xff1a; 计算机硬件在进行无符号整数的加法时&#xff0c;从最低位开始&#xff0c;按位相加&#xff0c;并往更高位进位。 当进行减法时&#xff0c;被减数不变&#xff0c;减数全部按位取反&#xff0c;末位加一&#xff08;将一个正数变负&#xff0c;或者…

关键词搜索淘宝商品数据接口(标题|主图|SKU|价格|优惠价|掌柜昵称|店铺链接|店铺所在地)

关键词搜索淘宝商品数据接口是可以通过API的方式来进行调用。这些接口可以获取到商品列表的标题、SKU ID、价格、优惠价、收藏数、月销售量等数据。 通过这些接口&#xff0c;可以实现关键词搜索淘宝商品列表的功能&#xff0c;也可以获取到商品详情页的数据信息&#xff0c;适…

微信自动通过好友请求是怎么设置的?

微信是一款必不可少的社交工具&#xff0c;尤其对于需要使用微信进行业务沟通和促进成交的人来说。 业务繁忙时可能每天有几十上百个微信好友申请&#xff0c;这时候如果手动“通过验证”不仅会工作质量和效率&#xff0c;有可能由于通过不及时而导致客户流失。 方式一 自动通…

leetCode 76. 最小覆盖子串 + 滑动窗口

76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻…

D71X-16Q手柄蝶阀型号解析

D71X-16Q型号字母含义解析 D71X-16Q是德特森阀门常用的手柄蝶阀型号字母分别代表的意思是: D——代表阀门类型《蝶阀》 7——代表连接方式《对夹》 1——代表结构形式《中线》 X——代表阀座材质《橡胶》 -代表分隔键 16——代表公称压力《1.6MPA》 Q——代表阀体材料《…

FPGA设计时序约束七、设置时钟不确定约束

一、背景 在之前的时序分析中&#xff0c;通常是假定时钟是稳定理想的&#xff0c;即设置主时钟周期后按照周期精确的进行边沿跳动。在实际中&#xff0c;时钟是非理想存在较多不确定的影响&#xff0c;存在时延和波形的变化&#xff0c;要准确分析时序也需将其考虑进来&#x…

2023深耕kotlin,谈谈前景

为什么学习kotlin&#xff1f; Kotlin 早就已经是 Google 官方推荐的开发语言了&#xff0c;而且 Android 新的 Compose 框架只支持 Kotlin &#xff0c;在 Google 那里&#xff0c;Android开发中 Java 其实已经被淘汰了。Java 和 Kotlin 虽然都属于高级语言&#xff0c;但是 …

利用nicegui开发ai工具示例

from fastapi import FastAPI import uvicorn from nicegui import uiclass PipRequirement:def __init__(self):ui.label("依赖安装与依赖展示")class BasicSettings:def __init__(self):self.project_select ui.select(["test"], label"项目选择&q…

驱动获取设备树节点信息

mycdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/of.h>struct device_node *dnode; //解析得到的设备树节点对象指针 struct property *pr; unsigned int lenth; static int __init mycdev_init(void) {//解析设备树节点信息d…

Hafnium安全分区管理器和示例参考软件栈

安全之安全(security)博客目录导读 目录 一、安全分区管理器 1、术语 2、对旧平台的支持 二、示例参考软件栈 一、安全分区管理器 安全分区管理器的三种实现在TF-A代码库并存&#xff1a; 1.基于FF-A规范的S-EL2 SPMC&#xff08;SPM Core&#xff09;&#xff0c;使能安全…

C++ 模板和泛型编程详解

C中的模板和泛型编程是非常重要的概念。模板是一种将数据类型作为参数的通用程序设计方法。它们允许开发人员编写可以处理各种数据类型的代码&#xff0c;而无需为每种数据类型编写不同的代码。下面介绍了一些关于C中模板和泛型编程的重要知识点 模板的定义 模板是一种通用程序…

论坛议程 | COSCon'23 开源治理(G)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

第十五章:L2JMobius学习 – 刷新NPC和对话

首先&#xff0c;我们介绍一下城镇里面的传送师NPC的刷新和对话。 传送师对应的类是L2TeleporterInstance&#xff0c;它继承L2FolkInstance&#xff0c;再继承L2NpcInstance。 我们要处理的是“单击/双击”传送师的业务逻辑&#xff0c;对应的是Action数据包。这个数据包具有…

Linux系统上安装FTP服务

文章背景 最近为了调试Linux系统FTP传输工具&#xff0c;刚好有Linux虚拟机环境&#xff0c;于是就搭建了vsftpd服务。 使用环境 Linux系统&#xff1a;BigCloud Enterprise Linux 7.8 (Core) 安装 1. 查询是否安装vsftpd [rootlocalhost ~]# rpm -qa | grep vsftpd 2. 安…

【CHI】Transaction structure

我们在前文【CHI】CHI协议&#xff0c;transaction事务汇总已经总结了事务类型&#xff0c;这篇开始讲述事务可以完成的方式。它显示了参与事务的各种组件可以使用的所有允许的选项。 注&#xff1a; 除了PCrdReturn 和PrefetchTgt之外&#xff0c;其他的事务在开始的时候都可…

APP分发-CDN加速原理

摘要 CDN的全称是(Content Delivery Network)&#xff0c;即内容分发网络。其目的是通过在现有的Internet中增加一层新的CACHE(缓存)层&#xff0c;将网站的内容发布到最接近用户的网络”边缘“的节点&#xff0c;使用户可以就近取得所需的内容&#xff0c;提高用户访问网站的…

疯狂java 三-六章

第三章 数据类型和运算符 Java语言是强类型语言&#xff0c;意思是每个变量和每个表达式都有一个在编译时就确定的类型&#xff0c;所有的变量都必须显式声明类型 标识符就是类&#xff0c;变量、方法命名的符号 标识符不能包含空格 标识符只能包含美元符($)&#xff0c;不…

2000-2021年三批“智慧城市”试点名单匹配数据

2000-2021年三批“智慧城市”试点名单匹配数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;行政区划代码、地区、所属省份、年份、智慧城市试点、最早试点年份 3、来源&#xff1a;住建部公布的三批“国家智慧城市名单” 4、说明&#xff1a;内含原始文件和匹配结…