MTK6577+Android编译之android
开发环境:虚拟机+Ubuntu14.04
MTK6577采用的内存芯片为H9TP32A4GDMCPR,包括4GB的eNAND和512MB的 LPDDR2,先升级为H9TP32A8JDMCPR,包括4GB的eNAND和1GB的LPDDR2
先来看MTK源代码树概观图:
图1
由图1可知编译的入口是makeMtk文件,其采用perl语言编写的,包装了编译命令,下面来看编译系统的概述:
图2
1. 编译命令、时间和生成的文件
(1) 编译命令和时间
编译命令./mk r dr,时间约为54分钟。
(2) 编译生成的文件
编译后发现有更新的文件有bootimg、kernel、ramdisk.img、ramdisk-recovery.img、recovery.img、secro.img和system.img
编译后有更新的log文件有hsimobile77_ics2_check-dep、hsimobile77_ics2_custgen、hsimobile77_ics2_check-modem、hsimobile77_ics2_sign-modem、hsimobile77_ics2_AppAssets_Overlay、hsimobile77_ics2_android
其中hsimobile77_ics2_check-dep、hsimobile77_ics2_custgen、hsimobile77_ics2_ptgen和编译preloader部分内容是一样的,可参考:
http://blog.csdn.net/loongembedded/article/details/38706537
(3) android镜像的文件名system.img
我们来看\mediatek\build\makemtk.mk下面的相关内容:
LOGDIR = $(MKTOPDIR)/out/target/product ANDROID_IMAGES := $(LOGDIR)/$(PROJECT)/system.img \ $(LOGDIR)/$(PROJECT)/boot.img \ $(LOGDIR)/$(PROJECT)/recovery.img \ $(LOGDIR)/$(PROJECT)/secro.img \ $(LOGDIR)/$(PROJECT)/userdata.img
其中boot.img和recovery.img是kernel相关的,system.img、secro.img、userdata.img和cache.img是有文件系统的,如果不烧录recovery.img,在启动过程中要进入recovery模式时黑屏。
2. android编译流程
(1) ./mk rdr
找到makeMtk源码(perl语言),编译命令最终是通过调用
$makeCmd ="make -f mediatek/build/makemtk.mk $cmdArg @mOpts";
这个编译命令进行编译的。GNU make可以添加DEBUG参数来获取调试信息,比如--debug=v。
可以通过修改$makeCmd来增加调试信息,比如:
$makeCmd ="make --debug=v -f mediatek/build/makemtk.mk $cmdArg @mOpts";
(2) makemtk.mk
$makeCmd命令指定makefile文件 mediatek/build/makemtk.mk,其对应
android: ifeq ($(ACTION), ) $(hide) /usr/bin/perlmediatek/build/tools/mtkBegin.pl $(FULL_PROJECT) endif ifneq($(DR_MODULE),) ifneq ($(ACTION), clean) $(hide) echo building android moduleMODULE=$(DR_MODULE) $(hide) perlmediatek/build/tools/javaoptgen.pl $(PRJ_MF) $(OPTR_MF) $(MAKECMD) $(DR_MODULE) else $(hide) echo cleaning android moduleMODULE=$(DR_MODULE) $(hide) $(MAKECMD) clean-$(DR_MODULE) endif else $(hide) echo $(SHOWTIME) $(SHOWBUILD)ing$@... $(hide) echo -e \\t\\t\\t\\b\\b\\b\\bLOG:$(S_MODULE_LOG) ifeq($(SHOWBUILD), build) $(hide) perlmediatek/build/tools/javaoptgen.pl $(PRJ_MF) $(OPTR_MF) $(DEAL_STDOUT) endif $(hide) $(MAKECMD) $(ACTION)$(DEAL_STDOUT) && \ $(call chkImgSize,$(ACTION),$(PROJECT),$(SCATTER_FILE),$(if $(strip$(ACTION)),$(CHECK_IMAGE),$(ANDROID_IMAGES)),$(DEAL_STDOUT),&&) \ $(SHOWRSLT) $${PIPESTATUS[0]} $(MODULE_LOG) $(ACTION) || \ $(SHOWRSLT) $${PIPESTATUS[0]} $(MODULE_LOG) $(ACTION) ifeq ($(ACTION), ) $(hide) /usr/bin/perlmediatek/build/tools/mtkFinalize.pl $(PROJECT) $(MTK_PLATFORM)$(MTK_EMMC_SUPPORT) endif endif
(3) 执行chkImgSize(if MTK_CHKIMGSIE_SUPPORT=yes)
主要是为了检查scatter file文件(MT6577_Android_scatter_emmc.txt)为uboot分配的空间是否可以容纳生成的image,目前看了mediatek\config\prj\ProjectConfig.mk文件中没有MTK_CHKIMGSIE_SUPPORT定义,后面应该考虑添加进来。
3. android编译涉及的源代码目录
修改以下文件或者目录需要./mk r(n) dr
这部分参考第4部分。
4. Boot.img、ramdisk.img、kernel、secro.img、ramdisk-revovery.img、system.img、cache.img和userdata.img
4.1 ./mk bootimag
编译生成boot.img、ramdisk.img和kernel,当修改kernel和root相关的代码时采用此命令:
alps/kernel/
alps/mediatek/platform/mt65xx/kernel/
alps/mediatek/source/kernel/
alps/mediatek/customer/mt65xx/kernel/
alps/mediatek/customer/common/kernel/
alps/mediatek/customer/$porject_name$/kernel
......
Android 产品中,内核格式是Linux标准的zImage,根文件系统采用ramdisk格式。这两者在Android下是直接合并在一起取名为boot.img,会放在一个独立分区当中。这个分区格式是Android自行制定的格式。Android开发时,最标准的做法是重新编译于内核和根文件系统,然后调用Android给的命令行文件mkbootimg来打包。
1) mkbootimage打包生成boot.img
图3
\build\core\Makefile文件相关的一部分内容如下:
INSTALLED_BOOTIMAGE_TARGET:= $(PRODUCT_OUT)/boot.img BUILT_RAMDISK_TARGET:= $(PRODUCT_OUT)/ramdisk.img INSTALLED_RAMDISK_TARGET:= $(BUILT_RAMDISK_TARGET) ifeq """$(CUSTOM_BUILD_VERNO)" CUSTOM_BUILD_VERNO := $(BUILD_NUMBER) CUSTOM_BUILD_VERNO := $(substeng.$(USER).,,$(CUSTOM_BUILD_VERNO)) endif #----------------------------------------------------------------- # the boot image,which is a collection of other images. INTERNAL_BOOTIMAGE_ARGS:= \ $(addprefix --second,$(INSTALLED_2NDBOOTLOADER_TARGET)) \ --kernel $(INSTALLED_KERNEL_TARGET) \ --ramdisk $(INSTALLED_RAMDISK_TARGET) ……………………… ifneq """$()" INTERNAL_BOOTIMAGE_ARGS += --board$(CUSTOM_BUILD_VERNO) Endif ……………………………………… $(INSTALLED_BOOTIMAGE_TARGET):$(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
由此可见mkbootimage打包生成boot.img时需要的参数有
--kernel $(PRODUCT_OUT)/kernel(或是kernel_$project.bin)
--ramdisk $(PRODUCT_OUT)/ramdisk.img
--board $(CUSTOM_BUILD_VERNO)
注意CUSTOM_BUILD_VERNO不要超过16个字节,其在/mediate/config/prj/ProjectConfig.mk中定义,但这里其值为空,所以其内容对应于BUILD_NUMBER的值,这里的信息对应System settings->About phone->Custom buildversion下的内容,比如1407736091
mkbootimage工具位于out/host/linux-x86/bin,要知道boot.img的格式,需要看对应的源代码\system\core\mkbootimg\mkbootimg.c,boot.img由文件头信息boot header,压缩的内核,文件系统数据ramdisk以及second stage loader(可选)组成,它们之间非页面对齐部分用0填充,相关的代码见mian()下面部分:
if(write(fd,&hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if(write_padding(fd, pagesize,sizeof(hdr))) goto fail; if(write(fd, kernel_data, hdr.kernel_size)!= hdr.kernel_size) goto fail; if(write_padding(fd, pagesize,hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data,hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; if(write_padding(fd, pagesize,hdr.ramdisk_size)) goto fail; if(second_data) { if(write(fd, second_data,hdr.second_size) != hdr.second_size) goto fail; if(write_padding(fd, pagesize,hdr.ramdisk_size)) goto fail; }
\system\core\mkbootimg\bootimg.h目录下boot_img_hdr定义了文件头信息:
typedef structboot_img_hdr boot_img_hdr; #define BOOT_MAGIC"ANDROID!" #defineBOOT_MAGIC_SIZE 8 #defineBOOT_NAME_SIZE 16 #defineBOOT_ARGS_SIZE 512 structboot_img_hdr { unsigned char magic[BOOT_MAGIC_SIZE]; unsigned kernel_size; /* size in bytes */ unsigned kernel_addr; /* physical load addr */ unsigned ramdisk_size; /* size in bytes */ unsigned ramdisk_addr; /* physical loadaddr */ unsigned second_size; /* size in bytes */ unsigned second_addr; /* physical load addr */ unsigned tags_addr; /* physical addr for kernel tags */ unsigned page_size; /* flash page size we assume */ unsigned unused[2]; /* future expansion: should be 0 */ unsigned char name[BOOT_NAME_SIZE]; /*asciiz product name */ unsigned char cmdline[BOOT_ARGS_SIZE]; unsigned id[8]; /* timestamp / checksum /sha1 / etc */ };
Boot.img的组成借用bootimg.h下给出的解释:
图4
2) mkbootfs打包生成ramdisk.img
图5
在build/core/Makefile文件中看下面主要的相关部分:
################################################################## # Targets forboot/OS images ################################################################## #----------------------------------------------------------------- # the ramdisk INTERNAL_RAMDISK_FILES:= $(filter $(TARGET_ROOT_OUT)/%, \ $(ALL_PREBUILT) \ $(ALL_COPIED_HEADERS) \ $(ALL_GENERATED_SOURCES) \ $(ALL_DEFAULT_INSTALLED_MODULES)) BUILT_RAMDISK_TARGET:= $(PRODUCT_OUT)/ramdisk.img # We just buildthis directly to the install location. INSTALLED_RAMDISK_TARGET:= $(BUILT_RAMDISK_TARGET) $(INSTALLED_RAMDISK_TARGET):$(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) | $(MINIGZIP) $(call pretty,"Target ram disk:$@") $(hide) $(MKBOOTFS) $(TARGET_ROOT_OUT) |$(MINIGZIP) > $@ ifneq ($(strip$(TARGET_NO_KERNEL)),true) $(hide) mediatek/build/tools/mkimage$(PRODUCT_OUT)/ramdisk.img ROOTFS > $(PRODUCT_OUT)/ramdisk_android.img mv $(PRODUCT_OUT)/ramdisk.imgmediatek/source/kernel/trace32/$(TARGET_PRODUCT)_ramdisk.img $(hide) mv$(PRODUCT_OUT)/ramdisk_android.img $(PRODUCT_OUT)/ramdisk.img Endif
MKBOOTFS =mkbootfs 就是位于out/host/linux-x86/bin目录下的mkbootfs。
Ramdisk.img是mkbootfs工具用\out\target\product\prj\out目录下的
需要注意system/core/rootdir中的部分内容是拷贝到了out/target/product/prj/system中的,并不是完完全全拷贝到out/target/product/prj/root目录中去的。
ramdisk映像是一个最基础的小型文件系统,它包括了初始化android系统所需要的全部核心文件,总之它控制着整个android的启动.例如:初始化init进程以及init.rc(可以用于设置很多系统的参数)等文件。以下是一个典型的ramdisk中包含的文件列表:
./init.trout.rc
./default.prop
./proc
./dev
./init.rc
./init
./sys
./init.goldfish.rc
./sbin
./sbin/adbd
./system
./data
详细可参考\system\core\rootdir\Android.mk。
3) kernel
图6
见http://blog.csdn.net/loongembedded/article/details/38778731
4.2 ./mk systemimage
1) 编译生成的文件
system.img、boot.img、ramdisk.img、ramdisk-recovery.img、recovery.img。
2) 修改system相关代码时用到此编译命令
alps/frameworks/
alps/packages/
alps/vendor/
alps/hardware/
alps/dalvik/
...........
3) System.img文件的内容
在源码之后在 out/host/linux-x86/bin/下面会生成一个mkyaffs2image的工具,用这个可以把system目录打包成system.img
system.img文件是system目录的一个映像,类似于linux的根文件系统的映像,它包含了整个系统,比如android的framework、application、配置文件、字体等,它会被挂接到 "/" 上,包含了系统中所有的二进制文件。
android启动时首先加载ramdisk.img镜像,并挂载到/目录下,并进行了一系列的初始化动作,包括创建各种需要的目录,初始化console,开启服务等。System.img是在init.rc中指定一些脚本命令,通过init.c进行解析并挂载到根目录下的/system目录下的。
对于android系统文件夹,比如out/target/product/prj/system目录,说明如下:
system/app
这个里面主要存放的是常规下载的应用程序,可以看到都是以APK格式结尾的文件。在这个文件夹下的程序为系统默认的组件,自己安装的软件将不会出现在这里,而是/data/文件夹中。
system/bin
这个目录下的文件都是系统的本地程序,从bin文件夹名称可以看出是binary二进制的程序,里面主要是Linux系统自带的组件。 system/etc 从文件夹名称来看保存的都是系统的配置文件,比如APN接入点设置等核心配置。
system/fonts
字体文件夹,除了标准字体和粗体、斜体外可以看到文件体积最大的可能是中文字库,或一些unicode字库。
system/framework
主要是一些核心的文件,从后缀名为jar可以看出是是系统平台框架。
system/lib
lib目录中存放的主要是系统底层库,如平台运行时库。
system/media
铃声音乐文件夹,除了常规的铃声外还有一些系统提示事件音
system/usr
用户文件夹,包含共享、键盘布局、时间区域文件等。
通过\out\target\product\prj\ installed-files.txt文件可以查看system.img加压后包括的目录信息。
4.3 ./mk recoveryimage
1) 编译生成的文件
boot.img、ramdisk.img、ramdisk-recovery.img、recovery.img。
2) 修改recovery相关代码时用到此编译命令
alps/bootable/recovery/
alps/mediatek/customer/$project_name$/recovery/
......
3) Recovery.img内容
Bootloader 会根据某些判定条件(比如按某个特殊键)决定是否进入 recovery 模式。Recovery 模式会装载 recovery 分区, 该分区包含recovery.img。recovery.img 包含了标准内核(和boot.img中的内核相同)以及recovery 根文件系统
图7
可以看出recovery.img和boot.img的差别在于boot.img包含的根文件系统对应于ramdisk.img,而recovery.img包含的根文件系统对应于ramdisk-recovery.img
recovery.img的生成过程可看build\core\Makefile下面相关部分:
recovery_kernel :=$(INSTALLED_KERNEL_TARGET) # same as a non-recovery system recovery_ramdisk:= $(PRODUCT_OUT)/ramdisk-recovery.img ……………………….. INSTALLED_RECOVERYIMAGE_TARGET:= $(PRODUCT_OUT)/recovery.img ………………………….. INTERNAL_RECOVERYIMAGE_ARGS:= \ $(addprefix --second,$(INSTALLED_2NDBOOTLOADER_TARGET)) \ --kernel $(recovery_kernel) \ --ramdisk $(recovery_ramdisk) …………………… $(INSTALLED_RECOVERYIMAGE_TARGET):$(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) \ $(INSTALLED_RAMDISK_TARGET)\ $(INSTALLED_BOOTIMAGE_TARGET)\ $(recovery_binary)\ $(recovery_initrc)$(recovery_kernel) \ $(INSTALLED_2NDBOOTLOADER_TARGET)\ $(recovery_build_prop)$(recovery_resource_deps) \ $(recovery_fstab)\ $(recovery_gzip)$(recovery_sec_ko) \ $(RECOVERY_INSTALL_OTA_KEYS) @echo----- Making recovery image ------ rm-rf $(TARGET_RECOVERY_OUT) mkdir-p $(TARGET_RECOVERY_OUT) mkdir-p $(TARGET_RECOVERY_ROOT_OUT) mkdir-p $(TARGET_RECOVERY_ROOT_OUT)/etc mkdir-p $(TARGET_RECOVERY_ROOT_OUT)/tmp echoCopying baseline ramdisk... cp-R $(TARGET_ROOT_OUT) $(TARGET_RECOVERY_OUT) rm-f $(TARGET_RECOVERY_ROOT_OUT)/init*.rc echoModifying ramdisk contents... rm-rf $(TARGET_RECOVERY_ROOT_OUT)/res cp-f $(recovery_initrc) $(TARGET_RECOVERY_ROOT_OUT)/ cp-f $(recovery_gzip) $(TARGET_RECOVERY_ROOT_OUT)/sbin/gzip cp-f $(recovery_sec_ko) $(TARGET_RECOVERY_ROOT_OUT)/ cp-f $(recovery_binary) $(TARGET_RECOVERY_ROOT_OUT)/sbin/ cp-rfL $(recovery_resources_common) $(TARGET_RECOVERY_ROOT_OUT)/ $(foreachitem,$(recovery_resources_private), \ cp -rf $(item) $(TARGET_RECOVERY_ROOT_OUT)/) $(foreachitem,$(recovery_fstab), \ cp -f $(item)$(TARGET_RECOVERY_ROOT_OUT)/etc/recovery.fstab) cp$(RECOVERY_INSTALL_OTA_KEYS) $(TARGET_RECOVERY_ROOT_OUT)/res/keys cat$(INSTALLED_DEFAULT_PROP_TARGET) $(recovery_build_prop) \ >$(TARGET_RECOVERY_ROOT_OUT)/default.prop $(MKBOOTFS)$(TARGET_RECOVERY_ROOT_OUT) | $(MINIGZIP) > $(recovery_ramdisk) mediatek/build/tools/mkimage$(PRODUCT_OUT)/ramdisk-recovery.img RECOVERY >$(PRODUCT_OUT)/ramdisk_recovery.img mv$(PRODUCT_OUT)/ramdisk_recovery.img $(PRODUCT_OUT)/ramdisk-recovery.img $(MKBOOTIMG)$(INTERNAL_RECOVERYIMAGE_ARGS) --output $@ @echo----- Made recovery image -------- $@ $(hide)$(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE),raw) 用到的一些环境变量在build\core\envsetup.mk文件下: TARGET_RECOVERY_OUT := $(PRODUCT_OUT)/recovery TARGET_RECOVERY_ROOT_OUT :=$(TARGET_RECOVERY_OUT)/root TARGET_RECOVERY_ROOT_OUT TARGET_ROOT_OUT := $(PRODUCT_OUT)/root
可知ramdisk.img对应的目录和ramdisk-recovery.img对应的目录差如下:
图8
4.4 ./mk secroimage
1) 编译生成的文件
secro.img。
2) 修改secro相关代码时用到此编译命令
alps/mediatek/source/secro/
alps/mediatek/customer/$project_name$/secro/
3) secro.img内容
图9
1) 复制\mediatek\custom\prj\secro目录到\out\target\product\prj\secro目录
2) \out\target\product\prj\secro文件夹打包成为secro.img
详细的生成过程见build\core\Makefile相关部分
BUILT_SECROIMAGE_TARGET:= $(PRODUCT_OUT)/secro.img
4.5 ./mk factoryimage
1) 编译生成的文件
factory.bin。
2) 修改factory相关代码时用到此编译命令
alps/mediatek/customer/$project_name$/factory/
alps/mediatek/customer/common/factory/
alps/mediatek/source/factory/
......
3) Factory.bin内容
Factory.bin大小为0,先来看build\core\Makefile相关文件:
factory_ramdisk :=$(PRODUCT_OUT)/ramdisk-factory.img INSTALLED_FACTORYIMAGE_TARGET:= $(PRODUCT_OUT)/factory.img …………………. .PHONY:factoryimage factoryimage:$(INSTALLED_FACTORYIMAGE_TARGET) @mediatek/build/tools/mkimage$(PRODUCT_OUT)/ramdisk-factory.img ROOTFS > $(PRODUCT_OUT)/factory.bin
可知factory.bin是ramdisk-factory.img打上ROOTFS标识后的文件,接着来看build\core\envsetup.mk下面的信息:
TARGET_FACTORY_OUT:= $(PRODUCT_OUT)/factory TARGET_FACTORY_ROOT_OUT:= $(TARGET_FACTORY_OUT)/root
可知其意向是把\out\target\product\prj\factory\root目录打包生成为ramdisk-factory.img的,但并没有存在此目录,所以最后生成的factory.bin为0。
4.6 ./mk userdataimage
生成out\target\product\prj\data目录,并将此文件夹打包生成userdata.img,但是实际上没有看到对应的userdata.img更新,好像只有./mk new时才生成新的。
userdata.img挂载到 /data 下的镜像,它包含了应用及用户相关的数据。
4.7 ./mk cacheimage
提示make: *** No rule to make target`cacheimage'. Stop.
参考链接:
《Android_Build_System_for_customer》
Android编译系统详解(一)
http://blog.csdn.net/mr_raptor/article/details/7539978
Android.mk的用法和基础
http://blog.csdn.net/zhandoushi1982/article/details/5316669
Android OTA升级之三:生成recovery.img
http://blog.csdn.net/zjujoe/article/details/6230575/