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
54 namespace Updater {
55 using Updater::Utils::SplitString;
56 using Updater::Utils::Trim;
57 using namespace Hpackage;
58
59 int g_percentage = 100;
60 int g_tmpProgressValue;
61 int g_tmpValue;
62
ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager,std::string & packagePath,const std::string & updaterBinary)63 int32_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
GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager,const std::string & path)91 int 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
IsSpaceCapacitySufficient(const UpdaterParams & upParams)106 UpdaterStatus 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
GetStashSizeList(const UpdaterParams & upParams)127 std::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
CheckStatvfs(const uint64_t totalPkgSize)183 int 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
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
GetTmpProgressValue()210 int GetTmpProgressValue()
211 {
212 return g_tmpProgressValue;
213 }
214
SetTmpProgressValue(int value)215 void SetTmpProgressValue(int value)
216 {
217 g_tmpProgressValue = value;
218 }
219
ProgressSmoothHandler(int beginProgress,int endProgress)220 void 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
PreStartBinaryEntry(const std::string & path)237 __attribute__((weak)) bool PreStartBinaryEntry([[maybe_unused]] const std::string &path)
238 {
239 LOG(INFO) << "pre binary process";
240 return true;
241 }
242
DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams,PackageUpdateMode updateMode)243 UpdaterStatus 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) != 0) {
261 UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true);
262 UPDATER_LAST_WORD(UPDATE_ERROR);
263 return UPDATE_ERROR;
264 }
265
266 if (upParams.retryCount > 0) {
267 LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)";
268 }
269 int ret = GetUpdatePackageInfo(pkgManager, upParams.updatePackage[upParams.pkgLocation]);
270 if (ret != 0) {
271 LOG(ERROR) << "get update package info fail";
272 return UPDATE_CORRUPT;
273 }
274 if (!PreStartBinaryEntry(upParams.updatePackage[upParams.pkgLocation])) {
275 LOG(ERROR) << "pre binary process failed";
276 return UPDATE_ERROR;
277 }
278
279 g_tmpProgressValue = 0;
280 int maxTemperature;
281 UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams, maxTemperature);
282 if (updateRet != UPDATE_SUCCESS) {
283 UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL));
284 LOG(ERROR) << "Install package failed.";
285 }
286 if (WriteResult(upParams.updatePackage[upParams.pkgLocation],
287 updateRet == UPDATE_SUCCESS ? "verify_success" : "verify_fail") != UPDATE_SUCCESS) {
288 LOG(ERROR) << "write update state fail";
289 }
290 return updateRet;
291 }
292
293 namespace {
SetProgress(const std::vector<std::string> & output,UpdaterParams & upParams)294 void SetProgress(const std::vector<std::string> &output, UpdaterParams &upParams)
295 {
296 if (upParams.callbackProgress == nullptr) {
297 LOG(ERROR) << "CallbackProgress is nullptr";
298 return;
299 }
300 if (output.size() < DEFAULT_PROCESS_NUM) {
301 LOG(ERROR) << "check output fail";
302 return;
303 }
304 auto outputInfo = Trim(output[1]);
305 float frac = std::stof(output[1]);
306 int tmpProgressValue = 0;
307 if (frac >= -EPSINON && frac <= EPSINON) {
308 return;
309 } else {
310 tmpProgressValue = static_cast<int>(frac * g_percentage);
311 }
312 if (frac >= FULL_EPSINON && g_tmpValue + g_percentage < FULL_PERCENT_PROGRESS) {
313 g_tmpValue += g_percentage;
314 g_tmpProgressValue = g_tmpValue;
315 upParams.callbackProgress(g_tmpProgressValue *
316 upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
317 return;
318 }
319 g_tmpProgressValue = tmpProgressValue + g_tmpValue;
320 if (g_tmpProgressValue == 0) {
321 return;
322 }
323 upParams.callbackProgress(g_tmpProgressValue *
324 upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
325 }
326 }
327
HandleChildOutput(const std::string & buffer,int32_t bufferLen,bool & retryUpdate,UpdaterParams & upParams)328 void HandleChildOutput(const std::string &buffer, int32_t bufferLen, bool &retryUpdate, UpdaterParams &upParams)
329 {
330 if (bufferLen == 0) {
331 return;
332 }
333 std::string str = buffer;
334 std::vector<std::string> output = SplitString(str, ":");
335 if (output.size() < DEFAULT_PROCESS_NUM) {
336 LOG(ERROR) << "check output fail";
337 return;
338 }
339 auto outputHeader = Trim(output[0]);
340 if (outputHeader == "write_log") {
341 auto outputInfo = Trim(output[1]);
342 LOG(INFO) << outputInfo;
343 } else if (outputHeader == "retry_update") {
344 retryUpdate = true;
345 auto outputInfo = Trim(output[1]);
346 HwFaultRetry::GetInstance().SetFaultInfo(outputInfo);
347 } else if (outputHeader == "ui_log") {
348 auto outputInfo = Trim(output[1]);
349 } else if (outputHeader == "show_progress") {
350 g_tmpValue = g_tmpProgressValue;
351 auto outputInfo = Trim(output[1]);
352 float frac;
353 std::vector<std::string> progress = SplitString(outputInfo, ",");
354 if (progress.size() != DEFAULT_PROCESS_NUM) {
355 LOG(ERROR) << "show progress with wrong arguments";
356 } else {
357 frac = std::stof(progress[0]);
358 g_percentage = static_cast<int>(frac * FULL_PERCENT_PROGRESS);
359 }
360 } else if (outputHeader == "set_progress") {
361 SetProgress(output, upParams);
362 } else {
363 LOG(WARNING) << "Child process returns unexpected message.";
364 }
365 }
366
ExcuteSubProc(const UpdaterParams & upParams,const std::string & fullPath,int pipeWrite)367 void ExcuteSubProc(const UpdaterParams &upParams, const std::string &fullPath, int pipeWrite)
368 {
369 // Set process scheduler to normal if current scheduler is
370 // SCHED_FIFO, which may cause bad performance.
371 int policy = syscall(SYS_sched_getscheduler, getpid());
372 if (policy == -1) {
373 LOG(INFO) << "Cannnot get current process scheduler";
374 } else if (policy == SCHED_FIFO) {
375 LOG(DEBUG) << "Current process with scheduler SCHED_FIFO";
376 struct sched_param sp = {
377 .sched_priority = 0,
378 };
379 if (syscall(SYS_sched_setscheduler, getpid(), SCHED_OTHER, &sp) < 0) {
380 LOG(WARNING) << "Cannot set current process schedule with SCHED_OTHER";
381 }
382 }
383 if (upParams.retryCount > 0) {
384 execl(fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(),
385 std::to_string(pipeWrite).c_str(), "retry", nullptr);
386 } else {
387 execl(fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(),
388 std::to_string(pipeWrite).c_str(), nullptr);
389 }
390 LOG(ERROR) << "Execute updater binary failed";
391 UPDATER_LAST_WORD(UPDATE_ERROR);
392 exit(-1);
393 }
394
HandlePipeMsg(UpdaterParams & upParams,int pipeRead,bool & retryUpdate)395 UpdaterStatus HandlePipeMsg(UpdaterParams &upParams, int pipeRead, bool &retryUpdate)
396 {
397 char buffer[MAX_BUFFER_SIZE] = {0};
398 FILE* fromChild = fdopen(pipeRead, "r");
399 if (fromChild == nullptr) {
400 LOG(ERROR) << "fdopen pipeRead failed";
401 return UPDATE_ERROR;
402 }
403 while (fgets(buffer, MAX_BUFFER_SIZE - 1, fromChild) != nullptr) {
404 char *pch = strrchr(buffer, '\n');
405 if (pch != nullptr) {
406 *pch = '\0';
407 }
408 HandleChildOutput(buffer, MAX_BUFFER_SIZE, retryUpdate, upParams);
409 }
410 fclose(fromChild);
411 return UPDATE_SUCCESS;
412 }
413
CheckProcStatus(pid_t pid,bool retryUpdate)414 UpdaterStatus CheckProcStatus(pid_t pid, bool retryUpdate)
415 {
416 int status;
417 if (waitpid(pid, &status, 0) == -1) {
418 LOG(ERROR) << "waitpid error";
419 return UPDATE_ERROR;
420 }
421 if (retryUpdate) {
422 return UPDATE_RETRY;
423 }
424
425 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
426 if (WIFEXITED(status)) {
427 LOG(ERROR) << "exited, status= " << WEXITSTATUS(status);
428 } else if (WIFSIGNALED(status)) {
429 LOG(ERROR) << "killed by signal " << WTERMSIG(status);
430 } else if (WIFSTOPPED(status)) {
431 LOG(ERROR) << "stopped by signal " << WSTOPSIG(status);
432 }
433 return UPDATE_ERROR;
434 }
435 LOG(DEBUG) << "Updater process finished.";
436 return UPDATE_SUCCESS;
437 }
438
StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams,int & maxTemperature)439 UpdaterStatus StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams, int &maxTemperature)
440 {
441 UPDATER_INIT_RECORD;
442 int pfd[DEFAULT_PIPE_NUM]; /* communication between parent and child */
443 if (pipe(pfd) < 0) {
444 LOG(ERROR) << "Create pipe failed: ";
445 UPDATER_LAST_WORD(UPDATE_ERROR);
446 return UPDATE_ERROR;
447 }
448 if (pkgManager == nullptr) {
449 LOG(ERROR) << "pkgManager is nullptr";
450 UPDATER_LAST_WORD(UPDATE_CORRUPT);
451 return UPDATE_CORRUPT;
452 }
453
454 int pipeRead = pfd[0];
455 int pipeWrite = pfd[1];
456 std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY);
457 (void)Utils::DeleteFile(fullPath);
458
459 if (ExtractUpdaterBinary(pkgManager, upParams.updatePackage[upParams.pkgLocation], UPDATER_BINARY) != 0) {
460 LOG(INFO) << "There is no valid updater_binary in package, use updater_binary in device";
461 fullPath = "/bin/updater_binary";
462 }
463
464 #ifdef UPDATER_UT
465 fullPath = "/data/updater/updater_binary";
466 #endif
467
468 if (chmod(fullPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
469 LOG(ERROR) << "Failed to change mode";
470 }
471
472 #ifdef WITH_SELINUX
473 Restorecon(fullPath.c_str());
474 #endif // WITH_SELINUX
475
476 pid_t pid = fork();
477 if (pid < 0) {
478 ERROR_CODE(CODE_FORK_FAIL);
479 UPDATER_LAST_WORD(UPDATE_ERROR);
480 return UPDATE_ERROR;
481 }
482
483 if (pid == 0) { // child
484 #ifdef WITH_SELINUX
485 setcon("u:r:updater_binary:s0");
486 #endif // WITH_SELINUX
487 close(pipeRead); // close read endpoint
488 ExcuteSubProc(upParams, fullPath, pipeWrite);
489 }
490
491 close(pipeWrite); // close write endpoint
492 bool retryUpdate = false;
493 if (HandlePipeMsg(upParams, pipeRead, retryUpdate) != UPDATE_SUCCESS) {
494 return UPDATE_ERROR;
495 }
496
497 return CheckProcStatus(pid, retryUpdate);
498 }
499
GetWorkPath()500 std::string GetWorkPath()
501 {
502 if (Utils::IsUpdaterMode()) {
503 return G_WORK_PATH;
504 }
505
506 return std::string(SYS_INSTALLER_PATH) + "/";
507 }
508 } // namespace Updater
509