xref: /base/update/updater/services/updater.cpp (revision fb299fa2)
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