xref: /developtools/hdc/src/host/host_updater.cpp (revision cc290419)
1/*
2 * Copyright (C) 2022 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
16#include "host_updater.h"
17
18#include <algorithm>
19#include <unordered_map>
20
21#include "common.h"
22#include "define.h"
23#include "serial_struct.h"
24
25namespace Hdc {
26namespace {
27constexpr uint8_t PERCENT_FINISH = 100;
28constexpr uint8_t PERCENT_CLEAR = UINT8_MAX;
29constexpr int MAX_RETRY_COUNT = 3;
30constexpr size_t FLASH_PARAM_MIN_COUNT = 2;
31constexpr size_t FLASH_FILE_INDEX = 1;
32constexpr size_t UPDATE_PARAM_MIN_COUNT = 1;
33constexpr size_t UPDATE_FILE_INDEX = 0;
34constexpr size_t FORMAT_PARAM_MIN_COUNT = 2;
35constexpr size_t ERASE_PARAM_MIN_COUNT = 2;
36
37const std::string CMD_STR_UPDATE = "update ";
38const std::string CMD_STR_FLASH = "flash ";
39const std::string CMD_STR_ERASE = "erase ";
40const std::string CMD_STR_FORMAT = "format ";
41
42const std::unordered_map<std::string, uint16_t> FLASHD_CMD = {
43    {CMD_STR_UPDATE, CMD_FLASHD_UPDATE_INIT},
44    {CMD_STR_FLASH, CMD_FLASHD_FLASH_INIT},
45    {CMD_STR_ERASE, CMD_FLASHD_ERASE},
46    {CMD_STR_FORMAT, CMD_FLASHD_FORMAT},
47};
48
49std::vector<std::string> Split(const std::string &src, const std::vector<std::string> &filter)
50{
51    std::vector<std::string> result;
52    if (src.empty()) {
53        return result;
54    }
55    const auto len = src.size() + 1;
56    auto buffer = std::vector<char>(len, 0);
57    buffer.assign(src.begin(), src.end());
58    const char delimit[] = "\t\r\n ";
59    char *nextToken = nullptr;
60    char *token = strtok_s(buffer.data(), delimit, &nextToken);
61    while (token != nullptr) {
62        if (std::find(filter.cbegin(), filter.cend(), token) == filter.cend()) {
63            result.push_back(token);
64        }
65        token = strtok_s(nullptr, delimit, &nextToken);
66    }
67    return result;
68}
69}
70
71HostUpdater::HostUpdater(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo)
72{
73    commandBegin = CMD_FLASHD_BEGIN;
74    commandData = CMD_FLASHD_DATA;
75}
76
77HostUpdater::~HostUpdater() {}
78
79bool HostUpdater::RunQueue(CtxFile &context)
80{
81    context.localPath = context.taskQueue.back();
82    uv_fs_t *openReq = new uv_fs_t;
83    if (openReq == nullptr) {
84        WRITE_LOG(LOG_FATAL, "HostUpdater::RunQueue new uv_fs_t failed");
85        OnFileOpenFailed(&context);
86        return false;
87    }
88    memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
89    openReq->data = &context;
90    refCount++;
91    uv_fs_open(loopTask, openReq, context.localPath.c_str(), O_RDONLY, 0, OnFileOpen);
92    context.master = true;
93    return true;
94}
95
96bool HostUpdater::BeginTransfer(const std::string &function, const uint8_t *payload, int payloadSize, size_t minParam,
97                                size_t fileIndex)
98{
99    if (payload[payloadSize - 1] != '\0') {
100        WRITE_LOG(LOG_FATAL, "payload is invalid");
101        return false;
102    }
103    std::string cmdParam(reinterpret_cast<const char *>(payload));
104    auto params = Split(cmdParam, {});
105    auto count = minParam;
106    auto index = fileIndex;
107    if (std::find(params.cbegin(), params.cend(), "-f") != params.cend()) {
108        count++;
109        index++;
110    }
111    if (params.size() != count || params.size() <= index) {
112        WRITE_LOG(LOG_FATAL, "param count is invalid");
113        return false;
114    }
115
116    std::string localPath = params[index];
117    if (!Base::CheckDirectoryOrPath(localPath.c_str(), true, true)) {
118        WRITE_LOG(LOG_FATAL, "localPath is invalid");
119        return false;
120    }
121
122    if (MatchPackageExtendName(localPath, ".img") || MatchPackageExtendName(localPath, ".bin") ||
123        MatchPackageExtendName(localPath, ".fd") || MatchPackageExtendName(localPath, ".cpio")) {
124        ctxNow.transferConfig.compressType = COMPRESS_NONE;
125    } else if (MatchPackageExtendName(localPath, ".zip")) {
126        WRITE_LOG(LOG_INFO, "file type is zip");
127    } else {
128        WRITE_LOG(LOG_FATAL, "file type is invalid");
129        return false;
130    }
131    ctxNow.transferConfig.functionName = function;
132    ctxNow.transferConfig.options = cmdParam;
133    ctxNow.localPath = localPath;
134    ctxNow.taskQueue.push_back(localPath);
135    return RunQueue(ctxNow);
136}
137
138void HostUpdater::CheckMaster(CtxFile *context)
139{
140    uv_fs_t fs;
141    Base::ZeroStruct(fs.statbuf);
142    uv_fs_fstat(nullptr, &fs, context->openFd, nullptr);
143    context->transferConfig.fileSize = fs.statbuf.st_size;
144    uv_fs_req_cleanup(&fs);
145    context->transferConfig.optionalName = Base::GetFileNameAny(context->localPath);
146    std::string bufString = SerialStruct::SerializeToString(context->transferConfig);
147
148    WRITE_LOG(LOG_DEBUG, "functionName = %s, fileSize = %llu", context->transferConfig.functionName.c_str(),
149        context->transferConfig.fileSize);
150
151    std::vector<uint8_t> buffer(sizeof(uint64_t) / sizeof(uint8_t), 0);
152    buffer.insert(buffer.end(), bufString.begin(), bufString.end());
153    SendToAnother(CMD_FLASHD_CHECK, (uint8_t *)buffer.data(), buffer.size());
154}
155
156bool HostUpdater::CheckCmd(HdcCommand command, uint8_t *payload, int payloadSize, size_t paramCount)
157{
158    if (payloadSize < 1 || payload[payloadSize - 1] != '\0') {
159        WRITE_LOG(LOG_FATAL, "payload is invalid");
160        return false;
161    }
162    std::string cmdParam(reinterpret_cast<char *>(payload));
163    WRITE_LOG(LOG_INFO, "cmdParam = %s, paramCount = %u", cmdParam.c_str(), paramCount);
164
165    auto result = Split(cmdParam, {});
166    auto iter = std::find(result.cbegin(), result.cend(), "-f");
167    bool ret = (iter != result.cend()) ? (result.size() == (paramCount + 1)) : (result.size() == paramCount);
168    if (!ret) {
169        WRITE_LOG(LOG_FATAL, "CheckCmd failed");
170        return false;
171    }
172
173    SendToAnother(command, payload, payloadSize);
174    ctxNow.taskQueue.push_back(cmdParam);
175    return true;
176}
177
178bool HostUpdater::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
179{
180    if (command == CMD_FLASHD_BEGIN) {
181        if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
182            return false;
183        }
184        std::string tip("Processing:    0%");
185        sendProgress_ = true;
186        SendRawData(tip);
187        return true;
188    }
189
190    if (payload == nullptr || payloadSize <= 0) {
191        WRITE_LOG(LOG_FATAL, "payload or payloadSize is invalid");
192        return false;
193    }
194    if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
195        return false;
196    }
197    bool ret = true;
198    switch (command) {
199        case CMD_FLASHD_UPDATE_INIT:
200            ret = BeginTransfer(CMDSTR_FLASHD_UPDATE, payload, payloadSize, UPDATE_PARAM_MIN_COUNT, UPDATE_FILE_INDEX);
201            break;
202        case CMD_FLASHD_FLASH_INIT:
203            ret = BeginTransfer(CMDSTR_FLASHD_FLASH, payload, payloadSize, FLASH_PARAM_MIN_COUNT, FLASH_FILE_INDEX);
204            break;
205        case CMD_FLASHD_FINISH:
206            ret = CheckUpdateContinue(command, payload, payloadSize);
207            break;
208        case CMD_FLASHD_ERASE:
209            ret = CheckCmd(CMD_FLASHD_ERASE, payload, payloadSize, ERASE_PARAM_MIN_COUNT);
210            break;
211        case CMD_FLASHD_FORMAT:
212            ret = CheckCmd(CMD_FLASHD_FORMAT, payload, payloadSize, FORMAT_PARAM_MIN_COUNT);
213            break;
214        case CMD_FLASHD_PROGRESS:
215            ProcessProgress(*payload);
216            break;
217        default:
218            break;
219    }
220    return ret;
221}
222
223void HostUpdater::ProcessProgress(uint8_t percentage)
224{
225    if (!sendProgress_) {
226        return;
227    }
228    if (percentage == PERCENT_CLEAR) {
229        SendRawData("\n");
230        sendProgress_ = false;
231        return;
232    }
233    std::string plrogress = "\rProcessing:    " + std::to_string(percentage) + "%";
234    SendRawData(plrogress);
235    if (percentage == PERCENT_FINISH) {
236        SendRawData("\n");
237        sendProgress_ = false;
238    }
239}
240
241bool HostUpdater::CheckUpdateContinue(const uint16_t command, const uint8_t *payload, int payloadSize)
242{
243    if (static_cast<size_t>(payloadSize) < sizeof(uint16_t)) {
244        return false;
245    }
246
247    MessageLevel level = static_cast<MessageLevel>(payload[1]);
248    if ((level == MSG_OK) && sendProgress_) {
249        ProcessProgress(PERCENT_FINISH);
250    }
251    std::string info(reinterpret_cast<char *>(const_cast<uint8_t *>(payload + sizeof(uint16_t))),
252                     payloadSize - sizeof(uint16_t));
253    if (!info.empty()) {
254        LogMsg(level, "%s", info.c_str());
255    }
256    WRITE_LOG(LOG_DEBUG, "CheckUpdateContinue payloadSize %d %d %s", payloadSize, level, info.c_str());
257    if (ctxNow.taskQueue.size() != 0) {
258        ctxNow.taskQueue.pop_back();
259    }
260    if (singalStop || !ctxNow.taskQueue.size()) {
261        return false;
262    }
263    return RunQueue(ctxNow);
264}
265
266bool HostUpdater::CheckMatchUpdate(const std::string &input, TranslateCommand::FormatCommand &outCmd)
267{
268    WRITE_LOG(LOG_DEBUG, "CheckMatchUpdate command:%s", input.c_str());
269    for (const auto &iter : FLASHD_CMD) {
270        if ((input.find(iter.first) == 0) && (input.size() > iter.first.size())) {
271            outCmd.cmdFlag = iter.second;
272            return true;
273        }
274    }
275    return false;
276}
277
278bool HostUpdater::ConfirmCommand(const string &commandIn, bool &closeInput)
279{
280    std::string tip = "";
281    if (!strncmp(commandIn.c_str(), CMD_STR_UPDATE.c_str(), CMD_STR_UPDATE.size())) {
282        closeInput = true;
283    } else if (!strncmp(commandIn.c_str(), CMD_STR_FLASH.c_str(), CMD_STR_FLASH.size())) {
284        tip = "Confirm flash partition";
285        closeInput = true;
286    } else if (!strncmp(commandIn.c_str(), CMD_STR_ERASE.c_str(), CMD_STR_ERASE.size())) {
287        tip = "Confirm erase partition";
288    } else if (!strncmp(commandIn.c_str(), CMD_STR_FORMAT.c_str(), CMD_STR_FORMAT.size())) {
289        tip = "Confirm format partition";
290    }
291    if (tip.empty() || strstr(commandIn.c_str(), " -f") != nullptr) {
292        return true;
293    }
294    const size_t minLen = strlen("yes");
295    int retryCount = 0;
296    do {
297        printf("%s ? (Yes/No) ", tip.c_str());
298        fflush(stdin);
299        std::string info = {};
300        size_t i = 0;
301        while (1) {
302            char c = getchar();
303            if (c == '\r' || c == '\n') {
304                break;
305            }
306            if (c == ' ') {
307                continue;
308            }
309            if (i < minLen && isprint(c)) {
310                info.append(1, std::tolower(c));
311                i++;
312            }
313        }
314        if (info == "n" || info == "no") {
315            return false;
316        }
317        if (info == "y" || info == "yes") {
318            return true;
319        }
320        retryCount++;
321    } while (retryCount < MAX_RETRY_COUNT);
322    return (retryCount >= MAX_RETRY_COUNT) ? false : true;
323}
324
325void HostUpdater::SendRawData(std::string rawData) const
326{
327    HdcSessionBase *sessionBase = (HdcSessionBase *)clsSession;
328    if (sessionBase == nullptr) {
329        WRITE_LOG(LOG_FATAL, "sessionBase is null");
330        return;
331    }
332    sessionBase->ServerCommand(taskInfo->sessionId, taskInfo->channelId, CMD_KERNEL_ECHO_RAW,
333        reinterpret_cast<uint8_t *>(rawData.data()), rawData.size());
334}
335} // namespace Hdc