UpdateAttempterAndroid及action机制

一、我们从上一篇已经知道整个update_engine的核心就是UpdateAttempterAndroid,那我们就接着来看UpdateAttempterAndroid都做了写什么事。
我们知道BinderUpdateEngineAndroidService的核心方法就是applyPayload(),而BinderUpdateEngineAndroidService :: applyPayload()的内部又调用的是UpdateAttempterAndroid的applyPayload(),这里就主要分析UpdateAttempterAndroid::applyPayload();

这里先把update.zip的内容展示一下
在这里插入图片描述

还是从分析代码开始:

system/update_engine/update_attempter_android.cc
void UpdateAttempterAndroid::Init() {
  // In case of update_engine restart without a reboot we need to restore the
  // reboot needed state.
  if (UpdateCompletedOnThisBoot()) { // 这里有一种case就是如果在升级下载刚完成时,update_engine程序挂掉了,但是机器并没有关机,update_engine被再次拉起,就先会去判断是否上次整个下载写入分区完成,如果完成就直接通知重启机器,
    SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
  } else { 
    if (!boot_control_->MarkBootSuccessfulAsync(Bind([](bool successful){}))) {
      LOG(WARNING) << "clear boot_control tries_remaining failed ";
    }
    SetStatusAndNotify(UpdateStatus::IDLE); // 如果不是上面的那种情况就进去空闲模式
    UpdatePrefsAndReportUpdateMetricsOnReboot();
  }
}

bool UpdateAttempterAndroid::ApplyPayload(
    const string& payload_url, //升级文件的file或者http 路径
    int64_t payload_offset,   // paylood.bin文件在update.zip中的偏移量
    int64_t payload_size,    // paylood.bin的大小
    const vector<string>& key_value_pair_headers, // payload_properties.txt的内容 如下
    /* FILE_HASH=3iyIhAclW0+nST5m6IcOHjcBJdqltnSjUpC00rH/QDM=
    FILE_SIZE=537106805
    METADATA_HASH=7G5qkHiV//xB07FfNBOJ65diSCgLeb46dTZctkoMydg=
    METADATA_SIZE=57962 */

    brillo::ErrorPtr* error) {
    // 一进来还是先判断是否上次升级完成了
  if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) { 
    return LogAndSetError(
        error, FROM_HERE, "An update already applied, waiting for reboot");
  }
  // 如果当前一个升级正在继续就取消这次升级任务
  if (ongoing_update_) { 
    return LogAndSetError(
        error, FROM_HERE, "Already processing an update, cancel it first.");
  }
  //确保ApplyPayload进来update_engine是空闲状态
  DCHECK(status_ == UpdateStatus::IDLE); 
  std::map<string, string> headers;
  // 解析payload_properties.txt的内容
  for (const string& key_value_pair : key_value_pair_headers) { 
    string key;
    string value;
    if (!brillo::string_utils::SplitAtFirst(
            key_value_pair, "=", &key, &value, false)) {
      return LogAndSetError(
          error, FROM_HERE, "Passed invalid header: " + key_value_pair);
    }
    if (!headers.emplace(key, value).second)
      return LogAndSetError(error, FROM_HERE, "Passed repeated key: " + key);
  }

  // Unique identifier for the payload. An empty string means that the payload
  // can't be resumed.
   payload_id 的到 FILE_HASH和METADATA_HASH
  string payload_id = (headers[kPayloadPropertyFileHash] +
                       headers[kPayloadPropertyMetadataHash]); 

  // Setup the InstallPlan based on the request.
   // 使用传入的参数构建install_plan_
  install_plan_ = InstallPlan();
  install_plan_.download_url = payload_url;
  install_plan_.version = "";
  // set base_offset for libcur or fileHttp, base_offset is payload Offset in update.zip
  base_offset_ = payload_offset;
  InstallPlan::Payload payload;
  payload.size = payload_size;
  if (!payload.size) {
    if (!base::StringToUint64(headers[kPayloadPropertyFileSize],
                              &payload.size)) {
      payload.size = 0;
    }
  }
  if (!brillo::data_encoding::Base64Decode(headers[kPayloadPropertyFileHash],
                                           &payload.hash)) {
    LOG(WARNING) << "Unable to decode base64 file hash: "
                 << headers[kPayloadPropertyFileHash];
  }
  if (!base::StringToUint64(headers[kPayloadPropertyMetadataSize],
                            &payload.metadata_size)) {
    payload.metadata_size = 0;
  }
  // The |payload.type| is not used anymore since minor_version 3.
  // 默认升级包的类型为 kUnknown
  payload.type = InstallPayloadType::kUnknown;
  install_plan_.payloads.push_back(payload);

  // The |public_key_rsa| key would override the public key stored on disk.
  install_plan_.public_key_rsa = "";

  install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild();
  install_plan_.is_resume = !payload_id.empty() &&
                            DeltaPerformer::CanResumeUpdate(prefs_, payload_id);
  if (!install_plan_.is_resume) {
    if (!DeltaPerformer::ResetUpdateProgress(prefs_, false)) {
      LOG(WARNING) << "Unable to reset the update progress.";
    }
    if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) {
      LOG(WARNING) << "Unable to save the update check response hash.";
    }
  }
  // 标记要升级的slot为target_slot 
  install_plan_.source_slot = boot_control_->GetCurrentSlot();
  install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;

  install_plan_.powerwash_required =
      GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false);

  install_plan_.switch_slot_on_reboot =
      GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true);

  install_plan_.run_post_install = true;
  // Optionally skip post install if and only if:
  // a) we're resuming
  // b) post install has already succeeded before
  // c) RUN_POST_INSTALL is set to 0.
  if (install_plan_.is_resume && prefs_->Exists(kPrefsPostInstallSucceeded)) {
    bool post_install_succeeded = false;
    prefs_->GetBoolean(kPrefsPostInstallSucceeded, &post_install_succeeded);
    if (post_install_succeeded) {
      install_plan_.run_post_install =
          GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true);
    }
  }

  NetworkId network_id = kDefaultNetworkId;
  if (!headers[kPayloadPropertyNetworkId].empty()) {
    if (!base::StringToUint64(headers[kPayloadPropertyNetworkId],
                              &network_id)) {
      return LogAndSetError(
          error,
          FROM_HERE,
          "Invalid network_id: " + headers[kPayloadPropertyNetworkId]);
    }
    if (!network_selector_->SetProcessNetwork(network_id)) {
      return LogAndSetError(
          error,
          FROM_HERE,
          "Unable to set network_id: " + headers[kPayloadPropertyNetworkId]);
    }
  }

  LOG(INFO) << "Using this install plan:";
  install_plan_.Dump(); // 这是我打出来的log, InstallPlan: new_update, version: , source_slot: A, target_slot: B, url: http://10.16.17.170:8080/downloads/ota_update.zip, payload: (size: 537106805, metadata_size: 57962, metadata signature: , hash: DE2C888407255B4FA7493E66E8870E1E370125DAA5B674A35290B4D2B1FF4033, payload type: unknown), hash_checks_mandatory: true, powerwash_required: false, switch_slot_on_reboot: true, run_post_install: true

  BuildUpdateActions(payload_url); // 1.1 解析如下
  // Setup extra headers.
  HttpFetcher* fetcher = download_action_->http_fetcher();
  if (!headers[kPayloadPropertyAuthorization].empty())
    fetcher->SetHeader("Authorization", headers[kPayloadPropertyAuthorization]);
  if (!headers[kPayloadPropertyUserAgent].empty())
    fetcher->SetHeader("User-Agent", headers[kPayloadPropertyUserAgent]);

  SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE); //1.2 解析如下
  ongoing_update_ = true;

  // Just in case we didn't update boot flags yet, make sure they're updated
  // before any update processing starts. This will start the update process.
  UpdateBootFlags(); //1.3 解析如下

  UpdatePrefsOnUpdateStart(install_plan_.is_resume);
  // TODO(xunchang) report the metrics for unresumable updates

  return true;
}

