Chinaunix首页 | 论坛 | 博客

OS

  • 博客访问: 2228842
  • 博文数量: 691
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2660
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-05 12:49
个人简介

不浮躁

文章分类

全部博文(691)

文章存档

2019年(1)

2017年(12)

2016年(99)

2015年(207)

2014年(372)

分类: Android平台

2014-12-07 17:14:55

一.  mkimage.sh
1. android目录下的mkimage.sh
  1. #!/bin/bash
  2. set -e

  3. . build/envsetup.sh >/dev/null && setpaths

  4. export PATH=$ANDROID_BUILD_PATHS:$PATH

  5. TARGET="withoutkernel"
  6. if [ "$1"x != ""x ]; then
  7.          TARGET=$1
  8. fi
  9. rm -rf rockdev/Image
  10. mkdir -p rockdev/Image

 //在init.rk30board.rc中搜索字符串mtd@system,发现其分区类型为ext4

  1. FSTYPE=`grep 'mtd@system' $OUT/root/init.rk30board.rc | head -n 1 | awk '{ print $2 }'`
  2. if [ "$FSTYPE" = "" ]; then
  3.        FSTYPE=`grep 'mtd@system' $OUT/root/init.rc | head -n 1 | awk '{ print $2 }'`
  4. fi
  5. echo system filesysystem is $FSTYPE

  6. BOARD_CONFIG=device/rockchip/rk30sdk/device.mk
  7. //KERNLE_SRC_PATH为空
  8. KERNEL_SRC_PATH=`grep TARGET_PREBUILT_KERNEL ${BOARD_CONFIG} |grep "^\s*TARGET_PREBUILT_KERNEL *:= *[\w]*\s" |awk '{print $3}'`
  9. [ $(id -u) -eq 0 ] || FAKEROOT=fakeroot

  10. BOOT_OTA="ota"
  11. echo "TARGET=$TARGET"
  12. [ $TARGET != $BOOT_OTA -a $TARGET != "withoutkernel" ] && echo "unknow target[${TARGET}],exit!" && exit 0

  13.     if [ ! -f $OUT/kernel ]   //这个文件存在不执行以下
  14.     then
  15.      echo "kernel image not fount![$OUT/kernel] "
  16.         read -p "copy kernel from TARGET_PREBUILT_KERNEL[$KERNEL_SRC_PATH] (y/n) n to exit?"
  17.         if [ "$REPLY" == "y" ]
  18.         then
  19.             [ -f $KERNEL_SRC_PATH ] || \
  20.                 echo -n "fatal! TARGET_PREBUILT_KERNEL not eixit! " || \
  21.                 echo -n "check you configuration in [${BOARD_CONFIG}] " || exit 0

  22.             cp ${KERNEL_SRC_PATH} $OUT/kernel

  23.         else
  24.             exit 0
  25.         fi
  26.     fi

   //1.boot.img的生成过程

  1. if [ $TARGET == $BOOT_OTA ]   //TARGET=withoutkernel, BOOT_OTA=ota不相等,执行else
  2. then
  3.     echo "make ota images... "
  4.     echo -n "create boot.img with kernel... "
  5.     [ -d $OUT/root ] && \
  6.     mkbootfs $OUT/root | minigzip > $OUT/ramdisk.img && \
  7.     mkbootimg --kernel $OUT/kernel --ramdisk $OUT/ramdisk.img --output $OUT/boot.img && \
  8.     cp -a $OUT/boot.img rockdev/Image/
  9.     echo "done."
  10. else
  11.     echo -n "create boot.img without kernel... "
  12.     [ -d $OUT/root ] && \                                    //目录out/target/product/rk30sdk/root存在
  13.     mkbootfs $OUT/root | minigzip > $OUT/ramdisk.img && \    //1.将root下的每个文件加上cpio头+每个文件的内容,打包成cpios格式
  14.     rkst/mkkrnlimg $OUT/ramdisk.img rockdev/Image/boot.img   //2. 将这个cpio文件用gzip压缩后写到文件ramdisk.img中
  15.     echo "done."                                             //3. mkkrnlimg会对ramdisk.img加上8个字节的头标志,尾部加上4个字字
  16. fi
  17.     //2.recovery.img的生成过程
  18.     echo -n "create recovery.img with kernel... "
  19.     [ -d $OUT/recovery/root ] && \
  20.     mkbootfs $OUT/recovery/root | minigzip > $OUT/ramdisk-recovery.img && \
  21.     mkbootimg --kernel $OUT/kernel --ramdisk $OUT/ramdisk-recovery.img --output $OUT/recovery.img && \
  22.     cp -a $OUT/recovery.img rockdev/Image/
  23.     echo "done."

  24.     echo -n "create misc.img.... "
  25.     cp -a rkst/Image/misc.img rockdev/Image/misc.img
  26.     cp -a rkst/Image/pcba_small_misc.img rockdev/Image/pcba_small_misc.img
  27.     cp -a rkst/Image/pcba_whole_misc.img rockdev/Image/pcba_whole_misc.img
  28.     echo "done."
  29.   
  30.    //3.system.img的生成过程

  31. if [ -d $OUT/system ]
  32. then
  33.     echo -n "create system.img... "
  34.     if [ "$FSTYPE" = "cramfs" ]
  35.     then
  36.         chmod -R 777 $OUT/system
  37.         $FAKEROOT mkfs.cramfs $OUT/system rockdev/Image/system.img
  38.     elif [ "$FSTYPE" = "squashfs" ]
  39.     then
  40.         chmod -R 777 $OUT/system
  41.         mksquashfs $OUT/system rockdev/Image/system.img -all-root >/dev/null
  42.     elif [ "$FSTYPE" = "ext3" ] || [ "$FSTYPE" = "ext4" ]
  43.     then                                                      //ext3或ext4的生成过程
  44.         delta=5120
  45.         num_blocks=`du -sk $OUT/system | tail -n1 | awk '{print $1;}'`
  46.         num_blocks=$(($num_blocks + $delta))

  47.         num_inodes=`find $OUT/system | wc -l`
  48.         num_inodes=$(($num_inodes + 500))

  49.         ok=0
  50.         while [ "$ok" = "0" ]; do
  51.             genext2fs -a -d $OUT/system -b $num_blocks -N $num_inodes -m 0 rockdev/Image/system.img >/dev/null 2>&1 && \
  52.             tune2fs -j -L system -c -1 -i 0 rockdev/Image/system.img >/dev/null 2>&1 && \
  53.             ok=1 || num_blocks=$(($num_blocks + $delta))
  54.         done
  55.         e2fsck -fy rockdev/Image/system.img >/dev/null 2>&1 || true

  56.         delta=1024
  57.         num_blocks=`resize2fs -P rockdev/Image/system.img 2>&1 | tail -n1 | awk '{print $7;}'`
  58.         rm -f rockdev/Image/system.img
  59.         ok=0
  60.         while [ "$ok" = "0" ]; do
  61.             genext2fs -a -d $OUT/system -b $num_blocks -N $num_inodes -m 0 rockdev/Image/system.img >/dev/null 2>&1 && \
  62.             tune2fs -O dir_index,filetype,sparse_super -j -L system -c -1 -i 0 rockdev/Image/system.img >/dev/null 2>&1 && \
  63.             ok=1 || num_blocks=$(($num_blocks + $delta))
  64.         done
  65.         e2fsck -fyD rockdev/Image/system.img >/dev/null 2>&1 || true
  66.     else
  67.         mkdir -p rockdev/Image/2k rockdev/Image/4k
  68.         mkyaffs2image -c 2032 -s 16 -f $OUT/system rockdev/Image/2k/system.img
  69.         mkyaffs2image -c 4080 -s 16 -f $OUT/system rockdev/Image/4k/system.img
  70.     fi
  71.     echo "done."
  72. fi

  73. 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是打包后的文件路径
  1. static void _archive_dir(char *in, char *out, int ilen, int olen)
  2. {
  3.     int i, t;
  4.     DIR *d;
  5.     struct dirent *de;
  6.     DIR* d = opendir(in);  //打开目录

  7.     int size = 32;
  8.     int entries = 0;
  9.     char** names = malloc(size * sizeof(char*)); //每次分配32个文件名的内存
  10.     //将./out/target/product/rk30sdk/root目录下所有的文件名存在name数组中
  11.     while((de = readdir(d)) != 0){
  12.         if(de->d_name[0] == '.') continue;       //跳过.目录
  13.         if(!strcmp(de->d_name, "root")) continue; //排除root,这是为了什么?
  14.         if (entries >= size) {
  15.           size *= 2;                 //如果超出32个文件名,则再多分配32*2个,依次类推       
  16.           names = realloc(names, size * sizeof(char*));  //realloc,又学习了一招
  17.         }
  18.         names[entries] = strdup(de->d_name);   //strdup可以分配内存并复制
  19.         ++entries;
  20.     }
  21.     //对name数组中的文件名进行排序
  22.     qsort(names, entries, sizeof(char*), compare);  

  23.     for (i = 0; i < entries; ++i) {
  24.         t = strlen(names[i]);
  25.         in[ilen] = '/';
  26.         memcpy(in + ilen + 1, names[i], t + 1);

  27.         if(olen > 0) {                  //out
  28.             out[olen] = '/';
  29.             memcpy(out + olen + 1, names[i], t + 1);
  30.             _archive(in, out, ilen + t + 1, olen + t + 1);
  31.         } else {
  32.             memcpy(out, names[i], t + 1);       //将文件名复制到out中
  33.             _archive(in, out, ilen + t + 1, t); //将这个文件打包到ramdisk.img中
  34.         }

  35.         in[ilen] = 0;
  36.         out[olen] = 0;

  37.         free(names[i]);
  38.     }
  39.     free(names);
  40. }
