> 技术文档 > 【教程】Android(AOSP)Framework开发/ROM定制快速教程_androidframework开发教程

【教程】Android(AOSP)Framework开发/ROM定制快速教程_androidframework开发教程


【教程】Android(AOSP)Framework开发/ROM定制快速教程

  • 备注
  • 一、基础知识
  • 二、基本操作
    • 1.源码获取
    • 2.编译刷机
    • 3.构建系统
  • 三、系统结构
    • 1.系统架构
    • 2.目录结构
    • 3.源码结构
  • 四、二次开发
    • 1.添加产品
    • 2.添加程序
    • 3.添加其他
  • 五、启动流程
    • 1.BootROM阶段
    • 2.Bootloader阶段
    • 3.Kernel阶段
    • 4.init阶段
    • 5.Zygote阶段
    • 6.system_server阶段
    • 7.Launcher阶段
  • 六、Binder
    • 1.原理
    • 2.组成
    • 3.流程
    • 4.AIDL
  • 七、核心服务
    • 1.AMS
    • 2.PMS
    • 3.WMS
  • 八、其他特性
    • 1.应用权限
    • 2.文件权限
    • 3.SELinux权限
    • 4.签名
    • 5.属性
    • 6.HAL

备注

2025/03/13 星期四
记录一下完整的Android系统开发知识,方便自己查阅

一、基础知识

Android是Google基于Linux内核研发的移动操作系统,Google将Android源码进行了开源称为AOSP(Android Open Source Project)。Android经过多年发展,除了手机还广泛应用于手表、平板、电视、车机等智能设备中。对AOSP源码做二次开发的工作一般称为Framework开发或者ROM定制。

Android设备制造行业一个基本的分工是:
1.Google开发AOSP
2.芯片厂商根据芯片适配AOSP(如高通、展锐、联发科、全志)
3.主板厂商(有的芯片厂商也当主板厂商)设计电路板,增加其他配件,在芯片厂商源码基础上继续修改做适配
4.设备制造商对主板厂商的源码定制UI、增加功能、优化系统(如华为、小米、OPPO、VIVO)
芯片厂商和主板厂商一般被称为vendor,设备制造商一般被称为oem或odm

另外,与传统固件(BIOS/UEFI、BootROM、硬件控制程序)概念不同,Android领域的固件很多时候也指包含了系统镜像、Linux内核、SE/TEE、Bootloader、Recovery等软件的线刷包。而“系统”多指基于AOSP修改得到的操作系统。

二、基本操作

1.源码获取

Google建议在Ubuntu上进行开发,提供了Android Studio for Platform作为开发工具。获取AOSP源码的操作如下:

# 安装基本依赖sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig# 安装源码管理工具reposudo apt-get install repo# 初始化仓库repo init --partial-clone -b [分支] -u https://android.googlesource.com/platform/manifest# 拉取源码repo sync -c -j8

2.编译刷机

对源码进行编译的操作如下:

source build/envsetup.shlunch make -j$(nproc)

(注:Android中的内核文件是预编译好的,如果想要修改内核需要拉取对应的内核代码,修改编译后将编译结果放到指定路径,再重新编译打包Android镜像。)
编译完成后进行刷机的操作如下:

adb reboot bootloaderfastboot flashall -w

顺便一提,刷机的方式有fastboot、recovery、EDL和ota应用,这里我们选的是fastboot俗称线刷,也可以自行选用其他方式进行刷机(recovery俗称卡刷,EDL是紧急下载模式用于救砖,最知名是高通的9008,其他芯片厂商也有类似的工具,ota应用最常见的就是手机设置中的系统更新)

3.构建系统

​ Android提供了两种构建方式,在Android 7.0之前使用基于make的构建系统,使用Android.mk文件描make述构建规则,在Android 7.0后引入了soong构建系统,使用Android.bp文件描述soong的构建规则。soong中采用了kati GNU Make克隆工具和ninja后端来加速对系统源码的构建,用于解决make在Android中构建缓慢、容易出错、无法扩展、难以测试等问题。虽然make构建系统已经逐步被soong构建系统取代,但是仍然可以使用。
Android.mk:

// 设置当前构建所在目录,通常作为一个Android.mk文件中的第一行LOCAL_PATH := $(call my-dir)// 清空所有的LOCAL_变量,避免模块之间的变量相互干扰。include $(CLEAR_VARS)// 定义模块名称,必须是唯一不重复的,构建系统会根据类型自动添加前缀后缀LOCAL_MODULE := my-module// 模块类型(可选项),如APPS、 EXECUTABLES、SHARED_LIBRARIES、ETCLOCAL_MODULE_CLASS := EXECUTABLES// 模块所需全部源文件LOCAL_SRC_FILES := src/test.cpp// C/C++搜索头文件的路径LOCAL_C_INCLUDES := $(LOCAL_PATH)/include// 模块依赖的库文件(静态库.a和动态库.so)LOCAL_STATIC_LIBRARIES:= lib1LOCAL_SHARED_LIBRARIES:= lib2// 编译选项LOCAL_CFLAGS := -Wall -WextraLOCAL_CPPFLAGS := -std=c++11// 构建类型,如BUILD_EXECUTABLE、BUILD_SHARED_LIBRARY、BUILD_STATIC_LIBRARY、BUILD_PACKAGE、BUILD_JAVA_LIBRARY、BUILD_PREBUILTinclude $(BUILD_XXX)

Android.bp:

// 构建类型,如cc_binary、cc_library_static、cc_library_shared、android_app、java_library、java_library_static、prebuilt_apkcc_library_shared {// 模块名,如果是库文件通常约定加上\'lib\'前缀 name: \"libdemo\", // 源文件列表 srcs: [ \"src/test.c\", ], // C/C++搜索头文件的路径 include_dirs: [\"include\"], // 编译选项 cflags: [\"-Wall\", \"-Wextra\"], cppflags: [\"-std=c++11\"], // 模块依赖的库文件(静态库.a和动态库.so) shared_libs: [ \"liblog\", \"libcutils\", ], // 控制哪些模块可以依赖此模块,如:[\"//visibility:public\"][\"//visibility:private\"][\"//path/to:other_module\"] visibility: [\"//visibility:public\"],}

另外Android提供了androidmk工具用于将Android.mk文件转换为Android.bp文件

三、系统结构

1.系统架构

【教程】Android(AOSP)Framework开发/ROM定制快速教程_androidframework开发教程
Android分为5层结构,从上到下依次是应用层、系统框架层、原生库和运行时层、HAL层、内核层
应用层:用户直接与之交互的部分,包括各种应用程序和系统界面
框架层:提供Java/Kotlin类接口
原生库:C/C++ 库,一般是用于实现核心系统功能高性能的原生库
运行时:ART和Dalvik的虚拟机,用于执行dex文件
HAL:标准硬件接口,使Android以统一的方式调用硬件的功能
Linux内核:Android定制后的Linux内核,提供最基本的CPU调度、内存管理、文件系统等功能

2.目录结构

目录 作用 /acct Linux内核管理进程的CPU、内存、IO等资源的信息 /cache 系统临时更新和缓存 /cache/backup 备份目录 /cache/recovery recovery目录 /config /data 用户数据目录 /data/anr 系统异常记录 /data/adb adb数据目录 /data/app 存放用户安装的第三方应用app文件 /data/dalvik-cache 存放优化后的字节码,用于应用快速启动 /data/data 所有应用包括系统应用和第三方应用的私有数据 /data/media 内部存储/sdcard或/storage/emulated/0的实际挂载点 /data/misc wifi、蓝牙、vpn、adb密钥等数据 /data/property persist属性 /data/system 存放系统核心配置,如应用列表、账户信息、设备策略、锁屏设置等 /data/user 多用户的环境下指向/data/data的符号链接,用于实现多用户数据隔离 /dev /mnt 挂载外接设备 /oem 设备制造商目录 /proc 进程实时信息 /root root用户家目录 /sbin root用户的二进制bin /sdcard 符号链接,指向data/media或/storage/emulated/0 /storage 挂载所有存储设备的根目录 /sys Linux内核的文件系统,提供虚拟文件系统、内核对象、设备驱动、硬件属性等 /system Android系统的核心文件 /system/app 存放Android的系统应用app /system/bin 存放系统的命令行工具二进制elf /system/etc 系统主机名、ip地址映射等配置文件 /system/lib 存放系统的动态库so /system/framework 系统框架的核心jar /system/media 存放系统铃声、提示音、开机动画等多媒体文件 /system/fonts 存放系统的字体 /system/priv-app 系统特权应用app /system/usr 存放用户键盘布局、共享、时区等配置文件 /system/xbin 存放额外的命令行工具二进制elf

3.源码结构

目录 作用 art 该目录是在Android 5.0中新增加的,主要是实现Android RunTime(ART)的目录,它作为Android 4.4中的Dalvik虚拟机的替代,主要处理Java字节码执行 bionic Android的C库,包含了很多标准的C库函数和头文件,还有一些Android特有的函数和头文件 build 该目录包含了编译Android源代码所需要的脚本,包括makefile文件和一些构建工具 compatibility Android设备的兼容性测试套件(CTS)和兼容性实现(Compatibility Implementation) cts Android设备兼容性测试套件(CTS),主要用来测试设备是否符合Android标准 dalvik Dalvik虚拟机,它是Android 2.3版本之前的主要虚拟机,它主要处理Java字节码执行 developers Android开发者文档和样例代码 development 调试工具,如systrace、monkey、ddms等 device 特定的Android设备的驱动程序 external 第三方库,如WebKit、OpenGL等 frameworks Android应用程序调用底层服务的API hardware Android设备硬件驱动代码,如摄像头驱动、蓝牙驱动等 kernel Android系统内核的源代码,它是Android系统的核心部分 libcore Android底层库,它提供了一些基本的API,如文件系统操作、网络操作等 packages Android系统中的系统应用程序的源码,例如短信、电话、浏览器、相机等 pdk Android平台开发套件,它包含了一些工具和API,以便开发者快速开发Android应用程序 platform_testing 测试工具,用于测试Android平台的稳定性和性能 prebuilts 预先编译的文件,如编译工具、驱动程序等 sdk Android SDK的源代码,Android SDK的API文档、代码示例、工具等 system Android系统的核心部分,如系统服务、应用程序、内存管理机制、文件系统、网络协议等 test 测试代码,用于测试Android系统的各个组件 toolchain 编译器和工具链,如GCC、Clang等,用于编译Android源代码 tools 开发工具,如Android SDK工具、Android Studio、Eclipse等 vendor 硬件厂商提供的驱动程序,如摄像头驱动、蓝牙驱动等

四、二次开发

首先了解一下不同分区的作用,这里优先区分一下system、vendor、odm和product分区,

分区 作用 system AOSP系统组件,所有product都通用的软件 vendor 芯片和主板厂商针对硬件开发的通用的可执行文件、库、系统服务和 app (不包含驱动) odm 产品硬件差异导致的相关软件差异部分都会放在odm分区 product 软件差异都放在product分区

因此可以从软硬件、通用和差异方面简单理解为:

软件 硬件 通用 system vendor 差异 product odm

编译后的文件位置和编译命令如下:

分区 Android.mk Android.bp system 默认就是输出到 system 分区 默认就是输出到 system 分区 vendor LOCAL_VENDOR_MODULE := true vendor: true odm LOCAL_ODM_MODULE := true device_specific: true product LOCAL_PRODUCT_MODULE := true product_specific: true

1.添加产品

不同产品的源码会存在差异,通过配置文件来实现区分,这些配置文件称为 Product,每一个 Product 适用于特定的硬件产品,在编译时通过lunch进行选择。
Google提供的product 配置文件会保存在build/target目录下,芯片厂商或主板厂商提供的product配置文件在device目录下。
当我们想要添加自己的product 配置文件时一般也会选择在device目录下新增/,再添加AndroidProducts.mk、.mk、BoardConfig.mk,可以参考AOSP原生文件进行编写。
AndroidProducts.mk是由构建系统自动扫描的入口文件,基本内容如下:

PRODUCT_MAKEFILES := \\ $(LOCAL_DIR)/<Product名>.mk \\ COMMON_LUNCH_CHOICES := \\ <Product名>-user \\ <Product名>-userdebug \\ <Product名>-eng

.mk是产品的核心配置文件,用于定义产品的基础信息、引用其他配置文件、设置系统分区、预装程序、系统属性等,基本内容如下:

# 基本信息PRODUCT_NAME := <Product名>PRODUCT_DEVICE := <Product名>PRODUCT_BRAND := <公司名>PRODUCT_MODEL := <机型名># 引用其他配置$(call inherit-product, <path/file.mk>)# 构建类型PRODUCT_BUILD_VARIANT := user#是否使用自定义内核TARGET_NO_KERNEL_OVERRIDE := true# 分区配置PRODUCT_SYSTEM_PROPERTIES += \\ ro.system.size=4GBOARD_SYSTEMIMAGE_PARTITION_SIZE := 4294967296# 添加程序PRODUCT_PACKAGES += \\ <XXX> \\ <YYY> \\ <ZZZ># 添加属性PRODUCT_PROPERTY_OVERRIDES := \\ persist.sys.flag=1 \\ ro.control.flag=0# 添加文件PRODUCT_COPY_FILES += \\ $(LOCAL_PATH)/<source_path/source_file>:$(TARGET_COPY_OUT_SYSTEM)/<target_path/target_file>

BoardConfig.mk是定义硬件底层配置、芯片架构、分区大小、bootloader 和 kernel, 是否支持摄像头,GPS导航等一些板级特性的文件。

2.添加程序

Android中有很多bin目录,其中都是一些二进制可执行文件或shell脚本,这些程序源码主要来自于external、system/core、frameworks/native/cmds和frameworks/base/cmds,这里我们参考已有工具新建工具名目录、编写Android.bp文件、新建src/工具名目录并编写源码,在.mk文件中添加

PRODUCT_PACKAGES += 程序名

如果直接编译文件会被放到system分区,还需要在.mk文件中指定目标位置才不会报错

PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \\ system/bin/程序名\\ system/app/程序名/程序名.apk \\ system/lib/lib库名.so \\

但是我们编写的工具大概率是产品相关的官方建议放到product分区下,Android.bp中添加product_specific: true即可

3.添加其他

类似的,还可以去添加库文件、配置文件、app等,方法大多差不多,只有一些细节差别,这里不过多赘述可以自行搜索

五、启动流程

Android系统启动可以分为七个阶段:BootROM阶段、Bootloader阶段、Kernel阶段、init阶段、zygote阶段、System Server阶段和Launcher阶段。

1.BootROM阶段

BootROM阶段在设备通电后,由SoC芯片内置只读程序初始化最基础的硬件(如CPU核心、时钟),查找并验签位于特定位置的Bootloader程序,如果验签通过则会加载Bootloader程序

2.Bootloader阶段

Bootloader一般分为两级,由BootROM加载的称为一级导加载程序(PBL),一级引导加载程序负责初始化更多基础硬件(如DRAM、eMMC/UFS、显示器),查找并验签位于特定分区的二级引导加载程序(SBL),如果验签通过则会加载二级引导加载程序。
二级引导加载程序继续初始化更多硬件,验签启动的镜像boot.img,如果验签通过则会加载boot.img到内存中。

3.Kernel阶段

Bootloader将boot.img 中的内核加载到内存中,CPU将控制权从Bootloader转交给内核,内核会初始化各类硬件设备、加载驱动程序、管理内存中断信号等。内核还会加载boot.img中一个最小临时文件系统initramfs,然后启动init进程

4.init阶段

