1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "include/updater/updater.h" 16#include <cerrno> 17#include <chrono> 18#include <cstdio> 19#include <iomanip> 20#include <string> 21#include <sched.h> 22#include <syscall.h> 23#include <sys/stat.h> 24#include <sys/statvfs.h> 25#include <sys/wait.h> 26#include <thread> 27#include <unistd.h> 28#include <vector> 29#include <algorithm> 30#include "fs_manager/mount.h" 31#include "language/language_ui.h" 32#include "log/dump.h" 33#include "log/log.h" 34#include "package/hash_data_verifier.h" 35#include "package/pkg_manager.h" 36#include "package/packages_info.h" 37#include "parameter.h" 38#include "misc_info/misc_info.h" 39#ifdef WITH_SELINUX 40#include <policycoreutils.h> 41#include "selinux/selinux.h" 42#endif // WITH_SELINUX 43#ifdef UPDATER_USE_PTABLE 44#include "ptable_parse/ptable_manager.h" 45#endif 46#include "updater/hwfault_retry.h" 47#include "updater/updater_preprocess.h" 48#include "updater/updater_const.h" 49#include "updater_main.h" 50#include "updater_ui_stub.h" 51#include "utils.h" 52#include "write_state/write_state.h" 53 54namespace Updater { 55using Updater::Utils::SplitString; 56using Updater::Utils::Trim; 57using namespace Hpackage; 58 59int g_percentage = 100; 60int g_tmpProgressValue; 61int g_tmpValue; 62 63int32_t ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager, std::string &packagePath, 64 const std::string &updaterBinary) 65{ 66 PkgManager::StreamPtr outStream = nullptr; 67 int32_t ret = manager->CreatePkgStream(outStream, GetWorkPath() + updaterBinary, 68 0, PkgStream::PkgStreamType_Write); 69 if (ret != PKG_SUCCESS) { 70 LOG(ERROR) << "ExtractUpdaterBinary create stream fail"; 71 UPDATER_LAST_WORD(UPDATE_CORRUPT); 72 return UPDATE_CORRUPT; 73 } 74 ret = manager->ExtractFile(updaterBinary, outStream); 75 if (ret != PKG_SUCCESS) { 76 LOG(ERROR) << "ExtractUpdaterBinary extract file failed"; 77 UPDATER_LAST_WORD(UPDATE_CORRUPT); 78 return UPDATE_CORRUPT; 79 } 80 HashDataVerifier verifier {manager}; 81 if (!verifier.LoadHashDataAndPkcs7(packagePath) || 82 !verifier.VerifyHashData("build_tools/", updaterBinary, outStream)) { 83 LOG(ERROR) << "verify updater_binary failed"; 84 UPDATER_LAST_WORD(UPDATE_CORRUPT); 85 return UPDATE_CORRUPT; 86 } 87 manager->ClosePkgStream(outStream); 88 return UPDATE_SUCCESS; 89} 90 91int GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager, const std::string &path) 92{ 93 std::vector<std::string> components; 94 if (pkgManager == nullptr) { 95 LOG(ERROR) << "pkgManager is nullptr"; 96 return UPDATE_CORRUPT; 97 } 98 int32_t ret = pkgManager->LoadPackage(path, Utils::GetCertName(), components); 99 if (ret != PKG_SUCCESS) { 100 LOG(INFO) << "LoadPackage fail ret :"<< ret; 101 return ret; 102 } 103 return PKG_SUCCESS; 104} 105 106UpdaterStatus IsSpaceCapacitySufficient(const UpdaterParams &upParams) 107{ 108 UPDATER_INIT_RECORD; 109 std::vector<uint64_t> stashSizeList = GetStashSizeList(upParams); 110 if (stashSizeList.size() == 0) { 111 LOG(ERROR) << "get stash size error"; 112 UPDATER_LAST_WORD(UPDATE_ERROR); 113 return UPDATE_ERROR; 114 } 115 uint64_t maxStashSize = *max_element(stashSizeList.begin(), stashSizeList.end()); 116 LOG(INFO) << "get max stash size:" << maxStashSize; 117 uint64_t totalPkgSize = maxStashSize + MIN_UPDATE_SPACE; 118 119 if (CheckStatvfs(totalPkgSize) != UPDATE_SUCCESS) { 120 LOG(ERROR) << "CheckStatvfs error"; 121 UPDATER_LAST_WORD(UPDATE_ERROR); 122 return UPDATE_ERROR; 123 } 124 return UPDATE_SUCCESS; 125} 126 127std::vector<uint64_t> GetStashSizeList(const UpdaterParams &upParams) 128{ 129 const std::string maxStashFileName = "all_max_stash"; 130 std::vector<uint64_t> stashSizeList; 131 for (unsigned int i = upParams.pkgLocation; i < upParams.updatePackage.size(); i++) { 132 PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance(); 133 if (pkgManager == nullptr) { 134 LOG(ERROR) << "pkgManager is nullptr"; 135 UPDATER_LAST_WORD(UPDATE_CORRUPT); 136 return std::vector<uint64_t> {}; 137 } 138 139 std::vector<std::string> fileIds; 140 int ret = pkgManager->LoadPackageWithoutUnPack(upParams.updatePackage[i], fileIds); 141 if (ret != PKG_SUCCESS) { 142 LOG(ERROR) << "LoadPackageWithoutUnPack failed " << upParams.updatePackage[i]; 143 PkgManager::ReleasePackageInstance(pkgManager); 144 UPDATER_LAST_WORD(UPDATE_CORRUPT); 145 return std::vector<uint64_t> {}; 146 } 147 148 const FileInfo *info = pkgManager->GetFileInfo(maxStashFileName); 149 if (info == nullptr) { 150 LOG(INFO) << "all_max_stash not exist " << upParams.updatePackage[i]; 151 stashSizeList.push_back(0); 152 PkgManager::ReleasePackageInstance(pkgManager); 153 continue; 154 } 155 156 PkgManager::StreamPtr outStream = nullptr; 157 ret = pkgManager->CreatePkgStream(outStream, maxStashFileName, info->unpackedSize, 158 PkgStream::PkgStreamType_MemoryMap); 159 if (outStream == nullptr || ret != PKG_SUCCESS) { 160 LOG(ERROR) << "Create stream fail " << maxStashFileName << " in " << upParams.updatePackage[i]; 161 PkgManager::ReleasePackageInstance(pkgManager); 162 UPDATER_LAST_WORD(UPDATE_CORRUPT); 163 return std::vector<uint64_t> {}; 164 } 165 166 ret = pkgManager->ExtractFile(maxStashFileName, outStream); 167 if (ret != PKG_SUCCESS) { 168 LOG(ERROR) << "ExtractFile fail " << maxStashFileName << " in " << upParams.updatePackage[i]; 169 PkgManager::ReleasePackageInstance(pkgManager); 170 UPDATER_LAST_WORD(UPDATE_CORRUPT); 171 return std::vector<uint64_t> {}; 172 } 173 PkgBuffer data {}; 174 outStream->GetBuffer(data); 175 std::string str(reinterpret_cast<char*>(data.buffer), data.length); 176 int64_t maxStashSize = std::stoll(str); 177 stashSizeList.push_back(static_cast<uint64_t>(maxStashSize)); 178 PkgManager::ReleasePackageInstance(pkgManager); 179 } 180 return stashSizeList; 181} 182 183int CheckStatvfs(const uint64_t totalPkgSize) 184{ 185 struct statvfs64 updaterVfs; 186 if (access("/sdcard/updater", 0) == 0) { 187 if (statvfs64("/sdcard", &updaterVfs) < 0) { 188 LOG(ERROR) << "Statvfs read /sdcard error!"; 189 UPDATER_LAST_WORD(UPDATE_ERROR); 190 return UPDATE_ERROR; 191 } 192 } else { 193 if (statvfs64("/data", &updaterVfs) < 0) { 194 LOG(ERROR) << "Statvfs read /data error!"; 195 UPDATER_LAST_WORD(UPDATE_ERROR); 196 return UPDATE_ERROR; 197 } 198 } 199 LOG(INFO) << "Number of free blocks = " << updaterVfs.f_bfree << ", Number of free inodes = " << updaterVfs.f_ffree; 200 if (static_cast<uint64_t>(updaterVfs.f_bfree) * static_cast<uint64_t>(updaterVfs.f_bsize) <= totalPkgSize) { 201 LOG(ERROR) << "Can not update, free space is not enough"; 202 UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SPACE_NOTENOUGH), true); 203 UPDATER_UI_INSTANCE.Sleep(UI_SHOW_DURATION); 204 UPDATER_LAST_WORD(UPDATE_ERROR); 205 return UPDATE_ERROR; 206 } 207 return UPDATE_SUCCESS; 208} 209 210int GetTmpProgressValue() 211{ 212 return g_tmpProgressValue; 213} 214 215void SetTmpProgressValue(int value) 216{ 217 g_tmpProgressValue = value; 218} 219 220void ProgressSmoothHandler(int beginProgress, int endProgress) 221{ 222 if (endProgress < 0 || endProgress > FULL_PERCENT_PROGRESS || beginProgress < 0) { 223 return; 224 } 225 while (beginProgress < endProgress) { 226 int increase = (endProgress - beginProgress) / PROGRESS_VALUE_CONST; 227 beginProgress += increase; 228 if (beginProgress >= endProgress || increase == 0) { 229 break; 230 } else { 231 UPDATER_UI_INSTANCE.ShowProgress(beginProgress); 232 UPDATER_UI_INSTANCE.Sleep(SHOW_FULL_PROGRESS_TIME); 233 } 234 } 235} 236 237__attribute__((weak)) bool PreStartBinaryEntry([[maybe_unused]] const std::string &path) 238{ 239 LOG(INFO) << "pre binary process"; 240 return true; 241} 242 243UpdaterStatus DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams, 244 PackageUpdateMode updateMode) 245{ 246 UPDATER_INIT_RECORD; 247 UPDATER_UI_INSTANCE.ShowProgressPage(); 248 if (upParams.callbackProgress == nullptr) { 249 LOG(ERROR) << "CallbackProgress is nullptr"; 250 UPDATER_LAST_WORD(UPDATE_CORRUPT); 251 return UPDATE_CORRUPT; 252 } 253 upParams.callbackProgress(upParams.initialProgress * FULL_PERCENT_PROGRESS); 254 if (pkgManager == nullptr) { 255 LOG(ERROR) << "pkgManager is nullptr"; 256 UPDATER_LAST_WORD(UPDATE_CORRUPT); 257 return UPDATE_CORRUPT; 258 } 259 260 if (SetupPartitions(updateMode != SDCARD_UPDATE || upParams.sdExtMode == SDCARD_UPDATE_FROM_DEV || 261 upParams.sdExtMode == SDCARD_UPDATE_FROM_DATA || Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE) || 262 Utils::CheckUpdateMode(Updater::FACTORY_INTERNAL_MODE)) != 0) { 263 UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true); 264 UPDATER_LAST_WORD(UPDATE_ERROR); 265 return UPDATE_ERROR; 266 } 267 268 if (upParams.retryCount > 0) { 269 LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)"; 270 } 271 int ret = GetUpdatePackageInfo(pkgManager, upParams.updatePackage[upParams.pkgLocation]); 272 if (ret != 0) { 273 LOG(ERROR) << "get update package info fail"; 274 return UPDATE_CORRUPT; 275 } 276 if (!PreStartBinaryEntry(upParams.updatePackage[upParams.pkgLocation])) { 277 LOG(ERROR) << "pre binary process failed"; 278 return UPDATE_ERROR; 279 } 280 281 g_tmpProgressValue = 0; 282 UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams); 283 if (updateRet != UPDATE_SUCCESS) { 284 UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL)); 285 LOG(ERROR) << "Install package failed."; 286 } 287 if (WriteResult(upParams.updatePackage[upParams.pkgLocation], 288 updateRet == UPDATE_SUCCESS ? "verify_success" : "verify_fail") != UPDATE_SUCCESS) { 289 LOG(ERROR) << "write update state fail"; 290 } 291 return updateRet; 292} 293 294namespace { 295void SetProgress(const std::vector<std::string> &output, UpdaterParams &upParams) 296{ 297 if (upParams.callbackProgress == nullptr) { 298 LOG(ERROR) << "CallbackProgress is nullptr"; 299 return; 300 } 301 if (output.size() < DEFAULT_PROCESS_NUM) { 302 LOG(ERROR) << "check output fail"; 303 return; 304 } 305 auto outputInfo = Trim(output[1]); 306 float frac = std::stof(output[1]); 307 int tmpProgressValue = 0; 308 if (frac >= -EPSINON && frac <= EPSINON) { 309 return; 310 } else { 311 tmpProgressValue = static_cast<int>(frac * g_percentage); 312 } 313 if (frac >= FULL_EPSINON && g_tmpValue + g_percentage < FULL_PERCENT_PROGRESS) { 314 g_tmpValue += g_percentage; 315 g_tmpProgressValue = g_tmpValue; 316 upParams.callbackProgress(g_tmpProgressValue * 317 upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS); 318 return; 319 } 320 g_tmpProgressValue = tmpProgressValue + g_tmpValue; 321 if (g_tmpProgressValue == 0) { 322 return; 323 } 324 upParams.callbackProgress(g_tmpProgressValue * 325 upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS); 326} 327} 328 329void HandleChildOutput(const std::string &buffer, int32_t bufferLen, bool &retryUpdate, UpdaterParams &upParams) 330{ 331 if (bufferLen == 0) { 332 return; 333 } 334 std::string str = buffer; 335 std::vector<std::string> output = SplitString(str, ":"); 336 if (output.size() < DEFAULT_PROCESS_NUM) { 337 LOG(ERROR) << "check output fail"; 338 return; 339 } 340 auto outputHeader = Trim(output[0]); 341 if (outputHeader == "write_log") { 342 auto outputInfo = Trim(output[1]); 343 LOG(INFO) << outputInfo; 344 } else if (outputHeader == "retry_update") { 345 retryUpdate = true; 346 auto outputInfo = Trim(output[1]); 347 HwFaultRetry::GetInstance().SetFaultInfo(outputInfo); 348 } else if (outputHeader == "ui_log") { 349 auto outputInfo = Trim(output[1]); 350 } else if (outputHeader == "show_progress") { 351 g_tmpValue = g_tmpProgressValue; 352 auto outputInfo = Trim(output[1]); 353 float frac; 354 std::vector<std::string> progress = SplitString(outputInfo, ","); 355 if (progress.size() != DEFAULT_PROCESS_NUM) { 356 LOG(ERROR) << "show progress with wrong arguments"; 357 } else { 358 frac = std::stof(progress[0]); 359 g_percentage = static_cast<int>(frac * FULL_PERCENT_PROGRESS); 360 } 361 } else if (outputHeader == "set_progress") { 362 SetProgress(output, upParams); 363 } else { 364 LOG(WARNING) << "Child process returns unexpected message."; 365 } 366} 367 368void ExcuteSubProc(const UpdaterParams &upParams, const std::string &fullPath, int pipeWrite) 369{ 370 // Set process scheduler to normal if current scheduler is 371 // SCHED_FIFO, which may cause bad performance. 372 int policy = syscall(SYS_sched_getscheduler, getpid()); 373 if (policy == -1) { 374 LOG(INFO) << "Cannnot get current process scheduler"; 375 } else if (policy == SCHED_FIFO) { 376 LOG(DEBUG) << "Current process with scheduler SCHED_FIFO"; 377 struct sched_param sp = { 378 .sched_priority = 0, 379 }; 380 if (syscall(SYS_sched_setscheduler, getpid(), SCHED_OTHER, &sp) < 0) { 381 LOG(WARNING) << "Cannot set current process schedule with SCHED_OTHER"; 382 } 383 } 384 const std::string retryPara = upParams.retryCount > 0 ? "retry=1" : "retry=0"; 385 execl(fullPath.c_str(), fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(), 386 std::to_string(pipeWrite).c_str(), retryPara.c_str(), nullptr); 387 LOG(ERROR) << "Execute updater binary failed"; 388 UPDATER_LAST_WORD(UPDATE_ERROR); 389 exit(-1); 390} 391 392UpdaterStatus HandlePipeMsg(UpdaterParams &upParams, int pipeRead, bool &retryUpdate) 393{ 394 char buffer[MAX_BUFFER_SIZE] = {0}; 395 FILE* fromChild = fdopen(pipeRead, "r"); 396 if (fromChild == nullptr) { 397 LOG(ERROR) << "fdopen pipeRead failed"; 398 return UPDATE_ERROR; 399 } 400 while (fgets(buffer, MAX_BUFFER_SIZE - 1, fromChild) != nullptr) { 401 char *pch = strrchr(buffer, '\n'); 402 if (pch != nullptr) { 403 *pch = '\0'; 404 } 405 if (strstr(buffer, "subProcessResult") != nullptr) { 406 LOG(INFO) << "subProcessResult: " << buffer; 407 break; 408 } 409 HandleChildOutput(buffer, MAX_BUFFER_SIZE, retryUpdate, upParams); 410 } 411 LOG(INFO) << "HandlePipeMsg end"; 412 fclose(fromChild); 413 return UPDATE_SUCCESS; 414} 415 416UpdaterStatus CheckProcStatus(pid_t pid, bool retryUpdate) 417{ 418 int status; 419 if (waitpid(pid, &status, 0) == -1) { 420 LOG(ERROR) << "waitpid error"; 421 return UPDATE_ERROR; 422 } 423 if (retryUpdate) { 424 return UPDATE_RETRY; 425 } 426 427 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 428 if (WIFEXITED(status)) { 429 LOG(ERROR) << "exited, status= " << WEXITSTATUS(status); 430 } else if (WIFSIGNALED(status)) { 431 LOG(ERROR) << "killed by signal " << WTERMSIG(status); 432 } else if (WIFSTOPPED(status)) { 433 LOG(ERROR) << "stopped by signal " << WSTOPSIG(status); 434 } 435 return UPDATE_ERROR; 436 } 437 LOG(DEBUG) << "Updater process finished."; 438 return UPDATE_SUCCESS; 439} 440 441UpdaterStatus StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams) 442{ 443 UPDATER_INIT_RECORD; 444 int pfd[DEFAULT_PIPE_NUM]; /* communication between parent and child */ 445 if (pipe(pfd) < 0) { 446 LOG(ERROR) << "Create pipe failed: "; 447 UPDATER_LAST_WORD(UPDATE_ERROR); 448 return UPDATE_ERROR; 449 } 450 if (pkgManager == nullptr) { 451 LOG(ERROR) << "pkgManager is nullptr"; 452 UPDATER_LAST_WORD(UPDATE_CORRUPT); 453 return UPDATE_CORRUPT; 454 } 455 456 int pipeRead = pfd[0]; 457 int pipeWrite = pfd[1]; 458 std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY); 459 (void)Utils::DeleteFile(fullPath); 460 461 if (ExtractUpdaterBinary(pkgManager, upParams.updatePackage[upParams.pkgLocation], UPDATER_BINARY) != 0) { 462 LOG(INFO) << "There is no valid updater_binary in package, use updater_binary in device"; 463 fullPath = "/bin/updater_binary"; 464 } 465 466#ifdef UPDATER_UT 467 fullPath = "/data/updater/updater_binary"; 468#endif 469 470 if (chmod(fullPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { 471 LOG(ERROR) << "Failed to change mode"; 472 } 473 474#ifdef WITH_SELINUX 475 Restorecon(fullPath.c_str()); 476#endif // WITH_SELINUX 477 478 pid_t pid = fork(); 479 if (pid < 0) { 480 ERROR_CODE(CODE_FORK_FAIL); 481 UPDATER_LAST_WORD(UPDATE_ERROR); 482 return UPDATE_ERROR; 483 } 484 485 if (pid == 0) { // child 486 #ifdef WITH_SELINUX 487 setcon("u:r:updater_binary:s0"); 488 #endif // WITH_SELINUX 489 close(pipeRead); // close read endpoint 490 ExcuteSubProc(upParams, fullPath, pipeWrite); 491 } 492 493 close(pipeWrite); // close write endpoint 494 bool retryUpdate = false; 495 if (HandlePipeMsg(upParams, pipeRead, retryUpdate) != UPDATE_SUCCESS) { 496 return UPDATE_ERROR; 497 } 498 499 return CheckProcStatus(pid, retryUpdate); 500} 501 502std::string GetWorkPath() 503{ 504 if (Utils::IsUpdaterMode()) { 505 return G_WORK_PATH; 506 } 507 508 return std::string(SYS_INSTALLER_PATH) + "/"; 509} 510} // namespace Updater 511