一、我们从上一篇已经知道整个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。