欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于问题学习安卓系统架构

程序员文章站 2022-04-14 11:22:57
基于问题学习安卓系统架构文章目录基于问题学习安卓系统架构1 原理1.1 什么是安卓系统架构APP层Framework层Native/ArtNative: C/C++ArtHAL层Kernal层1.2 Android8源码与系统架构的关系源码目录结构源码目录描述1.3 为什么安卓系统架构要这么设计1 原理本节要了解、弄懂安卓系统架构的原理,首先将安卓系统架构完全分析清楚,再根据下载好的Android8的源码,将源码目录中的内容与系统架构联合在一起,最后总结为什么安卓系统架构要这么设计。1.1 什么是安...

基于问题学习安卓系统架构

1 原理

本节要了解、弄懂安卓系统架构的原理,首先将安卓系统架构完全分析清楚,再根据下载好的Android8的源码,将源码目录中的内容与系统架构联合在一起,最后总结为什么安卓系统架构要这么设计。

1.1 什么是安卓系统架构

安卓系统架构,就是从底层硬件到高层软件的一整套技术体系,用户使用的移动端设备如果使用安卓系统搭建,那么用户就可以使用安卓平台上的应用,安卓系统架构图如下:

基于问题学习安卓系统架构

从顶层到底层依次是:APP --> Framework --> Native --> HAL --> Kernal,接下来对这些层进行三个层次的分析:为什么要有它、是什么、在哪里,一切要从为什么入手。

APP层

  1. why

    我今天早上睡过头迟到了,那么我就在想,如果有一个闹钟就好了,于是就出现了手机闹钟APP,就解决了用户每天起床需要有人按时提醒上班的需求。所以当应用设计出来后,一些页面、页面跳转、功能都需要在APP层进行实现。

  2. what

    就如同英文直译过来一样,是一些应用软件,比如系统自带的应用如:时钟、计算器,和用户自己安装的应用如:微信、微博。应用需要给用户提供好看的外观和满足需求的功能,是安卓系统架构中用户看得见摸得着的第一个东西,直接和用户的体验挂钩。

  3. where

    以apk的形式安装在用户的手机上,打开手机一看全是。

    源码根目录中的packages目录对应着系统应用层,如下所示。

    packages目录 描述
    apps 核心应用程序
    experimental 第三方应用程序
    inputmethods 输入法目录
    providers 内容提供者目录
    screensavers 屏幕保护
    services 通信服务
    wallpapers 墙纸

