Android_架构

分层

Android大致可以分为四层架构:Linux内核层、系统运行库层、应用框架层和应用层。

  1. 应用层。系统内置的应用程序以及非系统级的应用程序都属于应用层,负责与用户进行直接交互,通常都是用Java开发。

  2. 应用框架层。这一层是由Java代码编写的,可以称为Java API Framework。这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可以通过这些API来构建自己的应用程序。开发者API可以直接映射到底层HAL接口,并可提供与实现驱动程序相关的实用信息。这一层所提供的主要组件有:

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

    image-20220812120406746

  3. Binder IPC。Binder 进程间通信 (IPC) 机制允许应用框架跨越进程边界并调用Android系统服务代码,这使得高级框架API能与Android系统服务进行交互。在应用框架级别,开发者无法看到此类通信的过程,但一切似乎都在“按部就班地运行”。

  4. 系统服务层。系统服务是专注于特定功能的模块化组件,例如窗口管理器、搜索服务或通知管理器。应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。Android 包含两组服务:“系统”(诸如窗口管理器和通知管理器之类的服务)和“媒体”(涉及播放和录制媒体的服务)。

    1. 这一层通过一些C/C++库来为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。
    2. 这一层还有Android运行时库,它主要提供了一些核心库,能够允许开发者使用Java语言来编写Android应用。另外,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为ART运行环境),它使得每一个Android应用都能运行在独立的进程当中,并且拥有一个自己的Dalvik虚拟机实例。相较于Java虚拟机,Dalvik是专门为移动设备定制的,它针对手机内存、CPU性能有限等情况做了优化处理。
  5. 硬件抽象层。HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。HAL 实现会被封装成模块,并会由 Android 系统适时地加载。如需了解详情,请参阅硬件抽象层 (HAL)

  6. Linux内核。Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。开发设备驱动程序与开发典型的 Linux 设备驱动程序类似。Android 使用的 Linux 内核版本包含一些特殊的补充功能,例如低内存终止守护进程(一个内存管理系统,可更主动地保留内存)、唤醒锁定(一种 PowerManager 系统服务)、Binder IPC 驱动程序,以及对移动嵌入式平台来说非常重要的其他功能。这些补充功能主要用于增强系统功能,不会影响驱动程序开发。您可以使用任意版本的内核,只要它支持所需功能(如 Binder 驱动程序)即可。不过,我们建议您使用 Android 内核的最新版本。如需了解详情,请参阅构建内核一文。

HIDL(HAL接口定义语言) - AIDL

HAL Interface Definition Language。

Android 8.0 重新设计了 Android 操作系统框架(在一个名为“Treble”的项目中),以便让制造商能够以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。在这种新架构中,HAL 接口定义语言(HIDL,发音为“hide-l”)指定了 HAL 和其用户之间的接口,让用户无需重新构建 HAL,就能替换 Android 框架。在 Android 10 中,HIDL 功能已整合到 AIDL(Android Interface Definition Language, 即Android接口定义语言)中。此后,HIDL 就被废弃了,并且仅供尚未转换为 AIDL 的子系统使用。

Android进阶解密中的分层

Android系统架构分为5层,从上到下依次是应用层、应用框架层、系统运行库层、硬件抽象层和Linux内核层。

image-20220812144626701

  1. 应用层(System Apps)

    1. 系统内置的应用程序以及非系统级的应用程序都属于应用层,负责与用户进行直接交互,通常都是用Java进行开发的。
  2. 应用框架层(Java API Framework)

    1. 应用框架层为开发人员提供了开发应用程序所需要的API,我们平常开发应用程序都是调用这一层所提供的API,当然也包括系统应用。这一层是由Java代码编写的,可以称为Java Framework。下面来看这一层所提供的主要组件。

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

    1. C/C++程序库能被Android系统中的不同组件所使用,并通过应用程序框架为开发者提供服务,表列出了主要的C/C++程序库。

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

      1. 核心库提供了Java语言核心库的大多数功能,这样开发者可以使用Java语言来编写Android应用。
      2. 与JVM相比,Dalvik虚拟机(DVM)是专门为移动设备定制的,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为一个独立的Linux进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。DVM中的应用每次运行时,字节码都需要通过即时编译器(Just In Time,JIT)转换为机器码,这会使得应用的运行效率降低。而ART的机制与DVM不同,在ART中,系统在安装应用时会进行一次预编译(Ahead Of Time,AOT),将字节码预先编译成机器码并存储在本地,这样应用每次运行时就不需要执行编译了,运行效率也大大提高。
  4. 硬件抽象层(HAL)

    1. 硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化,为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。从软硬件测试的角度来看,软硬件的测试工作都可分别基于硬件抽象层来完成,使得软硬件测试工作的并行进行成为可能。通俗来讲,就是将控制硬件的动作放在硬件抽象层中。
  5. Linux内核层(Linux Kernel)

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