init进程是Android系统中的第一个用户空间进程,PID为1。init进程又会读取init.rc文件,根据该文件中的配置信息加载正式的文件系统、启动并配置SELinux、启动Android系统的各个组件。init进程启动流程可以分为三个主要阶段:第一阶段初始化(first_stage_init)、SELinux设置(selinux_setup)二阶段初始化(second_stage_init)。第一阶段初始化主要是挂载分区,SELinux设置阶段会初始化SELinux相关的内容,第二阶段初始化完成进程和服务的启动。
init进程刚开始运行的时候是内核态,然后运行一个用户态程序把自己强行转成用户态,后面的操作全在用户态下进行,当init进程从内核态跳到用户态后,用户态下的程序无法再回到内核态,想要进入内核态只能通过系统调用。【教程】Android(AOSP)Framework开发/ROM定制快速教程_androidframework开发教程
init.rc文件是一个专门用于Android inti的配置文件,有三类语句:On、Service、Import。On是在Action的情况下执行Command,Service是定义服务的名称、路径、启动参数和配置项,Import是引入其他rc文件:

import /init.environ.rcon    ... service   [  ]   ... 

5.Zygote阶段

Zygote是由init启动的进程,Zygote负责预加载核心资源(framework.jar, framework-res.apk 等)、 ​​初始化 Android Runtime(ART),启动 system_server(com.android.server.SystemServer)。

6.system_server阶段

system_server是Zygote fork出来的第一个进程,负责启动和管理几乎所有关键native和java服务(如AMS、PMS、WMS、LocationManagerService、TelephonyManagerService、Wi-FiService、BluetoothService等),system_server启动完成后会通过广播所有已启动的服务。

7.Launcher阶段

AMS收到system_server发送的启动完成广播后会启动 Launcher​,Android系统就完全启动了,用户可以进入桌面使用各种应用程序。

六、Binder

1.原理

Binder是Android为了代替Linux IPC设计的,是具有远程过程调用RPC(Remote Procedure Call)能力的进程间通信IPC(Inter-Process Communication)机制。为了保证不同进程之间互不干扰,Linux为每个进程都分配有独立的虚拟内存空间,不同进程之间的用户空间相互独立实现进程隔离,系统上的所有进程共用一个内核空间,如果进程间想要相互访问数据就需要借助内核空间来实现。将数据从一个进程的用户空间复制到内核空间,再从内核空间将数据复制到另一个进程的用户空间,就可以达到跨进程访问数据的目的。但是需要做两次复制操作,如果将一个进程用户空间虚拟地址直接映射到内核空间的物理地址,再让另一个进程从内核空间复制数据,就可以优化为一次复制操作,这就是Binder的一次复制原理。
同时Binder提供了RPC能力。RPC就是像调用本地函数一样调用远程函数(远程包括逻辑和隔离和物理隔离,即本机其他进程或者网络上其他机器的进程),因此需要将数据按照一定的规则打包并发送给目标进程,目标进程解析数据执行函数后再将结果按一定格式发回给调用者。
Android中常见的IPC机制如Intent、Messenger、ContentProvider、AIDL底层都是由Binder实现的。

2.组成

Android的Binder主要包括了Client、Server、ServiceManager和Binder驱动四个部分。
Client是发起调用的进程
Server是提供Service的进程,Service是被调用的函数集合
ServiceManager是用于管理Service的进程,Server需要将Service注册到ServiceManager才能被Client调用
Binder驱动是内核层的特殊​​字符设备驱动​​,用于实现IPC需要具有访问内核空间的能力,但是Android并不属于Linux内核,不能直接访问内核空间,因此使用Linux的动态可加载内核模块(Loadable Kernel Module,LKM)的机制,将Binder驱动单独编译后再链接到内核中。

3.流程

Binder的核心流程包括:系统启动ServiceManager、Server注册Service、Client调用Service

4.AIDL

由上文可见使用binder需要涉及到内核驱动、naive层、java层非常复杂,Android提供了AIDL用于简化binder使用

七、核心服务

1.AMS

2.PMS

3.WMS

八、其他特性

1.应用权限

2.文件权限

3.SELinux权限

4.签名

5.属性

6.HAL