五、try_update_binary详细流程

深入解析Android Recovery升级流程:从开机到OTA完成 本文详细解析了Android系统升级流程,重点剖析了Recovery模式的工作原理。文章首先介绍了Android的三种启动模式(Fastboot、Recovery和Main System)及其功能差异,随后深入探讨了OTA升级的具体实现机制,包括应用层检测升级、写入升级命令到BCB(Bootloader Control Block)、重启进入Recovery模式等关键步骤。 阅读详情

五、try_update_binary详细流程

本篇将介绍try_update_binary 执行升级包中的updater_binary可执行文件解析update-scrypt进行升级流程

 

bootable/recovery/install.cpp
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) {
  ......
  ......
  //根据之前install.cpp的流程分析,这里传入升级包的路径,和从内存地址中读出的升级包数据
  int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
  ......
  ......
}

try_update_binary方法

bootable/recovery/install.cpp
// If the package contains an update binary, extract it and run it.
static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache,
                             std::vector<std::string>* log_buffer, int retry_count,
                             int* max_temperature) {
  //将META/com/android/metadata中一些值写入到last_install中
  read_source_target_build(zip, log_buffer);
  //调用pipe在父子进程间使用管道
  //pipefd[0]用于读取数据 ,pipefd[1]用于写入数据
  int pipefd[2];
  pipe(pipefd);

  std::vector<std::string> args;
#ifdef AB_OTA_UPDATER
  int ret = update_binary_command(package, zip, "/sbin/update_engine_sideload", retry_count,
                                  pipefd[1], &args);
#else
  //找到update-binary,放入到tmp路径,和其他一些参数放入args容器中
  int ret = update_binary_command(package, zip, "/tmp/update-binary", retry_count, pipefd[1],
                                  &args);
#endif
  if (ret) {
    close(pipefd[0]);
    close(pipefd[1]);
    log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
    return ret;
  }
  // 将args中的参数转换为数组形式
  const char* chr_args[args.size() + 1];
  chr_args[args.size()] = nullptr;
  for (size_t i = 0; i < args.size(); i++) {
    chr_args[i] = args[i].c_str();
  }
  //fork一个子进程
  pid_t pid = fork();

  if (pid == -1) {
    close(pipefd[0]);
    close(pipefd[1]);
    PLOG(ERROR) << "Failed to fork update binary";
    log_buffer->push_back(android::base::StringPrintf("error: %d", kForkUpdateBinaryFailure));
    return INSTALL_ERROR;
  }

  if (pid == 0) {
    umask(022);
    close(pipefd[0]);
    //exevc调用可执行程序 执行updater-binary
    //int execl(const char *path, const char *arg, ...);        
    //path:可执行文件的路径
    //arg:传递的参数(一定要传递NULL)
    execv(chr_args[0], const_cast<char**>(chr_args));
    // Bug: 34769056
    // We shouldn't use LOG/PLOG in the forked process, since they may cause
    // the child process to hang. This deadlock results from an improperly
    // copied mutex in the ui functions.
    fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno));
    _exit(EXIT_FAILURE);
  }
  close(pipefd[1]);

  std::atomic<bool> logger_finished(false);
  std::thread temperature_logger(log_max_temperature, max_temperature, std::ref(logger_finished));

  *wipe_cache = false;
  bool retry_update = false;

  char buffer[1024];
  //函数说明:fdopen()会将参数fildes 的文件描述词, 转换为对应的文件指针后返回.
  FILE* from_child = fdopen(pipefd[0], "r");
  //C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。
  //当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
  //下面的while循环主要为了更新父进程UI,并通过管道与父进程交互
  while (fgets(buffer, sizeof(buffer), from_child) != nullptr) {
    std::string line(buffer);
    size_t space = line.find_first_of(" \n");
    std::string command(line.substr(0, space));
    if (command.empty()) continue;
    ......
    ......
  return INSTALL_SUCCESS;
}

update_binary_command方法

int update_binary_command(const std::string& package, ZipArchiveHandle zip,
                          const std::string& binary_path, int retry_count, int status_fd,
                          std::vector<std::string>* cmd) {
  CHECK(cmd != nullptr);

  // On traditional updates we extract the update binary from the package.
  //constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。
  //最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,
  //而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。
  //constexpr所修饰的变量一定是编译期可求值的,所修饰的函数在其所有参数都是constexpr时,一定会返回constexpr。
  static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
  //在升级包中找到脚本解释器updater-binary
  ZipString binary_name(UPDATE_BINARY_NAME);
  ZipEntry binary_entry;
  if (FindEntry(zip, binary_name, &binary_entry) != 0) {
    LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME;
    return INSTALL_CORRUPT;
  }

  unlink(binary_path.c_str());
  //创建/tmp/update-binary路径,并给到权限
  int fd = open(binary_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755);
  if (fd == -1) {
    PLOG(ERROR) << "Failed to create " << binary_path;
    return INSTALL_ERROR;
  }
  //将updater-binary放入到文件夹中
  int32_t error = ExtractEntryToFile(zip, &binary_entry, fd);
  close(fd);
  if (error != 0) {
    LOG(ERROR) << "Failed to extract " << UPDATE_BINARY_NAME << ": " << ErrorCodeString(error);
    return INSTALL_ERROR;
  }
  //定义cmd容器中所包含的元素
  *cmd = {
    binary_path,//updater-binary路径
    std::to_string(kRecoveryApiVersion),//recoveryapi版本
    std::to_string(status_fd),//pipefd[1]写入数据
    package,//升级包路径
  };
  if (retry_count > 0) {
    cmd->push_back("retry");
  }
  return 0;
}

execv 执行update-binary,update-binary是由bootable/recovery/updater/ 编译生成的可执行文件,所以执行后,将进入updater.cpp的main方法

int main(int argc, char** argv) {
  // Various things log information to stdout or stderr more or less
  // at random (though we've tried to standardize on stdout).  The
  // log file makes more sense if buffering is turned off so things
  // appear in the right order.
  setbuf(stdout, nullptr);
  setbuf(stderr, nullptr);

  // We don't have logcat yet under recovery. Update logs will always be written to stdout
  // (which is redirected to recovery.log).
  android::base::InitLogging(argv, &UpdaterLogger);
  //我们执行update-binary,首先还是看下时什么参数传进了main方法,以上次的经验,还是放在initlog之后
  fprintf(stderr, "\n============updater.cpp main============\n");
  int i;
  for (i = 0; i < argc; i++){
    fprintf(stderr, "argc && argv we need know how much the argc argv\n");
    fprintf(stderr, "argv %d is %s\n", i, argv[i]);
  }
  printf("\n========================================\n");
  if (argc != 4 && argc != 5) {
    LOG(ERROR) << "unexpected number of arguments: " << argc;
    return 1;
  }

  char* version = argv[1];
  if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || version[1] != '\0') {
    // We support version 1, 2, or 3.
    LOG(ERROR) << "wrong updater binary API; expected 1, 2, or 3; got " << argv[1];
    return 2;
  }

  // Set up the pipe for sending commands back to the parent process.
  int fd = atoi(argv[2]);
  FILE* cmd_pipe = fdopen(fd, "wb");
  setlinebuf(cmd_pipe);

  // Extract the script from the package.
  // 从升级包中提取出updater-scrypt
  const char* package_filename = argv[3];
  //加载内存空间
  MemMapping map;
  if (!map.MapFile(package_filename)) {
    LOG(ERROR) << "failed to map package " << argv[3];
    return 3;
  }
  //获取压缩包
  ZipArchiveHandle za;
  int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za);
  if (open_err != 0) {
    LOG(ERROR) << "failed to open package " << argv[3] << ": " << ErrorCodeString(open_err);
    CloseArchive(za);
    return 3;
  }
  //获取updater-scrypt脚本,读取到内存中
  ZipString script_name(SCRIPT_NAME);
  ZipEntry script_entry;
  int find_err = FindEntry(za, script_name, &script_entry);
  if (find_err != 0) {
    LOG(ERROR) << "failed to find " << SCRIPT_NAME << " in " << package_filename << ": "
               << ErrorCodeString(find_err);
    CloseArchive(za);
    return 4;
  }

  std::string script;
  script.resize(script_entry.uncompressed_length);
  int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]),
                                    script_entry.uncompressed_length);
  if (extract_err != 0) {
    LOG(ERROR) << "failed to read script from package: " << ErrorCodeString(extract_err);
    CloseArchive(za);
    return 5;
  }
#if 1
    //打印出脚本的内容
    fprintf(stderr, "====== Updater-Script:\n");
    fprintf(stderr, "%s\n\n", script.c_str());
#endif
  // Configure edify's functions.
  //注册脚本中语句处理函数,识别脚本中的命令
  RegisterBuiltins();
  RegisterInstallFunctions();
  RegisterBlockImageFunctions();
  RegisterDeviceExtensions();

  // Parse the script.
  // 智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象, unique_ptr 独占所指向的对象
  // 解析update-scrypt脚本
  std::unique_ptr<Expr> root;
  int error_count = 0;
  int error = parse_string(script.c_str(), &root, &error_count);
  if (error != 0 || error_count > 0) {
    LOG(ERROR) << error_count << " parse errors";
    CloseArchive(za);
    return 6;
  }

  sehandle = selinux_android_file_context_handle();
  selinux_android_set_sehandle(sehandle);

  if (!sehandle) {
    fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
  }

  // Evaluate the parsed script. 执行解析后的脚本

  UpdaterInfo updater_info;
  updater_info.cmd_pipe = cmd_pipe;
  updater_info.package_zip = za;
  updater_info.version = atoi(version);
  updater_info.package_zip_addr = map.addr;
  updater_info.package_zip_len = map.length;

  State state(script, &updater_info);

  if (argc == 5) {
    if (strcmp(argv[4], "retry") == 0) {
      state.is_retry = true;
    } else {
      printf("unexpected argument: %s", argv[4]);
    }
  }
  ota_io_init(za, state.is_retry);

  std::string result;
  bool status = Evaluate(&state, root, &result);

  if (have_eio_error) {
    fprintf(cmd_pipe, "retry_update\n");
  }

  if (!status) {
    if (state.errmsg.empty()) {
      LOG(ERROR) << "script aborted (no error message)";
      fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
    } else {
      LOG(ERROR) << "script aborted: " << state.errmsg;
      const std::vector<std::string> lines = android::base::Split(state.errmsg, "\n");
      for (const std::string& line : lines) {
        // Parse the error code in abort message.
        // Example: "E30: This package is for bullhead devices."
        if (!line.empty() && line[0] == 'E') {
          if (sscanf(line.c_str(), "E%d: ", &state.error_code) != 1) {
            LOG(ERROR) << "Failed to parse error code: [" << line << "]";
          }
        }
        fprintf(cmd_pipe, "ui_print %s\n", line.c_str());
      }
    }

    // Installation has been aborted. Set the error code to kScriptExecutionFailure unless
    // a more specific code has been set in errmsg.
    if (state.error_code == kNoError) {
      state.error_code = kScriptExecutionFailure;
    }
    fprintf(cmd_pipe, "log error: %d\n", state.error_code);
    // Cause code should provide additional information about the abort.
    if (state.cause_code != kNoCause) {
      fprintf(cmd_pipe, "log cause: %d\n", state.cause_code);
      if (state.cause_code == kPatchApplicationFailure) {
        LOG(INFO) << "Patch application failed, retry update.";
        fprintf(cmd_pipe, "retry_update\n");
      }
    }

    if (updater_info.package_zip) {
      CloseArchive(updater_info.package_zip);
    }
    return 7;
  } else {
    fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str());
  }

  if (updater_info.package_zip) {
    CloseArchive(updater_info.package_zip);
  }

  return 0;
}

 

Python-OpenCV及cv2,numpy库最新安装教程[最全步骤] 安装教程目录前言OpenCV-Python安装教程报错解决cv2安装numpy安装opencv安装(附加)总结 前言 首先,我知道一些看到我的Blog的人已经在网上找了很多歪路子,现在已经火冒三丈了(我也是这样过来的hhhh),那么现在,深呼吸,跟着我的教程,不要着急,每一步都要读一遍。完整安装过程需要1个小时左右(仅供参考,本人第一次安装python花了一天(确信)) OpenCV-Python... 阅读详情

相关推荐

过压保护电路(OVP)

作者:AirCity 2020.2.4 Aircity007@sina.com 本文所有权归作者Aircity所有 1 示例一 当VBUS=5V时,各点电压电流如图所示,Q1接近截止,输出信号是5V。 当VBUS=5.4V开始,输出信号开始下降,直到VBUS=6.1V,输出信号降低为0.6V。 下面是实测波形,这个电路,输出信号的电压不会超过5.4V,这个输出信号可用于电源的控制信号。 2 ...

AirCity123的博客 3万+

Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程

Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程           目前update-script脚本格式是edify,其与amend有何区别,暂不讨论,我们只分析其中主要的语法,以及脚本的流程控制。 一、update-script脚本语法简介:         我们顺着

mu0206mu的专栏 2万+

逆向实战:喜马拉雅新版xm-sign算法解析与本地化生成方案

本文深入解析了喜马拉雅新版xm-sign算法的逆向过程与本地化生成方案。通过详细拆解browserid和sessionid的生成机制,提供了基于Node.js的核心代码实现,帮助开发者在不依赖官方环境的情况下生成有效签名。文章还涵盖了参数获取技巧、常见问题排查及性能优化建议,为爬虫开发者提供了实用的技术参考。

weixin_29256771的博客 299

update-script脚本语法说明(根据android源代码中的recovery.c进行的定义)

update-script脚本语法说明(根据android源代码中的recovery.c进行的定义): 1.copy_dir 语法:copy_dir [] 表示原文件夹,表示目的文件夹,[]表示时间戳 作用:将文件夹中的内容复制到文件夹中。文件夹中的原始内容将会保存不变,除非文件夹中有相同的内容,这样中的内容将被覆盖 举例:copy_dir PACKAGE:system SY

Lidong_Zhou的专栏 1594

【2023版】基于JT808/JT1078协议的车载视频监控平台开发实战-开源架构解析

本文详细解析了基于JT808/JT1078协议的车载视频监控平台开发实战,涵盖协议核心作用、开源架构设计、开发避坑指南及二次开发建议。重点介绍了JT1078协议在音视频传输中的优化方案,以及海量位置数据存储、高可用架构等关键技术点,为开发者提供全面的实战参考。

weixin_26965807的博客 236

机器学习(ML)在材料领域应用

机器学习作为一种兼顾开发效率以及开发成本的方法,已经逐渐应用于材料发现、结构分析、性质预测、反向设计等多个领域,并且在材料学研究中展现出惊人的潜力。传统的发现新材料的方法,如经验试错法和基于密度泛函理论(DFT)的方法,往往需要较长的研发周期,成本高、效率低,已经不能很好的适应如今需求量激增的材料学领域 ...

W5632DE的博客 3716

android的刷机方式

刷机攻略,回归一下。 主要刷机方式,EDL(紧急下载,USB端口9008),fastboot工具线刷,OTA升级(全包/差分升级,nonAB系统与AB系统升级)。这个玩android系统的基本都知道,还是列个表: 环境 进入方式 工具 EDL模式 ...

鹅鹅鹅的博客 1万+

北京理工大学计算机学院赵曜,中国进出口银行2016年度拟接收毕业生情况公示...

《中国进出口银行2016年度拟接收毕业生情况公示》由会员分享,可在线阅读,更多相关《中国进出口银行2016年度拟接收毕业生情况公示(5页珍藏版)》请在技术文库上搜索。1、二级(三级)单位二级(三级)单位姓名姓名性别性别学历学历毕业学校毕业学校专业专业 中国进出口银行总行 机关 许凯男硕士研究生北京大学法学 中国进出口银行总行 机关 冯晨男硕士研究生北京大学教育技术学 中国进出口银行总行 机关 刘鹏...

weixin_42168902的博客 4274

Android系统Recovery工作原理之使用update.zip升级过程分析(八)---解析并执行升级脚本updater-script【转】...

本文转载自:http://blog.csdn.net/mu0206mu/article/details/7465551 Android系统Recovery工作原理之使用update.zip升级过程分析(八)---升级程序update_binary的执行过程 一、update_binary的执行过程分析 上一篇幅中的子进程所执行的程序binary实际上就是upd...

414

基于STM32避障/循迹/蓝牙遥控小车的硬件与软件底层设计

1、实现2m的自动直线行驶,要求左右偏移不大于10cm。2、车载显示屏显示车辆当前行驶速度或车辆运行时间,当前方20cm内出现障碍物时显示与前方障碍物的距离,车每次转弯蜂鸣器报警,同时通过左右指示灯指示转弯方向。3、依次驶过障碍物①②③④,且不触碰障碍物。4、成功进行调头转弯,行驶过程中车轮不碾压黑实线。5、在车道指定位置停车且不越界。6、通过红外、蓝牙、WiFi等任意一种方式实现对小车的控制,使其前进、后退、左转、右转。

2301_78758161的博客 1万+

腾讯2020 unreal虚幻面试题

解析一下,腾讯的unreal客户端面试题: 1.lua性能优化的方向 申请的内存,是造成卡顿的原因之一,在C++与lua交互中,如果参数或者返回值有类变量,那么这个变量不会再交互的栈中存放数据,而会通过申请内存,再指定在交互,这样就造成卡顿,因此可以通过把C++的对象的每个参数分开单独传递,可以解决问题,当时我们游戏改完这个问题后,整体提升了2帧。 其实,主要是Tick循环中,减少与C++的交互,需要的数据不要每帧都去拿,其次,经常拿的一些数据(比方说主角信息),可以做一个lua缓存,...

qq_17347313的博客 1万+

Android Recovery升级原理

Android Recovery升级原理 摘要 Recovery模式指的是一种可以对安卓机内部的数据或系统进行修改的模式(类似于windows PE或DOS)。也可以称之为安卓的恢复模式,在这个所谓的恢复模式下,我们可以刷入新的安卓系统,或者对已有的系统进行备份或升级,也可以在此恢复出厂设置(格式化数据和缓存)。 1. Recovery相关概念 Recovery: Recovery模式指的是一种可以对安卓机内部的数据或系统进行修改的模式,也指Android的Recovery分区 OTA: Ove.

u010783226的专栏 2360

8、水力压裂引起的地质材料力学性质变化的可视化研究

本研究探讨了水力压裂引起的地质材料力学性质变化的可视化方法。利用超声剪切波形数据,通过短时傅里叶变换(STFT)和主成分分析(PCA)进行特征提取和降维,并应用K-means聚类、凝聚聚类和DBSCAN等无监督学习方法对地质力学变化进行非侵入式可视化分析。研究比较了不同特征工程、聚类方法和降维策略对可视化效果的影响,并结合位移不连续性理论为聚类结果分配地质力学变化指数,以提高结果的物理解释性。最终,该方法成功实现了对水力压裂引起的岩石力学性质变化的高效、可靠可视化。

emacs5lisp的博客 109

try_update_binary

recovery代码分析之三:try_update_binary 2013年02月04日 ⁄ 综合 ⁄ 共 3675字 ⁄ 字号 小 中 大 ⁄ 评论关闭         OTA升级包路径META-INF\com\google\android中,存在着两个关键的文件:update-script和update-binary。在这两个脚本文件中,update

lin364812726的专栏 849

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

recovery代码分析之三:try_update_binary

