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 "daemon_updater.h"
16 #include "daemon_common.h"
17 #include "flashd/flashd.h"
18 #include "flash_utils.h"
19 #include "flash_define.h"
20
21 namespace Hdc {
DaemonUpdater(HTaskInfo hTaskInfo)22 DaemonUpdater::DaemonUpdater(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo)
23 {
24 commandBegin = CMD_UPDATER_BEGIN;
25 commandData = CMD_UPDATER_DATA;
26 }
27
~DaemonUpdater()28 DaemonUpdater::~DaemonUpdater()
29 {
30 WRITE_LOG(LOG_DEBUG, "~DaemonUpdater refCount %d", refCount);
31 }
32
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)33 bool DaemonUpdater::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
34 {
35 #ifndef UPDATER_UT
36 if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
37 return false;
38 }
39 #endif
40 if (flashHandle_ == nullptr) {
41 int ret = flashd::CreateFlashInstance(&flashHandle_, errorMsg_,
42 [&](uint32_t type, size_t dataLen, const void *context) {
43 SendProgress(dataLen);
44 });
45 FLASHDAEMON_CHECK(ret == 0, AsyncUpdateFinish(command, -1, errorMsg_);
46 return false, "Faild to create flashd");
47 }
48 switch (command) {
49 case CMD_UPDATER_DATA: {
50 const uint8_t payloadPrefixReserve = 64;
51 string serialStrring((char *)payload, payloadPrefixReserve);
52 TransferPayload pld {};
53 SerialStruct::ParseFromString(pld, serialStrring);
54 #ifdef UPDATER_UT
55 pld.uncompressSize = pld.compressSize;
56 #endif
57 SendProgress(pld.uncompressSize);
58 break;
59 }
60 case CMD_UPDATER_CHECK: {
61 ProcessUpdateCheck(payload, payloadSize);
62 break;
63 }
64 case CMD_UPDATER_ERASE: {
65 std::string param(reinterpret_cast<char *>(payload), payloadSize);
66 RunUpdateShell(flashd::UPDATEMOD_ERASE, param, "");
67 TaskFinish();
68 break;
69 }
70 case CMD_UPDATER_FORMAT: {
71 std::string param(reinterpret_cast<char *>(payload), payloadSize);
72 RunUpdateShell(flashd::UPDATEMOD_FORMAT, param, "");
73 TaskFinish();
74 break;
75 }
76 default:
77 WRITE_LOG(LOG_FATAL, "CommandDispatch command %d", command);
78 return false;
79 }
80 return true;
81 };
82
ProcessUpdateCheck(const uint8_t * payload,const int payloadSize)83 void DaemonUpdater::ProcessUpdateCheck(const uint8_t *payload, const int payloadSize)
84 {
85 uint64_t realSize = 0;
86 int ret = memcpy_s(&realSize, sizeof(realSize), payload, sizeof(realSize));
87 FLASHDAEMON_CHECK(ret == 0, return, "Faild to memcpy");
88 string bufString((char *)payload + sizeof(realSize), payloadSize - sizeof(realSize));
89 SerialStruct::ParseFromString(ctxNow.transferConfig, bufString);
90 ctxNow.master = false;
91 ctxNow.fsOpenReq.data = &ctxNow;
92 ctxNow.transferBegin = Base::GetRuntimeMSec();
93 ctxNow.fileSize = ctxNow.transferConfig.fileSize;
94 percentage_ = -1;
95
96 WRITE_LOG(LOG_DEBUG, "ProcessUpdateCheck local function %s size %llu realSize %llu",
97 ctxNow.transferConfig.functionName.c_str(), ctxNow.fileSize, realSize);
98 uint8_t type = flashd::UPDATEMOD_FLASH;
99 if (ctxNow.transferConfig.functionName == CMDSTR_UPDATE_SYSTEM) {
100 type = flashd::UPDATEMOD_UPDATE;
101 totalSize_ = static_cast<double>(ctxNow.fileSize);
102 if (!MatchPackageExtendName(ctxNow.transferConfig.optionalName, ".bin")) {
103 totalSize_ += static_cast<double>(realSize); // for decode from zip
104 }
105 totalSize_ += static_cast<double>(realSize); // for verify
106 totalSize_ += static_cast<double>(realSize); // for read to partition
107 totalSize_ += static_cast<double>(realSize); // for write partition
108 } else if (ctxNow.transferConfig.functionName == CMDSTR_FLASH_PARTITION) {
109 totalSize_ = static_cast<double>(ctxNow.fileSize);
110 type = flashd::UPDATEMOD_FLASH;
111 } else {
112 WRITE_LOG(LOG_FATAL, "ProcessUpdateCheck local function %s size %lu realSize %lu",
113 ctxNow.transferConfig.functionName.c_str(), ctxNow.fileSize, realSize);
114 AsyncUpdateFinish(type, -1, "Invalid command");
115 return;
116 }
117 ctxNow.localPath = ctxNow.transferConfig.optionalName;
118 ret = flashd::DoUpdaterPrepare(flashHandle_, type, ctxNow.transferConfig.options, ctxNow.localPath);
119 if (ret == 0) {
120 refCount++;
121 WRITE_LOG(LOG_DEBUG, "ProcessUpdateCheck localPath %s", ctxNow.localPath.c_str());
122 #ifndef UPDATER_UT
123 uv_fs_open(loopTask, &ctxNow.fsOpenReq, ctxNow.localPath.c_str(),
124 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IRUSR, OnFileOpen);
125 #endif
126 }
127 FLASHDAEMON_CHECK(ret == 0, AsyncUpdateFinish(type, ret, errorMsg_), "Faild to prepare for %d", type);
128 }
129
RunUpdateShell(uint8_t type,const std::string & options,const std::string & package)130 void DaemonUpdater::RunUpdateShell(uint8_t type, const std::string &options, const std::string &package)
131 {
132 int ret = flashd::DoUpdaterFlash(flashHandle_, type, options, package);
133 AsyncUpdateFinish(type, ret, errorMsg_);
134 }
135
SendProgress(size_t dataLen)136 void DaemonUpdater::SendProgress(size_t dataLen)
137 {
138 currSize_ += dataLen;
139 int32_t percentage = static_cast<int32_t>(currSize_ * (flashd::PERCENT_FINISH - 1) / totalSize_);
140 if (static_cast<uint32_t>(percentage) >= flashd::PERCENT_FINISH) {
141 WRITE_LOG(LOG_DEBUG, "SendProgress %lf percentage %d", currSize_, percentage);
142 return;
143 }
144 if (percentage_ < percentage) {
145 percentage_ = percentage;
146 WRITE_LOG(LOG_DEBUG, "SendProgress %lf percentage_ %d", currSize_, percentage_);
147 SendToAnother(CMD_UPDATER_PROGRESS, (uint8_t *)&percentage, sizeof(uint32_t));
148 }
149 }
150
WhenTransferFinish(CtxFile * context)151 void DaemonUpdater::WhenTransferFinish(CtxFile *context)
152 {
153 uint64_t nMSec = Base::GetRuntimeMSec() - context->transferBegin;
154 double fRate = static_cast<double>(context->indexIO) / nMSec; // / /1000 * 1000 = 0
155 WRITE_LOG(LOG_DEBUG, "File for %s transfer finish Size:%lld time:%lldms rate:%.2lfkB/s",
156 ctxNow.transferConfig.functionName.c_str(), context->indexIO, nMSec, fRate);
157
158 int ret = 0;
159 uint8_t type = flashd::UPDATEMOD_UPDATE;
160 if (ctxNow.transferConfig.functionName == CMDSTR_UPDATE_SYSTEM) {
161 type = flashd::UPDATEMOD_UPDATE;
162 ret = flashd::DoUpdaterFlash(flashHandle_, type, ctxNow.transferConfig.options, ctxNow.localPath);
163 } else if (ctxNow.transferConfig.functionName == CMDSTR_FLASH_PARTITION) {
164 type = flashd::UPDATEMOD_FLASH;
165 }
166 AsyncUpdateFinish(type, ret, errorMsg_);
167 TaskFinish();
168 }
169
AsyncUpdateFinish(uint8_t type,int32_t retCode,const string & result)170 void DaemonUpdater::AsyncUpdateFinish(uint8_t type, int32_t retCode, const string &result)
171 {
172 WRITE_LOG(LOG_DEBUG, "AsyncUpdateFinish retCode %d result %s", retCode, result.c_str());
173 uint32_t percentage = (retCode != 0) ? flashd::PERCENT_CLEAR : flashd::PERCENT_FINISH;
174 SendToAnother(CMD_UPDATER_PROGRESS, (uint8_t *)&percentage, sizeof(uint32_t));
175 (void)flashd::DoUpdaterFinish(flashHandle_, type, ctxNow.localPath);
176
177 string echo = result;
178 echo = Base::ReplaceAll(echo, "\n", " ");
179 vector<uint8_t> vecBuf;
180 vecBuf.push_back(type);
181 if (retCode != 0) {
182 vecBuf.push_back(MSG_FAIL);
183 } else {
184 vecBuf.push_back(MSG_OK);
185 }
186 vecBuf.insert(vecBuf.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size());
187 SendToAnother(CMD_UPDATER_FINISH, vecBuf.data(), vecBuf.size());
188 }
189
190 #ifdef UPDATER_UT
DoTransferFinish()191 void DaemonUpdater::DoTransferFinish()
192 {
193 WhenTransferFinish(&ctxNow);
194 }
195 #endif
196 } // namespace Hdc