Android P update_engine分析-- PostinstallRunnerAction的工作
Posted Give.Me.Five
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android P update_engine分析-- PostinstallRunnerAction的工作相关的知识,希望对你有一定的参考价值。
上篇已经分析过了InstallPlanAction、DownloadAction、FileSystemVerityAction 三个Action的工作内容,还有一个PostinstallRunnerAction的在这篇中继续分析,每个Action都是从PerformAction开始的:
void PostinstallRunnerAction::PerformAction() {
CHECK(HasInputObject());
install_plan_ = GetInputObject();
//确认下是否需要powerwash_, 如果有设置,一般在ApplyPayload的那个hashKey中会带有POWERWASH的key值
if (install_plan_.powerwash_required) {
if (hardware_->SchedulePowerwash()) {
powerwash_scheduled_ = true;
} else {
return CompletePostinstall(ErrorCode::kPostinstallPowerwashError);
}
}
// 初始化所有升级分区的权重
partition_weight_.resize(install_plan_.partitions.size());
total_weight_ = 0;
for (size_t i = 0; i < install_plan_.partitions.size(); ++i) {
partition_weight_[i] = install_plan_.partitions[i].run_postinstall;
total_weight_ += partition_weight_[i];
}
accumulated_weight_ = 0;
ReportProgress(0);
PerformPartitionPostinstall();
}
上面主要做判断是否需要powerwash_,一般的升级方式不需要powerwash,然后初始升级分区的权重,同时保存这些权重值,之后开始分区升级:
void PostinstallRunnerAction::PerformPartitionPostinstall() {
//判断是否在升级过程中
if (!install_plan_.run_post_install) {
LOG(INFO) << "Skipping post-install according to install plan.";
return CompletePostinstall(ErrorCode::kSuccess);
}
//判断下载路么为空
if (install_plan_.download_url.empty()) {
LOG(INFO) << "Skipping post-install during rollback";
return CompletePostinstall(ErrorCode::kSuccess);
}
//检查当前分区是否需要升级(升级文件大小与当前分区比较以及当前分区是否需要升级)
while (current_partition_ < install_plan_.partitions.size() &&
!install_plan_.partitions[current_partition_].run_postinstall) {
VLOG(1) << "Skipping post-install on partition "
<< install_plan_.partitions[current_partition_].name;
current_partition_++;
}
//当前要升给的分区等于分区数据,表示已经遍历完一遍分区了
if (current_partition_ == install_plan_.partitions.size())
return CompletePostinstall(ErrorCode::kSuccess);
//获取当前分区,同时挂载当前需要升级分区,挂载到/postinstall 目录下
const InstallPlan::Partition& partition =
install_plan_.partitions[current_partition_];
const string mountable_device =
utils::MakePartitionNameForMount(partition.target_path);
if (mountable_device.empty()) {
LOG(ERROR) << "Cannot make mountable device from " << partition.target_path;
return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
}
// Perform post-install for the current_partition_ partition. At this point we
// need to call CompletePartitionPostinstall to complete the operation and
// cleanup.
#ifdef __android__
fs_mount_dir_ = "/postinstall";
#else // __ANDROID__
base::FilePath temp_dir;
TEST_AND_RETURN(base::CreateNewTempDirectory("au_postint_mount", &temp_dir));
fs_mount_dir_ = temp_dir.value();
#endif // __ANDROID__
//再次确认,挂载路径是不是已经被挂载了
if (utils::IsMountpoint(fs_mount_dir_)) {
LOG(INFO) << "Found previously mounted filesystem at " << fs_mount_dir_;
utils::UnmountFilesystem(fs_mount_dir_);
}
//将升级包分区设备赋值
base::FilePath postinstall_path(partition.postinstall_path);
if (postinstall_path.IsAbsolute()) {
LOG(ERROR) << "Invalid absolute path passed to postinstall, use a relative"
"path instead: "
<< partition.postinstall_path;
return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
}
//设置挂载点的绝对路径,并检查
string abs_path =
base::FilePath(fs_mount_dir_).Append(postinstall_path).value();
if (!base::StartsWith(
abs_path, fs_mount_dir_, base::CompareCase::SENSITIVE)) {
LOG(ERROR) << "Invalid relative postinstall path: "
<< partition.postinstall_path;
return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
}
#ifdef __ANDROID__
// In Chromium OS, the postinstall step is allowed to write to the block
// device on the target image, so we don't mark it as read-only and should
// be read-write since we just wrote to it during the update.
// Mark the block device as read-only before mounting for post-install.
//在挂载前,将要升级包的设备设置为只读
if (!utils::SetBlockDeviceReadOnly(mountable_device, true)) {
return CompletePartitionPostinstall(
1, "Error marking the device " + mountable_device + " read only.");
}
#endif // __ANDROID__
if (!utils::MountFilesystem(mountable_device,
fs_mount_dir_,
MS_RDONLY,
partition.filesystem_type,
constants::kPostinstallMountOptions)) {
return CompletePartitionPostinstall(
1, "Error mounting the device " + mountable_device);
}
LOG(INFO) << "Performing postinst (" << partition.postinstall_path << " at "
<< abs_path << ") installed on device " << partition.target_path
<< " and mountable device " << mountable_device;
// Logs the file format of the postinstall script we are about to run. This
// will help debug when the postinstall script doesn't match the architecture
// of our build.
LOG(INFO) << "Format file for new " << partition.postinstall_path
<< " is: " << utils::GetFileFormat(abs_path);
//组合command:abs_path target_slot kPostinstallStatusFd
vector<string> command = {abs_path};
#ifdef __ANDROID__
// In Brillo and Android, we pass the slot number and status fd.
command.push_back(std::to_string(install_plan_.target_slot));
command.push_back(std::to_string(kPostinstallStatusFd));
#else
// Chrome OS postinstall expects the target rootfs as the first parameter.
command.push_back(partition.target_path);
#endif // __ANDROID__
//执行command指令,错误信息输出kRedirectStderrToStdout,输出管道使用kPostinstallStatusFd
current_command_ = Subprocess::Get().ExecFlags(
command,
Subprocess::kRedirectStderrToStdout,
{kPostinstallStatusFd},
base::Bind(&PostinstallRunnerAction::CompletePartitionPostinstall,
base::Unretained(this)));
// Subprocess::Exec should never return a negative process id.
CHECK_GE(current_command_, 0);
if (!current_command_) {
CompletePartitionPostinstall(1, "Postinstall didn't launch");
return;
}
//查看kPostinstallStatusFd是否可以打开
progress_fd_ =
Subprocess::Get().GetPipeFd(current_command_, kPostinstallStatusFd);
int fd_flags = fcntl(progress_fd_, F_GETFL, 0) | O_NONBLOCK;
if (HANDLE_EINTR(fcntl(progress_fd_, F_SETFL, fd_flags)) < 0) {
PLOG(ERROR) << "Unable to set non-blocking I/O mode on fd " << progress_fd_;
}
//监听progress_fd_, 从这里面读出升级的状态和进度
progress_task_ = MessageLoop::current()->WatchFileDescriptor(
FROM_HERE,
progress_fd_,
MessageLoop::WatchMode::kWatchRead,
true,
base::Bind(&PostinstallRunnerAction::OnProgressFdReady,
base::Unretained(this)));
}
上面执行partition.postinstall_path的指令,然后从执行的过程中,获取状态和进度,但从生成的update.zip包看查看,没有postinstall_path这个执行脚本。所以这一步在android升级中是没有做任何事情的。
下篇我们将重点的研究DownloadAction 里的工作和下载的流程,AB升级的实际分区升级的工作也是在这个里面进行的。
以上是关于Android P update_engine分析-- PostinstallRunnerAction的工作的主要内容,如果未能解决你的问题,请参考以下文章
Android P update_engine分析--升级核心DeltaPerformer的分析
Android P update_engine分析--升级核心DeltaPerformer的分析
Android P update_engine分析--升级核心DeltaPerformer的分析
Android P update_engine分析--升级核心DeltaPerformer的分析