Android底层驱动开发(四)

目录

一、Android源码编译

编译原理

编译组成

原生Android编译

二、Makefile文件

三、Android.mk文件

四、Android.bp文件

五、Android公码和私码

HLOS(公码)

non-HLOS(私码)

补充:http://t.csdn.cn/ktjxzhttp://t.csdn.cn/ktjxz


一、Android源码编译

编译原理

        编译: 将高级语言翻译成汇编语言或机器语言的过程,编译的本质就是一种翻译的过程。

高级语言(.c/.java)——编译——> 汇编语言(asm)——汇编——> 机器语言(二进制)——执行——> 硬件平台

        机器语言是机器能直接识别的程序语言或指令代码,无需经过翻译,指不经翻译即可为机器直接理解和接受的程序语言或指令代码。机器语言是由0和1组成的二进制数。

        编译流程实例:

hello.c —预处理器—> hello.i —编译器cc1—> hello.s —汇编器—> hello.o —链接器—> hello ——> 可执行文件

编译组成

1、预处理阶段

        主要是处理源文件中以“#”开头的预编译指令。

  • 宏定义指令,删除#define并展开宏
  • 条件编译指令,处理所有条件预编译指令,如#if, #ifdef, #endif
  • 头文件包含指令,插入头文件到“#include”处
  • 删除所有注释
  • 添加行号和文件名标识,以便编译时编译器产生调试用的行号信息
  • 保留所有#pragma编译指令

        预处理阶段会把头文件中的变量、函数都包含进来,所以hello.i文件非常大。

2、编译阶段

        将预处理得到的预处理文件进行语法分析,词法分析,语义分析,优化后,生成汇编代码文件(汇编语言源程序)。

3、汇编阶段

        利用汇编程序(汇编器)将汇编语言源程序转换成机器指令序列(机器语言程序)。

4、链接阶段

        将多个可重定位的目标文件.o合并以生成可执行文件,其可以被加载到内存中,由系统执行。

原生Android编译

        在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后面的选项以“产品名-编译类型”的形式命名。编译类型有以下几种:

  • eng:工程机
  • user:最终用户机
  • userdebug:调试测试机
  • tests:测试机

作用:显示菜单让我们选择编译平台(分支)以及平台相关的编译选项,也可以在lunch后面直接跟上参数。

(3)make -j4 showcommands dist

  • -j4,开启4个线程
  • Showcommands,显示编译过程中执行的命令
  • dist,将编译后产生的发布文件拷贝到out/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>编译一个指定的模块,local_target 为模块的名称
make clean-<local_target>清理一个指定模块的编译结果
make dump-products显示所有产品的编译配置信息,例如:产品名,产品支持的地区语言,产品中会包含的模块等信息
make help帮助信息,显示主要的 make 目标

Android系统的模块编译:

常用模块命令
LKmake aboot –j8
Kernel/Dtbomake bootimage -j8 / make kernel –j8
Systemmake systemimage -j8
Vendormake vendorimage -j8
Userdatamake userdataimage –j8
Recoverymake recoveryimage –j8
Cachemake 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命令设置的当前配置
crootCD到树的顶部

2、编译结果

所有的编译产物都将位于 out 目录下,该目录下主要有以下几个子目录:

路径说明
out/host/该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等。
out/target/common/该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库。
out/target/product/<product_name>/包含了针对特定设备的编译结果以及平台相关的 C/C++ 库和二进制文件。其中,<product_name>是具体目标设备的名称。
out/dist/包含了为多种分发而准备的包,通过“make disttarget”将文件拷贝到该目录,默认的编译目标不会产生该目录。

编译产物中最重要的是三个镜像文件(image文件),他们位于out/target/product/<product_name>/目录中。

其中,linux内核编译结果保存在obj/KERNEL_OBJ目录中(Linux内核也一同被编译了,而无需另外独立编译!)。

