以TCC88XX为例,当在Android顶层源码目录使用make编译完成后,会生成这样一个目录:
out/target/product/tcc8800,该目录内部有我们需要的boot.img和system.img,boot.mg
使用kernel和out/target/product/tcc8800/root目录打包而成(广义的ramdisk),也就是说,
boot.img是由kernel和ramdisk.img生成得到,在本文中主要分析root目录和ramdisk.img的生成,
在Android编译框架中,把许多固定的、反复用到的目录路径定义为宏变量,而上述生成的目录
out/target/product/tcc8800的宏即为:PRODUCT_OUT
out/target/product/tcc8800/system的宏即为:TARGET_OUT
而out/target/product/tcc8800/root的宏即为:TARGET_ROOT_OUT,
out/target/product/tcc8800/root主要是由system/core/rootdir目录拷贝得到的,
为此我分析了system/core/rootdir目录中的Android.mk文件,具体情况是这样的:
copy_from := etc/dbus.conf etc/hosts
copy_from += etc/vold.fstab
以上内容将需要拷贝的文件添加到copy_from变量中,以便后续处理。
拷贝到那里呢? 在看看copy_to的定义:
copy_to := $(addprefix $(TARGET_OUT)/,$(coby_from))
该语句即为copy_from中每个字符串片段添加一个TARGET_OUT前缀(即system),这样copy_to的
内容就很明了:
copy_to :=out/target/product/tcc8800/system/etc/dbus.conf ...之类,在此略掉。
之后,给copy_from添加路径前缀:
copy_from := $(addprefix $(LOCAL_PATH)/, $(copy_from)
之所以要添加前缀的原因是接下来马上要设置的拷贝语句:
1 |
$(copy_to) : $(TARGET_OUT)/% : $(LOCAL_PATH)/% | $(ACP) |
2 |
|
3 |
$(transform-prebuilt-to-target) |
上述语句会让Android在构建img前,自动完成拷贝工作,其中使用到符号%进行匹配,这也是为什么要
给copy_from添加前缀的原因。
随后,脚本将copy_to变量添加进 ALL_PREBUILT全局宏中:
ALL_PREBUILT += $(copy_to)
最后,在build/core/Makefile中看到copy_to的内容被提取到了另外一个全局宏 ,具体如下:
1 |
#build/core/Makefile |
2 |
|
3 |
INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%,$(ALL_PREBUILT) ...... |
由于上述4行内容设计到system.img的生成,在此不深究。
看来system/core/rootdir中的部分内容是拷贝到了out/target/product/tcc8800/system中的,并不是
完完全全拷贝到out/target/product/tcc8800/root目录中去的。
我们回头继续查看system/core/rootdir/Android.mk文件,该文件中剩下的内容才是与root密切相关的。
file := $(TARGET_ROOT_OUT)/init.rc
然后也是经典的拷贝设置:
1 |
$( file ) : $(LOCAL_PATH)/% | $(ACP) |
2 |
|
3 |
$(transform-prebuilt-to-target) |
接下来的脚本的内容是为生成boot.img而写的。
1 |
ALL_PREBUILT +=$( file ) |
2 |
|
3 |
$(INSTALLED_RAMDISK_TARGET):$( file ) |
看来原理也和上述system的拷贝相同,在build/core/Makefile中是由INTERNAL_RAMDISK_FILE提取的,
具体如下:INTERNAL_RAMDISK_FILES := $(filter $(TARGET_ROOT_OUT)/%, $(ALL_PREBUILT) ...
随后有一段很关键的句子直接道破了ramdisk.img的生成:
1 |
INSTALLED_RAMDISK_TARGET=$(BUILT_RAMDISK_TARGET) |
2 |
|
3 |
$(INSTALLED_RAMDISK_TARGET):$(MKBOOTFS $(INTERNAL_RAMDISK_FILES | $(MINIGZIP) |
4 |
|
5 |
$(hide) $(MKBOOTFS) $(TARGET_ROOT_OUT) | $(MINIGZIP) > $@ |
如此多的宏,让我们一一列出它们的值:
BUILT_RAMDISK_TARGET = $(PRODUCT_OUT/ramdisk.img 这是我们的目标
INSTALLED_RAMDISK_TARGET = BUILT_RAMDISK_TARGET 目标伪装了一下。
MKBOOTFS = mkbootfs 就是位于out/host/linux-x86/bin目录下的mkbootfs,这东西自然也有后话。
INTERNAL_RAMDISK_FILES = 所有TARGET_ROOT_OUT中的文件
由此可以看出root目录先被打包生成了ramdisk.img,然后才合并进boot.img的。
[Android]构建boot.img(二):kernel的拷贝与打包
上文已经对boot.img其中组成部分之一ramdisk.img做了分析,boot.img另外一个重要的组成部分就是kernel了,
这里所说的kernel,可以只理解为位于out/target/product/tcc8800/中的kernel文件,本文主要分析kernel的拷贝
过程以及如何被打包到boot.img中。经过分析得知位于out/target/product/tcc8800/中的kernel文件其实就是内核
编译后的Image文件,位于kernel/arch/arm/boot目录下,线索就是这个Image文件,经过搜索发现一处定义:
LOCAL_KERNEL := kernel/arch/arm/boot/Image
该定义位于devices/telechips/tcc88xx-common/BoardConfigCommon.mk中,紧接着,在同目录的Android.mk中
有以下一段定义:
1 |
PRODUCT_COPY_FILES += \ |
2 |
|
3 |
$(LOCAL_KERNEL):kernel |
意在将Image文件拷贝且重命名为kernel,随后的拷贝设置是在build/core/Makefile中完成的,在此略掉。
那么,拷贝完成后,kernel文件如何被打包到boot.img中呢?同样在build/core/Makefile中有以下一段内容:
INTERNAL_BOOTIMAGE_ARGS := ... --kernel $(INSTALLED_KERNEL_TARGET)
现在的问题就是查看 INSTALLED_KERNEL_TARGET的定义,该宏位于build/target/board/Android.mk中:
INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
内容很明显了,至此,内核Image算是到位了。
另外INSTALL_KERNEL_TARGET定义在build/target/board/Android.mk中有点怪怪的,
build/target/board/Android.mk在main.mk中通过subdir_makefiles抽取得到,并包含进main.mk中
[Android]构建boot.img(三):boot.img的生成与结构
1 |
#build/core/Makefile |
2 |
|
3 |
INTERNAL_BOOTIMAGE_ARGS := \ |
4 |
|
5 |
--kernel $(INSTALLED_KERNEL_TARGET) \ |
6 |
|
7 |
--ramdisk $(INSTALLED_RAMDISK_TARGET) |
显然,boot.img中包含了Image和ramdisk.img文件,但boot.img中的内容远不只这么多,本文将介绍
boot.img中的其它参数,boot.img的生成以及最终boot.img的组成格式.
INTERNAL_BOOTIMAGE_ARGS还包含以下内容:
1.附加的内核命令行(cmdline): BOARD_KERNEL_CMDLINE
同样在build/core/Makefile中,有以下一段内容(strip起到去除空格的作用):
1 |
BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE) |
2 |
|
3 |
ifdef BOARD_KERNEL_CMDLINE |
4 |
|
5 |
INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)" |
6 |
|
7 |
#endif |
而BOARD_KERNEL_CMDLINE则在文件device/telechips/tcc88xx-common/BoardConfigCommon.mk中定义:
1 |
BOARD_KERNEL_CMDLINE := console=ttyTCC, 115200n8 |
2.内核加载的基地址,BOARD_KERNEL_BASE
同样在build/core/Makefile中,有以下一段内容:
1 |
BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE)) |
2 |
|
3 |
ifdef BOARD_KERNEL_BASE |
4 |
|
5 |
INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE) |
6 |
|
7 |
endif |
而BOARD_KERNEL_BASE也在device/telechips/tcc88xx-common/BoardConfigCommon.mk中定义。
1 |
BOARD_KERNEL_BASE := 0x40000000 |
3.映像的页面大小:BOARD_KERNEL_PAGESIZE
同样在build/core/Makefile中,有以下一段内容:
1 |
BOARD_KERNEL_PAGESIZE:= $(strip $(BOARD_KERNEL_PAGESIZE)) |
2 |
|
3 |
ifdef BOARD_KERNEL_PAGESIZE |
4 |
|
5 |
INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE) |
6 |
|
7 |
endif |
而BOARD_KERNEL_PAGESIZE 却在device/telechips/tcc8800/BoardConfig.mk中定义:
1 |
BOARD_KERNEL_PAGESIZE := 8192 |
剩下的内容就是生成boot.img的关键语句,在 build/core/Makefile中,内容如下:
1 |
INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img |
2 |
|
3 |
$(INTALLED_BOOTIMAGE_TARGET) : $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILE |
4 |
|
5 |
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@ |
到此,我们可以知道 INTERNAL_BOOTIMAGE_ARGS的内容是:
1 |
--kernel out/target/product/tcc8800/kernel |
2 |
--ramdisk out/target/product/tcc8800/ramdisk.img |
3 |
--cmdline console=ttyTCC,115200n8 |
4 |
--base 0x40000000 --pagesize 8192 |
而预知boot.img的格式,必须查看MKBOOTIMG这个程序,其实就是out/host/linux-x86/bin/mkbootimg中的mkbootimg程序。
mkbootimg程序由system/core/mkbootimg工程生成得到,为此我们来看看其中的mkbootimg.c文件,其中有这样一段:
01 |
//信息头部分 |
02 |
if (write(fd,&hdr, sizeof (hdr)) != sizeof (hdr)) goto fail; |
03 |
if (write_padding(fd,pagesize, sizeof (hdr))) goto fail; |
04 |
|
05 |
//内核部分 |
06 |
if (write(fd,&kernel_data, hdr.kernel_size)!= hdr.kernel_size) |
07 |
goto fail; |
08 |
if (write_padding(fd,pagesize,hdr.kernel_size)) goto fail; |
09 |
|
10 |
//文件系统部分 |
11 |
if (write(fd,&ramdisk_data,hdr.ramdisk_size)!= hdr.ramdisk_size) |
12 |
goto fail; |
13 |
if (wirte_padding(fd,pagesize,hdr.ramdisk_size)) goto fail; |
可见boot.img是由文件头信息,内核数据以及文件系统数据组成,它们之间非页面对齐部分用0填充(可以
查看write_padding的代码),文件头信息的具体结构可以在system/core/mkbootimg/bootimg.h中看到:
01 |
struct boot_img_hdr |
02 |
|
03 |
{
|
04 |
|
05 |
unsigned char magic[BOOT_MAGIC_SIZE]; |
06 |
|
07 |
unsigned kernel_size; |
08 |
|
09 |
unsigned kernel_addr; |
10 |
|
11 |
unsigned ramdisk_size; |
12 |
|
13 |
unsigned ramdisk_addr; |
14 |
|
15 |
unsigned second_size; |
16 |
|
17 |
unsigned second_addr; |
18 |
|
19 |
unsigned tags_addr; |
20 |
|
21 |
unsigned page_size; |
22 |
|
23 |
unsigned unused[2]; |
24 |
|
25 |
unsigned char name[BOOT_NAME_SIZE] |
26 |
|
27 |
unsigned char cmdline[BOOT_ARGS_SIZE] |
28 |
|
29 |
unsigned id [8]; //存放时间戳,校验和,SHA加密等内容 |
30 |
|
31 |
} |
其它成员也很明了,由此可知boot.img的大致组成结构了
from http://my.oschina.net/armsky/blog/32018
文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文
文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作 导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释: cwy_init/init_123..._达梦数据库导入导出
文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js
文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6
文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输
文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...
文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure
文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割
文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答
文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。
文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入
文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf