aosp源码分析 5.0 BlockImageUpdateFn

block_image_update("/dev/block/bootdevice/by-name/system", package_extract_file("system.transfer.list"), "system.new.dat", "system.patch.dat");

// args:
//    - block device (or file) to modify in-place
//    - transfer list (blob)
//    - new data stream (filename within package.zip)
//    - patch stream (filename within package.zip, must be uncompressed)
 
Value* BlockImageUpdateFn( const   char * name, State* state,  int   argc, Expr* argv[]) {
     Value* blockdev_filename;
     Value* transfer_list_value;
     char * transfer_list = NULL;
     Value* new_data_fn;
     Value* patch_data_fn;
     bool   success =  false ;
 
// 因为 block_image_update 中有类似p ackage_extract_file("system.transfer.list")这种还需要执行
// 才能得到返回值的函数
// 在 ReadValueArgs 中利用va_list等C语言的可变参数宏,将block_image_update的四个输入参数
"/dev/block/bootdevice/by-name/system", package_extract_file("system.transfer.list"), "system.new.dat", "system.patch.dat",分别赋值给 blockdev_filename transfer_list_value new_data_fn patch_data_fn
     if   (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
                       &new_data_fn, &patch_data_fn) < 0) {
         return   NULL;
     }
 
     if   (blockdev_filename->type != VAL_STRING) {
         ErrorAbort(state,  "blockdev_filename argument to %s must be string" , name);
         goto   done;
     }

//在 package_extract_file("system.transfer.list"), 中将type设为了VAL_BLOB
// BLOB  (binary large object),二进制大对象,是一个可以存储二进制文件的容器
BLOB 是一个大文件,典型的 BLOB 是一张图片或一个声音文件,由于它们的尺寸,必须使用特殊的方式来处理(例如:上传、下载或者存放到一个数据库)
     if   (transfer_list_value->type != VAL_BLOB) {
         ErrorAbort(state,  "transfer_list argument to %s must be blob" , name);
         goto   done;
     }
     if   (new_data_fn->type != VAL_STRING) {
         ErrorAbort(state,  "new_data_fn argument to %s must be string" , name);
         goto   done;
     }
     if   (patch_data_fn->type != VAL_STRING) {
         ErrorAbort(state,  "patch_data_fn argument to %s must be string" , name);
         goto   done;
     }
 
这里的ui是 updater info的含义 ,而不是user interface
     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
     FILE * cmd_pipe = ui->cmd_pipe;
 
     ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
 
//patch_data_fn->data指向的是“ system.patch.dat ”这段字符串,而不是 ystem.patch.dat 这个文件的内容,
//因此patch_entry就代表内存中的zip安装包中的 system.patch.dat 这一项
     const   ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
     if   (patch_entry == NULL) {
         ErrorAbort(state,  "%s(): no file \"%s\" in package" , name, patch_data_fn->data);
         goto   done;
     }
 //计算出 patch_entry 的起始地址,因为注释中说patch stream must be uncompressed
     uint8_t* patch_start = ((UpdaterInfo*)(state->cookie))->package_zip_addr +
         mzGetZipEntryOffset(patch_entry);
 
// new_data_fn->data指向的数据是“ system.new.dat ”,而不是 ystem.new.dat 这个文件的内容,
     const   ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
     if   (new_entry == NULL) {
         ErrorAbort(state,  "%s(): no file \"%s\" in package" , name, new_data_fn->data);
         goto   done;
     }
 
     // The transfer list is a text file containing commands to
     // transfer data from one place to another on the target
     // partition.  We parse it and execute the commands in order:
     //
     //    zero [rangeset]
     //      - fill the indicated blocks with zeros
     //
     //    new [rangeset]
     //      - fill the blocks with data read from the new_data file
     //
     //    bsdiff patchstart patchlen [src rangeset] [tgt rangeset]
     //    imgdiff patchstart patchlen [src rangeset] [tgt rangeset]
     //      - read the source blocks, apply a patch, write result to
     //        target blocks.  bsdiff or imgdiff specifies the type of
     //        patch.
     //
     //    move [src rangeset] [tgt rangeset]
     //      - copy data from source blocks to target blocks (no patch
     //        needed; rangesets are the same size)
     //
     //    erase [rangeset]
     //      - mark the given blocks as empty
     //
     // The creator of the transfer list will guarantee that no block
     // is read (ie, used as the source for a patch or move) after it
     // has been written.
     //
     // Within one command the source and target ranges may overlap so
     // in general we need to read the entire source into memory before
     // writing anything to the target blocks.
     //
     // All the patch data is concatenated into one patch_data file in
     // the update package.  It must be stored uncompressed because we
     // memory-map it in directly from the archive.  (Since patches are
     // already compressed, we lose very little by not compressing
     // their concatenation.)
 
     pthread_t new_data_thread;