(1)这三个镜像文件是:

  • system.img:包含了Android OS的系统文件、库、可执行文件以及预置的应用程序,将被挂载为根分区。system.img 文件是system目录的一个映像,类似于linux的根文件系统的映像。

        system目录:

        1)app目录:包含所有的apk包,即包含了Android源码自身所发布的应用程序,又包含了用户自己编译的应用程序apk包。

        2)bin目录:包含基本的命令,系统的本地程序,主要是Linux系统自带的组件。

        3)etc目录:包含了一些配置文件和脚本文件,比如APN接入点设置等核心配置。

        4)framework目录:包含了系统运行所需要众多的jar包。

        5)lib目录:存放了所有的库,文件系统底层库,如平台运行时库。

        6)xbin目录:也包含了多种命令。

        7)usr目录,有用户文件夹,包含共享、键盘布局、时间区域文件等。

  • ramdisk.img:是根文件系统,Android启动时首先加载ramdisk.img镜像,并挂载到/目录下,并进行了一系列的初始化动作,包括创建各种需要的目录,初始化console,开启服务等。在启动时将被Linux内核挂载为只读分区,ramdisk.img其实是对root目录的打包和压缩,它包含了init文件和一些配置文件,它用来挂载其他系统镜像并启动 init 进程。

        root目录:

        1)init:Android最重要的进程——init,这是Android启动运行的的第一个进程。还有两个非常重要的脚本文件init.fs100.rc和init.rc,这是Android在刚开始启动时需要首先加载的两个启动脚本,根据脚本里的内容,来完成一系列的启动工作。

        2)data目录:是 userdata.img镜像要挂载的目录。

        3)system目录:即为 system.img镜像需要挂载的目录。

        4)dev目录:是系统启动后,系统的设备文件目录。

  • userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。

(2)其他image文件介绍:

  • boot.img:Android系统中,通常会把zImage(内核镜像uImage文件。通过mkimage命令,给zImage文件加上了64个字节的数据头得到uImage文件,这样才能被u-boot识别)和ramdisk.img打包到一起,生成一个boot.img镜像文件,放到boot分区,由bootloader来引导启动,其启动过程本质也是和分开的uImage&ramdisk.img类似,只不过把两个镜像按照一定的格式合并为一个镜像而已。bootloader会从boot分区开始启动,一般针对每个机型的完整刷机包中会有一个 boot.img文件,这就是boot分区镜像文件。boot分区的格式是固定的,首先是2K或者4K的文件头,后面跟着用gzip压缩过的 内核,再后面是ramdisk根文件系统,然后是第二阶段的载入程序(可选)。
  • recovery.img:recovery分区的镜像,一般用作系统恢复。

(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来进行代码编译。主要涉及到如下流程:

  • Android.mk转换成ninja文件:soong_ui.bash将指定目录下的所有Android.mk(包括makefile)文件转换成out/build-<product_name>.ninja文件
  • Android.bp转换成ninja文件:soong_ui.bash将指定目录下所有的Android.bp文件也转换成out/soong/build.ninja文件
  • 组合nijia文件:soong_ui.bash还会生成一个较小的out/combined-<product_name>.ninja文件,负责把二者组合起来作为执行入口
  • Soong根据nijia来控制源码编译

 (2)转换关系

        通过Kati工具将Android.mk和makefile文件转换成ninja格式的文件

        通过Buleprint工具解析Android.bp文件,再通过Soong将被解析后的Android.bp转换成ninja格式的文件

        通过androidmk工具可以直接将没有分支和循环流程控制的Android.mk文件转换成Android.bp文件(一般开发者可能会用到该工具)

 相关术语:

术语介绍
Ninjaninja是一个编译框架,会根据相应的ninja格式的配置文件进行编译,但是ninja文件一般不会手动修改,而是通过将Android.bp文件转换成ninja格文件来编译。
Android.mkAndroid.mk其本质是执行envsetup.sh之后,编译系统对makefile进行了一层封装,让开发者更加简单的使用makefile。因此可直接把他当成makefile看待。
Katikati是专为Android开发的一个基于Golang和C++的工具,主要功能是把Android中的Android.mk文件转换成Ninja文件。
Android.bpAndroid.bp的出现就是为了替换Android.mk文件。bp跟mk文件不同,它是纯粹的配置,没有分支、循环等流程控制,不能做算数逻辑运算。如果需要控制逻辑,那么只能通过Go语言编写。
SoongSoong类似于之前的Makefile编译系统的核心,负责提供Android.bp语义解析,并将之转换成Ninja文件。Soong还会编译生成一个androidmk命令,用于将Android.mk文件转换为Android.bp文件,不过这个转换功能仅限于没有分支、循环等流程控制的Android.mk才有效。
BlueprintBlueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong负责Android编译而设计的工具,而Blueprint只是解析文件格式,Soong解析内容的具体含义。Blueprint和Soong都是由Golang写的项目,从Android 7.0,prebuilts/go/目录下新增Golang所需的运行环境,在编译时使用。
androidmkandroidmk是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根据名称也知道是我们编译执行的主函数,当然其比较复杂,我们比较感兴趣大概流程如下三步:

  • 导入build/make/core/config.mk进行环境变量或重要参数的配置(比如常用的CLEAR_VARS、BUILD_PACKAGE)

  • 导入build/make/core/definitions.mk也定义了一些其他变量(比如常用的my-dir、all-subdir-makefiles、all-subdir-java-files)
  • 定义了一系列规则,规则的目标就是编译要生成的目标文件(比如单独编译某个分区可以直接使用make vendorimage、make xxximage)

(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文件中定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。因为makefile就像一个Shell脚本一样, 其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

        makefile文件的命名:makefile或者Makefile。

1、编写规则:

目标:依赖

<tab>命令1

<tab>命令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命令中的特殊符号:

  • -     此条命令出错,make也会继续执行后续的命令。如:-rm main.o
  • rm –f    强制执行, 比如若要删除的文件不存在使用-f不会报错

6、makefile函数

        makefile中的函数有很多, 在makefile中所有的函数都是有返回值的。

(1)wildcard函数

        查找指定目录下的指定类型的文件。

例:src=$(wildcard *.c)  //找到当前目录下所有后缀为.c的文件,赋值给src

(2)patsubst函数

        匹配替换。

        格式:$(patsubst <pattern>, <replacement>, <text>)

例:obj=$(patsubst %.c,%.o, $(src))  //把src变量里所有后缀为.c的文件替换成.o

(3)subst函数

        完成字符串替换。

        格式:$(subst <from>, <to>, <text>)

例:$(subst aaa, AAA, 3a transform 3A aaa)  //将字符串“3a transform 3A aaa ”中的“aaa”替换为“AAA”即:“3a transform 3A AAA”

(4)dir函数

        获取目录。

        格式:$(dir <name...>)

例:$(dir </src/a.c>)    //提取文件“/src/a.c”的目录部分“/src”

(5)notdir函数

        提取目录名。

        格式:$(notdir <name...>)

例:$(notdir </src/a.c>)    //提取文件“/src/a.c”的非目录部分“a.c”

(6)foreach函数

        完成循环。

        格式:$(foreach <var>, <list>, <text>)

三、Android.mk文件

        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_INCLUDESc或c++语言需要的头文件的路径。
LOCAL_CFLAGS提供给C/C++编译器的额外编译参数。编译器标志覆盖。
LOCAL_STATIC_LIBRARIES当前模块在运行时依赖的静态库的名称。
LOCAL_SHARED_LIBRARIES当前模块在运行时依赖的动态库的名称。
LOCAL_PACKAGE_NAME编译生成的 apk 名字
include $(BUILD_PACKAGE)编译生成 apk
LOCAL_DEX_PREOPTapk的odex优化开关,默认是false。
include $(BUILD_EXECUTABLE)编译成可执行程序
include $(BUILD_SHARED_LIBRARY)编译生成动态库
include $(BUILD_STATIC_LIBRARY)编译生成静态库
include $(BUILD_STATIC_JAVA_LIBRARY)编译成Java静态库

3、除此之外,Build系统中还定义了一些函数方便在Android.mk中使用,包括:

  • $(call my-dir):获取当前文件夹的路径。
  • $(call all-java-files-under,):获取指定目录下的所有java文件。
  • $(call all-c-files-under,):获取指定目录下的所有c文件。
  • $(call all-Iaidl-files-under,):获取指定目录下的所有AIDL文件。
  • $(call all-makefiles-under,):获取指定目录下的所有Make文件。
  • $(call intermediates-dir-for,,,,):获取Build输入的目标文件夹路径。

四、Android.bp文件

        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支持如下几种类型:

  • Bool(true or false):布尔类型
  • Integers(int):整数
  • Strings("string"):字符串
  • Listsof strings (["string1", "string2"]):字符串列表
  • Maps({key1: "value1", key2: ["value2"]}):键值对

注:String类型、字符串列表类型和Map类型支持操做符“+”。

        在Android源码的build/soong/androidmk/cmd/androidmk/android.go能够查看Android.bp文件的配置:

(1)查看Android.bp支持的模块类型

(2)查看Android.bp支持的编译类型

五、Android公码和私码

HLOS(公码)

        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。

non-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能够直接进行寻址,之后启动各个子系统。

补充:​​​​​​​http://t.csdn.cn/ktjxzhttp://t.csdn.cn/ktjxz

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值