Action的类图
在这里插入图片描述

1.1 这里面主要做的就是构建四个action然后将这四个action set到ActionProcessor的 std::deque<AbstractAction*> actions_中。
void UpdateAttempterAndroid::BuildUpdateActions(const string& url) {
  // 检查ActionProcessor是否已经处于Running状态
  CHECK(!processor_->IsRunning());
  //将自己设置为ActionProcessor的代理对象,ActionProcessor只需要通过代理对象就可以向外发送通知
  processor_->set_delegate(this);

  // Actions:
  // 构建 InstallPlanAction
  shared_ptr<InstallPlanAction> install_plan_action(
      new InstallPlanAction(install_plan_));

  HttpFetcher* download_fetcher = nullptr;
  if (FileFetcher::SupportedUrl(url)) { // 判断是url是 file还是http
    DLOG(INFO) << "Using FileFetcher for file URL.";
    download_fetcher = new FileFetcher(); //url 是 file 就是FileFetcher负责read
  } else {
#ifdef _UE_SIDELOAD
    LOG(FATAL) << "Unsupported sideload URI: " << url;
#else
    LibcurlHttpFetcher* libcurl_fetcher =
        new LibcurlHttpFetcher(&proxy_resolver_, hardware_); // url是http LibcurlHttpFetcher负责下载
    libcurl_fetcher->set_server_to_check(ServerToCheck::kDownload);
    download_fetcher = libcurl_fetcher;
#endif  // _UE_SIDELOAD
  }
  // 构建 DownloadAction
  shared_ptr<DownloadAction> download_action(
      new DownloadAction(prefs_,
                         boot_control_,
                         hardware_,
                         nullptr,           // system_state, not used.
                         download_fetcher,  // passes ownership
                         true /* is_interactive */));
  //构建 FilesystemVerifierAction
  shared_ptr<FilesystemVerifierAction> filesystem_verifier_action(
      new FilesystemVerifierAction());

 //构建 PostinstallRunnerAction
  shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
      new PostinstallRunnerAction(boot_control_, hardware_));

  download_action->set_delegate(this);
  download_action->set_base_offset(base_offset_);
  download_action_ = download_action;
  postinstall_runner_action->set_delegate(this);

  // 将四个action都set到ActionProcessor的 std::deque<AbstractAction*> actions_中。
  actions_.push_back(shared_ptr<AbstractAction>(install_plan_action));
  actions_.push_back(shared_ptr<AbstractAction>(download_action));
  actions_.push_back(shared_ptr<AbstractAction>(filesystem_verifier_action));
  actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));

  // Bond them together. We have to use the leaf-types when calling
  // BondActions().
  //通过ActionPipe将4个Action连接起来,前面action的结果作为输入到下一个action。
  BondActions(install_plan_action.get(), download_action.get());
  BondActions(download_action.get(), filesystem_verifier_action.get());
  BondActions(filesystem_verifier_action.get(),
              postinstall_runner_action.get());

  // Enqueue the actions.
  //将Action添加到ActionProcessor的管理队列中
  for (const shared_ptr<AbstractAction>& action : actions_)
    processor_->EnqueueAction(action.get());
}