mkbootfs $OUT/root
    main
       --> archive(*argv, x); //*argv 要打包的源文件路径, x是打包后的文件路径
        --> _archive_dir(in, out, strlen(in), strlen(out)); //in要打包的源文件路径, out是打包后的文件路径
        --> _archive    //对普通文件 目录  链接分开处理
  1. static void _archive(char *in, char *out, int ilen, int olen)
  2. {
  3.     struct stat s;
  4.     if(S_ISREG(s.st_mode)){       //1.对普通文件的处理
  5.         int fd = open(in, O_RDONLY);
  6.         char* tmp = (char*) malloc(s.st_size);
  7.         read(fd, tmp, s.st_size);
  8.         _eject(&s, out, olen, tmp, s.st_size);
  9.         free(tmp);
  10.         close(fd);
  11.     } else if(S_ISDIR(s.st_mode)) {  //2.对目录的处理
  12.         _eject(&s, out, olen, 0, 0);
  13.         _archive_dir(in, out, ilen, olen);
  14.     } else if(S_ISLNK(s.st_mode)) {  //3.对链接文件的处理
  15.         char buf[1024];
  16.         int size;
  17.         size = readlink(in, buf, 1024);    //调用readlink读符号链接的大小及内容
  18.         _eject(&s, out, olen, buf, size);  
  19.     } else {
  20.         die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
  21.     }
  22. }
