四、install_package详细流程

四、install_package详细流程

本篇将介绍install_package的流程,将重点分析install.cpp和roots.cpp,大致分为

1、UI设置

2、升级包路径挂载

3、分配内存空间

4、校验升级包

5、校验compatibility

6、try_update_binary(下个篇幅单独讲解,核心内容)

 

install.cpp 

//返回status int类型
int install_package(const std::string& path, bool* wipe_cache, const std::string& install_file,
                    bool needs_mount, int retry_count) {
  //传进来的参数中,needs_mount = true retry_count = 0 path = update_package
  CHECK(!path.empty());
  CHECK(!install_file.empty());
  CHECK(wipe_cache != nullptr);

  modified_flash = true;
  //std::chrono::system_clock 它表示当前的系统时钟,系统中运行的所有进程使用now()得到的时间是一致的。now() 当前时间time_point
  auto start = std::chrono::system_clock::now();
  
  int start_temperature = GetMaxValueFromThermalZone();
  int max_temperature = start_temperature;

  int result;
  std::vector<std::string> log_buffer;
  //追踪判断roots.cpp
  if (setup_install_mounts() != 0) {
    LOG(ERROR) << "failed to set up expected mounts for install; aborting";
    result = INSTALL_ERROR;
  } else {
    //主要install流程
    result = really_install_package(path, wipe_cache, needs_mount, &log_buffer, retry_count,
                                    &max_temperature);
  }

setup_install_mounts() != 0方法分析

roots.cpp

int setup_install_mounts() {
  //判断static struct fstab* fstab是否为空
  if (fstab == nullptr) {
    LOG(ERROR) << "can't set up install mounts: no fstab loaded";
    return -1;
  }
  printf("\n====roots.cpp setup_install_mounts====\n");
  for (int i = 0; i < fstab->num_entries; ++i) {
    const Volume* v = fstab->recs + i;
    //这里打印出来的,其实跟我们之前加载分区表得到的时相同的,不过只是再次确认下mount_point的信息  char* mount_point
    printf("  %d %s %s %s %lld\n", i, v->mount_point, v->fs_type, v->blk_device, v->length);
    // We don't want to do anything with "/".这里通过log其实可以看到挂载点为/ 的只有system
    if (strcmp(v->mount_point, "/") == 0) {
      continue;
    }
    //如果mount_point中有tmp 和cache,判断是不是可以挂载成功
    if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) {
      if (ensure_path_mounted(v->mount_point) != 0) {
        LOG(ERROR) << "Failed to mount " << v->mount_point;
        return -1;
      }
    } else {
    //如果不是tmp和cache,判断是不是可以不挂载
      if (ensure_path_unmounted(v->mount_point) != 0) {
        LOG(ERROR) << "Failed to unmount " << v->mount_point;
        return -1;
      }
    }
  }
  return 0;
}

ensure_path_mounted方法  看这个方法之前,我们先把其中一些调用方法整理清楚

Volume* v = volume_for_path(path)

roots.cpp
//传入mount_point 具体为/tmp 和 /cache
static Volume* volume_for_path(const char* path) {
  //如果路径为空,或者路径第一个字节为空,返回nullptr
  if (path == nullptr || path[0] == '\0') return nullptr;
  //将路径转换为string格式
  std::string str(path);
  while (true) {
    //传入获取的静态fstab,和路径,获取到对应的fstab_rec结构体
    Volume* result = fs_mgr_get_entry_for_mount_point(fstab, str);
    if (result != nullptr || str == "/") {
      return result;
    }
    //为了使自己的程序有很好的移植性,c++程序员应该尽量使用size_t和size_type而不是int, unsigned
    //size_t是全局定义的类型;size_type是STL类中定义的类型属性,用以保存任意string和vector类对象的长度
    size_t slash = str.find_last_of('/');
    if (slash == std::string::npos) return nullptr;
    if (slash == 0) {
      str = "/";
    } else {
      str = str.substr(0, slash);
    }
  }
  return nullptr;
}

fs_mgr_get_entry_for_mount_point

system/core/fs_mgr/fs_mgr_fstab.cpp
/*
 * Returns the fstab_rec* whose mount_point is path. 返回fstab_rec结构体
 * Returns nullptr if not found.
 */
struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
    if (!fstab) {
        return nullptr;
    }
    //如果当前路径在recs的挂载点中存在,返回该挂载点的fstab_rec结构体,之前我们已经知道了结构体fstab和fstab_rec的内容
    //fstab包含了分区表中条目的个数,recs,分区表的名称,fstab_rec包含了详细的条目信息,这里返回的就是包含当前挂载点的条目信息
    for (int i = 0; i < fstab->num_entries; i++) {
        //如果当前条目mount_point不为空,而且等于我们传进来的mount_point,返回这个条目
        if (fstab->recs[i].mount_point && path == fstab->recs[i].mount_point) {
            return &fstab->recs[i];
        }
    }
    return nullptr;
}

!scan_mounted_volumes()

bootable/recovery/mounts.cpp

struct MountedVolume {
    std::string device;
    std::string mount_point;
    std::string filesystem;
    std::string flags;
};

std::vector<MountedVolume*> g_mounts_state;
bool scan_mounted_volumes() {
    for (size_t i = 0; i < g_mounts_state.size(); ++i) {
        delete g_mounts_state[i];
    }
    //执行之前先清除了容器中的内容,其实按目前的代码看,本身就是没有赋值的,
    g_mounts_state.clear();

    // Open and read mount table entries.
    //setmntent,getmument,endmnment获取文件信息,得到mnment结构体,拿到文件中的详细信息
    //介绍非常详细https://blog.csdn.net/lixiaogang_theanswer/article/details/79431318
    FILE* fp = setmntent("/proc/mounts", "re");
    if (fp == NULL) {
        return false;
    }
    mntent* e;
    //遍历出mntent中的参数,赋值给g_mounts_state
    while ((e = getmntent(fp)) != NULL) {
        MountedVolume* v = new MountedVolume;
        v->device = e->mnt_fsname;
        v->mount_point = e->mnt_dir;
        v->filesystem = e->mnt_type;
        v->flags = e->mnt_opts;
        //将组装好的结构体放入g_mounts_state容器中
        g_mounts_state.push_back(v);
    }
    endmntent(fp);
    printf("\n==========mounts.cpp scan_mounted_volumes g_mounts_state==========\n");
    for (size_t i = 0; i < g_mounts_state.size(); ++i) {       
      printf("  %s %s %s %s\n", g_mounts_state[i]->mount_point.c_str(), g_mounts_state[i]->device.c_str(), g_mounts_state[i]->filesystem.c_str(), g_mounts_state[i]->flags.c_str());
    }
    printf("\n==================================================================\n");
    return true;
}

find_mounted_volume_by_mount_point

bootable/recovery/mounts.cpp
MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point) {
    printf("\n==========mounts.cpp find_mounted_volume_by_mount_point before for==========\n");
    for (size_t i = 0; i < g_mounts_state.size(); ++i) {
        //如果g_mounts_state[i]的挂载点存在传入的mount_point,那么就返回当前位置在的MountedVolumes结构体
        if (g_mounts_state[i]->mount_point == mount_point){
          printf("\n==========mounts.cpp find_mounted_volume_by_mount_point after for==========\n");
          printf("  %s %s %s %s\n", g_mounts_state[i]->mount_point.c_str(), g_mounts_state[i]->device.c_str(), g_mounts_state[i]->filesystem.c_str(), g_mounts_state[i]->flags.c_str());
          return g_mounts_state[i];
        }
    }
    return nullptr;
}

ensure_path_mounted这个方法在下面really_install_package中也有走到,上述几个方法是加在该方法中的一些条件,我加了很多的打印,具体看了下,下载到data和sdcard中的一些区别,以下代码中会做一些说明

roots.cpp
//注意参数这里传入的是mount_point
int ensure_path_mounted(const char* path) {
  // Mount at the default mount point.
  return ensure_path_mounted_at(path, nullptr);
}
//传进来的mount_point为空
int ensure_path_mounted_at(const char* path, const char* mount_point) {
  Volume* v = volume_for_path(path);
  printf("\n==========ensure_path_mounted_at volume_for_path==========\n");
  printf("  %s %s %s\n",v->mount_point, v->fs_type, v->blk_device);
//adupsfota start
#ifdef ADUPS_FOTA_SUPPORT
    if (strncmp(path, "/fotaupdate/", 12) == 0) {
        return 0;
    }
#endif
//adupsfota end
  //如果得到的fstab_rec为空,则打印错误unknown volume for path
  if (v == nullptr) {
    LOG(ERROR) << "unknown volume for path [" << path << "]";
    return -1;
  }
  //如果得到的fstab_rec中fs_type为 ramdisk 则返回0 无需执行挂载操作
  if (strcmp(v->fs_type, "ramdisk") == 0) {
    // The ramdisk is always mounted.
    return 0;
  }
  //这个判断条件中是从mounts文件中读取数据,在机器中路径为/proc/mounts,pull出来可以看到,具体打印如下
  //[    6.937196] ==========mounts.cpp scan_mounted_volumes g_mounts_state==========
  //[    6.937230]   / rootfs rootfs rw,seclabel
  //[    6.937263]   /dev tmpfs tmpfs rw,seclabel,nosuid,relatime,mode=755
  //[    6.937295]   /dev/pts devpts devpts rw,seclabel,relatime,mode=600
  //[    6.937326]   /proc proc proc rw,relatime,gid=3009,hidepid=2
  //[    6.937357]   /sys sysfs sysfs rw,seclabel,relatime
  //[    6.937389]   /sys/fs/selinux selinuxfs selinuxfs rw,relatime
  //[    6.937421]   /mnt tmpfs tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=755,gid=1000
  //[    6.937452]   /acct none cgroup rw,relatime,cpuacct
  //[    6.937483]   /tmp tmpfs tmpfs rw,seclabel,relatime
  //[    6.937514]   /config none configfs rw,relatime
  //[    6.937545]   /dev/usb-ffs/adb adb functionfs rw,relatime
  //[    6.937577]   /cache /dev/block/platform/bootdevice/by-name/cache ext4 rw,seclabel,nosuid,nodev,noatime,discard,noauto_da_alloc,data=ordered
  if (!scan_mounted_volumes()) {
    LOG(ERROR) << "Failed to scan mounted volumes";
    return -1;
  }
  //如果mount_point为空,把fstab_rec中的值给到mount_point
  if (!mount_point) {
    mount_point = v->mount_point;
  }
  //从g_mounts_state中读取数据,看是否有对应的挂载点
  //根据我们上个方法拿到的数据不难发现,g_mount_state中并没有sdcard的条目
  //所以 路径为data时,mv不为空,直接return 0,路径为sdcard时 mv为空,需要执行后续的mount方法
  //data打印结果
  //[    7.032122] ==========roots.cpp find_mounted_volume_by_mount_point before==========
  //[    7.032179] ==========mounts.cpp find_mounted_volume_by_mount_point before for==========
  //[    7.032237] ==========mounts.cpp find_mounted_volume_by_mount_point after for==========
  //[    7.032269]   /cache /dev/block/platform/bootdevice/by-name/cache ext4 rw,seclabel,nosuid,nodev,noatime,discard,noauto_da_alloc,data=ordered
  //[    7.032326] ==========roots.cpp find_mounted_volume_by_mount_point after==========
  //sdcard打印结果
  //[    7.022144] ==========roots.cpp find_mounted_volume_by_mount_point before==========
  //[    7.022393] ==========mounts.cpp find_mounted_volume_by_mount_point before for==========
  //[    7.022647] ==========roots.cpp find_mounted_volume_by_mount_point after==========
  printf("\n==========roots.cpp find_mounted_volume_by_mount_point before==========\n");
  const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
  printf("\n==========roots.cpp find_mounted_volume_by_mount_point after==========\n");
  if (mv != nullptr) {
    printf("\n==========roots.cpp mv != nullptr==========\n");
    return 0;
  }

  mkdir(mount_point, 0755);  // in case it doesn't already exist

  if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
      strcmp(v->fs_type, "vfat") == 0) {
    int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
    if (result == -1 && fs_mgr_is_formattable(v)) {
      PLOG(ERROR) << "Failed to mount " << mount_point << "; formatting";
      bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
      if (fs_mgr_do_format(v, crypt_footer) == 0) {
        result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
      } else {
        PLOG(ERROR) << "Failed to format " << mount_point;
        return -1;
      }
    }
    if (result == -1) {
      PLOG(ERROR) << "Failed to mount " << mount_point;
      return -1;
    }
    return 0;
  }
  LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
  return -1;
}