Android_项目目录结构

项目目录结构

  1. .gradle.idea:这两个目录都是Android Studio自动生成的文件。无须关心,不要手动编辑。
  2. app:项目中的代码、资源等内容几乎都是放置在这个目录下,开发工作也基本都是在这个目录下进行。
  3. build:这个目录主要包含了一些在编译时自动生成的文件。
  4. gradle:这个目录下包含了gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle。Android Studio默认没有启用gradle wrapper的方式,如果需要打开,可以点击File, Settings, Build, Execution, Deployment, Gradle,进行配置更改。
  5. .gitignore:这个文件用来将指定的目录或文件排除在版本控制之外。
  6. build.gradle:项目全局的gradle构建脚本,文件内容通常不需要修改。
  7. gradle.properties:项目全局的gradle配置文件,在这里配置的属性将会影响到项目中所有的gradle编译脚本。
  8. gradlew和gradlew.bat:这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Mac系统使用,gradlew.bat是在Windows系统中使用。
  9. 项目名.iml:iml文件是所有IntelliJ IDEA项目都会自动生成的一个文件(Android Studio是基于IntelliJ IDEA开发的),用于标识这是一个IntelliJ IDEA项目,我们不需要修改这个文件中的任何内容。
  10. local.properties:这个文件用于指定本机中的Android SDK路径,通常内容都是自动生成的,并不需要修改。除非本机中的Android SDK位置发生了变化,那么就将这个文件中的路径改成新的位置即可。
  11. settings.gradle:用于指定项目中所有引入的模块。由于此时项目中只有一个app模块,因此文件中只引入了app这一个模块。通常情况下,模块的引入是自动完成的,很少去手动修改此文件。

发现,基本上除了app目录之外,大多数目录、文件都是自动生成的。下面对app内容进行更为详细的分析。

  1. build:这个目录和外层的build目录类似,主要也是包含了一些在编译时自动生成的文件,不过它里面的内容更多更杂,不需要过多关心。

  2. libs:如果你的项目中使用到了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去。

  3. androidTest:此处是用来编写Android Test测试用例的,可以对项目进行一些自动化测试。

  4. java:java目录是放置所有Java代码的地方,展开该目录,将看到刚才创建的HelloWorldActivity文件就在里面。

  5. res:这个目录下的内容有点多。简单点说,就是在项目中使用到的所有图片、布局、字符串等资源都要存放在这个目录下。当然这个目录下还有很多子目录,图片放在drawable目录下,布局放在layout目录下,字符串放在values目录下,所以不用担心会把整个res目录弄得乱糟糟的。

  6. AndroidManifest.xml:这是整个Android项目的配置文件,在程序中定义的所有四大组件都需要在这个文件里注册,另外还可以在这个文件中给应用程序添加权限声明。

  7. test:此处是用来编写Unit Test测试用例的,是对项目进行自动化测试的另一种方式。

  8. .gitignore:这个文件用于将app模块内的指定的目录或文件排除在版本控制之外,作用和外层的.gitignore文件类似。

  9. app.iml:IntelliJ IDEA项目自动生成的文件,不需要关心或修改这个文件中的内容。

  10. build.gradle:这是app模块的gradle构建脚本,这个文件中会指定很多项目构建相关的配置。

  11. proguard-rules.pro:这个文件用于指定项目代码的混淆规则,当代码开发完成后打成安装包文件,如果不希望代码被别人破解,通常会将代码进行混淆,从而让破解者难以阅读。

AndroidManifest.xml

1
2
3
4
5
6
<activity anroid:name=".HelloWorldActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
<category android:name="android.intent.category.LAUNCHER"></category>
</intent-filter>
</activity>

这段代码表示对HelloWorldActivity这个活动进行注册, 没有在AndroidManifest.xml里注册的活动是不能使用的。其中intent-filter里的两行代码非常重要,<action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/>表示HelloWorldActivity是这个项目的主活动,在手机上点击应用图标, 首先启动的就是这个活动。

Activity是Android应用程序的门面,凡是在应用中看得到的东西,都是放在活动中的。因此看到的界面,其实就是HelloWorldActivity这个活动。打开HelloWorldActivity,代码如下所示:

1
2
3
4
5
6
7
public class HelloWorldActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_world_layout);
}
}

可以看到,HelloWorldActivity是继承自AppCompatActivity的,这是一种向下兼容的Activity,可以将Activity在各个系统版本中增加的特性和功能最低兼容到Android2.1系统。

Activity是Android系统提供的一个活动基类,我们项目中所有的活动都必须继承它或者它的子类才能拥有活动的特性(AppCompatActivity是Activity的子类)。然后可以看到HelloWorldActivity中有一个onCreate()方法,这个方法是一个活动被创建时必定要执行的方法,其中只有两行代码,并且没有Hello World!的字样。那么显示的Hello World!是在哪里定义的呢?

其实Android程序的设计讲究逻辑和视图分离,因此是不推荐在活动中直接编写界面的,更加通用的一种做法是,在布局文件中编写界面,然后在活动中引入进来。可以看到,在onCreate方法的第二行调用了setContentView方法,就是这个方法给当前的活动引入了一个hello_world_layout布局,Hello World!就是在这里定义的。

布局文件都是定义在res/layout目录下的,展开layout目录,会看到hello_world_layout.xml这个文件。打开该文件并切换到Text视图,代码就出来了:

项目中的资源

  1. 所有以drawable开头的文件夹都是用来放图片的;
  2. 所有以mipmap开头的文件夹都是用来放应用图标的;
  3. 所有以values开头的文件夹都是用来放字符串、样式、颜色等配置的;
  4. layout文件夹是用来放布局文件的。

mipmap开头的文件夹有很多,主要是为了兼容各种设备。drawable文件夹也是相同的道理,虽然Android Studio没有自动生成,但应该自己创建drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等文件夹。在制作程序的时候最好能够给同一张图片提供几个不同分辨率的版本,分别放在对应的文件夹下。当程序运行的时候,会自动根据当前运行设备分辨率的高低选择加载。如果只有一份图片,那就都放在drawable-xxhdpi文件夹下。

values

打开res/values/strings.xml文件,内容如下所示:

1
2
3
<resources>
<string name="app_name">HelloWorld</string>
</resources>

这里定义了一个应用程序名的字符串,有以下两种方式来引用它。

  • 在代码中通过R.string.app_name可以获得该字符串的引用
  • 在XML中通过@string/app_name可以获得该字符串的引用

其中string部分可以替换,如果引用的是图片资源可以替换成drawable,如果引用的是应用图标可以替换成mipmap,如果引用的是布局文件可以替换成layout

打开AndroidManifest.xml文件,找到如下代码:

1
2
3
4
5
6
7
8
<application>
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportRtl="true"
android:theme="@style/AppTheme"
...
</application>

其中,HelloWorld项目的应用图标是通过android:icon来指定的,应用的名称则是通过android:label属性指定的。

build.gradle文件

Android Studio采用Gradle来构建项目。Gradle使用一种基于Groovy的领域特定预言(DSL)来声明项目设置,摒弃了传统基于XML(如Ant和Maven)的烦琐配置。

HelloWorld项目中有两个build.gradle文件,一个是在最外层目录下,一个是在app目录下。

Android系统源码目录

整体结构

各个版本的源码目录基本是类似的,如果是编译后的源码目录,会多一个out文件夹,用来存储编译产生的文件。

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

packages目录结构

应用层位于整个Android系统的最上层,开发者开发的应用程序以及系统内置的应用程序都在应用层。源码根目录中的packages目录对应着系统应用层,它的目录结构如表所示。

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

应用框架层部分

应用框架层是系统的核心部分,一方面向上提供接口给应用层调用,另一方面向下与C/C++程序库及硬件抽象层等进行衔接。应用框架层的主要实现代码在frameworks/baseframeworks/av目录下,其中frameworks/base目录结构如表所示。

frameworks/base目录 描述
api 定义API
cmds 重要命令:am、app_proce
core 核心库
data 字体和声音等数据文件
graphics 与图形图像相关
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无线网络

C/C++程序库部分

系统运行库层(Native)中的C/C++程序库的类型繁多,功能强大,C/C++程序库并不完全在一个目录中,这里给出几个常用且比较重要的C/C++程序库所在的目录位置,如表所示。

目录位置 描述
bionic Google开发的系统C库,以BSD许可形式开源
frameworks/av/media 系统媒体库
frameworks/native/opengl 第三方图形渲染库
frameworks/native/services/surfaceflinger 图形显示库,主要负责图形的渲染、叠加和绘制等功能
external/sqlite 轻量级关系型数据库SQLite的C++实现

Android运行时库的代码在art/目录中;硬件抽象层的代码在hardware/目录中,这是手机厂商改动最大的部分,根据手机终端所采用的硬件平台不同会有不同的实现。

源码阅读

系统源码的阅读有很多种方式,总的来说分为两种:一种是在线阅读,另一种是下载源码到本地用软件工具阅读。

  1. 在线阅读
    1. Android 在线阅读源码的网站有很多,比如www.grepcode.comwww.androidxref.com,www.androidos.net.cn等,这里推荐使用www.androidxref.com进行在线阅读。
  2. 使用本地工具,本地阅读源码可以采用Android Studio、Eclipse、Sublime和Source Insight等软件。