注: 符号链接
假设有这样的符号连接
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中去
  1. static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
  2. {
  3.     static unsigned next_inode = 300000;

  4.     while(total_size & 3) {
  5.         total_size++;
  6.         putchar(0);
  7.     }

  8.     fix_stat(out, s);
  9.     //这儿的printf实际上是要写入到ramdisk.img中去的 
  10.     printf("%06x%08x%08x%08x%08x%08x%08x"
  11.            "%08x%08x%08x%08x%08x%08x%08x%s%c",
  12.            0x070701,                   <<<<---   标志
  13.            next_inode++, // s.st_ino,    //inode_number
  14.            s->st_mode,                   //mode
  15.            0, // s.st_uid,               //uid
  16.            0, // s.st_gid,               //gid
  17.            1, // s.st_nlink,             //链接数
  18.            0, // s.st_mtime,             //最后修改时间
  19.            datasize,                     //文件长度
  20.            0, // volmajor                //主号
  21.            0, // volminor                //次号
  22.            0, // devmajor                //主设备号
  23.            0, // devminor,               //次设备号
  24.            olen + 1,                     //name_len名字长度
  25.            0,                         --->>>>
  26.            out,
  27.            0
  28.            );

  29.     total_size += 6 + 8*13 + olen + 1;


  30.     while(total_size & 3) {
  31.         total_size++;
  32.         putchar(0);
  33.     }

  34.     if(datasize) {
  35.         fwrite(data, datasize, 1, stdout);   //这是文件的内容
  36.         total_size += datasize;
  37.     }
  38. }
 最后写入一个结束标志:
  1. static void _eject_trailer()
  2. {
  3.     struct stat s;
  4.     memset(&s, 0, sizeof(s));
  5.     _eject(&s, "TRAILER!!!", 10, 0, 0);

  6.     while(total_size & 0xff) {
  7.         total_size++;
  8.         putchar(0);
  9.     }
  10. }
注: CPIO 的结构包括:
                   110字节的Head(6 + 8*13)
                     不定长的文件名(文件名的长度是olen)
                     结束字符 \0
                     文件的内容
                     .... //重复上面4个
                   最后的文件名是一个 TRAILER!!!

附1. ramdisk.img的解压过程
  1. cong@ubuntu:/tmp/test$ file ./bak/ramdisk.img
  2. ./bak/ramdisk.img: gzip compressed data, from Unix
  3. cong@ubuntu:/tmp/test$ cp ./bak/ramdisk.img ./bak/ramdisk.img_bak.gz  //新copy一份
  4. cong@ubuntu:/tmp/test$ gunzip ./bak/ramdisk.img_bak.gz                //gunzip解压缩
  5. cong@ubuntu:/tmp/test$ ls ./bak/
  6. ramdisk.img ramdisk.img_bak ramdisk.img.gz
  7. cong@ubuntu:/tmp/test$ file ./bak/ramdisk.img_bak                     //解压后的文件就是cpio格式的
  8. ./bak/ramdisk.img_bak: ASCII cpio archive (SVR4 with no CRC)
  9. cong@ubuntu:/tmp/test$ cpio -i -F ./bak/ramdisk.img_bak               //解压cpio格式
  10. 463 blocks
  11. cong@ubuntu:/tmp/test$ ls                                             //这就能看到所有文件了
  12. bak data default.prop dev forlinx.rc init init.goldfish.rc init.rc linuxrc proc sbin sys system ueventd.goldfish.rc ueventd.rc
  13. cong@ubuntu:/tmp/test$

阅读(1509) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~