// we expand the new data from the archive in a
// background thread, and block that threads 'receive uncompressed
// data' function until the main thread has reached a point where we
// want some new data to be written. We signal the background thread
// with the destination for the data and block the main thread,
// waiting for the background thread to complete writing that section.
// Then it signals the main thread to wake up and goes back to
// blocking waiting for a transfer.
//
// NewThreadInfo is the struct used to pass information back and forth
// between the two threads. When the main thread wants some data
// written, it sets rss to the destination location and signals the
// condition. When the background thread is done writing, it clears
// rss and signals the condition again.
typedef struct {
ZipArchive* za;
const ZipEntry* entry;

RangeSinkState* rss;

pthread_mutex_t mu;
pthread_cond_t cv;
} NewThreadInfo;
     NewThreadInfo nti;
     nti.za = za;
     nti.entry = new_entry;
     nti.rss = NULL; //先将rss标记置空
     pthread_mutex_init(&nti.mu, NULL); // 互斥锁的初始化
     pthread_cond_init(&nti.cv, NULL); // 创建一个条件变量,cv就是condition value的意思
  extern int pthread_cond_init __P ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr));
  其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指 针。结构 pthread_condattr_t是条件变量的属性结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可用, 默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用
     pthread_attr_t attr; // 线程具有属性,用 pthread_attr_t 表示,在对该结构进行处理之前必须进行初始化,我们用pthread_attr_init函数对其初始化, 用pthread_attr_destroy对其去除初始化
     pthread_attr_init(&attr);
//pthread_attr_setdetachstate 修改线程的分离状态属性,可以使用pthread_attr_setdetachstate函数把线程属性detachstate设置为下面的两个合法值之一:设置为PTHREAD_CREATE_DETACHED,以分离状态启动线程;或者设置为PTHREAD_CREATE_JOINABLE,正常启动线程。线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//pthread_create的四个参数:1指向线程 标识符的指针 2 设置线程属性 3 线程运行函数的起始地址 4 运行函数的参数。
     pthread_create(&new_data_thread, &attr, unzip_new_data, &nti);
 
     int   i, j;
 
     char * linesave;
     char * wordsave;
 
     int   fd = open(blockdev_filename->data, O_RDWR);
     if   (fd < 0) {
         ErrorAbort(state,  "failed to open %s: %s" , blockdev_filename->data,  strerror ( errno ));
         goto   done;
     }
 
     char * line;
     char * word;
 
     // The data in transfer_list_value is not necessarily
     // null-terminated, so we need to copy it to a new buffer and add
     // the null that strtok_r will need.
// char* transfer_list = NULL;
     transfer_list =  malloc (transfer_list_value->size+1);
     if   (transfer_list == NULL) {
         fprintf (stderr,  "failed to allocate %zd bytes for transfer list\n" ,
                 transfer_list_value->size+1);
         exit (1);
     }
//将system.transfer.list 文件的所有内容读取到了transfer_list中
     memcpy (transfer_list, transfer_list_value->data, transfer_list_value->size);
     transfer_list[transfer_list_value->size] =  '\0' ;
  // 按行分割读取 system.transfer.list 中的命令
     line = strtok_r(transfer_list,  "\n" , &linesave);
 
     // first line in transfer list is the version number; currently
     // there's only version 1.
// recovery 5.0对应的api是1
     if   ( strcmp (line,  "1" ) != 0) {
         ErrorAbort(state,  "unexpected transfer list version [%s]\n" , line);
         goto   done;
     }
 
     // second line in transfer list is the total number of blocks we
     // expect to write.
     line = strtok_r(NULL,  "\n" , &linesave);
     int   total_blocks =  strtol (line, NULL, 0);
     // shouldn't happen, but avoid divide by zero.避免除以0
     if   (total_blocks == 0) ++total_blocks;
     int   blocks_so_far = 0;
 
     uint8_t* buffer = NULL;
     size_t   buffer_alloc = 0;
 
     // third and subsequent lines are all individual transfer commands.
