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