以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
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数