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

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android开发案例驱动教程》 配套代码。 注: 由于第12,13,14章代码太大,无法上传到一个包中。 这三节代码会放到其他压缩包中。 作者:关东升,赵志荣 Java或C++程序员转变成为Android程序员 采用案例驱动模式展开讲解知识点,即介绍案例->案例涉及技术->展开知识点->总结的方式 本书作者从事多年一线开发和培训,讲解知识点力求细致,深入浅出 目 录 前言 第1章 Android操作系统概述 1 1.1 Android历史介绍 1 1.2 Android架构 1 1.3 Android平台介绍 2 1.4 现有智能手机操作系统比较 4 第2章 Android开发环境搭建 5 2.1 Eclipse和ADT插件 5 2.1.1 Eclipse安装 5 2.1.2 ADT插件 6 2.2 Android SDK 8 2.2.1 Android SDK的获得 8 2.2.2 Android SDK版本说明 10 2.2.3 ADT配置 10 2.3 Android开发模拟器 11 2.3.1 创建模拟器 11 2.3.2 启动模拟器 13 2.3.3 键盘映射与模拟器控制 13 2.3.4 横屏与竖屏切换 14 第3章 第一个Android程序 15 3.1 HelloAndroid 15 3.1.1 在Eclipse中创建项目 15 3.1.2 编写程序项目代码 17 3.1.3 运行HelloAndroid 18 3.1.4 Android工程目录 19 3.1.5 AndroidManifest.xml文件 21 3.2 Android中的组件介绍 22 3.3 使用Android SDK帮助 23 3.3.1 Android SDK API文档 23 3.3.2 Android SDK开发指南 24 3.3.3 Android SDK samples 24 3.4 使用DDMS帮助调试程序 26 3.4.1 启动DDMS 26 3.4.2 Device 28 3.4.3 Emulator Control 29 3.4.4 File Explorer 30 3.4.5 LogCat 31 3.5 使用ADB帮助调试程序 33 3.5.1 查询模拟器实例和设备 34 3.5.2 进入shell 34 3.5.3 导入导出文件 35 3.6 应用程序的打包、安装和卸载 37 3.6.1 应用程序打包 37 3.6.2 应用程序安装 40 3.6.3 应用程序卸载 40 本章小结 42 第4章 UI基础知识 43 4.1 Android UI组件概述 43 4.1.1 View 43 4.1.2 ViewGroup 44 4.1.3 布局管理器 44 4.2 UI设计工具 44 4.2.1 DroidDraw工具 44 4.2.2 ADT插件UI设计工具 46 4.3 事件处理模型 47 4.3.1 接口实现事件处理模型 47 4.3.2 内部类事件处理模型 49 4.3.3 匿名内部类事件处理模型 51 4.4 Activity中的常用事件 53 4.4.1 触摸事件 53 4.4.2 键盘事件 55 4.5 菜单 57 4.5.1 文本菜单 57 4.5.2 图片文本菜单 59 本章小结 60 第5章 UI基础控件 61 5.1 按钮 61 5.1.1 Button 62 5.1.2 ImageButton 63 5.1.3 ToggleButton 64 5.2 TextView 64 5.3 EditText 65 5.4 RadioButton和RadioGroup 66 5.4.1 RadioButton 66 5.4.2 RadioGroup 67 5.5 CheckBox 68 5.6 ImageView 70 5.7 Progress Bar 70 5.7.1 条状进度条 71 5.7.2 圆形进度条 73 5.7.3 对话框进度条 74 5.7.4 标题栏中进度条 75 5.8 SeekBar 76 5.9 RatingBar 78 本章小结 82 第6章 UI高级控件 83 6.1 列表类控件 83 6.1.1 Adapter概念 83 6.1.2 AutoComplete 84 6.1.3 Spinner 87 6.1.4 ListView 90 6.1.5 GridView 96 6.1.6 Gallery 99 6.2 Toast 103 6.2.1 文本类型 103 6.2.2 图片类型 104 6.2.3 复合类型 105 6.2.4 自定义显示位置Toast 106 6.3 对话框 107 6.3.1 文本信息对话框 107 6.3.2 简单列表项对话框 109 6.3.3 单选项列表项对话框 111 6.3.4 复选框列表项对话框 113 6.3.5 复杂布局列表项对话框 115 6.4 Android国际化和本地化 118 本章小结 121 第7章 UI布局 122 7.1 FrameLayout 122 7.1.1 TextSwitcher 124 7.1.2 ImageSwitcher 126 7.1.3 DatePicker 129 7.1.4 TimePicker 131 7.1.5 ScrollView 133 7.1.6 选项卡 134 7.2 LinearLayout 138 7.3 RelativeLayout 139 7.4 AbsoluteLayout 141 7.5 TableLayout 143 7.6 布局嵌套 146 7.7 屏幕旋转 152 本章小结 154 第8章 多线程 155 8.1 多线程案例--计时器 155 8.2 线程概念 156 8.2.1 进程概念 156 8.2.2 线程概念 156 8.3 Java中的线程 157 8.3.1 Java中的实现线程体方式1 157 8.3.2 Java中的实现线程体方式2 160 8.3.3 Java中的实现线程体方式3 162 8.4 Android中的线程 163 8.4.1 Android线程应用中的问题与分析 164 8.4.2 Message和MessageQueue 169 8.4.3 Handler 169 8.4.4 Looper和HandlerThread 172 本章小结 178 第9章 Activity和Intent 179 9.1 Activity 179 9.1.1 创建Activity 179 9.1.2 Activity生命周期 180 9.2 Intent 183 9.2.1 显式Intent 184 9.2.2 隐式Intent 186 9.2.3 匹配组件 186 9.3 多Activity之间跳转 188 9.3.1 多个Activity之间数据传递 189 9.3.2 跳转与返回 192 9.3.3 任务与标志 196 9.4 Android系统内置Intent 199 本章小结 201 第10章 数据存储 203 10.1 健康助手案例 203 10.2 Android数据存储概述 205 10.3 本地文件 205 10.3.1 访问SD卡 207 10.3.2 访问应用文件目录 212 10.4 SQLite数据库 216 10.4.1 SQLite数据类型 216 10.4.2 Android平台下管理SQLite数据库 216 10.5 编写访问SQLite数据库组件 220 10.5.1 DBHelper类 220 10.5.2 数据插入 222 10.5.3 数据删除 224 10.5.4 数据修改 224 10.5.5 数据查询 227 10.6 案例重构 229 10.6.1 系统架构设计 229 10.6.2 重构数据访问层 230 10.7 为案例增加参数设置功能 238 10.7.1 Shared Preferences 240 10.7.2 Preferences控件介绍 243 10.7.3 使用Preferences控件的案例 248 本章小结 250 第11章 Content Provider 251 11.1 Content Provider概述 251 11.2 Content URI 252 11.2.1 Content URI含义 252 11.2.2 内置的Content URI 253 11.3 通过Content Provider访问联系人 253 11.3.1 查询联系人 255 11.3.2 通过联系人ID查询联系人的Email 258 11.3.3 按照过滤条件查询Email 259 11.3.4 查询联系人的电话 261 11.4 通过Content Provider访问通话记录 262 11.4.1 查询通话记录 262 11.4.2 按照过滤条件查询通话记录 264 11.5 通过Content Provider访问短信 266 11.6 自定义Content Provider实现数据访问 269 11.6.1 编写Content Provider 269 11.6.2 在不同的应用中调用Content Provider 277 11.6.3 重构Content Provider调用 278 本章小结 281 第12章 多媒体 282 12.1 多媒体文件介绍 282 12.1.1 音频多媒体文件介绍 282 12.1.2 视频多媒体文件介绍 283 12.2 Android音频播放 284 12.2.1 Android音频/视频播放状态 284 12.2.2 音频播放案例介绍 286 12.2.3 资源音频文件播放 287 12.2.4 本地音频文件播放 291 12.2.5 网络音频文件播放 292 12.2.6 完善案例其他功能 293 12.3 Android音频录制 303 12.3.1 Android音频/视频录制状态 303 12.3.2 音频录制案例介绍 303 12.3.3 音频录制案例实现 305 12.4 Android视频播放 309 12.4.1 视频播放案例 309 12.4.2 采用MediaPlayer类播放视频 310 12.4.3 使用VideoView控件重构案例 315 本章小结 316 第13章 Service 317 13.1 Service概述 317 13.1.1 本地Service生命周期 317 13.1.2 远程Service生命周期 318 13.2 本地Service 319 13.2.1 本地Service案例 319 13.2.2 编写AudioService 320 13.2.3 调用Service 322 13.2.4 重构案例 323 13.3 远程Service 325 13.3.1 远程Service调用原理 325 13.3.2 远程Service案例 326 13.3.3 设计AIDL文件 327 13.3.4 编写AudioService 331 13.3.5 调用远程Service 336 13.3.6 组件间参数传递 343 本章小结 347 第14章 Broadcast Receiver和Notification 348 14.1 Broadcast Receiver 348 14.1.1 音频播放案例 349 14.1.2 编写音频播放Broadcast Receiver 350 14.1.3 注册音频播放Broadcast Receiver 351 14.1.4 接收系统的广播 353 14.1.5 MP3下载服务案例 353 14.2 Notification 358 14.2.1 完善MP3下载服务案例 358 14.2.2 完善音频播放案例 363 14.2.3 其他形式的Notification 369 本章小结 371 第15章 云端应用 372 15.1 典型云端应用--城市天气信息服务 372 15.2 网络通信技术与实现 374 15.2.1 网络通信技术介绍 376 15.2.2 Java URL类实现方式 377 15.2.3 Apache HttpClient实现方式 378 15.3 数据交换格式 380 15.3.1 纯文本格式 381 15.3.2 XML格式 381 15.3.3 JSON格式 385 15.4 自定义服务器端程序实例 387 15.4.1 Java Servlet概述 387 15.4.2 编写城市信息服务的Servlet 388 15.4.3 编写城市天气服务的Servlet 393 15.4.4 再次探讨HttpClient的POST请求 395 15.5 云端应用案例优化 400 本章小结 404 第16章 Google Map和定位服务 405 16.1 MyMap服务系统案例 405 16.2 Android Google Map 406 16.2.1 申请Google Map Android API Key 407 16.2.2 编写Android Google Map骨架程序 409 16.2.3 控制地图 412 16.2.4 地图的显示模式 416 16.2.5 地图的图层 419 16.2.6 查询与定位 422 16.3 Android定位服务 430 16.3.1 开启定位服务 431 16.3.2 模拟测试 433 16.3.3 GPS与Google Map结合 435 16.4 案例重构 437 16.4.1 重构"定位查询"方法 438 16.4.2 重构"查询周围"方法 440 本章小结 443 第17章 Android通信应用 444 17.1 电话应用开发 444 17.1.1 拨打电话功能 444 17.1.2 呼入电话状态 446 17.2 短信和彩信应用开发 450 17.2.1 Android内置的发送短信/彩信功能 450 17.2.2 自己编写发送文本内容的短信 452 17.2.3 自己编写接收文本内容的短信 458 17.2.4 自己编写发送二进制内容的短信 459 17.2.5 自己编写接收二进制内容的短信 461 17.3 蓝牙通信 463 17.3.1 Android 2 BluetoothChat案例 464 17.3.2 Android 2 蓝牙API介绍 464 17.3.3 TCP Socket与蓝牙Socket的区别 465 17.3.4 BluetoothChat中的类 466 17.3.5 初始化本地蓝牙设备 467 17.3.6 查找蓝牙设备 471 17.3.7 管理连接 476 17.3.8 互相之间的通信 480 17.4 WiFi通信 484 17.4.1 管理WiFi 484 17.4.2 扫描热点 487 17.4.3 Socket通信 489
### 回答1: Android是一种广泛使用的移动操作系统,其开发涉及到多个层次,其中底层驱动的开发是其中重要的一环。底层驱动开发是指为Android设备上的硬件提供驱动程序的开发过程。驱动程序是操作系统与硬件之间的桥梁,它们负责管理和控制硬件设备的工作。 在Android底层驱动开发的过程中,首先需要了解设备的硬件结构和规格,以及相应的硬件接口和协议。根据硬件设备的不同,可能包括显示器、触摸屏、摄像头、声卡等各种设备。开发者需要研究硬件设备的工作原理和特性,以便编写相应的驱动程序。 其次,开发者需要熟悉Android底层的相关开发工具和API,如HAL(硬件抽象层)、Binder IPC(进程间通信)等,以便与操作系统和应用程序进行交互。底层驱动的开发还需要理解Linux内核的相关知识,因为Android是基于Linux内核开发的。 在实际的驱动开发过程中,开发者需要根据硬件设备的特性和要求,编写对应的设备驱动程序。这些驱动程序通常使用C或C++语言编写,并需要遵循一定的编程规范和命名规则。开发者需要确保驱动程序的正确性和稳定性,以及与操作系统的兼容性。 总之,Android底层驱动开发是一项复杂且技术要求较高的工作。它需要开发者具备扎实的硬件和软件知识,以及良好的编程能力。只有通过深入研究和实践,才能开发出高质量的驱动程序,为Android设备的稳定运行做出贡献。 ### 回答2: Android 底层驱动开发是指在 Android 操作系统中编写和调试设备驱动程序的过程。设备驱动程序是连接硬件和操作系统之间的桥梁,能使操作系统识别和与硬件进行通信。对于 Android 应用程序开发人员来说,了解底层驱动开发至关重要,因为它可以帮助他们更好地理解系统的工作原理,并在需要时进行定制和优化。 编写 Android 底层驱动程序需要掌握 C/C++ 编程语言、Linux 内核知识和硬件架构相关概念。在开发过程中,需要了解设备的硬件接口和规范,包括寄存器配置、中断处理、数据传输等。通过编写驱动程序,开发人员可以为设备提供访问系统资源的接口,并处理各种硬件事件和数据传输。 开发 Android 底层驱动程序的主要步骤包括以下几个方面: 1. 硬件初始化:配置设备的寄存器、中断等硬件资源,并注册到操作系统中。这包括初始化 I/O 端口、设备中断控制器、时钟和 DMA 控制器等。 2. 中断处理:在中断发生时,驱动程序需要对中断进行处理。处理中断的程序需要根据中断的类型和来源来执行相应的操作。例如,处理数据接收中断、数据发送中断等。 3. 数据传输:驱动程序需要实现对设备的数据传输功能。这包括读取和写入设备的数据。数据传输可以使用 DMA、中断或轮询方式进行。 4. 设备控制:驱动程序需要实现对设备的控制功能。这包括设置设备的工作模式、参数调整和状态查询等。通过提供合适的接口,应用程序可以通过系统调用来与设备进行交互和控制。 5. 调试和优化:在驱动程序开发的过程中,需要使用调试工具进行问题排查和性能优化。这包括使用 printk() 输出调试信息、使用 gdb 进行调试和性能剖析等。 总之,Android 底层驱动开发涉及到多个技术领域和专业知识,需要开发人员具备扎实的编程基础和理解操作系统和硬件的能力。掌握底层驱动开发可以帮助开发人员更好地理解系统的工作原理,并在需求变化时进行相应的定制和优化。 ### 回答3: Android是目前最流行的移动操作系统之一,其特点是开放源代码、可定制性强以及适应性广泛。在Android系统中,底层驱动的开发是非常重要的一部分,它涉及到硬件和操作系统之间的交互。 Android底层驱动开发PDF主要介绍了Android系统中的底层驱动开发相关知识和技术。这些知识和技术包括硬件抽象层(HAL)、内核驱动开发、设备树(Device Tree)、引导加载程序(Bootloader)等。 首先,硬件抽象层(HAL)是Android系统的一个重要组成部分,用于提供硬件与操作系统之间的接口。通过HAL,Android系统可以与各种硬件设备进行通信和交互。PDF中会介绍如何编写和调试HAL,以及如何实现硬件的适配和兼容性。 其次,内核驱动开发Android底层驱动开发的核心之一。PDF中将详细介绍如何编写设备驱动程序,如独立设备驱动和平台设备驱动。此外,还会涉及到设备树(Device Tree)的使用,设备树用于描述硬件设备的信息和属性。 另外,引导加载程序(Bootloader)也是Android底层驱动开发的重要环节之一。PDF中会介绍如何编写和调试引导加载程序,以及如何通过引导加载程序来引导Android系统。 总之,Android底层驱动开发PDF会全面介绍Android系统中的底层驱动开发相关知识和技术,包括HAL、内核驱动开发、设备树、引导加载程序等。对于想要深入了解Android系统底层开发的开发者来说,这本PDF是一本非常有价值的参考书。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值