• 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 "host_updater.h"
16 
17 #include <cstring>
18 #include "common.h"
19 #include "flash_define.h"
20 #include "transfer.h"
21 #include "serial_struct.h"
22 
23 namespace {
24 static const std::string helpCmd = "flash";
25 static const std::string updateCmd = "update ";
26 static const std::string flashCmd = "flash ";
27 static const std::string eraseCmd = "erase ";
28 static const std::string formatCmd = "format ";
29 static const int PERCENT_FINISH = 100;
30 static const uint32_t PERCENT_CLEAR = ((uint32_t)-1);
31 }
32 namespace Hdc {
HostUpdater(HTaskInfo hTaskInfo)33 HostUpdater::HostUpdater(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo)
34 {
35     commandBegin = CMD_UPDATER_BEGIN;
36     commandData = CMD_UPDATER_DATA;
37 }
38 
~HostUpdater()39 HostUpdater::~HostUpdater() {}
40 
RunQueue(CtxFile & context)41 void HostUpdater::RunQueue(CtxFile &context)
42 {
43     refCount++;
44     context.localPath = context.taskQueue.back();
45     uv_fs_open(loopTask, &context.fsOpenReq, context.localPath.c_str(), O_RDONLY, 0, OnFileOpen);
46     context.master = true;
47 }
48 
BeginTransfer(CtxFile & context,const std::string & function,const char * payload,int minParam,int fileIndex)49 bool HostUpdater::BeginTransfer(CtxFile &context,
50     const std::string &function, const char *payload, int minParam, int fileIndex)
51 {
52     int argc = 0;
53     char **argv = Base::SplitCommandToArgs(payload, &argc);
54     HOSTUPDATER_CHECK(!(argv == nullptr || argc < minParam || fileIndex >= argc), delete[]((char *)argv);
55         return false, "Invalid param for cmd \"%s\"", function.c_str());
56 
57     int maxParam = minParam;
58     bool force = strstr(payload, "-f") != nullptr;
59     if (force) {
60         maxParam += 1;
61     }
62     HOSTUPDATER_CHECK(argc == maxParam, delete[]((char *)argv);
63         return false, "Invalid param for cmd \"%s\" %d", function.c_str(), maxParam);
64 
65     context.transferConfig.functionName = function;
66     context.transferConfig.options = payload;
67     if (force && (fileIndex + 1 < argc) && strcmp(argv[fileIndex + 1], "-f") != 0) {
68         context.localPath = argv[fileIndex + 1];
69     } else {
70         context.localPath = argv[fileIndex];
71     }
72 
73     if (MatchPackageExtendName(context.localPath, ".img")) {
74         context.transferConfig.compressType = COMPRESS_NONE;
75     } else if (MatchPackageExtendName(context.localPath, ".bin")) {
76         const char *part = strstr(payload, "fastboot");
77         HOSTUPDATER_CHECK(part != nullptr, delete[]((char *)argv);
78             return false, "Invalid image %s for cmd \"%s\"", context.localPath.c_str(), function.c_str());
79         context.transferConfig.compressType = COMPRESS_NONE;
80     } else {
81         HOSTUPDATER_CHECK((MatchPackageExtendName(context.localPath, ".zip") ||
82             MatchPackageExtendName(context.localPath, ".lz4") ||
83             MatchPackageExtendName(context.localPath, ".gz2")), delete[]((char *)argv);
84             return false,
85             "Invaid extend name \"%s\" for cmd \"%s\"", context.localPath.c_str(), function.c_str());
86     }
87 
88     WRITE_LOG(LOG_DEBUG, "BeginTransfer function: %s localPath: %s command: %s ",
89         context.transferConfig.functionName.c_str(), context.localPath.c_str(), payload);
90     // check path
91     bool ret = Base::CheckDirectoryOrPath(context.localPath.c_str(), true, true);
92     HOSTUPDATER_CHECK(ret, delete[]((char *)argv);
93         return false,
94         "Invaid path \"%s\" for cmd \"%s\"", context.localPath.c_str(), function.c_str());
95     context.taskQueue.push_back(context.localPath);
96     RunQueue(context);
97     return true;
98 }
99 
GetFileName(const std::string & fileName) const100 std::string HostUpdater::GetFileName(const std::string &fileName) const
101 {
102     int32_t pos = fileName.find_last_of('/');
103     if (pos < 0) { // win32
104         pos = fileName.find_last_of('\\');
105     }
106     return fileName.substr(pos + 1, fileName.size());
107 }
108 
CheckMaster(CtxFile * context)109 void HostUpdater::CheckMaster(CtxFile *context)
110 {
111     uv_fs_t fs;
112     Base::ZeroStruct(fs.statbuf);
113     uv_fs_fstat(nullptr, &fs, context->fsOpenReq.result, nullptr);
114     context->transferConfig.fileSize = fs.statbuf.st_size;
115     uv_fs_req_cleanup(&fs);
116 
117     WRITE_LOG(LOG_DEBUG, "CheckMaster %s %llu", context->transferConfig.functionName.c_str(), fs.statbuf.st_size);
118     context->transferConfig.optionalName = GetFileName(context->localPath);
119     std::string bufString = SerialStruct::SerializeToString(context->transferConfig);
120 
121     const uint64_t verdorSize = static_cast<uint64_t>(1024 * 1024) * 256;
122     const uint64_t systemSize = static_cast<uint64_t>(1024 * 1024) * 1500;
123     const uint64_t minSize = static_cast<uint64_t>(1024 * 1024) * 10;
124     uint64_t realSize = verdorSize;
125     if (fs.statbuf.st_size > minSize) {
126         realSize += systemSize;
127     }
128     std::vector<uint8_t> buffer(sizeof(realSize) + bufString.size());
129     int ret = memcpy_s(buffer.data(), buffer.size(), &realSize, sizeof(realSize));
130     int ret2 = memcpy_s(buffer.data() + sizeof(realSize), buffer.size(), bufString.c_str(), bufString.size());
131     if ((ret == 0) && (ret2 == 0)) {
132         SendToAnother(CMD_UPDATER_CHECK, (uint8_t *)buffer.data(), buffer.size());
133     }
134 }
135 
CheckCmd(const std::string & function,const char * payload,int param)136 bool HostUpdater::CheckCmd(const std::string &function, const char *payload, int param)
137 {
138     int argc = 0;
139     char **argv = Base::SplitCommandToArgs(payload, &argc);
140     HOSTUPDATER_CHECK(argv != nullptr, return false, "Can not parser cmd \"%s\"", function.c_str());
141     delete[]((char *)argv);
142     HOSTUPDATER_CHECK(argc >= param, return false, "Invalid param for cmd \"%s\" %d", function.c_str(), argc);
143     WRITE_LOG(LOG_DEBUG, "CheckCmd command: %s ", payload);
144 
145     int maxParam = param;
146     if (strstr(payload, "-f") != nullptr) {
147         maxParam += 1;
148     }
149     if (strstr(payload, "-t") != nullptr) {
150         maxParam += 1;
151         maxParam += 1;
152     }
153     HOSTUPDATER_CHECK(argc == maxParam, return false,
154         "Invalid param for cmd \"%s\" %d %d", function.c_str(), argc, maxParam);
155     return true;
156 }
157 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)158 bool HostUpdater::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
159 {
160     const int cmdFroErase = 2;
161     const int cmdFroFormat = 2;
162 #ifndef UPDATER_UT
163     if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
164         return false;
165     }
166 #endif
167     bool ret = true;
168     switch (command) {
169         case CMD_UPDATER_BEGIN: {
170             std::string s("Processing:    0%%");
171             sendProgress = true;
172             SendRawData(reinterpret_cast<uint8_t *>(s.data()), s.size());
173             break;
174         }
175         case CMD_UPDATER_UPDATE_INIT:
176             ret = BeginTransfer(ctxNow, CMDSTR_UPDATE_SYSTEM, reinterpret_cast<const char *>(payload), 1, 0);
177             break;
178         case CMD_UPDATER_FLASH_INIT:
179             ret = BeginTransfer(ctxNow, CMDSTR_FLASH_PARTITION,
180                 reinterpret_cast<const char *>(payload), 2, 1); // 2 cmd min param for flash
181             break;
182         case CMD_UPDATER_FINISH:
183             ret = CheckUpdateContinue(command, payload, payloadSize);
184             break;
185         case CMD_UPDATER_ERASE: {
186             if (!CheckCmd(CMDSTR_ERASE_PARTITION, reinterpret_cast<const char *>(payload), cmdFroErase)) {
187                 return false;
188             }
189             SendToAnother(CMD_UPDATER_ERASE, payload, payloadSize);
190             ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload));
191             break;
192         }
193         case CMD_UPDATER_FORMAT: {
194             if (!CheckCmd(CMDSTR_FORMAT_PARTITION, reinterpret_cast<const char *>(payload), cmdFroFormat)) {
195                 return false;
196             }
197             SendToAnother(CMD_UPDATER_FORMAT, payload, payloadSize);
198             ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload));
199             break;
200         }
201         case CMD_UPDATER_PROGRESS:
202             if (payloadSize >= (int)sizeof(uint32_t)) {
203                 ProcessProgress(*(uint32_t *)payload);
204             }
205             break;
206         default:
207             break;
208     }
209     return ret;
210 }
211 
ProcessProgress(uint32_t percentage)212 void HostUpdater::ProcessProgress(uint32_t percentage)
213 {
214     if (!sendProgress) {
215         return;
216     }
217     std::string backStr = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
218     std::string breakStr = "\n";
219     WRITE_LOG(LOG_INFO, "ProcessProgress %d", percentage);
220     const int bufferSize = 128;
221     std::vector<char> buffer(bufferSize);
222     if (percentage == PERCENT_CLEAR) { // clear
223         SendRawData(reinterpret_cast<uint8_t *>(backStr.data()), backStr.size());
224         SendRawData(reinterpret_cast<uint8_t *>(breakStr.data()), breakStr.size());
225         sendProgress = false;
226         return;
227     }
228     int len = sprintf_s(buffer.data(), buffer.size() - 1, "%sProcessing:   %3d%%", backStr.c_str(), percentage);
229     HOSTUPDATER_CHECK(len > 0, return, "Failed to format progress info ");
230     SendRawData(reinterpret_cast<uint8_t *>(buffer.data()), len);
231     if (percentage == PERCENT_FINISH) {
232         SendRawData(reinterpret_cast<uint8_t *>(breakStr.data()), breakStr.size());
233         sendProgress = false;
234     }
235 }
236 
CheckUpdateContinue(const uint16_t command,const uint8_t * payload,int payloadSize)237 bool HostUpdater::CheckUpdateContinue(const uint16_t command, const uint8_t *payload, int payloadSize)
238 {
239     HOSTUPDATER_CHECK(static_cast<size_t>(payloadSize) >= sizeof(uint16_t),
240         return false, "Failed to check payload size %d ", payloadSize);
241     MessageLevel level = (MessageLevel)payload[1];
242     if ((level == MSG_OK) && sendProgress) {
243         ProcessProgress(PERCENT_FINISH);
244     }
245     std::string info((char*)(payload + sizeof(uint16_t)), payloadSize - sizeof(uint16_t));
246     if (!info.empty()) {
247         LogMsg(level, "%s", info.c_str());
248     }
249     WRITE_LOG(LOG_DEBUG, "CheckUpdateContinue payloadSize %d %d %s", payloadSize, level, info.c_str());
250     if (ctxNow.taskQueue.size() != 0) {
251         ctxNow.taskQueue.pop_back();
252     }
253     if (singalStop || !ctxNow.taskQueue.size()) {
254         return false;
255     }
256     RunQueue(ctxNow);
257     return true;
258 }
259 
CheckMatchUpdate(const std::string & input,std::string & stringError,uint16_t & cmdFlag,bool & bJumpDo)260 bool HostUpdater::CheckMatchUpdate(const std::string &input,
261     std::string &stringError, uint16_t &cmdFlag, bool &bJumpDo)
262 {
263     WRITE_LOG(LOG_DEBUG, "CheckMatchUpdate command:%s", input.c_str());
264     size_t cmdLen = updateCmd.size();
265     if (!strncmp(input.c_str(), updateCmd.c_str(), updateCmd.size())) {
266         cmdFlag = CMD_UPDATER_UPDATE_INIT;
267         cmdLen = updateCmd.size();
268     } else if (!strncmp(input.c_str(), flashCmd.c_str(), flashCmd.size())) {
269         cmdFlag = CMD_UPDATER_FLASH_INIT;
270         cmdLen = flashCmd.size();
271     } else if (!strncmp(input.c_str(), eraseCmd.c_str(), eraseCmd.size())) {
272         cmdFlag = CMD_UPDATER_ERASE;
273         cmdLen = eraseCmd.size();
274     } else if (!strncmp(input.c_str(), formatCmd.c_str(), formatCmd.size())) {
275         cmdFlag = CMD_UPDATER_FORMAT;
276         cmdLen = formatCmd.size();
277     } else {
278         return false;
279     }
280     if (input.size() <= cmdLen) {
281         stringError = "Incorrect command";
282         bJumpDo = true;
283     }
284     return true;
285 }
286 
287 #ifdef UPDATER_UT
288 static std::string g_input = "yes";
SetInput(const std::string & input)289 void HostUpdater::SetInput(const std::string &input)
290 {
291     g_input = input;
292 }
293 #endif
ConfirmCommand(const string & commandIn,bool & closeInput)294 bool HostUpdater::ConfirmCommand(const string &commandIn, bool &closeInput)
295 {
296     std::string tip = "";
297     if (!strncmp(commandIn.c_str(), updateCmd.c_str(), updateCmd.size())) {
298         closeInput = true;
299     } else if (!strncmp(commandIn.c_str(), flashCmd.c_str(), flashCmd.size())) {
300         tip = "Confirm flash partition";
301         closeInput = true;
302     } else if (!strncmp(commandIn.c_str(), eraseCmd.c_str(), eraseCmd.size())) {
303         tip = "Confirm erase partition";
304     } else if (!strncmp(commandIn.c_str(), formatCmd.c_str(), formatCmd.size())) {
305         tip = "Confirm format partition";
306     }
307     if (tip.empty() || strstr(commandIn.c_str(), " -f") != nullptr) { // check if -f
308         return true;
309     }
310     const size_t minLen = strlen("yes");
311     int retryCount = 0;
312     do {
313         printf("%s ? (Yes/No) ", tip.c_str());
314         fflush(stdin);
315         std::string info = {};
316         size_t i = 0;
317         while (1) {
318 #ifndef UPDATER_UT
319             char c = getchar();
320 #else
321             char c = '\n';
322             info = g_input;
323 #endif
324             if (c == '\r' || c == '\n') {
325                 break;
326             }
327             if (c == ' ') {
328                 continue;
329             }
330             if (i < minLen && isprint(c)) {
331                 info.append(1, std::tolower(c));
332                 i++;
333             }
334         }
335         if (info == "n" || info == "no") {
336             return false;
337         }
338         if (info == "y" || info == "yes") {
339             return true;
340         }
341         retryCount++;
342     } while (retryCount < 3); // 3 retry max count
343     return (retryCount >= 3) ? false : true; // 3 retry max count
344 }
345 
SendRawData(uint8_t * bufPtr,const int size)346 void HostUpdater::SendRawData(uint8_t *bufPtr, const int size)
347 {
348 #ifndef UPDATER_UT
349     HdcSessionBase *sessionBase = (HdcSessionBase *)clsSession;
350     sessionBase->ServerCommand(taskInfo->sessionId,
351         taskInfo->channelId, CMD_KERNEL_ECHO_RAW, bufPtr, size);
352 #endif
353 }
354 } // namespace Hdc