really_install_package

install.cpp
//还是先说明传进来的参数 needs_mount = true retry_count = 0 path = update_package
static int really_install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
                                  std::vector<std::string>* log_buffer, int retry_count,
                                  int* max_temperature) {
  //ui部分的处理设置背景和进度条 TODO 后续有时间再处理UI部分
  ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
  ui->Print("Finding update package...\n");
  // Give verification half the progress bar...
  ui->SetProgressType(RecoveryUI::DETERMINATE);
  ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
  LOG(INFO) << "Update location: " << path;

  // Map the update package into memory.
  ui->Print("Opening update package...\n");
  //needs_mount =true,所以进入判断
  if (needs_mount) {
    //如果path的开始位置为@,也就是内置存储转换之后的路径,那么取去除第一个位置之后的string 也就是cache/recovery/block.map
    //ensure_path_mounted,以上已经做过分析,这里不做描述
    if (path[0] == '@') {
      ensure_path_mounted(path.substr(1).c_str());
    } else {
      ensure_path_mounted(path.c_str());
    }
  }
  //映射内存空间
  MemMapping map;
  if (!map.MapFile(path)) {
    LOG(ERROR) << "failed to map file";
    log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
    return INSTALL_CORRUPT;
  }

  // Verify package.校验升级包签名
  if (!verify_package(map.addr, map.length)) {
    log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
    return INSTALL_CORRUPT;
  }

  // Try to open the package.从内存中打开升级包
  ZipArchiveHandle zip;
  int err = OpenArchiveFromMemory(map.addr, map.length, path.c_str(), &zip);
  if (err != 0) {
    LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err);
    log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));

    CloseArchive(zip);
    return INSTALL_CORRUPT;
  }
  // Check partition size between source and target
  // 校验前后版本的分区
#ifndef AB_OTA_UPDATER 
  int ret=INSTALL_SUCCESS;
  if (mt_really_install_package_check_part_size(ret, path.c_str(), zip)) {
    CloseArchive(zip);
    return ret;
  }
#endif

  // Additionally verify the compatibility of the package.
  // 校验升级包中的compatibility.zip 
  // 关于compatibility.zip的介绍https://blog.csdn.net/csdn66_2016/article/details/81704720
  if (!verify_package_compatibility(zip)) {
    log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure));
    CloseArchive(zip);
    return INSTALL_CORRUPT;
  }

  // Verify and install the contents of the package.
  ui->Print("Installing update...\n");
  if (retry_count > 0) {
    ui->Print("Retry attempt: %d\n", retry_count);
  }
  ui->SetEnableReboot(false);
  //调用脚本解释器执行升级脚本
  int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
  ui->SetEnableReboot(true);
  ui->Print("\n");

  CloseArchive(zip);
  return result;
}

map.MapFile(path)方法,虽然对于路径也有方法的区分,但是大致的流程都需要把升级包的数据映射到内存空间,后续校验方法传入的也是内存映射地址

bootable/recovery/otautil/SysUtil.cpp

bool MemMapping::MapFile(const std::string& fn) {
  if (fn.empty()) {
    LOG(ERROR) << "Empty filename";
    return false;
  }
  //这里分为了两种情况,走了不同的内存地址映射的方法,data区和其他路径
  if (fn[0] == '@') {
    // Block map file "@/cache/recovery/block.map".
    if (!MapBlockFile(fn.substr(1))) {
      LOG(ERROR) << "Map of '" << fn << "' failed";
      return false;
    }
  } else {
    // This is a regular file.
    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY)));
    if (fd == -1) {
      PLOG(ERROR) << "Unable to open '" << fn << "'";
      return false;
    }

    if (!MapFD(fd)) {
      LOG(ERROR) << "Map of '" << fn << "' failed";
      return false;
    }
  }
  return true;
}