OTA升级包路径META-INF\com\google\android中,存在着两个关键的文件:update-script和update-binary。在这两个脚本文件中,update-script记载着系统升级所需要执行的命令(如图1所示),而update-binary则是对于每条命令的解析。进入recovery模式后,系统将会执行文件中记载的命令,完成升级。 图1 update-scri

霜只哀伤的专栏 6702

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

install.cpp文件try_update_binary()函数安装过程分析

static int try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);//lefty_lan:在zip格式的更新...

Hellolefty的博客 611

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Android OTA升级包制作脚本详解(五,升级脚本updater-script的执行<1>)

写在前面: 首先当我们执行升级脚本updater-script的时候,就表示我们已经进入了升级安装状态。那么在我们就从实际的安装作为入口开始分析。也就是说我们从install.cpp中的install_package函数开始一步步来分析。 这里主要分析与脚本相关的部分,其他的请参考这位朋友的博文http://blog.chinaunix.net/uid-22028566-id-

从0到1,突破自己 5034

android ota 升级脚本,Android OTA升級包制作腳本詳解(五,升級腳本updater-script的執行<1>)...

寫在前面:首先當我們執行升級腳本updater-script的時候,就表示我們已經進入了升級安裝狀態。那么在我們就從實際的安裝作為入口開始分析。也就是說我們從install.cpp中的install_package函數開始一步步來分析。這里主要分析與腳本相關的部分,其他的請參考這位朋友的博文http://blog.chinaunix.net/uid-22028566-id-3533856.html...

weixin_39765280的博客 245

Recovery启动流程--recovery.cpp分析

这篇文章主要通过分析高通recovery目录下的recovery.cpp源码,对recovery启动流程有一个宏观的了解。 当开机以后,在lk阶段,如果是recovery,会设置boot_into_recovery=1,然后读取recovery.img镜像,把recovery.img的地址和ramdisk等信息作为参数启动kernel,从而进入recovery模式,下面进行简单的分析。 ...

weixin_30666401的博客 1141

Android系统Recovery工作原理之使用update.zip升级过程分析(七)

Android系统Recovery工作原理之使用update.zip升级过程分析(七)---Recovery服务的核心install_package函数 一、 Recovery服务的核心install_package(升级update.zip特有) 和Recovery服务中的wipe_data、wipe_cache不同,in...

FLY_THINK2012的博客 190

recovery代码分析(二)

really_install_package()函数 really_install_package()函数位于install.cpp。 static int really_install_package(const std::string &path, bool *wipe_cache, bool needs_mount, std::vector<std::string> *log_buffer, int retry_c

我是Timothy 614

【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析

今天我们直接来看下android中具体的升级过程是如何的。 升级流程概述 升级的流程图: 升级流程分析 第一步:升级包获取 升级获取可以通过远程下载,也可直接拷贝到指定目录即可。 第二步:准备升级 然后调用RecoverySystem.installPackage将目录通过传参方式传递下去。这是应用层代码如下: public void updateSyst...

看图的博客 6013

Android Recovery OTA升级(二)—— Recovery源码解析

目录目录 Recovery源码分析 概述 main函数 输出重定向 填充fstab结构体 挂载cache分区 获取Recovery命令参数 分析recovery命令 install_package load_keys加载公钥原文件 verify_file对升级包进行签名校验 mzOpenZipArchive-打开升级包获取相关信息 try_update_binary-ota真正执行的地方Recove

小一的专栏 1万+

学习笔记—— 一些UPDATE语句

UPDATE语句原来还有许多种写法,有的还很复杂,孤陋寡闻的我甚至闻所未闻。幸甚至哉,记而志之。0、UPDATE 表名 SET 字段。。。 FROM 。。。的方式USE AdventureWorks2012;GOUPDATE Production.ScrapReasonSET Name += ' - tool malfunction'FROM Production.ScrapReason AS...

weixin_34218890的博客 202
上一篇: 四、install_package详细流程
下一篇: 三年Android技术支持工作总结及心得
李标标
博客等级 码龄11年 124粉丝 43原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值