* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "include/updater/updater.h"
#include <cerrno>
#include <chrono>
#include <cstdio>
#include <iomanip>
#include <string>
#include <sched.h>
#include <syscall.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
#include <thread>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include "fs_manager/mount.h"
#include "language/language_ui.h"
#include "log/dump.h"
#include "log/log.h"
#include "package/hash_data_verifier.h"
#include "package/pkg_manager.h"
#include "package/packages_info.h"
#include "parameter.h"
#include "misc_info/misc_info.h"
#ifdef WITH_SELINUX
#include <policycoreutils.h>
#include "selinux/selinux.h"
#endif
#ifdef UPDATER_USE_PTABLE
#include "ptable_parse/ptable_manager.h"
#endif
#include "scope_guard.h"
#include "slot_info/slot_info.h"
#include "trace/io_collect.h"
#include "updater/hardware_fault_retry.h"
#include "updater/updater_preprocess.h"
#include "updater/updater_const.h"
#include "updater_main.h"
#include "updater_ui_stub.h"
#include "utils.h"
#include "write_state/write_state.h"
namespace Updater {
using Updater::Utils::SplitString;
using Updater::Utils::Trim;
using namespace Hpackage;
using namespace Utils;
thread_local int g_percentage = 100;
thread_local int g_tmpProgressValue;
thread_local int g_tmpValue;
thread_local bool g_canceled = false;
void SetCancelStatus(bool isCanceled)
{
g_canceled = isCanceled;
}
bool GetCancelStatus(void)
{
return g_canceled;
}
static void SetBinaryDeathSig(void)
{
if (Utils::IsUpdaterMode()) {
LOG(INFO) << "no need set death sig, when updater mode";
return;
}
if (prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
LOG(ERROR) << "prctl failed " << strerror(errno);
}
}
std::string GetCurrentPackagePath(const UpdaterParams &upParams)
{
if (upParams.pkgLocation >= upParams.updatePackage.size()) {
LOG(ERROR) << "pkg location is invalid " << upParams.pkgLocation << " " << upParams.updatePackage.size();
return "";
}
return upParams.updatePackage[upParams.pkgLocation];
}
int32_t ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager, std::string &packagePath,
const std::string &updaterBinary)
{
UPDATER_INIT_RECORD;
PkgManager::StreamPtr outStream = nullptr;
int32_t ret = manager->CreatePkgStream(outStream, GetWorkPath() + updaterBinary,
0, PkgStream::PkgStreamType_Write);
if (ret != PKG_SUCCESS) {
LOG(ERROR) << "ExtractUpdaterBinary create stream fail";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "ExtractUpdaterBinary create stream fail");
return UPDATE_CORRUPT;
}
ret = manager->ExtractFile(updaterBinary, outStream);
if (ret != PKG_SUCCESS) {
LOG(ERROR) << "ExtractUpdaterBinary extract file failed";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "ExtractUpdaterBinary extract file failed");
return UPDATE_CORRUPT;
}
HashDataVerifier verifier {manager};
if (!verifier.LoadHashDataAndPkcs7(packagePath) ||
!verifier.VerifyHashData("build_tools/", updaterBinary, outStream)) {
LOG(ERROR) << "verify updater_binary failed";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "verify updater_binary failed");
return UPDATE_CORRUPT;
}
manager->ClosePkgStream(outStream);
return UPDATE_SUCCESS;
}
int GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager, const std::string &path)
{
std::vector<std::string> components;
if (pkgManager == nullptr) {
LOG(ERROR) << "pkgManager is nullptr";
return UPDATE_CORRUPT;
}
int32_t ret = pkgManager->LoadPackage(path, Utils::GetCertName(), components);
if (ret != PKG_SUCCESS) {
LOG(INFO) << "LoadPackage fail ret :"<< ret;
return ret;
}
return PKG_SUCCESS;
}
UpdaterStatus IsSpaceCapacitySufficient(UpdaterParams &upParams)
{
UPDATER_INIT_RECORD;
std::vector<uint64_t> stashSizeList = GetStashSizeList(upParams);
if (stashSizeList.size() == 0) {
LOG(ERROR) << "get stash size error";
UPDATER_LAST_WORD(UPDATE_ERROR, "get stash size error");
return UPDATE_ERROR;
}
uint64_t maxStashSize = *max_element(stashSizeList.begin(), stashSizeList.end());
LOG(INFO) << "get max stash size: " << maxStashSize;
uint64_t totalPkgSize = maxStashSize + MIN_UPDATE_SPACE;
LOG(INFO) << "needed totalPkgSize = " << totalPkgSize;
if (CheckStatvfs(totalPkgSize) != UPDATE_SUCCESS) {
LOG(ERROR) << "CheckStatvfs error";
UPDATER_LAST_WORD(UPDATE_ERROR, "CheckStatvfs error");
return UPDATE_ERROR;
}
upParams.allMaxStashSize = totalPkgSize;
return UPDATE_SUCCESS;
}
static bool ConvertStrToLongLong(PkgManager::StreamPtr outStream, int64_t &value)
{
UPDATER_INIT_RECORD;
PkgBuffer data {};
if (outStream == nullptr) {
LOG(ERROR) << "outStream is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "outStream is nullptr");
return false;
}
outStream->GetBuffer(data);
if (data.buffer == nullptr) {
LOG(ERROR) << "data.buffer is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "data.buffer is nullptr");
return false;
}
std::string str(reinterpret_cast<char*>(data.buffer), data.length);
if (!Utils::ConvertToLongLong(str, value)) {
LOG(ERROR) << "ConvertToLongLong failed";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "ConvertToLongLong failed");
return false;
}
return true;
}
std::vector<uint64_t> GetStashSizeList(const UpdaterParams &upParams)
{
UPDATER_INIT_RECORD;
const std::string maxStashFileName = "all_max_stash";
std::vector<uint64_t> stashSizeList;
for (unsigned int i = upParams.pkgLocation; i < upParams.updatePackage.size(); i++) {
PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
if (pkgManager == nullptr) {
LOG(ERROR) << "pkgManager is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "pkgManager is nullptr");
return std::vector<uint64_t> {};
}
ON_SCOPE_EXIT(releasePackage) {
PkgManager::ReleasePackageInstance(pkgManager);
};
std::vector<std::string> fileIds;
if (pkgManager->LoadPackageWithoutUnPack(upParams.updatePackage[i], fileIds) != PKG_SUCCESS) {
LOG(ERROR) << "LoadPackageWithoutUnPack failed " << upParams.updatePackage[i];
UPDATER_LAST_WORD(UPDATE_CORRUPT, "LoadPackageWithoutUnPack failed");
return std::vector<uint64_t> {};
}
const FileInfo *info = pkgManager->GetFileInfo(maxStashFileName);
if (info == nullptr) {
LOG(INFO) << "all_max_stash not exist " << upParams.updatePackage[i];
stashSizeList.push_back(0);
continue;
}
PkgManager::StreamPtr outStream = nullptr;
int ret = pkgManager->CreatePkgStream(outStream, maxStashFileName, info->unpackedSize,
PkgStream::PkgStreamType_MemoryMap);
if (outStream == nullptr || ret != PKG_SUCCESS) {
LOG(ERROR) << "Create stream fail " << maxStashFileName << " in " << upParams.updatePackage[i];
UPDATER_LAST_WORD(UPDATE_CORRUPT, "CreatePkgStream failed");
return std::vector<uint64_t> {};
}
if (pkgManager->ExtractFile(maxStashFileName, outStream) != PKG_SUCCESS) {
LOG(ERROR) << "ExtractFile fail " << maxStashFileName << " in " << upParams.updatePackage[i];
UPDATER_LAST_WORD(UPDATE_CORRUPT, "ExtractFile failed");
return std::vector<uint64_t> {};
}
int64_t maxStashSize = 0;
if (!ConvertStrToLongLong(outStream, maxStashSize)) {
UPDATER_LAST_WORD(UPDATE_CORRUPT, "ConvertStrToLongLong failed");
return std::vector<uint64_t> {};
}
stashSizeList.push_back(static_cast<uint64_t>(maxStashSize));
}
return stashSizeList;
}
int CheckStatvfs(const uint64_t totalPkgSize)
{
UPDATER_INIT_RECORD;
struct statvfs64 updaterVfs;
if (access("/sdcard/updater", 0) == 0) {
if (statvfs64("/sdcard", &updaterVfs) < 0) {
LOG(ERROR) << "Statvfs read /sdcard error!";
UPDATER_LAST_WORD(UPDATE_ERROR, "Statvfs read /sdcard error!");
return UPDATE_ERROR;
}
} else {
if (statvfs64("/data", &updaterVfs) < 0) {
LOG(ERROR) << "Statvfs read /data error!";
UPDATER_LAST_WORD(UPDATE_ERROR, "Statvfs read /data error!");
return UPDATE_ERROR;
}
}
LOG(INFO) << "Number of free blocks = " << updaterVfs.f_bfree << ", Number of free inodes = " << updaterVfs.f_ffree;
if (static_cast<uint64_t>(updaterVfs.f_bfree) * static_cast<uint64_t>(updaterVfs.f_bsize) <= totalPkgSize) {
LOG(ERROR) << "Can not update, free space is not enough";
UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SPACE_NOTENOUGH), true);
UPDATER_UI_INSTANCE.Sleep(UI_SHOW_DURATION);
UPDATER_LAST_WORD(UPDATE_ERROR, "Can not update, free space is not enough");
return UPDATE_ERROR;
}
return UPDATE_SUCCESS;
}
int GetTmpProgressValue()
{
return g_tmpProgressValue;
}
void SetTmpProgressValue(int value)
{
g_tmpProgressValue = value;
}
void ProgressSmoothHandler(int beginProgress, int endProgress,
[[maybe_unused]] UpdaterParams upParams, [[maybe_unused]] bool isFinish)
{
if (endProgress < 0 || endProgress > FULL_PERCENT_PROGRESS || beginProgress < 0) {
return;
}
while (beginProgress < endProgress) {
int increase = (endProgress - beginProgress) / PROGRESS_VALUE_CONST;
beginProgress += increase;
if (beginProgress >= endProgress || increase == 0) {
break;
} else {
UPDATER_UI_INSTANCE.ShowProgress(beginProgress);
UPDATER_UI_INSTANCE.Sleep(SHOW_FULL_PROGRESS_TIME);
}
}
}
__attribute__((weak)) bool PreStartBinaryEntry([[maybe_unused]] const std::string &path)
{
LOG(INFO) << "pre binary process";
return true;
}
__attribute__((weak)) bool EnableCodeSignForBinary([[maybe_unused]] const std::string &fullPath)
{
LOG(INFO) << "no need to enable code sign for binary";
return true;
}
float g_progressRatio = 1.0;
void SetTotalProgressRatio(float ratio)
{
g_progressRatio = ratio;
}
float GetTotalProgressRatio()
{
return g_progressRatio;
}
bool IsUpdateBasePkg(UpdaterParams &upParams)
{
for (auto pkgPath : upParams.updatePackage) {
if (pkgPath.find("_base") != std::string::npos) {
LOG(INFO) << "this update include base pkg";
return true;
}
}
return false;
}
UpdaterStatus SetUpdateSlotParam(UpdaterParams &upParams, bool isUpdateCurrSlot)
{
if (!Utils::IsVabDevice() && !Utils::IsAbDevice()) {
return UPDATE_SUCCESS;
}
if (!isUpdateCurrSlot && upParams.updatePackage.size() == 1) {
std::string pkgPath = upParams.updatePackage[0];
if (pkgPath.find("updater.zip") != std::string::npos) {
isUpdateCurrSlot = true;
}
}
int currentSlot = GetCurrentSlot();
if (currentSlot < 1 || currentSlot > 2) {
LOG(ERROR) << "GetCurrentSlot failed";
return UPDATE_ERROR;
}
bool isUpdateSlotA = (currentSlot == SLOT_A && isUpdateCurrSlot) ||
(currentSlot == SLOT_B && !isUpdateCurrSlot);
int updateSlot = isUpdateSlotA ? SLOT_A : SLOT_B;
if (!Utils::SetUpdateSlot(updateSlot)) {
LOG(ERROR) << "set update.part.slot fail";
return UPDATE_ERROR;
}
LOG(INFO) << "set update.part.slot is " << updateSlot;
return UPDATE_SUCCESS;
}
UpdaterStatus SetUpdateSuffixParam()
{
std::string updateSuffix = "";
GetPartitionSuffix(updateSuffix);
if (!Utils::SetUpdateSuffix(updateSuffix)) {
LOG(ERROR) << "set update.part.suffix fail";
return UPDATE_ERROR;
}
return UPDATE_SUCCESS;
}
UpdaterStatus ClearUpdateSlotParam()
{
if (!Utils::IsVabDevice() && !Utils::IsAbDevice()) {
return UPDATE_SUCCESS;
}
int updateSlot = -10;
if (!Utils::SetUpdateSlot(updateSlot)) {
LOG(ERROR) << "clear update.part.slot fail";
return UPDATE_ERROR;
}
return UPDATE_SUCCESS;
}
UpdaterStatus ClearUpdateSuffixParam()
{
std::string updateSuffix = " ";
if (!Utils::SetUpdateSuffix(updateSuffix)) {
LOG(ERROR) << "clear update.part.suffix fail";
return UPDATE_ERROR;
}
return UPDATE_SUCCESS;
}
bool IsNeedMountData(UpdaterParams &upParams, PackageUpdateMode updateMode)
{
return updateMode != SDCARD_UPDATE || upParams.sdExtMode == SDCARD_UPDATE_FROM_DEV ||
upParams.sdExtMode == SDCARD_UPDATE_FROM_DATA || Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE) ||
Utils::CheckUpdateMode(Updater::FACTORY_INTERNAL_MODE);
}
bool IsNeedMountMetadata(UpdaterParams &upParams, PackageUpdateMode updateMode)
{
return Utils::IsVabDevice() && updateMode == HOTA_UPDATE;
}
UpdaterStatus DoInstallUpdaterBinfile(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams,
PackageUpdateMode updateMode)
{
UPDATER_INIT_RECORD;
UPDATER_UI_INSTANCE.ShowProgressPage();
if (upParams.callbackProgress == nullptr) {
LOG(ERROR) << "CallbackProgress is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "CallbackProgress is nullptr");
return UPDATE_CORRUPT;
}
upParams.callbackProgress(GetTotalProgressRatio() * (upParams.initialProgress * FULL_PERCENT_PROGRESS));
if (pkgManager == nullptr) {
LOG(ERROR) << "pkgManager is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "pkgManager is nullptr");
return UPDATE_CORRUPT;
}
if (SetupPartitions(IsNeedMountData(upParams, updateMode), IsNeedMountMetadata(upParams, updateMode)) != 0) {
UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true);
UPDATER_LAST_WORD(UPDATE_ERROR, "SetupPartitions failed");
return UPDATE_ERROR;
}
if (upParams.retryCount > 0) {
LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)";
}
int ret = GetUpdatePackageInfo(pkgManager, STREAM_ZIP_PATH);
if (ret != 0) {
LOG(ERROR) << "get update package info fail";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "GetUpdatePackageInfo failed");
return UPDATE_CORRUPT;
}
if (!PreStartBinaryEntry(upParams.updateBin[upParams.pkgLocation])) {
LOG(ERROR) << "pre binary process failed";
UPDATER_LAST_WORD(UPDATE_ERROR, "PreStartBinaryEntry failed");
return UPDATE_ERROR;
}
g_tmpProgressValue = 0;
UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams);
if (updateRet != UPDATE_SUCCESS) {
UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL));
UPDATER_LAST_WORD(updateRet, "StartUpdaterProc failed");
LOG(ERROR) << "Install package failed.";
}
if (WriteResult(upParams.updateBin[upParams.pkgLocation],
updateRet == UPDATE_SUCCESS ? "verify_success" : "verify_fail") != UPDATE_SUCCESS) {
LOG(ERROR) << "write update state fail";
}
return updateRet;
}
UpdaterStatus DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams,
PackageUpdateMode updateMode)
{
UPDATER_INIT_RECORD;
UPDATER_UI_INSTANCE.ShowProgressPage();
if (upParams.callbackProgress == nullptr) {
LOG(ERROR) << "CallbackProgress is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "CallbackProgress is nullptr");
return UPDATE_CORRUPT;
}
upParams.callbackProgress(upParams.initialProgress * FULL_PERCENT_PROGRESS);
if (pkgManager == nullptr) {
LOG(ERROR) << "pkgManager is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "pkgManager is nullptr");
return UPDATE_CORRUPT;
}
if (SetupPartitions(IsNeedMountData(upParams, updateMode), IsNeedMountMetadata(upParams, updateMode)) != 0) {
UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true);
UPDATER_LAST_WORD(UPDATE_ERROR, "SetupPartitions failed");
return UPDATE_ERROR;
}
if (upParams.retryCount > 0) {
LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)";
}
std::string packagePath = GetCurrentPackagePath(upParams);
if (GetUpdatePackageInfo(pkgManager, packagePath) != 0) {
LOG(ERROR) << "get update package info fail";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "GetUpdatePackageInfo failed");
return UPDATE_CORRUPT;
}
if (!PreStartBinaryEntry(packagePath)) {
LOG(ERROR) << "pre binary process failed";
UPDATER_LAST_WORD(UPDATE_ERROR, "PreStartBinaryEntry failed");
return UPDATE_ERROR;
}
g_tmpProgressValue = 0;
UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams);
if (updateRet != UPDATE_SUCCESS) {
UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL));
UPDATER_LAST_WORD(updateRet, "StartUpdaterProc failed");
LOG(ERROR) << "Install package failed.";
}
if (g_canceled) {
LOG(WARNING) << "install canceled, no need to write result";
return updateRet;
}
if (WriteResult(packagePath, updateRet == UPDATE_SUCCESS ? "verify_success" : "verify_fail") != UPDATE_SUCCESS) {
LOG(ERROR) << "write update state fail";
}
return updateRet;
}
__attribute__((weak)) void ReportPID([[maybe_unused]] const pid_t &pid, [[maybe_unused]] const int &reportMode)
{
LOG(INFO) << "ReportPID";
return;
}
namespace {
void SetProgress(const std::vector<std::string> &output, UpdaterParams &upParams)
{
if (upParams.callbackProgress == nullptr) {
LOG(ERROR) << "CallbackProgress is nullptr";
return;
}
if (output.size() < DEFAULT_PROCESS_NUM) {
LOG(ERROR) << "check output fail";
return;
}
auto outputInfo = Trim(output[1]);
float frac = 0;
if (!Utils::ConvertToFloat(output[1], frac)) {
LOG(ERROR) << "ConvertToFloat failed";
return;
}
int tmpProgressValue = 0;
if (frac >= -EPSINON && frac <= EPSINON) {
return;
} else {
tmpProgressValue = static_cast<int>(frac * g_percentage);
}
if (frac >= FULL_EPSINON && g_tmpValue + g_percentage < FULL_PERCENT_PROGRESS) {
g_tmpValue += g_percentage;
g_tmpProgressValue = g_tmpValue;
upParams.callbackProgress(GetTotalProgressRatio() * (g_tmpProgressValue *
upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS));
return;
}
g_tmpProgressValue = tmpProgressValue + g_tmpValue;
if (g_tmpProgressValue == 0) {
return;
}
upParams.callbackProgress(GetTotalProgressRatio() * (g_tmpProgressValue *
upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS));
}
}
void HandleChildOutput(const std::string &buffer, int32_t bufferLen, bool &retryUpdate, UpdaterParams &upParams)
{
if (bufferLen == 0) {
return;
}
std::string str = buffer;
std::vector<std::string> output = SplitString(str, ":");
if (output.size() < DEFAULT_PROCESS_NUM) {
LOG(ERROR) << "check output fail";
return;
}
auto outputHeader = Trim(output[0]);
if (outputHeader == "write_log") {
auto outputInfo = Trim(output[1]);
LOG(INFO) << outputInfo;
} else if (outputHeader == "retry_update") {
retryUpdate = true;
auto outputInfo = Trim(output[1]);
HardwareFaultRetry::GetInstance().SetFaultInfo(outputInfo);
} else if (outputHeader == "ui_log") {
auto outputInfo = Trim(output[1]);
} else if (outputHeader == "show_progress") {
g_tmpValue = g_tmpProgressValue;
auto outputInfo = Trim(output[1]);
float frac;
std::vector<std::string> progress = SplitString(outputInfo, ",");
if (progress.size() != DEFAULT_PROCESS_NUM) {
LOG(ERROR) << "show progress with wrong arguments";
} else {
if (!Utils::ConvertToFloat(progress[0], frac)) {
LOG(ERROR) << "ConvertToFloat failed";
return;
}
g_percentage = static_cast<int>(frac * FULL_PERCENT_PROGRESS);
}
} else if (outputHeader == "set_progress") {
CollectTmpProcessIo(upParams.binaryPid);
SetProgress(output, upParams);
} else if (outputHeader == "set_binary_tids") {
UpdateBinaryTids(output, upParams);
} else {
LOG(WARNING) << "Child process returns unexpected message.";
}
}
void ExcuteSubProc(const UpdaterParams &upParams, const std::string &fullPath, int pipeWrite)
{
UPDATER_INIT_RECORD;
SetBinaryDeathSig();
std::string packagePath = GetCurrentPackagePath(upParams);
int policy = syscall(SYS_sched_getscheduler, getpid());
if (policy == -1) {
LOG(INFO) << "Cannnot get current process scheduler";
} else if (policy == SCHED_FIFO) {
LOG(DEBUG) << "Current process with scheduler SCHED_FIFO";
struct sched_param sp = {
.sched_priority = 0,
};
if (syscall(SYS_sched_setscheduler, getpid(), SCHED_OTHER, &sp) < 0) {
LOG(WARNING) << "Cannot set current process schedule with SCHED_OTHER";
}
}
const std::string retryPara = upParams.retryCount > 0 ? "retry=1" : "retry=0";
const std::string procName = (upParams.isSingularUpdate ? "ai_binary" : "updater_binary");
int ret = -1;
if (upParams.updateBin.size() > 0) {
LOG(INFO) << "Binary Path:" << upParams.updateBin[upParams.pkgLocation].c_str();
ret = execl(fullPath.c_str(), procName.c_str(), upParams.updateBin[upParams.pkgLocation].c_str(),
std::to_string(pipeWrite).c_str(), retryPara.c_str(), nullptr);
} else if (upParams.updatePackage.size() > 0) {
LOG(INFO) << "Binary Path:" << packagePath.c_str();
ret = execl(fullPath.c_str(), procName.c_str(), packagePath.c_str(),
std::to_string(pipeWrite).c_str(), retryPara.c_str(), nullptr);
}
if (ret < 0) {
LOG(ERROR) << "Execute updater binary failed, errno = " << errno;
UPDATER_LAST_WORD(UPDATE_ERROR, "Execute updater binary failed, errno = ", errno);
exit(-1);
}
}
UpdaterStatus HandlePipeMsg(UpdaterParams &upParams, int pipeRead, bool &retryUpdate)
{
UPDATER_INIT_RECORD;
char buffer[MAX_BUFFER_SIZE] = {0};
FILE* fromChild = fdopen(pipeRead, "r");
if (fromChild == nullptr) {
LOG(ERROR) << "fdopen pipeRead failed";
UPDATER_LAST_WORD(UPDATE_ERROR, "fdopen pipeRead failed");
return UPDATE_ERROR;
}
while (fgets(buffer, MAX_BUFFER_SIZE - 1, fromChild) != nullptr) {
char *pch = strrchr(buffer, '\n');
if (pch != nullptr) {
*pch = '\0';
}
if (strstr(buffer, "subProcessResult") != nullptr) {
LOG(INFO) << "subProcessResult: " << buffer;
break;
}
HandleChildOutput(buffer, MAX_BUFFER_SIZE, retryUpdate, upParams);
}
LOG(INFO) << "HandlePipeMsg end";
fclose(fromChild);
return UPDATE_SUCCESS;
}
UpdaterStatus CheckProcStatus(UpdaterParams &upParams, bool retryUpdate)
{
int status;
ON_SCOPE_EXIT(resetBinaryPid) {
ReportPID(upParams.binaryPid, 0);
upParams.binaryPid = -1;
};
CollectTotalProcessIo(upParams.binaryPid);
if (waitpid(upParams.binaryPid, &status, 0) == -1) {
LOG(ERROR) << "waitpid error";
return UPDATE_ERROR;
}
if (retryUpdate) {
return UPDATE_RETRY;
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (WIFEXITED(status)) {
LOG(ERROR) << "exited, status= " << WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
LOG(ERROR) << "killed by signal " << WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
LOG(ERROR) << "stopped by signal " << WSTOPSIG(status);
}
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
LOG(WARNING) << "crash retry update";
return UPDATE_RETRY;
}
return UPDATE_ERROR;
}
LOG(DEBUG) << "Updater process finished.";
return UPDATE_SUCCESS;
}
static std::string GetBinaryPathFromBin(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams)
{
std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY);
(void)Utils::DeleteFile(fullPath);
std::string toolPath = "/data/updater/update_stream.zip";
if (ExtractUpdaterBinary(pkgManager, toolPath, UPDATER_BINARY) != 0) {
LOG(INFO) << "There is no valid updater_binary in package, use updater_binary in device";
fullPath = "/bin/updater_binary";
}
#ifdef UPDATER_UT
fullPath = "/data/updater/updater_binary";
#endif
char useDeviceBinary[PARAM_SIZE + 1] = {0};
if (GetParameter("update.updater.use_device_binary", "", useDeviceBinary, sizeof(useDeviceBinary) - 1) <= 0) {
LOG(ERROR) << "get update.updater.use_device_binary failed";
return fullPath;
}
if (strcmp(useDeviceBinary, "1") == 0) {
return "/bin/updater_binary";
}
return fullPath;
}
static std::string GetBinaryPath(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams)
{
if (upParams.isSingularUpdate) {
return "/bin/updater_binary_lite";
}
std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY);
(void)Utils::DeleteFile(fullPath);
std::string packagePath = GetCurrentPackagePath(upParams);
if (access("/data/updater/rollback", F_OK) == 0) {
LOG(INFO) << "There is rollback, use updater_binary_lite in device";
fullPath = "/bin/updater_binary_lite";
} else if (ExtractUpdaterBinary(pkgManager, packagePath, UPDATER_BINARY) != 0) {
LOG(INFO) << "There is no valid updater_binary in package, use updater_binary_lite in device";
fullPath = "/bin/updater_binary_lite";
}
#ifdef UPDATER_UT
fullPath = "/data/updater/updater_binary";
#endif
return fullPath;
}
static std::string GetFullPath(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams)
{
std::string fullPath = "";
if (upParams.updateBin.size() > 0) {
fullPath = GetBinaryPathFromBin(pkgManager, upParams);
} else if (upParams.updatePackage.size() > 0) {
fullPath = GetBinaryPath(pkgManager, upParams);
}
if (chmod(fullPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
LOG(ERROR) << "Failed to change mode";
}
#ifdef WITH_SELINUX
Restorecon(fullPath.c_str());
#endif
if (!EnableCodeSignForBinary(fullPath)) {
LOG(ERROR) << "Failed to sign for binary";
return "";
}
return fullPath;
}
UpdaterStatus StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams)
{
UPDATER_INIT_RECORD;
if (pkgManager == nullptr) {
LOG(ERROR) << "pkgManager is nullptr";
UPDATER_LAST_WORD(UPDATE_CORRUPT, "pkgManager is nullptr");
return UPDATE_CORRUPT;
}
int pfd[DEFAULT_PIPE_NUM];
if (pipe(pfd) < 0) {
LOG(ERROR) << "Create pipe failed: ";
UPDATER_LAST_WORD(UPDATE_ERROR, "Create pipe failed");
return UPDATE_ERROR;
}
int pipeRead = pfd[0];
int pipeWrite = pfd[1];
std::string fullPath = GetFullPath(pkgManager, upParams);
if (fullPath == "") {
LOG(ERROR) << "Failed to sign for binary";
UPDATER_LAST_WORD(UPDATE_ERROR, "Failed to sign for binary");
return UPDATE_ERROR;
}
pid_t pid = fork();
if (pid < 0) {
ERROR_CODE(CODE_FORK_FAIL);
upParams.binaryPid = -1;
UPDATER_LAST_WORD(UPDATE_ERROR, "fork failed, error no is ", errno);
close(pipeRead);
close(pipeWrite);
return UPDATE_ERROR;
}
if (pid == 0) {
#ifdef WITH_SELINUX
setcon("u:r:updater_binary:s0");
#endif
close(pipeRead);
ExcuteSubProc(upParams, fullPath, pipeWrite);
}
ResetCollectTmpIo();
upParams.binaryPid = pid;
ReportPID(upParams.binaryPid, 1);
close(pipeWrite);
bool retryUpdate = false;
if (HandlePipeMsg(upParams, pipeRead, retryUpdate) != UPDATE_SUCCESS) {
UPDATER_LAST_WORD(UPDATE_ERROR, "HandlePipeMsg failed");
return UPDATE_ERROR;
}
return CheckProcStatus(upParams, retryUpdate);
}
std::string GetWorkPath()
{
if (Utils::IsUpdaterMode()) {
return G_WORK_PATH;
}
return std::string(UPDATER_PATH) + "/";
}
}