• 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 "fs_manager/mount.h"
30 #include "language/language_ui.h"
31 #include "log/dump.h"
32 #include "log/log.h"
33 #include "package/pkg_manager.h"
34 #include "package/packages_info.h"
35 #include "parameter.h"
36 #include "misc_info/misc_info.h"
37 #ifdef WITH_SELINUX
38 #include <policycoreutils.h>
39 #endif // WITH_SELINUX
40 #ifdef UPDATER_USE_PTABLE
41 #include "ptable_parse/ptable_manager.h"
42 #endif
43 #include "updater/updater_preprocess.h"
44 #include "updater/updater_const.h"
45 #include "updater_main.h"
46 #include "updater_ui_stub.h"
47 #include "utils.h"
48 
49 namespace Updater {
50 using Updater::Utils::SplitString;
51 using Updater::Utils::Trim;
52 using namespace Hpackage;
53 
54 int g_percentage;
55 int g_tmpProgressValue;
56 int g_tmpValue;
57 
58 namespace {
ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager,const std::string & updaterBinary)59 int32_t ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager, const std::string &updaterBinary)
60 {
61     PkgManager::StreamPtr outStream = nullptr;
62     int32_t ret = manager->CreatePkgStream(outStream,  GetWorkPath() + updaterBinary,
63         0, PkgStream::PkgStreamType_Write);
64     if (ret != PKG_SUCCESS) {
65         LOG(ERROR) << "ExtractUpdaterBinary create stream fail";
66         UPDATER_LAST_WORD(UPDATE_CORRUPT);
67         return UPDATE_CORRUPT;
68     }
69     ret = manager->ExtractFile(updaterBinary, outStream);
70     manager->ClosePkgStream(outStream);
71     return ret;
72 }
73 }
74 
GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager,const std::string & path)75 int GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager, const std::string &path)
76 {
77     std::vector<std::string> components;
78     if (pkgManager == nullptr) {
79         LOG(ERROR) << "Fail to GetPackageInstance";
80         return UPDATE_CORRUPT;
81     }
82     int32_t ret = pkgManager->LoadPackage(path, Utils::GetCertName(), components);
83     if (ret != PKG_SUCCESS) {
84         LOG(INFO) << "LoadPackage fail ret :"<< ret;
85         return ret;
86     }
87     return PKG_SUCCESS;
88 }
89 
IsSpaceCapacitySufficient(const std::vector<std::string> & packagePath)90 UpdaterStatus IsSpaceCapacitySufficient(const std::vector<std::string> &packagePath)
91 {
92     uint64_t totalPkgSize = 0;
93     for (auto path : packagePath) {
94         PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
95         if (pkgManager == nullptr) {
96             LOG(ERROR) << "pkgManager is nullptr";
97             return UPDATE_CORRUPT;
98         }
99         std::vector<std::string> fileIds;
100         int ret = pkgManager->LoadPackageWithoutUnPack(path, fileIds);
101         if (ret != PKG_SUCCESS) {
102             LOG(ERROR) << "LoadPackageWithoutUnPack failed";
103             PkgManager::ReleasePackageInstance(pkgManager);
104             return UPDATE_CORRUPT;
105         }
106 
107         const FileInfo *info = pkgManager->GetFileInfo("update.bin");
108         if (info == nullptr) {
109             LOG(ERROR) << "update.bin is not exist";
110             PkgManager::ReleasePackageInstance(pkgManager);
111             return UPDATE_CORRUPT;
112         }
113         PkgManager::ReleasePackageInstance(pkgManager);
114         totalPkgSize += static_cast<uint64_t>(info->unpackedSize + MAX_LOG_SPACE);
115     }
116 
117     struct statvfs64 updaterVfs;
118     if (access("/sdcard/updater", 0) == 0) {
119         if (statvfs64("/sdcard", &updaterVfs) < 0) {
120             LOG(ERROR) << "Statvfs read /sdcard error!";
121             return UPDATE_ERROR;
122         }
123     } else {
124         if (statvfs64("/data", &updaterVfs) < 0) {
125             LOG(ERROR) << "Statvfs read /data error!";
126             return UPDATE_ERROR;
127         }
128     }
129 
130     if (static_cast<uint64_t>(updaterVfs.f_bfree) * static_cast<uint64_t>(updaterVfs.f_bsize) <= totalPkgSize) {
131         LOG(ERROR) << "Can not update, free space is not enough";
132         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SPACE_NOTENOUGH), true);
133         UPDATER_UI_INSTANCE.Sleep(UI_SHOW_DURATION);
134         return UPDATE_ERROR;
135     }
136     return UPDATE_SUCCESS;
137 }
138 
GetTmpProgressValue()139 int GetTmpProgressValue()
140 {
141     return g_tmpProgressValue;
142 }
143 
ProgressSmoothHandler(int beginProgress,int endProgress)144 void ProgressSmoothHandler(int beginProgress, int endProgress)
145 {
146 #ifdef UPDATER_UI_SUPPORT
147     if (endProgress < 0 || endProgress > FULL_PERCENT_PROGRESS || beginProgress < 0) {
148         return;
149     }
150     while (beginProgress < endProgress) {
151         int increase = (endProgress - beginProgress) / PROGRESS_VALUE_CONST;
152         beginProgress += increase;
153         if (beginProgress >= endProgress || increase == 0) {
154             break;
155         } else {
156             UPDATER_UI_INSTANCE.ShowProgress(beginProgress);
157             UPDATER_UI_INSTANCE.Sleep(SHOW_FULL_PROGRESS_TIME);
158         }
159     }
160 #endif
161 }
162 
163 #ifdef UPDATER_USE_PTABLE
PtableProcess(PkgManager::PkgManagerPtr pkgManager,PackageUpdateMode updateMode)164 bool PtableProcess(PkgManager::PkgManagerPtr pkgManager, PackageUpdateMode updateMode)
165 {
166     DevicePtable& devicePtb = DevicePtable::GetInstance();
167     devicePtb.LoadPartitionInfo();
168     PackagePtable& packagePtb = PackagePtable::GetInstance();
169     packagePtb.LoadPartitionInfo(pkgManager);
170     if (!devicePtb.ComparePtable(packagePtb)) {
171         LOG(INFO) << "Ptable NOT changed, no need to process!";
172         return true;
173     }
174     if (updateMode == HOTA_UPDATE) {
175         if (devicePtb.ComparePartition(packagePtb, "USERDATA")) {
176             LOG(ERROR) << "Hota update not allow userdata partition change!";
177             return false;
178         }
179     }
180     if (!packagePtb.WritePtableToDevice()) {
181         LOG(ERROR) << "Ptable changed, write new ptable failed!";
182         return false;
183     }
184     return true;
185 }
186 #endif
187 
DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams,PackageUpdateMode updateMode)188 UpdaterStatus DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams,
189     PackageUpdateMode updateMode)
190 {
191     UPDATER_INIT_RECORD;
192     UPDATER_UI_INSTANCE.ShowProgressPage();
193     UPDATER_UI_INSTANCE.ShowProgress(upParams.initialProgress * FULL_PERCENT_PROGRESS);
194     UPDATER_ERROR_CHECK(pkgManager != nullptr, "Fail to GetPackageInstance", UPDATER_LAST_WORD(UPDATE_CORRUPT);
195         return UPDATE_CORRUPT);
196     UPDATER_CHECK_ONLY_RETURN(SetupPartitions(updateMode) == 0,
197         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true);
198         UPDATER_LAST_WORD(UPDATE_ERROR);
199         return UPDATE_ERROR);
200 
201     if (upParams.retryCount > 0) {
202         LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)";
203     } else {
204         pkgManager = PkgManager::GetPackageInstance();
205     }
206     int32_t verifyret = GetUpdatePackageInfo(pkgManager, upParams.updatePackage[upParams.pkgLocation]);
207     g_tmpProgressValue = 0;
208     UPDATER_ERROR_CHECK(verifyret == PKG_SUCCESS, "Verify package bin file Fail...",
209         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_VERIFYFAIL), true);
210         return UPDATE_CORRUPT);
211     LOG(INFO) << "Package bin file verified. start to install package...";
212     int32_t versionRet = PreProcess::GetInstance().DoUpdatePreProcess(pkgManager);
213     UPDATER_ERROR_CHECK(versionRet == PKG_SUCCESS, "Version Check Fail...", return UPDATE_CORRUPT);
214 
215 #ifdef UPDATER_USE_PTABLE
216     if (!PtableProcess(pkgManager, updateMode)) {
217         LOG(ERROR) << "Ptable process failed!";
218         return UPDATE_CORRUPT;
219     }
220 #endif
221 
222     int maxTemperature;
223     UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams, maxTemperature);
224     if (updateRet != UPDATE_SUCCESS) {
225         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL));
226         LOG(ERROR) << "Install package failed.";
227     }
228     return updateRet;
229 }
230 
231 namespace {
232 #ifdef UPDATER_UI_SUPPORT
SetProgress(const std::vector<std::string> & output,UpdaterParams & upParams)233 void SetProgress(const std::vector<std::string> &output, UpdaterParams &upParams)
234 {
235     if (output.size() < DEFAULT_PROCESS_NUM) {
236         LOG(ERROR) << "check output fail";
237         return;
238     }
239     auto outputInfo = Trim(output[1]);
240     float frac = std::stof(output[1]);
241     int tmpProgressValue = 0;
242     if (frac >= -EPSINON && frac <= EPSINON) {
243         return;
244     } else {
245         tmpProgressValue = static_cast<int>(frac * g_percentage);
246     }
247     if (frac >= FULL_EPSINON && g_tmpValue + g_percentage < FULL_PERCENT_PROGRESS) {
248         g_tmpValue += g_percentage;
249         g_tmpProgressValue = g_tmpValue;
250         UPDATER_UI_INSTANCE.ShowProgress(g_tmpProgressValue *
251             upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
252         return;
253     }
254     g_tmpProgressValue = tmpProgressValue + g_tmpValue;
255     if (g_tmpProgressValue == 0) {
256         return;
257     }
258     UPDATER_UI_INSTANCE.ShowProgress(g_tmpProgressValue *
259         upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
260 }
261 #endif
262 
HandleChildOutput(const std::string & buffer,int32_t bufferLen,bool & retryUpdate,UpdaterParams & upParams)263 void HandleChildOutput(const std::string &buffer, int32_t bufferLen, bool &retryUpdate, UpdaterParams &upParams)
264 {
265     if (bufferLen == 0) {
266         return;
267     }
268     std::string str = buffer;
269     std::vector<std::string> output = SplitString(str, ":");
270     if (output.size() < 1) {
271         LOG(ERROR) << "check output fail";
272         return;
273     }
274     auto outputHeader = Trim(output[0]);
275     if (outputHeader == "write_log") {
276         if (output.size() < DEFAULT_PROCESS_NUM) {
277             LOG(ERROR) << "check output fail";
278             return;
279         }
280         auto outputInfo = Trim(output[1]);
281         LOG(INFO) << outputInfo;
282     } else if (outputHeader == "retry_update") {
283         retryUpdate = true;
284 #ifdef UPDATER_UI_SUPPORT
285     } else if (outputHeader == "ui_log") {
286         if (output.size() < DEFAULT_PROCESS_NUM) {
287             LOG(ERROR) << "check output fail";
288             return;
289         }
290         auto outputInfo = Trim(output[1]);
291     } else if (outputHeader == "show_progress") {
292         if (output.size() < DEFAULT_PROCESS_NUM) {
293             LOG(ERROR) << "check output fail";
294             return;
295         }
296         g_tmpValue = g_tmpProgressValue;
297         auto outputInfo = Trim(output[1]);
298         float frac;
299         std::vector<std::string> progress = SplitString(outputInfo, ",");
300         if (progress.size() != DEFAULT_PROCESS_NUM) {
301             LOG(ERROR) << "show progress with wrong arguments";
302         } else {
303             UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_START));
304             frac = std::stof(progress[0]);
305             g_percentage = static_cast<int>(frac * FULL_PERCENT_PROGRESS);
306         }
307     } else if (outputHeader == "set_progress") {
308         SetProgress(output, upParams);
309     } else {
310         LOG(WARNING) << "Child process returns unexpected message.";
311 #endif
312     }
313 }
314 }
315 
StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams,int & maxTemperature)316 UpdaterStatus StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams, int &maxTemperature)
317 {
318     UPDATER_INIT_RECORD;
319     int pfd[DEFAULT_PIPE_NUM]; /* communication between parent and child */
320     UPDATER_FILE_CHECK(pipe(pfd) >= 0, "Create pipe failed: ", UPDATER_LAST_WORD(UPDATE_ERROR);
321         return UPDATE_ERROR);
322     UPDATER_ERROR_CHECK(pkgManager != nullptr, "Fail to GetPackageInstance", UPDATER_LAST_WORD(UPDATE_CORRUPT);
323         return UPDATE_CORRUPT);
324     int pipeRead = pfd[0];
325     int pipeWrite = pfd[1];
326     std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY);
327     (void)Utils::DeleteFile(fullPath);
328     if (ExtractUpdaterBinary(pkgManager, UPDATER_BINARY) != 0) {
329         LOG(INFO) << "There is no updater_binary in package, use updater_binary in device";
330         fullPath = "/bin/updater_binary";
331     }
332     pid_t pid = fork();
333     UPDATER_CHECK_ONLY_RETURN(pid >= 0, ERROR_CODE(CODE_FORK_FAIL);
334         UPDATER_LAST_WORD(UPDATE_ERROR);
335         return UPDATE_ERROR);
336     if (pid == 0) { // child
337         close(pipeRead);   // close read endpoint
338 #ifdef UPDATER_UT
339         if (packagePath.find("updater_binary_abnormal") != std::string::npos) {
340             fullPath = "/system/bin/updater_binary_abnormal";
341         } else {
342             fullPath = "/system/bin/test_update_binary";
343         }
344 #endif
345         UPDATER_ERROR_CHECK_NOT_RETURN(chmod(fullPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0,
346             "Failed to change mode");
347 
348 #ifdef WITH_SELINUX
349         Restorecon(fullPath.c_str());
350 #endif // WITH_SELINUX
351 
352         // Set process scheduler to normal if current scheduler is
353         // SCHED_FIFO, which may cause bad performance.
354         int policy = syscall(SYS_sched_getscheduler, getpid());
355         if (policy == -1) {
356             LOG(INFO) << "Cannnot get current process scheduler";
357         } else if (policy == SCHED_FIFO) {
358             LOG(DEBUG) << "Current process with scheduler SCHED_FIFO";
359             struct sched_param sp = {
360                 .sched_priority = 0,
361             };
362             if (syscall(SYS_sched_setscheduler, getpid(), SCHED_OTHER, &sp) < 0) {
363                 LOG(WARNING) << "Cannot set current process schedule with SCHED_OTHER";
364             }
365         }
366         if (upParams.retryCount > 0) {
367             execl(fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(),
368                 std::to_string(pipeWrite).c_str(), "retry", nullptr);
369         } else {
370             execl(fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(),
371                 std::to_string(pipeWrite).c_str(), nullptr);
372         }
373         LOG(INFO) << "Execute updater binary failed";
374         UPDATER_LAST_WORD(UPDATE_ERROR);
375         exit(-1);
376     }
377 
378     close(pipeWrite); // close write endpoint
379     char buffer[MAX_BUFFER_SIZE] = {0};
380     bool retryUpdate = false;
381     FILE* fromChild = fdopen(pipeRead, "r");
382     UPDATER_ERROR_CHECK(fromChild != nullptr, "fdopen pipeRead failed", return UPDATE_ERROR);
383     while (fgets(buffer, MAX_BUFFER_SIZE - 1, fromChild) != nullptr) {
384         char *pch = strrchr(buffer, '\n');
385         if (pch != nullptr) {
386             *pch = '\0';
387         }
388         HandleChildOutput(buffer, MAX_BUFFER_SIZE, retryUpdate, upParams);
389     }
390     fclose(fromChild);
391 
392     int status;
393     pid_t w = waitpid(pid, &status, 0);
394     if (w == -1) {
395         LOG(ERROR) << "waitpid error";
396         return UPDATE_ERROR;
397     }
398     UPDATER_CHECK_ONLY_RETURN(!retryUpdate, return UPDATE_RETRY);
399     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
400         if (WIFEXITED(status)) {
401             LOG(ERROR) << "exited, status= " << WEXITSTATUS(status);
402         } else if (WIFSIGNALED(status)) {
403             LOG(ERROR) << "killed by signal " << WTERMSIG(status);
404         } else if (WIFSTOPPED(status)) {
405             LOG(ERROR) << "stopped by signal " << WSTOPSIG(status);
406         }
407         return UPDATE_ERROR;
408     }
409     LOG(DEBUG) << "Updater process finished.";
410     return UPDATE_SUCCESS;
411 }
412 
GetWorkPath()413 std::string GetWorkPath()
414 {
415     if (Utils::IsUpdaterMode()) {
416         return G_WORK_PATH;
417     }
418 
419     return std::string(UPDATER_PATH) + "/";
420 }
421 } // namespace Updater
422