Framework层

  1. why

    当产品的定位和设计出来后,安卓软件工程师就要进行开发,手机上的产品,都是软件和硬件一起协助开发完成的,那是不是每次开发产品的时候都要将硬件和软件都写好呢?当然不是,这样开发的效率太低、所需要的开发知识的门槛太高了,所以就需要有人帮助安卓应用工程师把一些与系统打交道、通用的东西都封装好,变成有描述、可以调用的API接口,达到提效率、降门槛的效果。

  2. what

    Framework层是一些封装好的api,主要由Java代码实现。当安卓应用工程师在编程的时候,就可以调用Framework层的api对系统层面比如电源管理、消息队列、包管理等做操作。Framework同下层打交到的方式有很多种,参考Android Framework层和Native层通信的6种方式,同上层打交到的方式就是抽象出各种Java接口。

    往上层看,在AS中开发app的时候,import的各种android.*,就是Framework层的api。

    package com.leo.helloworld;
    
    import android.app.ActivityManager;// 这边都是
    import android.content.Context;
    import android.os.Bundle;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class leo extends AppCompatActivity {
    
        public  void activityManagerDemo(Context context){
            ActivityManager activityManager =
                    (ActivityManager)(context.getSystemService(android.content.Context.ACTIVITY_SERVICE )) ;
            return;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_leo1);
        }
    }
    

    往下层看,Framework层提供了jni.h的文件去连接Native中的C或C++代码,达到了Java代码调用C或C++代码的效果。

    下面引用网上对于 ‘Framework是什么’ 的回答:

    直接翻译的意思是架构,但这样说可能不懂,下面我从两个方面来给你说吧:

    一是比喻来说,假设你现在要盖楼房,framework就好比一个建筑公司,它里面有专门采集石料的,专门的租夹板的,专门的磨砂,搬砖的,运输的等等一系列的,你需要做的就是要通过这家建筑公司来盖楼,比如说你要采集石料,你通过公司采购部门,直接采集来了石料,然后通过他们进行一系列的工作,这要比你自己去河里采砂,到山上去炸石头(这些活都是不使用framework的底层嵌入式开发人员做的)要简单的多,这也是为什么farmework要高效的多,所以说,对于开发人员来说,他就像是会为开发省很多事情,但这种框架下开发的软件有一定的依赖性,所以,对于不是开发人员的用户来说,如果你的电脑上有这种框架下开发的软件,你必须有这个框架软件才可以,就好像你如果要用扩展名为EXE的应用程序,你必须先有windows系统一样

    另外呢,就是通过实际案例来说明framework

    如果我们要完成屏幕打印“hello world”,你如果没用框架软件,你或许会先了解底层如何实现在屏幕上显示字符,又如何启动显示器,如何控制字符位置等等,然后再考虑如何打印hello world

    但是在framework下,框架下的Console类下有个静态方法Write直接实现了打印,你只需要调用这个方法,然后告诉他你要打印的信息就可以了,Console.Write(“hello world”)

    不管你是不是开发人员,解释的觉得还是透彻的,不懂的话可以再追问,希望能得到最佳~

    引用来源:XJZWX

    Framework层主要提供的组件如下:

    名称 功能描述
    Activity Manager(活动管理器) 管理各个应用程序生命周期以及通常的导航回退功能
    Location Manager(位置管理器) 提供地理位置以及定位功能服务
    Package Manager(包管理器) 管理所有安装在Android系统中的应用程序
    Notification Manager(通知管理器) 使得应用程序可以在状态栏中显示自定义的提示信息
    Resource Manager(资源管理器) 提供应用程序使用的各种非代码资源,如本地化字符串、图片、布局文件、颜色文件等
    Telephony Manager(电话管理器) 管理所有的移动设备功能
    Window Manager(窗口管理器) 管理所有开启的窗口程序
    Content Providers(内容提供器) 使得不同应用程序之间可以共享数据
    View System(视图系统) 构建应用程序的基本组件
  3. where

    应用框架层的主要实现代码在/frameworks/base和/frameworks/av目录下,其中/frameworks/base目录结构如下所示:

    /frameworks/base目录 描述 /frameworks/base目录 描述
    api 定义API cmds 重要命令:am、app_proce等
    core 核心库 data 字体和声音等数据文件
    docs 文档 graphics 图形图像相关
    include 头文件 keystore 和数据签名证书相关
    libs location 地理位置相关库
    media 多媒体相关库 native 本地库
    nfc-extras NFC相关 obex 蓝牙传输
    opengl 2D/3D 图形API packages 设置、TTS、VPN程序
    sax XML解析器 services 系统服务
    telephony 电话通讯管理 test-runner 测试工具相关
    tests 测试相关 tools 工具
    wifi wifi无线网络

    参考链接:Android系统架构与系统源码目录

Native/Art

Native: C/C++
  1. why

    首先,安卓的应用和framework层主要使用Java语言开发,但是Java是高级语言的一种,虽然在编程时比较容易学习,但是如果要完成一些复杂运算和偏向底层的操作,Java非常难实现,而使用C/C++会很简单,所以一般会使用虚拟机:JVM等,将Java代码编译后再解释成机器语言,来驱动硬件。那么除开使用虚拟机将.class文件解释后变成机器可识别的文件,我们可以通过给Java代码加上native关键字、Java代码利用jni.h文件调用C/C++代码的方式,把复杂的Java难以实现的功能,交给C/C++代码来实现。

  2. what

    常见一些本地服务和一些链接库等。这一层的一个特点就是通过C和C++语言实现。

  3. where

    C/C++程序库并不完全在一个目录中,主要的C/C++程序库如:

    名称 功能描述
    OpenGL ES 3D绘图函数库
    Libc 从BSD继承来的标准C系统函数库,专门为基于嵌入式Linux的设备定制
    Media Framework 多媒体库,支持多种常用的音频、视频格式录制和回放。
    SQLite 轻型的关系型数据库引擎
    SGL 底层的2D图形渲染引擎
    SSL 安全套接层,是为网络通信提供安全及数据完整性的一种安全协议
    FreeType 可移植的字体引擎,它提供统一的接口来访问多种字体格式文件

    要查看framework层对应的native层源码,参考:如何查找native方法所对应的底层文件

Art
  1. why

    在安卓系统中,APP开发和Framework层开发都是Java代码,Java代码执行在虚拟机上,如:JVM。Art也是虚拟机的一种,所以其存在的理由就是为了支持Java代码编译、解释。

  2. what

    Art,Android Runtime,是安卓手机上运行的虚拟机,Android4.4及以前使用的都是Dalvik虚拟机,Android5.0才开始使用Art。

    为什么不使用JVM做为虚拟机?

    Java VM是以基于栈的虚拟机(Stack-based),而Dalvik是基于寄存器的虚拟机(Register-based)。 显然,后者最大的好处在于可以根据硬件实现更大的优化,这更适合移动设备的特点。DVM非常适合在移动终端上使用,与PC相比,它不需要很快的CPU和大量的内存空间。

    为什么要从Dalvik变为Art?

    • Dalvik
      Android4.4及以前使用的都是Dalvik虚拟机,我们知道Apk在打包的过程中会先将Java等源码通过javac编译成.class文件,但是我们的Dalvik虚拟机只会执行.dex文件,这个时候dx会将.class文件转换成Dalvik虚拟机执行的.dex文件。Dalvik虚拟机在启动的时候会先将.dex文件转换成快速运行的机器码,又因为65535这个问题,导致我们在应用冷启动的时候有一个合包的过程,最后导致的一个结果就是我们的app启动慢,这就是Dalvik虚拟机的JIT特性(Just In Time)。
    • Art
      ART虚拟机是在Android5.0才开始使用的Android虚拟机,ART虚拟机必须要兼容Dalvik虚拟机的特性,但是ART有一个很好的特性AOT(ahead of time),这个特性就是我们在安装APK的时候就将dex直接处理成可直接供ART虚拟机使用的机器码,ART虚拟机将.dex文件转换成可直接运行的.oat文件,ART虚拟机天生支持多dex,所以也不会有一个合包的过程,所以ART虚拟机会很大的提升APP冷启动速度。

    简而言之,就是Dalvik是边运行边解释.dex文件,Art是启动时就预解释.dex文件为.oat文件,Dalvik启动时更快,Art运行时更快。

    参考链接

    Android Dalvik虚拟机和ART虚拟机对比

    一篇文章带你了解 Android的 JIT 、AOT、Dalvik、ART ,不再傻傻分不清

    JVM:.java文件->.class文件->.jar文件

    DVM:.java文件->.class文件->.dex文件->.apk文件

    ART:.java文件->.class文件->.dex文件->.oat文件->.apk文件

  3. where

    • .oat文件;
    • art目录。

HAL层

  1. why

    设想一下使用Java开发后端的情况,似乎在JVM后,就直接是操作系统,利用操作系统内提供的对机器的指令完成软件对硬件的操作,但是为啥安卓系统架构中Art之下还需要有一个硬件抽象层?下面引用一下罗老师对于HAL层的介绍:

    Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在Linux驱动层,那就意味着发布时要公开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了,在手机市场竞争激烈的今天,这对厂家来说,损害是非常大的。因此,Android才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android被踢出了Linux内核主线代码树中。大家想想,Android放在内核空间的驱动程序对硬件的支持是不完整的,把Linux内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说Android是开放系统而不是开源系统的原因。

    参考链接Android硬件抽象层(HAL)概要介绍和学习计划

    我的理解是,其实安卓系统架构中的HAL层和Kernal层组合起来,起到的是操作系统的作用,但是为了将关键源码不开源,所以将一些不能公布的源码放在HAL层,一些能开源的代码放在Kernal层。

  2. what

    硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化,为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。

    在HAL层,代码也是保存在jni.h和.c类型的文件中,与Framework层调用Native层不一样的是,HAL层的代码需要遵循固定的格式、命名进行编写。

    参考链接:Android中HAL如何向上层提供接口总结-hw_device_t

  3. where

    • hardware/libhardware/
    • hardware/libhardware_legacy/
    • hardware/xxxx/