针对cache/recovery/block.map的MapBlockFile

bootable/recovery/otautil/SysUtil.cpp
bool MemMapping::MapBlockFile(const std::string& filename) {
  std::string content;
  //以是否可以读取出字符串判断,如果block.map为空,将会报错failed to read
  if (!android::base::ReadFileToString(filename, &content)) {
    PLOG(ERROR) << "Failed to read " << filename;
    return false;
  }
  //以换行分割block.map到string类型的容器中
  std::vector<std::string> lines = android::base::Split(android::base::Trim(content), "\n");
  //加了打印用于输出lines容器中的内容,输出结果:
  //[    7.034186] =================MapBlockFile block.map data 
                "/dev/block/platform/bootdevice/by-name/userdata"
  //[    7.034245]  "19485612 4096"
  //[    7.034276]  "2"
  //[    7.034307]  "556032 557056"
  //[    7.034337]  "583680 587414"
  printf("\n=================MapBlockFile block.map data====================\n");
  for (const auto& line : lines) {
    printf(" \"%s\"\n", line.c_str());
  }
  if (lines.size() < 4) {
    LOG(ERROR) << "Block map file is too short: " << lines.size();
    return false;
  }

  size_t size;
  size_t blksize;
  // %d输出int型。 %zu输出size_t型
  // int sscanf() 从字符串读取格式化输入 返回输入时几个参数,这个读取的第二行的两个参数,如果返回的不是2 那说明block.map缺失数据
  // sscanf介绍:https://www.cnblogs.com/wwjyt/p/3182892.html
  if (sscanf(lines[1].c_str(), "%zu %zu", &size, &blksize) != 2) {
    LOG(ERROR) << "Failed to parse file size and block size: " << lines[1];
    return false;
  }

  size_t range_count;
  //判断第三行有没有block区间的总数
  if (sscanf(lines[2].c_str(), "%zu", &range_count) != 1) {
    LOG(ERROR) << "Failed to parse block map header: " << lines[2];
    return false;
  }

  size_t blocks;
  //如果blksize不为空,那么计算出blocks的数量
  if (blksize != 0) {
    blocks = ((size - 1) / blksize) + 1;
  }
  //再次确认各项数值有无异常和空值
  //这里的SIZE_MAX 是./bionic/libc/include/stdint.h中宏定义的数值 #define SIZE_MAX  UINT64_MAX
  if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0 ||
      lines.size() != 3 + range_count) {
    LOG(ERROR) << "Invalid data in block map file: size " << size << ", blksize " << blksize
               << ", range_count " << range_count << ", lines " << lines.size();
    return false;
  }

  // Reserve enough contiguous address space for the whole file.
  //使用mmap用来在进程虚拟地址空间中分配创建一片虚拟内存地址映射,返回值:成功返回映射的虚拟内存地址的起始地址,失败返回MAP_FAILED
  //内存映射:https://blog.csdn.net/qq_33611327/article/details/81738195  http://blog.itpub.net/7728585/viewspace-2142411/
  void* reserve = mmap(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
  if (reserve == MAP_FAILED) {
    PLOG(ERROR) << "failed to reserve address space";
    return false;
  }
  ///dev/block/platform/msm_sdcc.1/by-name/userdata
  //o_rdonly read only 只读 o_wronly write only 只写 o_rdwr read write 可读可写,fd为文件描述符
  const std::string& block_dev = lines[0];
  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(block_dev.c_str(), O_RDONLY)));
  if (fd == -1) {
    PLOG(ERROR) << "failed to open block device " << block_dev;
    munmap(reserve, blocks * blksize);
    return false;
  }
  //ranges_ 在sysutil.h中定义 ,是每个元素为结构体MappedRange的容器,std::vector<MappedRange> ranges_;
  //  struct MappedRange {
  //  void* addr;
  //  size_t length;
  //};
  //装入之前清除容器中内容
  ranges_.clear();
  //static_cast相当于传统的C语言里的强制转换,将reserve强制转换为char类型
  unsigned char* next = static_cast<unsigned char*>(reserve);
  //blocks = ((size - 1) / blksize) + 1;
  size_t remaining_size = blocks * blksize;
  bool success = true;
  for (size_t i = 0; i < range_count; ++i) {
    const std::string& line = lines[i + 3];

    size_t start, end;//1000 1008 从第四行开始处理
    if (sscanf(line.c_str(), "%zu %zu\n", &start, &end) != 2) {
      LOG(ERROR) << "failed to parse range " << i << ": " << line;
      success = false;
      break;
    }
    //区间的大小为区间长度×块大小
    size_t range_size = (end - start) * blksize;
    if (end <= start || (end - start) > SIZE_MAX / blksize || range_size > remaining_size) {
      LOG(ERROR) << "Invalid range: " << start << " " << end;
      success = false;
      break;
    }
    //将第一个block range放入到我们分配的内存地址中,偏移量为第一个区间的起始位置
    void* range_start = mmap(next, range_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd,
                             static_cast<off_t>(start) * blksize);
    if (range_start == MAP_FAILED) {
      PLOG(ERROR) << "failed to map range " << i << ": " << line;
      success = false;
      break;
    }
    //将第一个区间的MappedRange结构体放入到ranges容器中
    ranges_.emplace_back(MappedRange{ range_start, range_size });
    //第一个区间放入后,将起始位置加上之前的range_size
    next += range_size;
    //而总的大小减去第一个ranges,这两个数据的变动是为了第二个区间的放入
    remaining_size -= range_size;
  }
  if (success && remaining_size != 0) {
    LOG(ERROR) << "Invalid ranges: remaining_size " << remaining_size;
    success = false;
  }
  if (!success) {
    munmap(reserve, blocks * blksize);
    return false;
  }
  //数据全部放入后,拿到的addr内存映射地址就是我们升级包的数据
  addr = static_cast<unsigned char*>(reserve);
  length = size;

  LOG(INFO) << "mmapped " << range_count << " ranges";

  return true;
}

