目录
一、Android源码编译
编译原理
编译组成
原生Android编译
二、Makefile文件
三、Android.mk文件
四、Android.bp文件
五、Android公码和私码
HLOS(公码)
non-HLOS(私码)
补充:http://t.csdn.cn/ktjxzhttp://t.csdn.cn/ktjxz
编译: 将高级语言翻译成汇编语言或机器语言的过程,编译的本质就是一种翻译的过程。
高级语言(.c/.java)——编译——> 汇编语言(asm)——汇编——> 机器语言(二进制)——执行——> 硬件平台
机器语言是机器能直接识别的程序语言或指令代码,无需经过翻译,指不经翻译即可为机器直接理解和接受的程序语言或指令代码。机器语言是由0和1组成的二进制数。
编译流程实例:
hello.c —预处理器—> hello.i —编译器cc1—> hello.s —汇编器—> hello.o —链接器—> hello ——> 可执行文件
1、预处理阶段
主要是处理源文件中以“#”开头的预编译指令。
预处理阶段会把头文件中的变量、函数都包含进来,所以hello.i文件非常大。
2、编译阶段
将预处理得到的预处理文件进行语法分析,词法分析,语义分析,优化后,生成汇编代码文件(汇编语言源程序)。
3、汇编阶段
利用汇编程序(汇编器)将汇编语言源程序转换成机器指令序列(机器语言程序)。
4、链接阶段
将多个可重定位的目标文件.o合并以生成可执行文件,其可以被加载到内存中,由系统执行。
在Linux系统中,我们可以通过make命令来编译代码。执行make命令默认会在当前目录找到一个Makefile文件和Kconfig文件,然后根据Makefile文件中的指令来对代码进行编译。也就是说make命令执行的是Makefile文件中的指令,Makefile文件中的指令可以是编译命令(例如gcc),也可以是其它命令。
在Android系统中,随着源代码越来越复杂,光一个Makefile在性能上已经满足不了,因此在该机制之上新增了自己的Android.mk和Android.bp方式,为了优雅的与Makefile兼容,soong就此诞生了。
1、google给出了Android的原生编译流程,在Android根目录下执行:
(1)source build/envsetup.sh
作用:将envsetup.sh里的所有用到的命令加载到环境变量里去,设置android的编译环境。注意,该命令只在当前终端生效,如果未生效那么lunch和mm等命令是无法使用的。
(2)lunch
lunch后面的选项以“产品名-编译类型”的形式命名。编译类型有以下几种:
作用:显示菜单让我们选择编译平台(分支)以及平台相关的编译选项,也可以在lunch后面直接跟上参数。
(3)make -j4 showcommands dist
作用:make命令其实直接执行了当前目录下的Makefile脚本,编译整个android系统。
make编译命令:
命令 | 说明 |
make clean | 执行清理,删除此配置的所有输出和中间文件,等同于:rm -rf out/ |
make all | 编译所有内容,不管当前产品的定义中是否会包含 |
make sdk | 编译出 Android 的 SDK(软件开发工具包) |
make clean-sdk | 清理 SDK 的编译产物 |
make update-api | 更新 API。在 framework API 改动之后,需要首先执行该命令来更新 API,公开的 API 记录在 frameworks/base/api 目录下 |
make snod | 从已经编译出的包快速重建系统镜像 |
make libandroid_runtime | 编译所有 JNI framework 内容 |
make framework | 编译所有 Java framework 内容 |
make services | 编译系统服务和相关内容 |
make |
编译一个指定的模块,local_target 为模块的名称 |
make clean- |
清理一个指定模块的编译结果 |
make dump-products | 显示所有产品的编译配置信息,例如:产品名,产品支持的地区语言,产品中会包含的模块等信息 |
make help | 帮助信息,显示主要的 make 目标 |
Android系统的模块编译:
常用模块 | 命令 |
LK | make aboot –j8 |
Kernel/Dtbo | make bootimage -j8 / make kernel –j8 |
System | make systemimage -j8 |
Vendor | make vendorimage -j8 |
Userdata | make userdataimage –j8 |
Recovery | make recoveryimage –j8 |
Cache | make cacheimage |
其他编译命令:
命令 | 作用 |
m | 相当于是在执行make命令,对整个Android源码进行编译。命令很有用,因为用户可以在子目录中运行make命令。 |
mm | 构建当前目录中的所有模块,但不包含依赖。 如果是在Android源码根目录下执行,那么就相当于是执行make命令对整个源码进行编译;如果是在Android源码根目录下的某一个子目录执行,那么就会从该子目录开始,一直往上一个目录直至到根目录,寻找是否存在一个Android.mk文件,如果存在的话,就通过make命令对该Android.mk文件描述的模块进行编译。 |
mma | 编译当前路径下所有模块,且包含依赖 |
mmm [module_path] | 构建所提供目录中的所有模块,但不包含依赖。 后面可以跟一个或者若干个目录。如果指定了多个目录,那么目录之间以空格分隔,并且每一个目录下都必须存在一个Android,mk文件。 如果没有在目录后面通过冒号指定模块名称,那么在Android.mk文件中描述的所有模块都会被编译,否则只有指定的模块会被编译。如果需要同时指定多个模块,那么这些模块名称必须以逗号分隔。 |
mmma [module_path] | 构建所提供目录中的所有模块,且包含依赖。 |
printconfig | 打印lunch命令设置的当前配置 |
croot | CD到树的顶部 |
2、编译结果
所有的编译产物都将位于 out 目录下,该目录下主要有以下几个子目录:
路径 | 说明 |
out/host/ | 该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等。 |
out/target/common/ | 该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库。 |
out/target/product/ |
包含了针对特定设备的编译结果以及平台相关的 C/C++ 库和二进制文件。其中, |
out/dist/ | 包含了为多种分发而准备的包,通过“make disttarget”将文件拷贝到该目录,默认的编译目标不会产生该目录。 |
编译产物中最重要的是三个镜像文件(image文件),他们位于out/target/product/
其中,linux内核编译结果保存在obj/KERNEL_OBJ目录中(Linux内核也一同被编译了,而无需另外独立编译!)。
(1)这三个镜像文件是:
system目录:
1)app目录:包含所有的apk包,即包含了Android源码自身所发布的应用程序,又包含了用户自己编译的应用程序apk包。
2)bin目录:包含基本的命令,系统的本地程序,主要是Linux系统自带的组件。
3)etc目录:包含了一些配置文件和脚本文件,比如APN接入点设置等核心配置。
4)framework目录:包含了系统运行所需要众多的jar包。
5)lib目录:存放了所有的库,文件系统底层库,如平台运行时库。
6)xbin目录:也包含了多种命令。
7)usr目录,有用户文件夹,包含共享、键盘布局、时间区域文件等。
root目录:
1)init:Android最重要的进程——init,这是Android启动运行的的第一个进程。还有两个非常重要的脚本文件init.fs100.rc和init.rc,这是Android在刚开始启动时需要首先加载的两个启动脚本,根据脚本里的内容,来完成一系列的启动工作。
2)data目录:是 userdata.img镜像要挂载的目录。
3)system目录:即为 system.img镜像需要挂载的目录。
4)dev目录:是系统启动后,系统的设备文件目录。
(2)其他image文件介绍:
(3)ramdisk.img、boot.img、recovery.img之间的关系
ramdisk.img会被打包到boot.img和recovery.img中 (不是同一个ramdisk.img),在不同分区中的作用不同。
ramdisk.img中比较重要的文件是"init","init.rc",其中init是system/core/init/init.c编译而来。boot.img中ramdisk里的init.rc位于system/core/init/init.rc,而recovery.img中ramdisk里的init.rc位于bootable/recovery/etc/init.rc。
kernel加载结束以后第一个进程是执行init,init会解析init.rc文件,并起相应的服务。由此可以知道正常开机和进入recovery模式起的进程是不同的。
(4)BootLoader的启动通常分为两个阶段
第一阶段在固态存储中(Flash)执行,负责初始化硬件,例如设置CPU工作模式、时钟频率以及初始化内存等,并且将第二阶段拷贝到RAM去准备执行。
第二阶段就是在RAM中执行,因此速度会更快,主要负责建立内存映像,以及加载 Kernel镜像和Ramdisk镜像。
BootLoader的第二阶段执行完成后,就开始启动Kernel了。Kernel负责启动各个子系统,例如CPU调度子系统和内存管理子系统等等。Kernel启动完成之后,就会将 Ramdisk镜像安装为根系统,并且在其中找到一个init文件,将其启动为第一个进程。init进程启动就意味着系统进入到用户空间执行了,这时候各种用户空间运行时以及守护进程就会被加载起来。最终完成整个系统的启动过程。
3、Soong工具
随着android工程越来越大,包含的module越来越多,以makefile(包括android.mk)组织的项目编译花费的时间越来越多。谷歌在7.0开始引入了ninja进行编译系统的组织,相对于make来说ninja在大的项目管理中速度和并行方面有突出的优势,因此谷歌采用了ninja来取代之前使用的make。但是现有的android项目还是由makefile组织,因此谷歌引入了kati(后来被称为soong)将makefile(包括android.mk)翻译成ninja文件。
Android 7.0开始逐步引入kati soong(未正式使用默认关闭,需要USE_SOONG=true手动开启),将makefile文件和Android.mk文件转化成ninja文件,使用ninja文件对编译系统进行管理。
Android 8.0开始引入了Android.bp文件来替代之前的Android.mk文件。Android.bp只是纯粹的配置文件(类似json),不包括分支、循环等流程控制(如果想要进行分支循环控制可自己写go来完成),因此Android.bp文件被转化成ninja文件的效率远远高于Android.mk文件。
Android 9.0开始强制使用Android.bp来代替Android.mk。
(1)Soong工作原理
Soong源代码路径位于/android/build/soong/,从第一章的内容了解到目前的Android代码编译命令make(包括mm等命令)都基本上使用的该目录下的soong_ui.bash来进行代码编译。主要涉及到如下流程:
(2)转换关系
通过Kati工具将Android.mk和makefile文件转换成ninja格式的文件
通过Buleprint工具解析Android.bp文件,再通过Soong将被解析后的Android.bp转换成ninja格式的文件
通过androidmk工具可以直接将没有分支和循环流程控制的Android.mk文件转换成Android.bp文件(一般开发者可能会用到该工具)
相关术语:
术语 | 介绍 |
Ninja | ninja是一个编译框架,会根据相应的ninja格式的配置文件进行编译,但是ninja文件一般不会手动修改,而是通过将Android.bp文件转换成ninja格文件来编译。 |
Android.mk | Android.mk其本质是执行envsetup.sh之后,编译系统对makefile进行了一层封装,让开发者更加简单的使用makefile。因此可直接把他当成makefile看待。 |
Kati | kati是专为Android开发的一个基于Golang和C++的工具,主要功能是把Android中的Android.mk文件转换成Ninja文件。 |
Android.bp | Android.bp的出现就是为了替换Android.mk文件。bp跟mk文件不同,它是纯粹的配置,没有分支、循环等流程控制,不能做算数逻辑运算。如果需要控制逻辑,那么只能通过Go语言编写。 |
Soong | Soong类似于之前的Makefile编译系统的核心,负责提供Android.bp语义解析,并将之转换成Ninja文件。Soong还会编译生成一个androidmk命令,用于将Android.mk文件转换为Android.bp文件,不过这个转换功能仅限于没有分支、循环等流程控制的Android.mk才有效。 |
Blueprint | Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong负责Android编译而设计的工具,而Blueprint只是解析文件格式,Soong解析内容的具体含义。Blueprint和Soong都是由Golang写的项目,从Android 7.0,prebuilts/go/目录下新增Golang所需的运行环境,在编译时使用。 |
androidmk | androidmk是Soong提供的一套可直接通过命令的方式将一个android.mk生成一个对应的android.bp。通常开发者需要手动替换Android.mk的时候用到。 |
4、make流程
在android源码根目录输入make命令之后,将以树结构的方式编译整个工程所有子目录,这里只介绍一下从make是如何走到我们lunch选择的平台mk。
(1)编译开端main.mk
根据前面两章的内容我们应该很容易知道,在进行模块编译的时候执行mm其实就是执行了当前目录下的android.mk或者android.bp文件里面的指定的内容。那么在根目录下执行make其本质还是执行的根目录下面的Makefile文件(跟linux一模一样)。根目录下的Android.bp内容是空,Makefile直接指向了build/make/core/main.mk文件,如下图:
main.mk根据名称也知道是我们编译执行的主函数,当然其比较复杂,我们比较感兴趣大概流程如下三步:
(2)编译配置config.mk
config.mk定义了很多变量,这些变量对应某个mk文件并有对应的逻辑功能,例如CLEAR_VARS其实就是对应执行clear_vars.mk脚本,如下代码:
config.mk除了定义一些可以使用的变量之外,还导入了其他mk文件来帮他完成一些类似任务,例如配置全局变量的时候就导入了当前目录下的envsetup.mk,如下代码:
envsetup.mk主要给一些变量设置却省值,但最关心的还是加载了产品配置相关的product_config.mk,如下:
(3)配置产品product.mk
关于product的相关设定,则是由build/core/product_config.mk所处理,使用 build/core/product.mk提供宏载入。根据AndroidProducts.mk的內容,product_config.mk确定product目标。当然AndroidProducts.mk并不止一个,一般被定义在device/厂商名/项目名/下,如果多个项目工基线的话就可以在device目录下配置多个项目。
由上节我们已经知道主控main.mk最终引入到了product_config.mk来进行product相关的配置,在第107行导入了product.mk来读取当前所选择的product(即lunch的时候选择的产品)。
(4)加载产品product_config.mk
根据上面代码,可以得出如下逻辑,在android目录下执行make的时候,最终会根据lunch选择的product在COMMON_LUNCH_CHOICES中去寻找对应的product,然后再加载该AndroidProducts.mk文件中PRODUCT_MAKEFILES指定的.mk文件。
makefile文件中定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。因为makefile就像一个Shell脚本一样, 其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
makefile文件的命名:makefile或者Makefile。
1、编写规则:
目标:依赖
命令1
命令2 … …
指令:
命令1
命令2
… …
注:命令前是tab键,不是空格!
2、工作原理
若想生成目标, 检查规则中的所有的依赖文件是否都存在:
如果有的依赖文件不存在, 则向下搜索规则, 看是否有生成该依赖文件的规则。如果有规则用来生成该依赖文件, 则执行规则中的命令生成依赖文件;如果没有规则用来生成该依赖文件, 则报错。
如果所有依赖都存在, 检查规则中的目标是否需要更新, 必须先检查它的所有依赖,依赖中有任何一个被更新, 则目标必须更新(检查的规则是哪个时间大哪个最新)。
若目标的时间 > 依赖的时间, 不更新;
若目标的时间 < 依赖的时间, 则更新。
3、makefile的变量
在makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使makefile易于维护,修改起来变得简单。makefile有三种类型的变量: 普通变量、自带变量、自动变量。
(1)普通变量
变量定义直接用 =
使用变量值用 $(变量名)
(2)自带变量
除了使用用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值。
(3)自动变量
特别注意:自动变量只能在规则的命令中使用。
4、makefile模式规则
a.o : a.c
gcc -c a.c
b.o : b.c
gcc -c b.c
%.o : %.c
gcc -c $<
运行模式规则“%”:当目标中重现“%”时,目标中“%”所代表的值决定了依赖文件中的“%”的值。
5、makefile伪目标
伪目标主要是为了避免Makefile中定义的执行指令和工作目录下的实际文件出现名字冲突。
举例说明:当前目录下如果有一个名为“clean”的文件,执行make clean指令(清除编译生成的中间.o文件和最终目标文件),因为没有依赖文件,所以后续的rm指令不会被执行。解决方法为在Makefiel中将指令声明为伪目标即可“.PHONY”,声明目标为伪目标之后, makefile将不会检查该目标是否存在或者该目标是否需要更新。
.PHONY:clean //伪目标声明
clean:
-rm –f *.o
... ...
clean命令中的特殊符号:
6、makefile函数
makefile中的函数有很多, 在makefile中所有的函数都是有返回值的。
(1)wildcard函数
查找指定目录下的指定类型的文件。
例:src=$(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
(2)patsubst函数
匹配替换。
格式:$(patsubst
例:obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
(3)subst函数
完成字符串替换。
格式:$(subst
例:$(subst aaa, AAA, 3a transform 3A aaa) //将字符串“3a transform 3A aaa ”中的“aaa”替换为“AAA”即:“3a transform 3A AAA”
(4)dir函数
获取目录。
格式:$(dir
例:$(dir ) //提取文件“/src/a.c”的目录部分“/src”
(5)notdir函数
提取目录名。
格式:$(notdir
例:$(notdir ) //提取文件“/src/a.c”的非目录部分“a.c”
(6)foreach函数
完成循环。
格式:$(foreach , ,
Android.mk文件用来向编译系统描述如何编译你的源代码。更确切地说,该文件其实就是一个小型的Makefile。由于该文件会被NDK的编译工具解析多次,因此应该尽量减少源码中声明变量,因为这些变量可能会被多次定义从而影响到后面的解析。
1、这个文件的语法允许把源代码组织成模块,每个模块属于下列类型之一:
类型 | 说明 |
APK程序 | 一般的Android程序,编译打包生成apk文件 |
JAVA库 | java类库,编译打包生成jar包文件 |
C\C++应用程序 | 可执行的C/C++应用程序 |
C\C++静态库 | 编译生产C/C++静态库,并打包成.a文件 |
C\C++共享库 | 编译生成共享库,并打包成.so文件,有且只有共享库才能被安装/复制到APK包中 |
2、模块描述变量
下面的变量用于向系统描述我们自己的模块,它应该定义在include $(CLEAR_VARS)和include $(BUILD_***)之间。
变量 | 作用 |
LOCAL_PATH | 这个变量用于给出当前文件的路径,必须在Android.mk的开头定义,可以这样使用:LOCAL_PATH := $(call my-dir),my-dir是由系统提供的宏函数,返回当前文件所在的路径,$(call my-dir) 表示调用这个函数。这样这个变量不会被$(CLEAR_VARS)清除,因为每个Android.mk只需要定义一次(即使一个文件中定义了多个模块的情况下)。 |
include $(CLEAR_VARS) | 清空当前环境变量,除了 LOCAL_PATH。 |
LOCAL_SRC_FILES | 编译该模块需要的源文件。只要列出要传递给编译器的文件即可,编译系统会自动计算依赖关系。源代码文件路径都是相相对于LOCAL_PATH的,因此可以使用相对路径进行描述。 |
LOCAL_MODULE | 编译生成的模块名称,这个名称应当是唯一的,并且不能包含空格。模块间的依赖关系就是通过这个名称来引用的。 |
LOCAL_MODULE_TAGS | 当前模块所包含的标签,一个模块可以包含多个标签。标签的值可能是eng、user、debug、development、optional。其中,optional是默认标签。 |
LOCAL_MODULE_CLASS | 标识所编译模块最后放置的位置。ETC表示放置在/system/etc.目录下,APPS表示放置在/system/app目录下,SHARED_LIBRARIES表示放置在/system/lib目录下。如果具体指定,则编译的模块不会放到编译系统中,最后会在out对应product的obj目录下的对应目录中。 |
LOCAL_MODULE_PATH | 指定生成的 apk 目录 |
LOCAL_CERTIFICATE | 签署当前应用的证书名称。 platform:该 APK 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试。 shared:该APK需要和 home/contacts 进程共享数据。 media:该APK是 media/download 系统中的一环。 |
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES | 需要进行预编译的库 |
include $(BUILD_MULTI_PREBUILT) | 将 prebuild 定义的库拷到本地进行编译。 |
LOCAL_STATIC_JAVA_LIBRARIES | 当前模块依赖的Java静态库,在Android里,导入的jar包和引用的第三方工程都属于Java静态库。 |
LOCAL_JAVA_LIBRARIES | 当前模块依赖的Java共享库,也叫Java动态库。例如framework.jar包。 |
LOCAL_C_INCLUDES | c或c++语言需要的头文件的路径。 |
LOCAL_CFLAGS | 提供给C/C++编译器的额外编译参数。编译器标志覆盖。 |
LOCAL_STATIC_LIBRARIES | 当前模块在运行时依赖的静态库的名称。 |
LOCAL_SHARED_LIBRARIES | 当前模块在运行时依赖的动态库的名称。 |
LOCAL_PACKAGE_NAME | 编译生成的 apk 名字 |
include $(BUILD_PACKAGE) | 编译生成 apk |
LOCAL_DEX_PREOPT | apk的odex优化开关,默认是false。 |
include $(BUILD_EXECUTABLE) | 编译成可执行程序 |
include $(BUILD_SHARED_LIBRARY) | 编译生成动态库 |
include $(BUILD_STATIC_LIBRARY) | 编译生成静态库 |
include $(BUILD_STATIC_JAVA_LIBRARY) | 编译成Java静态库 |
3、除此之外,Build系统中还定义了一些函数方便在Android.mk中使用,包括:
Android.bp 是一种纯粹的配置文件,设计简单,没有条件判断或控制流语句,采用的 Go 语言编写控制逻辑。
Android.bp 文件记录着模块信息,每一个模块以模块类型开始,后面跟着一组模块的属性,以名值对(name:value)表示,每个模块都必须有一个 name 属性。基本格式,以kernel/configs/Android.bp文件为例:
android_app {
name: "Provision",
srcs: ["**/*.java"],
platform_apis: true,
product_specific: true,
certificate: "platform",
}
同时,Android.mk可以引用Android.bp中的模块,反之Android.bp不能引用Android.mk中的模块。
语法说明:
属性 | 作用 |
name | 必须指定,其属性值必须是全局惟一的。编译出的模块的名称,类似于Android.mk中的LOCAL_MODULE |
cc_defaults | 默认模块名称,可用于在多个模块中重复相同的属性。 |
cc_library_shared | 编译成动态库,类似于Android.mk中的BUILD_SHARED_LIBRARY |
cc_binary | 编译成可执行文件,类似于Android.mk中的BUILD_EXECUTABLE |
srcs | 源文件,类似于Android.mk中的LOCAL_SRC_FILES。以字符串列表的形式指定用于编译模块的源文件,您可使用模块引用语法 “:” 来引用生成源文件的其余模块的输出,如 genrule 或 filegroup。 |
local_include_dirs | 指定路径查找头文件,类似于Android.mk中的LOCAL_C_INCLUDES |
shared_libs | 编译所依赖的动态库,类似于Android.mk中的LOCAL_SHARED_LIBRARIES |
static_libs | 编译所依赖的静态库,类似于Android.mk中的LOCAL_STATIC_LIBRARIES |
cflags | 编译flag,类似于Android.mk中的LOCAL_CFLAGS |
Android.bp使用单行注释//和多行注释/* */两种方式。
Android.bp变量范围限定为声明它们的文件的其他部分,可使用 “=” 号赋值, 可是不能使用 “:=” 赋值。变量是不可变的,但有一个例外它们能够附上+= 赋值,但仅在变量被引用以前。
Android.bp支持如下几种类型:
注:String类型、字符串列表类型和Map类型支持操做符“+”。
在Android源码的build/soong/androidmk/cmd/androidmk/android.go能够查看Android.bp文件的配置:
(1)查看Android.bp支持的模块类型
(2)查看Android.bp支持的编译类型
High-Level Operating System,高级别操作系统,在高通代码里面指的是LINUX/android。proprietary HLOS指高通发布的高通专有代码,open source HLOS指Code Aurora Forum,Linux开源组织发布的代码。
高通开放的Android代码称为HLOS。
The software image running on the main processor is termed as HLOS. → 在主处理器上运行的软件映像称为HLOS。
高通代码中,Linux之外的子系统。
高通私有的Android代码称为non-HLOS。为了维护厂商自身利益,不对外公开一部分模块的源码,仅提供代码编译后的产物(二进制文件)。
while the OS running on the remaining cores is termed as non-HLOS. → 而在其余内核上运行的OS被称为非HLOS。
高通平台私有镜像指non-hlos.bin包含的wcnss、modem、adsp等等子系统镜像。现有的高通私有镜像编译过程会将各子系统镜像都打包在non-hlos.bin中,然后non-hlos.bin烧写android终端的modem分区,在android终端的开机过程中,会将non-hlos.bin里面的各个子系统镜像安装到/vendor/firware_mnt/image路径下,kernel通过pil(peripheral image loader,外围镜像加载)驱动程序加载这些镜像到ddr(double data rate sdram,双倍速率同步动态随机存储器),以使得cpu能够直接进行寻址,之后启动各个子系统。