// 在这个for循环中依次读取每行命令
     for   (line = strtok_r(NULL,  "\n" , &linesave); line;
          line = strtok_r(NULL,  "\n" , &linesave)) {
// style代表每行前的命令名称,如 move ,bsdiff等
         char * style;
         style = strtok_r(line,  " " , &wordsave);
 
         if   ( strcmp ( "move" , style) == 0) {
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* src = parse_range(word);
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* tgt = parse_range(word);
 
             printf ( "  moving %d blocks\n" , src->size);
 
             allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
             size_t   p = 0;
             for   (i = 0; i < src->count; ++i) {
                 check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
                 size_t   sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
                 readblock(fd, buffer+p, sz);
                 p += sz;
             }
 
             p = 0;
             for   (i = 0; i < tgt->count; ++i) {
                 check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
                 size_t   sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
                 writeblock(fd, buffer+p, sz);
                 p += sz;
             }
 
             blocks_so_far += tgt->size;
             fprintf (cmd_pipe,  "set_progress %.4f\n" , ( double )blocks_so_far / total_blocks);
             fflush (cmd_pipe);
 
             free (src);
             free (tgt);
 
         else   if   ( strcmp ( "zero" , style) == 0 ||
                    (DEBUG_ERASE &&  strcmp ( "erase" , style) == 0)) {
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* tgt = parse_range(word);
 
             printf ( "  zeroing %d blocks\n" , tgt->size);
 
             allocate(BLOCKSIZE, &buffer, &buffer_alloc);
             memset (buffer, 0, BLOCKSIZE);
             for   (i = 0; i < tgt->count; ++i) {
                 check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
                 for   (j = tgt->pos[i*2]; j < tgt->pos[i*2+1]; ++j) {
                     writeblock(fd, buffer, BLOCKSIZE);
                 }
             }
 
             if   (style[0] ==  'z' ) {    // "zero" but not "erase"
                 blocks_so_far += tgt->size;
                 fprintf (cmd_pipe,  "set_progress %.4f\n" , ( double )blocks_so_far / total_blocks);
                 fflush (cmd_pipe);
             }
 
             free (tgt);
         else   if   ( strcmp ( "new" , style) == 0) {
 
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* tgt = parse_range(word);
 
             printf ( "  writing %d blocks of new data\n" , tgt->size);
 
             RangeSinkState rss;
             rss.fd = fd;
             rss.tgt = tgt;
             rss.p_block = 0;
             rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
             check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
 
             pthread_mutex_lock(&nti.mu);
             nti.rss = &rss;
             pthread_cond_broadcast(&nti.cv);
             while   (nti.rss) {
                 pthread_cond_wait(&nti.cv, &nti.mu);
             }
             pthread_mutex_unlock(&nti.mu);
 
             blocks_so_far += tgt->size;
             fprintf (cmd_pipe,  "set_progress %.4f\n" , ( double )blocks_so_far / total_blocks);
             fflush (cmd_pipe);
 
             free (tgt);
 
         else   if   ( strcmp ( "bsdiff" , style) == 0 ||
                    strcmp ( "imgdiff" , style) == 0) {
             word = strtok_r(NULL,  " " , &wordsave);
             size_t   patch_offset =  strtoul (word, NULL, 0);
             word = strtok_r(NULL,  " " , &wordsave);
             size_t   patch_len =  strtoul (word, NULL, 0);
 
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* src = parse_range(word);
             word = strtok_r(NULL,  " " , &wordsave);
             RangeSet* tgt = parse_range(word);
 
             printf ( "  patching %d blocks to %d\n" , src->size, tgt->size);
 
             // Read the source into memory.
             allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
             size_t   p = 0;
             for   (i = 0; i < src->count; ++i) {
                 check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
                 size_t   sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
                 readblock(fd, buffer+p, sz);
                 p += sz;
             }
 
             Value patch_value;
             patch_value.type = VAL_BLOB;
             patch_value.size = patch_len;
             patch_value.data = ( char *)(patch_start + patch_offset);
 
             RangeSinkState rss;
             rss.fd = fd;
             rss.tgt = tgt;
             rss.p_block = 0;
             rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
             check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
 
             if   (style[0] ==  'i' ) {       // imgdiff
                 ApplyImagePatch(buffer, src->size * BLOCKSIZE,
                                 &patch_value,
                                 &RangeSinkWrite, &rss, NULL, NULL);
             else   {
                 ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE,
                                  &patch_value, 0,
                                  &RangeSinkWrite, &rss, NULL);
             }
 
             // We expect the output of the patcher to fill the tgt ranges exactly.
             if   (rss.p_block != tgt->count || rss.p_remain != 0) {
                 fprintf (stderr,  "range sink underrun?\n" );
             }
 
             blocks_so_far += tgt->size;
             fprintf (cmd_pipe,  "set_progress %.4f\n" , ( double )blocks_so_far / total_blocks);
             fflush (cmd_pipe);
 
             free (src);
             free (tgt);
         else   if   (!DEBUG_ERASE &&  strcmp ( "erase" , style) == 0) {
             struct   stat st;
             if   (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
                 word = strtok_r(NULL,  " " , &wordsave);
                 RangeSet* tgt = parse_range(word);
 
                 printf ( "  erasing %d blocks\n" , tgt->size);
 
                 for   (i = 0; i < tgt->count; ++i) {
                     uint64_t range[2];
                     // offset in bytes
                     range[0] = tgt->pos[i*2] * (uint64_t)BLOCKSIZE;
                     // len in bytes
                     range[1] = (tgt->pos[i*2+1] - tgt->pos[i*2]) * (uint64_t)BLOCKSIZE;
 
                     if   (ioctl(fd, BLKDISCARD, &range) < 0) {
                         printf ( "    blkdiscard failed: %s\n" strerror ( errno ));
                     }
                 }
 
                 free (tgt);
             else   {
                 printf ( "  ignoring erase (not block device)\n" );
             }
         else   {
             fprintf (stderr,  "unknown transfer style \"%s\"\n" , style);
             exit (1);
         }
     }
 
     pthread_join(new_data_thread, NULL);
     success =  true ;
 
     free (buffer);
     printf ( "wrote %d blocks; expected %d\n" , blocks_so_far, total_blocks);
     printf ( "max alloc needed was %zu\n" , buffer_alloc);
 
   done:
     free (transfer_list);
     FreeValue(blockdev_filename);
     FreeValue(transfer_list_value);
     FreeValue(new_data_fn);
     FreeValue(patch_data_fn);
     return   StringValue(success ? strdup( "t" ) : strdup( "" ));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值