以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
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法