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#include "daemon_updater.h"
16
17#include "daemon_common.h"
18#include "flashd_define.h"
19#include "hdi/client/update_hdi_client.h"
20#include "updater/updater.h"
21#include "updater/updater_const.h"
22using namespace std;
23namespace Hdc {
24namespace {
25constexpr uint8_t PAYLOAD_FIX_RESERVER = 64;
26}
27
28std::atomic<bool> DaemonUpdater::isRunning_ = false;
29
30DaemonUpdater::DaemonUpdater(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo)
31{
32    commandBegin = CMD_UPDATER_BEGIN;
33    commandData = CMD_UPDATER_DATA;
34}
35
36DaemonUpdater::~DaemonUpdater()
37{
38    FLASHD_LOGI("~DaemonUpdater refCount %d", refCount);
39}
40
41bool DaemonUpdater::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
42{
43    if (IsDeviceLocked()) {
44        std::string echo = "operation is not allowed";
45        vector<uint8_t> buffer;
46        buffer.push_back(command);
47        buffer.push_back(Hdc::MSG_FAIL);
48        buffer.insert(buffer.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size());
49        SendToAnother(Hdc::CMD_UPDATER_FINISH, buffer.data(), buffer.size());
50        FLASHD_LOGE("The devic is locked and operation is not allowed");
51        return false;
52    }
53
54    if (!isInit_) {
55        Init();
56        isInit_ = true;
57    }
58
59    auto iter = cmdFunc_.find(command);
60    if (iter == cmdFunc_.end()) {
61        FLASHD_LOGE("command is invalid, command = %d", command);
62        return false;
63    }
64    iter->second(payload, payloadSize);
65    return true;
66}
67
68bool DaemonUpdater::SendToHost(Flashd::CmdType type, Flashd::UpdaterState state, const std::string &msg)
69{
70    if (!DaemonUpdater::isRunning_) {
71        FLASHD_LOGW("flasd is not runing");
72        return true;
73    }
74
75    if (state == Flashd::UpdaterState::DOING) {
76        uint32_t temp = 0;
77        std::stringstream percentageStream(msg);
78        if (!(percentageStream >> temp)) {
79            temp = 0;
80        }
81        uint8_t percentage = static_cast<uint8_t>(temp);
82        SendToAnother(Hdc::CMD_UPDATER_PROGRESS, &percentage, sizeof(percentage));
83        return true;
84    }
85
86    if (state == Flashd::UpdaterState::FAIL || state == Flashd::UpdaterState::SUCCESS) {
87        uint8_t percentage = (state == Flashd::UpdaterState::SUCCESS) ? Flashd::PERCENT_FINISH : Flashd::PERCENT_CLEAR;
88        SendToAnother(Hdc::CMD_UPDATER_PROGRESS, &percentage, sizeof(percentage));
89
90        std::string echo = Hdc::Base::ReplaceAll(msg, "\n", " ");
91        vector<uint8_t> buffer;
92        buffer.push_back(static_cast<uint8_t>(type));
93        buffer.push_back((state == Flashd::UpdaterState::SUCCESS) ? Hdc::MSG_OK : Hdc::MSG_FAIL);
94        buffer.insert(buffer.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size());
95        SendToAnother(Hdc::CMD_UPDATER_FINISH, buffer.data(), buffer.size());
96        TaskFinish();
97        if (commander_ != nullptr) {
98            commander_->PostCommand();
99        }
100        DaemonUpdater::isRunning_ = false;
101    }
102    return true;
103}
104
105std::unique_ptr<Flashd::Commander> DaemonUpdater::CreateCommander(const std::string &cmd)
106{
107    if (DaemonUpdater::isRunning_) {
108        FLASHD_LOGE("flashd has been running");
109        return nullptr;
110    }
111    DaemonUpdater::isRunning_ = true;
112    auto callback = [this](Flashd::CmdType type, Flashd::UpdaterState state, const std::string &msg) {
113        SendToHost(type, state, msg);
114    };
115    return Flashd::CommanderFactory::GetInstance().CreateCommander(cmd, callback);
116}
117
118void DaemonUpdater::CheckCommand(const uint8_t *payload, int payloadSize)
119{
120    if (payloadSize < static_cast<int>(sizeof(int64_t))) {
121        FLASHD_LOGE("payloadSize is invalid");
122        return;
123    }
124
125    string bufString(reinterpret_cast<const char *>(payload + sizeof(int64_t)), payloadSize - sizeof(int64_t));
126    SerialStruct::ParseFromString(ctxNow.transferConfig, bufString);
127
128    ctxNow.master = false;
129    ctxNow.fsOpenReq.data = &ctxNow;
130    ctxNow.fileSize = ctxNow.transferConfig.fileSize;
131
132    FLASHD_LOGI("functionName = %s, options = %s, fileSize = %u", ctxNow.transferConfig.functionName.c_str(),
133        ctxNow.transferConfig.options.c_str(), ctxNow.transferConfig.fileSize);
134
135    commander_ = CreateCommander(ctxNow.transferConfig.functionName.c_str());
136    if (commander_ == nullptr) {
137        FLASHD_LOGE("commander_ is null for cmd = %s", ctxNow.transferConfig.functionName.c_str());
138        return;
139    }
140    commander_->DoCommand(ctxNow.transferConfig.options, ctxNow.transferConfig.fileSize);
141
142    SendToAnother(commandBegin, nullptr, 0);
143    refCount++;
144}
145
146void DaemonUpdater::DataCommand(const uint8_t *payload, int payloadSize) const
147{
148    if (commander_ == nullptr) {
149        FLASHD_LOGE("commander_ is null");
150        return;
151    }
152
153    if (payloadSize <= PAYLOAD_FIX_RESERVER) {
154        FLASHD_LOGE("payloadSize is invaild");
155        return;
156    }
157
158    string serialStrring(reinterpret_cast<const char *>(payload), PAYLOAD_FIX_RESERVER);
159    TransferPayload pld = {};
160    SerialStruct::ParseFromString(pld, serialStrring);
161    commander_->DoCommand(payload + PAYLOAD_FIX_RESERVER, pld.uncompressSize);
162}
163
164void DaemonUpdater::EraseCommand(const uint8_t *payload, int payloadSize)
165{
166    commander_ = CreateCommander(CMDSTR_ERASE_PARTITION);
167    if (commander_ == nullptr) {
168        FLASHD_LOGE("commander_ is null for cmd = %s", CMDSTR_ERASE_PARTITION);
169        return;
170    }
171    commander_->DoCommand(payload, payloadSize);
172}
173
174void DaemonUpdater::FormatCommand(const uint8_t *payload, int payloadSize)
175{
176    commander_ = CreateCommander(CMDSTR_FORMAT_PARTITION);
177    if (commander_ == nullptr) {
178        FLASHD_LOGE("commander_ is null for cmd = %s", CMDSTR_FORMAT_PARTITION);
179        return;
180    }
181    commander_->DoCommand(payload, payloadSize);
182}
183
184void DaemonUpdater::Init()
185{
186    cmdFunc_.emplace(CMD_UPDATER_CHECK, bind(&DaemonUpdater::CheckCommand, this, placeholders::_1, placeholders::_2));
187    cmdFunc_.emplace(CMD_UPDATER_DATA, bind(&DaemonUpdater::DataCommand, this, placeholders::_1, placeholders::_2));
188    cmdFunc_.emplace(CMD_UPDATER_ERASE, bind(&DaemonUpdater::EraseCommand, this, placeholders::_1, placeholders::_2));
189    cmdFunc_.emplace(CMD_UPDATER_FORMAT, bind(&DaemonUpdater::FormatCommand, this, placeholders::_1, placeholders::_2));
190}
191
192bool DaemonUpdater::IsDeviceLocked() const
193{
194    bool isLocked = true;
195    if (auto ret = Updater::UpdateHdiClient::GetInstance().GetLockStatus(isLocked); ret != 0) {
196        FLASHD_LOGE("GetLockStatus fail, ret = %d", ret);
197        return true;
198    }
199    return isLocked;
200}
201
202InvalidDaemon::InvalidDaemon(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo)
203{
204    FLASHD_LOGI("InvalidDaemon init");
205}
206
207InvalidDaemon::~InvalidDaemon()
208{
209    FLASHD_LOGI("~InvalidDaemon refCount %d", refCount);
210}
211
212bool InvalidDaemon::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
213{
214    std::string echo = "operation is not allowed";
215    vector<uint8_t> buffer;
216    buffer.push_back(command);
217    buffer.push_back(Hdc::MSG_FAIL);
218    buffer.insert(buffer.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size());
219    LogMsg(MSG_FAIL, "Operation is not allowed");
220    TaskFinish();
221    FLASHD_LOGE("The operation is not allowed");
222    return false;
223}
224} // namespace Hdc