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