接下来准备把以前写的Android编译系统方面的资料整理成MarkDown.
这次Android编译系统的代码基于Android 6.0.
在整体来看Android编译系统的时候,有两个概念必须要十分清楚:Product和Device.
Product产品
不同的人对于产品的理解不一样,对于设计人员来讲,不同的产品对应着不同的外观,不同的尺寸,不同的材质。但是对于Android来讲,产品就是不同模块的组合。每一个模块由一个Android.mk编译。模块分为三类:
- 基础模块
比如AMS,PMS和Binder等都是基础模块,这些模块都是必须要编译的,否则Android无法启动
-
可选的基础模块
比如packages/apps下面的应用
项目私有模块
大部分是和硬件特性相关的模块,比如双摄像头,指纹识别等。
我们一般都是根据足以让用户区分的硬件特性来定义产品,比如小米5和小米6是两款产品,他们拥有不同的外观设计,不同的硬件规格,比如小米5是单摄像头,小米6是双摄像头,他们的CPU也不一样,他们的外观和材质也不一样。这些不同的硬件feature软件上就对应不同的模块,模块的不同构成了产品的不同。
Device设备
同一个产品可能有不同的设备,比如小米5会有全网通版本,移动版本,电信版本等。这些不同的版本在软件概念上就对应不同的Device。虽然他们都叫小米5,但是由于硬件板级上的不同,造成了不同的Device.
我们编译出来的img,最终都要烧到对应的板子上,也就是对应的Device上。那么我们在编译过程中怎么确定我们正在编译的这个Rom是对应哪个Device呢?答案就是Target_Device这个变量,这是在编译过程中非常重要的一个变量,该变量决定了我们的img最终可以烧写到哪个Device上。
所以总结如下:
- Product决定了这编译过程中都有哪些模块需要编译
- Device决定了我们编译出来的img可以烧写到哪些设备上。
既然Target_Device这么重要,我们就来看一下编译系统是如何确定Target_Device的值得。
根据Android编译规范,我们的编译过程是从 source build/envsteup.sh
开始的。
我们看一下这个envsetup.sh都做了哪些事情:
定义了很多函数,比如mm,lunch等,也就是说只有在执行完这一步之后,这些函数才可以使用
-
然后执行
for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \ `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
去device和vendor目录下的4层文件夹之内寻找vendorsetup.sh这个文件。
这个vendorsetup.sh这个文件是做什么用的呢?
所有的vendorsetup.sh几乎都有这么一句类似的话
add_lunch_combo aosp_deb-userdebug
,这句话的作用是把aosp_deb-userdebug加入到lunch菜单中。
我们在输入lunch命令之后,会出现一个编译菜单,比如:
- aosp_x86_64-eng
- aosp_deb-userdebug
- aosp_flo-userdebug
一般这个编译菜单格式固定:ProductName_DeviceName-BuildVarient
比如aosp_deb-userdebug,ProductName是aosp,DeviceName是deb,BuildVarient是userdebug。
在我印象中,在2.3之前必须按照这种格式定义lunch菜单,系统会根据这个这里的定义来推断Target_Device的值。但是由于现在我们可以在Makefile中指定Product_Device这个变量的值,然后会根据Product_Device的值去推断Target_Device的值,所以现在也可以不按照这种格式来定义lunch菜单了。
还有一个tips就是:
在Makefile中,类似Target_XXX这种格式的变量,都是编译框架根据别的变量自动生成的,所以一般我们不要再Makefile中更改Target_XXX这种形式的变量
Product_XXX这种形式的变量是编译系统提供给我们来修改的,我们可以对Prodcut_XXX这种形式的变量赋值。比如Product_Device := flo,编译框架会根据Product_Device的值来生成Target_Device的值。