转载自https://www.jianshu.com/p/cae37c737d51
ramdisk.img是编译Android生成的一个镜像文件,最后和kernel一起打包生成boot.img镜像。ramdisk.img中主要是存放android启动后第一个用户进程init可执行文件和init.*.rc
等相关启动脚本以及sbin目录下的adbd工具。
file ramdisk.img
//ramdisk.img: gzip compressed data, from Unix
一个android12中的例子如下,
├── debug_ramdisk
├── dev
├── fstab.xxx
├── init
├── metadata
├── mnt
├── proc
├── second_stage_resources
├── sys
├── system
│ └── etc
│ └── ramdisk
│ └── build.prop
└── vendor
看出为gzip压缩过的文件,将ramdisk.img重命名为ramdisk.img.gz .
使用下面的命令可以把ramdisk解压出来
mv ramdisk.img ramdisk.img.gz
gunzip ramdisk.img.gz
file ramdisk.img
//ramdisk.img: ASCII cpio archive (SVR4 with no CRC)
cpio -i -F ramdisk.img
rootfs之所以存在,是因为需要在VFS机制下给系统提供最原始的挂载点。
1.initrd (init:initialized, rd:ramdisk)
在早期的linux系统中,一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。
为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块,可执行文件和启动脚本。当系统启动的时候,bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核
内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,
然后执行根目录中的/linuxrc脚本(cpio格式的initrd为/init
,而image格式的initrd<也称老式块设备的initrd或传统的文件镜像格式的initrd为/initrc
),
2.Initramfs
initramfs,它的作用和initrd类似,只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs
上
其中全局变量__initramfs_start
和__initramfs_end
分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs
段中的数据进行解压,然后使用它作为临时的根文件系统。
支持initrd的内核配置(需要内核支持内存盘驱动):
General setup->Initial RAM filesystem and RAM disk(initramfs/initrd) support
RamDisk内存盘驱动
Device Drivers->Block devices->RAM block device support
启动参数
Boot options->Default kernel command string
填写如下:mem=32M console=ttySAC0 root=/dev/ram initrd=0xc1000000,0x00600000 ramdisk_size=8192 rw
cpio
cpio 可以从 cpio 或 tar 格式的归档包中存入和读取文件, 归档包是一种包含其他文件和有关信息的文件。 有关信息包括:文件名, 属主, 时标(timestamp), 和访问权限。 归档包可以是磁盘上的 其他文件, 也可以是磁带或管道。
cpio命令有三种操作模式:copy-out、copy-in、copy-pass,生成 ramdisk.img 用的是它的copy-out模式,即把文件打包的操作模式。cpio的copy-out操作模式使用 -o
命令行选项指定
cd ~/root
find . | cpio -o -Hnewc |gzip -9 > ../image.cpio.gz
rootfs 启动过程
rootfs是ramfs或tmpfs的一种实例,它不能被umount,对于内核而言,rootfs体积小且简单,主要用于确保某些目录不能为空。
ramfs是一种非常简单的RAM系统,它基于linux系统硬盘缓冲机制,可以动态改变大小。
__init start_kernel(void)
vfs_caches_init_early();
dcache_init_early();
inode_init_early();
--> vfs_caches_init(num_physpages);
dcache_init();
inode_init();
files_init(mempages);
--> mnt_init();
--> init_rootfs();
--> init_mount_tree();
以上代码中,从start_kernel开始,初始化虚拟文件系统,包括dcache、inode初始,创建内核对象fs,然后开始初始化rootfs。
内核挂载rootfs之后需要将ramdisk中的解压到rootfs中,因此内核必须知道ramdisk在内存上的地址。已知有三种方式可以通知内核ramdisk的位置。
1.通过cmdline传入
2.bootloader 通过setup_initrd_tag函数把initrd_start设置到内核 tag中,内核通过parse_tag解析
init_mount_tree(void)
vfs_kern_mount(type, 0, "rootfs", NULL);
rootfs_mount(struct file_system_type *fs_type,
//内核就把rootfs挂载起来了,此时rootfs还是个空目录,并且只有一个根目录‘/’。
do_initcalls(void)
define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
populate_rootfs(void)
unpack_to_rootfs
//unpack_to_rootfs会先解压ramdisk成一个cpio文件,然后解析解析cpio文件中所有文件,并生成对应的文件到rootfs中
ramdisk的制作
out/host/linux-x86/bin/mkbootfs out/target/product//root | out/host/linux-x86/bin/minigzip > out/target/product//ramdisk.img
上述命令分两步进行:
out/host/linux-x86/bin/mkbootfs out/target/product/*/root
生成一个cpio文件,利用cpio 可将文件或目录从文件库获取出来或将散列文件拷贝到文件库。
out/host/linux-x86/bin/minigzip
将生成的cpio文件压缩成一个gzip格式的文件out/target/product/*/ramdisk.img
mkbootfs
mkbootfs 生成ramdisk.img ( 源码在system/core/cpio)
$(hide) $(MKBOOTFS) $(TARGET_ROOT_OUT) | $(MINIGZIP) > $@
mkbootimg
mkbootimg的源代码在system/core/mkbootimg中。
mkbootimg --kernel kernel --ramdisk ramdisk.img --output /tmp/boot.img
minigzip
minigzip的源代码在external/zlib中。
fs_config
源码位于:build/tools/fs_config。
其中的fs_config.c包含了system/core/include/private/android_filesystem_config.h,真正权限配置和fs_config的实现都在这个头文件中。
signapk
signapk的源码位于:build/tools/signapk。
评论 (0)