Kernal层

  1. why

    如果说上面的所有层,都是决定逻辑上去驱动那个硬件,那么需要有一层只负责对硬件做操作,不是说上面的所有层没办法对硬件做操作,毕竟大家都是图灵完备的Java/C/C++代码,而是要把相同类似的事物放在一起,这样可以解耦,所以Kernal层,主要负责对硬件做操作,也叫驱动层。

    为什么安卓要采用linux作为操作系统呢?

    Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动(如显示,音频,照相机,蓝牙,WI-FI,电源管理等等),那么Android为什么会选择采用linux呢?原因与Linux的特性有关,内核作为一个抽象层存在硬件和软件之间,强大的内存管理和进程管理,基于权限的安全模式,支持共享库,经过认证的驱动模式,Linux本身就是开源项目等等。

  2. what

    Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。

    主要驱动:增强显示驱动、键盘驱动、Flash内存驱动、照相机驱动、音频驱动、蓝牙驱动、WiFi驱动、Binder IPC驱动、Power Management(电源管理),包括硬件时钟,内存分配和共享,低内存管理,kernel调试,日志设备,android IPC机制,电源管理等。

    如果要写一个驱动应该怎样写呢?Android 从上层到底层-----kernel层

  3. where

    主要在Driver目录下。

    1、Binder IPC驱动:基于OpenBinder框架的一个驱动,用于提供 Android平台的进程间通信功能。源代码位于drivers/staging/android/binder.c。

    2、电源管理(PM) :一个基于标准Linux电源管理系统的轻量级Android电源管理驱动,针对嵌入式设备做了很多优化,比如电池电量。源代码位于:kernel/power/earlysuspend.c、kernel/power/consoleearlysuspend.c、kernel/power/fbearlysuspend.c、kernel/power/wakelock.c、kernel/power/userwakelock.c

    3、低内存管理器:比Linux的标准的OOM机制更加灵活,它可以根据需要杀死进程以释放需要的内存。源代码位于 drivers/staging/ android/lowmemorykiller.c。

    4、匿名共享内存: 为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。源代码位于mm/ashmem.c。

    5、 PMEM :用于向用户空间提供连续的物理内存区域,DSP和某些设备只能工作在连续的物理内存上。源代码位于drivers/misc/pmem.c。

    6、 Logger :一个轻量级的日志设备,用于抓取Android系统的各种日志。源代码位于drivers/staging/android/logger.c。

    7、 Alarm :提供了一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会 运行的时钟基准。源代码位于drivers/rtc/alarm.c。

    8、USB Gadget:驱动 一个基于标准 Linux USB gadget驱动框架的设备驱动,Android的USB驱动是基于gaeget框 架的。源代码位于drivers/usb/gadget/。

    9、Ram Console: 为了提供调试功能,Android允许将调试日志信息写入一个被称为RAM Console的设备里,它是一个基于RAM的Buffer。源代码位于drivers/staging/android / ram_console.c。

    10、timed device: 提供了对设备进行定时控制的功能,目前支持vibrator和LED设备。源代码位于drivers/staging/android /timed_output.c(timed_gpio.c)。

    11、Yaffs2 :是文件系统 Android采用Yaffs2作为MTD nand flash文件系统,源代码位于fs/yaffs2/目录下。Yaffs2是一个快速稳定的应用于NAND和NOR Flash的跨平台的嵌入式设备文件系统,同其他Flash文件系统相比,Yaffs2能使用更小的内存来保存其运行状态,因此它占用内存小。Yaffs2的垃圾回收非常简单而且快速,因此能表现出更好的性能。Yaffs2在大容量的NAND Flash上的性能表现尤为突出,非常适合大容量的Flash存储。

1.2 Android8源码与系统架构的关系

从安卓8的源码目录入手,分析安卓系统架构的每一层,大概在源码中的什么位置。

源码目录结构

目录图如下:

基于问题学习安卓系统架构

源码目录描述

Android源码根目录 描述
art 全新的ART运行环境
bionic 系统C库
bootable 启动引导相关代码
build 存放系统编译规则及generic等基础开发包配置
cts Android兼容性测试套件标准
dalvik dalvik虚拟机
developers 开发者目录
development 应用程序开发相关
device 设备相关配置
docs 参考文档目录
external 开源模组相关文件
frameworks 应用程序框架,Android系统核心部分,由Java和C++编写
hardware 主要是硬件抽象层的代码
kernel Linux Kernal,需要单独去下载
libcore 核心库相关文件
libnativehelper 动态库,实现JNI库的基础
packages 应用程序包
pdk Plug Development Kit 的缩写,本地开发套件
platform_testing 平台测试
prebuilts x86和arm架构下预编译的一些资源
sdk sdk和模拟器
system 底层文件系统库、应用和组件
toolchain 工具链文件
tools 工具文件
Makefile 全局Makefile文件,用来定义编译规则

App层:packages

Framework层:frameworks

Native/ART层

​ NativeC/C++:bionic

​ Art:art

HAL层:hardware

Kernal层:kernel

1.3 为什么安卓系统架构要这么设计

思路:从整体架构分析,再从大到小,到每层分工来分析。

从0开始,什么都没有,我们收到需求:做一款能在手机上运行的应用,分析本质,就是软件和硬件的交互,完成一种满足用户需求的产品。那么现在开始开发了,写了很多代码,配合上硬件,能完成功能,那么这些代码里面,肯定必须得有软件能直接驱动硬件的代码,而这些代码肯定是最后被调用,又因为要和硬件打交道,C语言很合适,于是选择C语言编写,这时候把这些驱动硬件的代码拉出来放在一个文件夹里面,把这个文件夹叫做操作系统代码。由于在软件选语言的时候,觉得Java的可移植性好,所以选择用Java进行开发,接下来再看看写的代码,除去驱动硬件的代码后,发现有一些代码是用来写APP的页面、页面跳转之类的,那也把这些代码整合一下,放在一个文件夹里面,就叫业务代码吧。而Java开发,那必须得有虚拟机才能变成机器识别的代码,所以又将虚拟机的代码放在一个文件夹里,就叫虚拟机代码吧。

开发的某一天,我们忽然碰到一个很复杂的功能,Java实现起来太难了,这时候想到一个办法–使用C/C++来实现,然后用Java调用这些C/C++代码来实现功能,那也把这些C/C++代码也放在一个文件夹里,就叫调用的C/C++代码吧。

开发工作结束了,现在的项目结构是:业务代码、虚拟机代码、调用的C/C++代码、操作系统代码最后连接到硬件。

在休息两天后,又接到新的需求,要开发另外一款新的产品,这下根据上一款项目的代码,忽然发现,好像业务代码中,有一部分是可以重复使用的,比如一些位置、电话之类的通用模块,那新建一个文件夹,把这部分重复的代码也放在一个文件夹里面,就叫通用代码吧。这时候忽然收到通知,操作系统的代码要求要开源了,但是里面有一部分代码涉及商业机密不允许开源啊,于是把这部分无法开源的代码放在一个文件夹里,就叫不开源代码吧。

第二款APP开发结束了,现在的项目结构是:业务代码、通用代码、虚拟机代码、调用的C/C++代码、不开源代码、操作系统代码,对应了安卓系统架构的:APP层、Framework层、Art、Native、HAL层、Kernal层

本文地址:https://blog.csdn.net/qq_19903753/article/details/107951546