SetStatusAndNotify的通知时序图
在这里插入图片描述
1.2 通过 SetStatusAndNotify通知到 BinderUpdateEngineAndroidService再通知到UI

void UpdateAttempterAndroid::SetStatusAndNotify(UpdateStatus status) {
  status_ = status;
  size_t payload_size =
      install_plan_.payloads.empty() ? 0 : install_plan_.payloads[0].size;
  UpdateEngineStatus status_to_send = {.status = status_,
                                       .progress = download_progress_,
                                       .new_size_bytes = payload_size};

  for (auto observer : daemon_state_->service_observers()) {
    observer->SendStatusUpdate(status_to_send); //通知 BinderUpdateEngineAndroidService::SendStatusUpdate()
  }
  last_notify_time_ = TimeTicks::Now();
}

1.3 UpdateBootFlags 从这个后面就会走到actionProcess中去,具体执行内容是在ActionProcess中的调用。
见整体调用时序图,黑框内的。
在这里插入图片描述

void UpdateAttempterAndroid::UpdateBootFlags() {
  if (updated_boot_flags_) { //是否成功调用过boot_control_-> MarkBootSuccessfulAsync()标记当前slot
    LOG(INFO) << "Already updated boot flags. Skipping.";
    CompleteUpdateBootFlags(true);
    return;
  }
  // This is purely best effort.
  LOG(INFO) << "Marking booted slot as good.";
  if (!boot_control_->MarkBootSuccessfulAsync(
          Bind(&UpdateAttempterAndroid::CompleteUpdateBootFlags,
               base::Unretained(this)))) {
    LOG(ERROR) << "Failed to mark current boot as successful.";
    CompleteUpdateBootFlags(false);
  }
}

二,action机制。
在UpdateAttempterAndroid中重点就是Action机制

2.1、Action机制:
Action机制主要有三个部分组成: Action, ActionProcessor和ActionPipe
2.1.1 Action
基于Action机制,Update Engine里面的每一个任务都被封装为一个Action,在UpdateAttempterAndroid中大致分为是三个任务段,1、DownloadAction 主要负责下载数据和写入数据到相应的分区。 2 、FilesystemVerifierAction主要负责验证写入的数据hash值和下载包里面带的原有的hash值是否有差别。3、PostinstallRunnerAction 更新完成后所有收尾动作。但是还有一个Action InstallPlanAction,其实这个action没有具体的大任务,就是负责第一个传递install_plan_这个对象,暂且这么理解吧。

2.1.2、ActionProcessor
在ActionProcessor里面定义了一个Action的队列, 在Update Engine准备更新时,会根据当前传入的参数构造多个Action并放入ActionProcessor的Action队列,除了Action队列,ActionProcessor中还有一个指针,用于指示当前正在运行的ActionActionProcessor通过StartProcessing()操作开始工作,先挑选队列中的第一个Action作为当前Action。然后当前Action调用,PerformAction()开始工作,Action结束后会调用ActionProcessor的ActionComplete()接口通知当前Action已经完成。随后ActionProcessor通过StartNextActionOrFinish()挑选队列中的下一个Action进行操作。循环往复,直到队列中的所有Action都完成操作。

2.1.3 Action pipe
类似于Unix系统的管道,Action机制中,也会通过管道ActionPipe将这些Action链接在一起。上一个Action的输出会作为下一个Action的输入,因此在Update Engine中,所有的Action之间有一个先后关系。例如,只有DownloadAction完成操作了,才能开始FilesystemVerifierAction操作;也只有FilesystemVerifierAction结束了,才会开始PostinstallRunnerAction操作。

总结:从上面我们知道了UpdateAttempterAndroid的核心又是四个action的具体任务,并且四个action是通过action机制进行管理的每一个action的执行结果都作为参数传递给后一个action。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值