针对sdcard的MapFD方法

bootable/recovery/otautil/SysUtil.cpp
bool MemMapping::MapFD(int fd) {
  struct stat sb;
  if (fstat(fd, &sb) == -1) {
    PLOG(ERROR) << "fstat(" << fd << ") failed";
    return false;
  }
  //分配内存地址映射
  void* memPtr = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (memPtr == MAP_FAILED) {
    PLOG(ERROR) << "mmap(" << sb.st_size << ", R, PRIVATE, " << fd << ", 0) failed";
    return false;
  }
  addr = static_cast<unsigned char*>(memPtr);
  length = sb.st_size;
  ranges_.clear();
  ranges_.emplace_back(MappedRange{ memPtr, static_cast<size_t>(sb.st_size) });

  return true;
}

verify_package校验签名

bootable/recovery/install.cpp TODO 这里可以作为了解,看下里面的打印信息,知道大概流程
bool verify_package(const unsigned char* package_data, size_t package_size) {
  static constexpr const char* PUBLIC_KEYS_FILE = "/res/keys";
  std::vector<Certificate> loadedKeys;
  if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) {
    LOG(ERROR) << "Failed to load keys";
    return false;
  }
  LOG(INFO) << loadedKeys.size() << " key(s) loaded from " << PUBLIC_KEYS_FILE;

  // Verify package.
  ui->Print("Verifying update package...\n");
  auto t0 = std::chrono::system_clock::now();
  int err = verify_file(package_data, package_size, loadedKeys,
                        std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
  std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0;
  ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err);
  if (err != VERIFY_SUCCESS) {
    LOG(ERROR) << "Signature verification failed";
    LOG(ERROR) << "error: " << kZipVerificationFailure;
    return false;
  }
  return true;
}

try_update_binary将作为单独讲解,recovery使用update_binary,解析update-scrypt进行具体升级流程

 

上一篇:ansible格式化使用记录


下一篇:vue生命周期