rk3188--1.mkimage.sh及cpio打包过程分析
2016-06-13 16:05
477 查看
一. mkimage.sh
1. android目录下的mkimage.sh
. build/envsetup.sh >/dev/null && setpaths
export PATH=ANDROIDBUILDPATHS:PATH
TARGET=”withoutkernel”
if [ “1”x!=“”x];thenTARGET=1
fi
rm -rf rockdev/Image
mkdir -p rockdev/Image
//在init.rk30board.rc中搜索字符串mtd@system,发现其分区类型为ext4
FSTYPE=
if [ “$FSTYPE” = “” ]; then
FSTYPE=
fi
echo system filesysystem is $FSTYPE
BOARD_CONFIG=device/rockchip/rk30sdk/device.mk
//KERNLE_SRC_PATH为空
KERNEL_SRC_PATH=
[ $(id -u) -eq 0 ] || FAKEROOT=fakeroot
BOOT_OTA=”ota”
echo “TARGET=TARGET”[TARGET != BOOTOTA−aTARGET != "withoutkernel" ] && echo "unknow target[${TARGET}],exit!” && exit 0
//1.boot.img的生成过程
if [ TARGET==BOOT_OTA ] //TARGET=withoutkernel, BOOT_OTA=ota不相等,执行else
then
echo “make ota images… ”
echo -n “create boot.img with kernel… ”
[ -d OUT/root ] && \
mkbootfsOUT/root | minigzip > OUT/ramdisk.img && \
mkbootimg –kernelOUT/kernel --ramdisk OUT/ramdisk.img–outputOUT/boot.img && \
cp -a OUT/boot.imgrockdev/Image/echo“done.”elseecho−n“createboot.imgwithoutkernel…”[−dOUT/root ] && \ //目录out/target/product/rk30sdk/root存在
mkbootfs OUT/root|minigzip>OUT/ramdisk.img && \ //1.将root下的每个文件加上cpio头+每个文件的内容,打包成cpios格式
rkst/mkkrnlimg OUT/ramdisk.imgrockdev/Image/boot.img//2.将这个cpio文件用gzip压缩后写到文件ramdisk.img中echo“done.”//3.mkkrnlimg会对ramdisk.img加上8个字节的头标志,尾部加上4个字字fi//2.recovery.img的生成过程echo−n“createrecovery.imgwithkernel…”[−dOUT/recovery/root ] && \
mkbootfs OUT/recovery/root|minigzip>OUT/ramdisk-recovery.img && \
mkbootimg –kernel OUT/kernel−−ramdiskOUT/ramdisk-recovery.img –output OUT/recovery.img && \
cp -aOUT/recovery.img rockdev/Image/
echo “done.”
//3.system.img的生成过程
if [ -d OUT/system]thenecho−n“createsystem.img…”if[“FSTYPE” = “cramfs” ]
then
chmod -R 777 OUT/systemFAKEROOT mkfs.cramfs OUT/systemrockdev/Image/system.imgelif[“FSTYPE” = “squashfs” ]
then
chmod -R 777 OUT/systemmksquashfsOUT/system rockdev/Image/system.img -all-root >/dev/null
elif [ “FSTYPE"="ext3"]||["FSTYPE” = “ext4” ]
then //ext3或ext4的生成过程
delta=5120
num_blocks=
num_blocks=((num_blocks + $delta))
fi
chmod a+r -R rockdev/Image/
2. mkbootfs分析
mkbootfs在system/core/cpio/mkbootfs.c中
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
static void _archive_dir(char *in, char *out, int ilen, int olen)
{
int i, t;
DIR *d;
struct dirent *de;
DIR* d = opendir(in); //打开目录
}
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
–> _archive //对普通文件 目录 链接分开处理
static void _archive(char *in, char *out, int ilen, int olen)
{
struct stat s;
if(S_ISREG(s.st_mode)){ //1.对普通文件的处理
int fd = open(in, O_RDONLY);
char* tmp = (char*) malloc(s.st_size);
read(fd, tmp, s.st_size);
_eject(&s, out, olen, tmp, s.st_size);
free(tmp);
close(fd);
} else if(S_ISDIR(s.st_mode)) { //2.对目录的处理
_eject(&s, out, olen, 0, 0);
_archive_dir(in, out, ilen, olen);
} else if(S_ISLNK(s.st_mode)) { //3.对链接文件的处理
char buf[1024];
int size;
size = readlink(in, buf, 1024); //调用readlink读符号链接的大小及内容
_eject(&s, out, olen, buf, size);
} else {
die(“Unknown ‘%s’ (mode %d)?\n”, in, s.st_mode);
}
}
注: 符号链接
假设有这样的符号连接
ln -s /home/cong/Desktop/record.txt link
则调用readlink后,buf=”/home/cong/Desktop/record.txt”, size=sizeof(“/home/cong/Desktop/record.txt”);
即realink所读到的就是link所指向的路径的内容及长度
函数的作用是:把文件的信息与文件的内容写到ramdisk.img中去
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
–> _archive //对普通文件 目录 链接分开处理
–> _eject //将文件信息与内容写入到ramdisk.img中去
static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
{
static unsigned next_inode = 300000;
}
最后写入一个结束标志:
static void _eject_trailer()
{
struct stat s;
memset(&s, 0, sizeof(s));
_eject(&s, “TRAILER!!!”, 10, 0, 0);
}
注: CPIO 的结构包括:
110字节的Head(6 + 8*13)
不定长的文件名(文件名的长度是olen)
结束字符 \0
文件的内容
…. //重复上面4个
最后的文件名是一个 TRAILER!!!
附1. ramdisk.img的解压过程
cong@ubuntu:/tmp/testfile./bak/ramdisk.img./bak/ramdisk.img:gzipcompresseddata,fromUnixcong@ubuntu:/tmp/test cp ./bak/ramdisk.img ./bak/ramdisk.img_bak.gz //重新copy一份
cong@ubuntu:/tmp/testgunzip./bak/ramdisk.imgbak.gz//gunzip解压缩cong@ubuntu:/tmp/test ls ./bak/
ramdisk.img ramdisk.img_bak ramdisk.img.gz
cong@ubuntu:/tmp/testfile./bak/ramdisk.imgbak//解压后的文件就是cpio格式的./bak/ramdisk.imgbak:ASCIIcpioarchive(SVR4withnoCRC)cong@ubuntu:/tmp/test cpio -i -F ./bak/ramdisk.img_bak //解压cpio格式
463 blocks
cong@ubuntu:/tmp/testls//这就能看到所有文件了bakdatadefault.propdevforlinx.rcinitinit.goldfish.rcinit.rclinuxrcprocsbinsyssystemueventd.goldfish.rcueventd.rccong@ubuntu:/tmp/test
1. android目录下的mkimage.sh
!/bin/bash
set -e. build/envsetup.sh >/dev/null && setpaths
export PATH=ANDROIDBUILDPATHS:PATH
TARGET=”withoutkernel”
if [ “1”x!=“”x];thenTARGET=1
fi
rm -rf rockdev/Image
mkdir -p rockdev/Image
//在init.rk30board.rc中搜索字符串mtd@system,发现其分区类型为ext4
FSTYPE=
grep 'mtd@system' $OUT/root/init.rk30board.rc | head -n 1 | awk '{ print $2 }'
if [ “$FSTYPE” = “” ]; then
FSTYPE=
grep 'mtd@system' $OUT/root/init.rc | head -n 1 | awk '{ print $2 }'
fi
echo system filesysystem is $FSTYPE
BOARD_CONFIG=device/rockchip/rk30sdk/device.mk
//KERNLE_SRC_PATH为空
KERNEL_SRC_PATH=
grep TARGET_PREBUILT_KERNEL ${BOARD_CONFIG} |grep "^\s*TARGET_PREBUILT_KERNEL *:= *[\w]*\s" |awk '{print $3}'
[ $(id -u) -eq 0 ] || FAKEROOT=fakeroot
BOOT_OTA=”ota”
echo “TARGET=TARGET”[TARGET != BOOTOTA−aTARGET != "withoutkernel" ] && echo "unknow target[${TARGET}],exit!” && exit 0
if [ ! -f $OUT/kernel ] //这个文件存在不执行以下 then echo "kernel image not fount![$OUT/kernel] " read -p "copy kernel from TARGET_PREBUILT_KERNEL[$KERNEL_SRC_PATH] (y/n) n to exit?" if [ "$REPLY" == "y" ] then [ -f $KERNEL_SRC_PATH ] || \ echo -n "fatal! TARGET_PREBUILT_KERNEL not eixit! " || \ echo -n "check you configuration in [${BOARD_CONFIG}] " || exit 0 cp ${KERNEL_SRC_PATH} $OUT/kernel else exit 0 fi fi
//1.boot.img的生成过程
if [ TARGET==BOOT_OTA ] //TARGET=withoutkernel, BOOT_OTA=ota不相等,执行else
then
echo “make ota images… ”
echo -n “create boot.img with kernel… ”
[ -d OUT/root ] && \
mkbootfsOUT/root | minigzip > OUT/ramdisk.img && \
mkbootimg –kernelOUT/kernel --ramdisk OUT/ramdisk.img–outputOUT/boot.img && \
cp -a OUT/boot.imgrockdev/Image/echo“done.”elseecho−n“createboot.imgwithoutkernel…”[−dOUT/root ] && \ //目录out/target/product/rk30sdk/root存在
mkbootfs OUT/root|minigzip>OUT/ramdisk.img && \ //1.将root下的每个文件加上cpio头+每个文件的内容,打包成cpios格式
rkst/mkkrnlimg OUT/ramdisk.imgrockdev/Image/boot.img//2.将这个cpio文件用gzip压缩后写到文件ramdisk.img中echo“done.”//3.mkkrnlimg会对ramdisk.img加上8个字节的头标志,尾部加上4个字字fi//2.recovery.img的生成过程echo−n“createrecovery.imgwithkernel…”[−dOUT/recovery/root ] && \
mkbootfs OUT/recovery/root|minigzip>OUT/ramdisk-recovery.img && \
mkbootimg –kernel OUT/kernel−−ramdiskOUT/ramdisk-recovery.img –output OUT/recovery.img && \
cp -aOUT/recovery.img rockdev/Image/
echo “done.”
echo -n "create misc.img.... " cp -a rkst/Image/misc.img rockdev/Image/misc.img cp -a rkst/Image/pcba_small_misc.img rockdev/Image/pcba_small_misc.img cp -a rkst/Image/pcba_whole_misc.img rockdev/Image/pcba_whole_misc.img echo "done."
//3.system.img的生成过程
if [ -d OUT/system]thenecho−n“createsystem.img…”if[“FSTYPE” = “cramfs” ]
then
chmod -R 777 OUT/systemFAKEROOT mkfs.cramfs OUT/systemrockdev/Image/system.imgelif[“FSTYPE” = “squashfs” ]
then
chmod -R 777 OUT/systemmksquashfsOUT/system rockdev/Image/system.img -all-root >/dev/null
elif [ “FSTYPE"="ext3"]||["FSTYPE” = “ext4” ]
then //ext3或ext4的生成过程
delta=5120
num_blocks=
du -sk $OUT/system | tail -n1 | awk '{print $1;}'
num_blocks=((num_blocks + $delta))
num_inodes=`find $OUT/system | wc -l` num_inodes=$(($num_inodes + 500)) ok=0 while [ "$ok" = "0" ]; do genext2fs -a -d $OUT/system -b $num_blocks -N $num_inodes -m 0 rockdev/Image/system.img >/dev/null 2>&1 && \ tune2fs -j -L system -c -1 -i 0 rockdev/Image/system.img >/dev/null 2>&1 && \ ok=1 || num_blocks=$(($num_blocks + $delta)) done e2fsck -fy rockdev/Image/system.img >/dev/null 2>&1 || true delta=1024 num_blocks=`resize2fs -P rockdev/Image/system.img 2>&1 | tail -n1 | awk '{print $7;}'` rm -f rockdev/Image/system.img ok=0 while [ "$ok" = "0" ]; do genext2fs -a -d $OUT/system -b $num_blocks -N $num_inodes -m 0 rockdev/Image/system.img >/dev/null 2>&1 && \ tune2fs -O dir_index,filetype,sparse_super -j -L system -c -1 -i 0 rockdev/Image/system.img >/dev/null 2>&1 && \ ok=1 || num_blocks=$(($num_blocks + $delta)) done e2fsck -fyD rockdev/Image/system.img >/dev/null 2>&1 || true else mkdir -p rockdev/Image/2k rockdev/Image/4k mkyaffs2image -c 2032 -s 16 -f $OUT/system rockdev/Image/2k/system.img mkyaffs2image -c 4080 -s 16 -f $OUT/system rockdev/Image/4k/system.img fi echo "done."
fi
chmod a+r -R rockdev/Image/
2. mkbootfs分析
mkbootfs在system/core/cpio/mkbootfs.c中
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
static void _archive_dir(char *in, char *out, int ilen, int olen)
{
int i, t;
DIR *d;
struct dirent *de;
DIR* d = opendir(in); //打开目录
int size = 32; int entries = 0; char** names = malloc(size * sizeof(char*)); //每次分配32个文件名的内存 //将./out/target/product/rk30sdk/root目录下所有的文件名存在name数组中 while((de = readdir(d)) != 0){ if(de->d_name[0] == '.') continue; //跳过.目录 if(!strcmp(de->d_name, "root")) continue; //排除root,这是为了什么? if (entries >= size) { size *= 2; //如果超出32个文件名,则再多分配32*2个,依次类推 names = realloc(names, size * sizeof(char*)); //realloc,又学习了一招 } names[entries] = strdup(de->d_name); //strdup可以分配内存并复制 ++entries; } //对name数组中的文件名进行排序 qsort(names, entries, sizeof(char*), compare); for (i = 0; i < entries; ++i) { t = strlen(names[i]); in[ilen] = '/'; memcpy(in + ilen + 1, names[i], t + 1); if(olen > 0) { //out为空 out[olen] = '/'; memcpy(out + olen + 1, names[i], t + 1); _archive(in, out, ilen + t + 1, olen + t + 1); } else { memcpy(out, names[i], t + 1); //将文件名复制到out中 _archive(in, out, ilen + t + 1, t); //将这个文件打包到ramdisk.img中 } in[ilen] = 0; out[olen] = 0; free(names[i]); } free(names);
}
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
–> _archive //对普通文件 目录 链接分开处理
static void _archive(char *in, char *out, int ilen, int olen)
{
struct stat s;
if(S_ISREG(s.st_mode)){ //1.对普通文件的处理
int fd = open(in, O_RDONLY);
char* tmp = (char*) malloc(s.st_size);
read(fd, tmp, s.st_size);
_eject(&s, out, olen, tmp, s.st_size);
free(tmp);
close(fd);
} else if(S_ISDIR(s.st_mode)) { //2.对目录的处理
_eject(&s, out, olen, 0, 0);
_archive_dir(in, out, ilen, olen);
} else if(S_ISLNK(s.st_mode)) { //3.对链接文件的处理
char buf[1024];
int size;
size = readlink(in, buf, 1024); //调用readlink读符号链接的大小及内容
_eject(&s, out, olen, buf, size);
} else {
die(“Unknown ‘%s’ (mode %d)?\n”, in, s.st_mode);
}
}
注: 符号链接
假设有这样的符号连接
ln -s /home/cong/Desktop/record.txt link
则调用readlink后,buf=”/home/cong/Desktop/record.txt”, size=sizeof(“/home/cong/Desktop/record.txt”);
即realink所读到的就是link所指向的路径的内容及长度
函数的作用是:把文件的信息与文件的内容写到ramdisk.img中去
mkbootfs $OUT/root
main
–> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
–> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
–> _archive //对普通文件 目录 链接分开处理
–> _eject //将文件信息与内容写入到ramdisk.img中去
static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
{
static unsigned next_inode = 300000;
while(total_size & 3) { total_size++; putchar(0); } fix_stat(out, s); //这儿的printf实际上是要写入到ramdisk.img中去的 printf("%06x%08x%08x%08x%08x%08x%08x" "%08x%08x%08x%08x%08x%08x%08x%s%c", 0x070701, <<<<--- 标志 next_inode++, // s.st_ino, //inode_number s->st_mode, //mode 0, // s.st_uid, //uid 0, // s.st_gid, //gid 1, // s.st_nlink, //链接数 0, // s.st_mtime, //最后修改时间 datasize, //文件长度 0, // volmajor //主号 0, // volminor //次号 0, // devmajor //主设备号 0, // devminor, //次设备号 olen + 1, //name_len名字长度 0, --->>>> out, 0 ); total_size += 6 + 8*13 + olen + 1; while(total_size & 3) { total_size++; putchar(0); } if(datasize) { fwrite(data, datasize, 1, stdout); //这是文件的内容 total_size += datasize; }
}
最后写入一个结束标志:
static void _eject_trailer()
{
struct stat s;
memset(&s, 0, sizeof(s));
_eject(&s, “TRAILER!!!”, 10, 0, 0);
while(total_size & 0xff) { total_size++; putchar(0); }
}
注: CPIO 的结构包括:
110字节的Head(6 + 8*13)
不定长的文件名(文件名的长度是olen)
结束字符 \0
文件的内容
…. //重复上面4个
最后的文件名是一个 TRAILER!!!
附1. ramdisk.img的解压过程
cong@ubuntu:/tmp/testfile./bak/ramdisk.img./bak/ramdisk.img:gzipcompresseddata,fromUnixcong@ubuntu:/tmp/test cp ./bak/ramdisk.img ./bak/ramdisk.img_bak.gz //重新copy一份
cong@ubuntu:/tmp/testgunzip./bak/ramdisk.imgbak.gz//gunzip解压缩cong@ubuntu:/tmp/test ls ./bak/
ramdisk.img ramdisk.img_bak ramdisk.img.gz
cong@ubuntu:/tmp/testfile./bak/ramdisk.imgbak//解压后的文件就是cpio格式的./bak/ramdisk.imgbak:ASCIIcpioarchive(SVR4withnoCRC)cong@ubuntu:/tmp/test cpio -i -F ./bak/ramdisk.img_bak //解压cpio格式
463 blocks
cong@ubuntu:/tmp/testls//这就能看到所有文件了bakdatadefault.propdevforlinx.rcinitinit.goldfish.rcinit.rclinuxrcprocsbinsyssystemueventd.goldfish.rcueventd.rccong@ubuntu:/tmp/test
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories