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 "applypatch/transfer_manager.h"
16 #include <fcntl.h>
17 #include <sstream>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include "applypatch/command_function.h"
21 #include "log/log.h"
22 #include "utils.h"
23
24 namespace Updater {
25 using namespace Updater::Utils;
26 static TransferManagerPtr g_transferManagerInstance = nullptr;
GetTransferManagerInstance()27 TransferManagerPtr TransferManager::GetTransferManagerInstance()
28 {
29 if (g_transferManagerInstance == nullptr) {
30 g_transferManagerInstance = new TransferManager();
31 g_transferManagerInstance->Init();
32 }
33 return g_transferManagerInstance;
34 }
35
ReleaseTransferManagerInstance(TransferManagerPtr transferManager)36 void TransferManager::ReleaseTransferManagerInstance(TransferManagerPtr transferManager)
37 {
38 delete transferManager;
39 g_transferManagerInstance = nullptr;
40 transferManager = nullptr;
41 }
42
~TransferManager()43 TransferManager::~TransferManager()
44 {
45 if (globalParams != nullptr) {
46 if (globalParams->writerThreadInfo != nullptr) {
47 globalParams->writerThreadInfo.reset();
48 }
49 globalParams.reset();
50 }
51 }
52
CommandsExecute(int fd,Command & cmd)53 bool TransferManager::CommandsExecute(int fd, Command &cmd)
54 {
55 cmd.SetFileDescriptor(fd);
56 std::unique_ptr<CommandFunction> cf = CommandFunctionFactory::GetCommandFunction(cmd.GetCommandType());
57 if (cf == nullptr) {
58 LOG(ERROR) << "Failed to get cmd exec";
59 return false;
60 }
61 CommandResult ret = cf->Execute(cmd);
62 CommandFunctionFactory::ReleaseCommandFunction(cf);
63 if (!CheckResult(ret, cmd.GetCommandLine(), cmd.GetCommandType())) {
64 return false;
65 }
66 return true;
67 }
68
CommandsParser(int fd,const std::vector<std::string> & context)69 bool TransferManager::CommandsParser(int fd, const std::vector<std::string> &context)
70 {
71 if (context.size() < 1) {
72 LOG(ERROR) << "too small context in transfer file";
73 return false;
74 }
75 if (globalParams == nullptr) {
76 LOG(ERROR) << "globalParams is nullptr";
77 return false;
78 }
79
80 std::vector<std::string>::const_iterator ct = context.begin();
81 globalParams->version = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
82 globalParams->blockCount = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
83 globalParams->maxEntries = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
84 globalParams->maxBlocks = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
85 size_t totalSize = globalParams->blockCount;
86 std::string retryCmd = "";
87 if (globalParams->env != nullptr && globalParams->env->IsRetry()) {
88 retryCmd = ReloadForRetry();
89 }
90 size_t initBlock = 0;
91 for (; ct != context.end(); ct++) {
92 std::unique_ptr<Command> cmd = std::make_unique<Command>();
93 if (cmd == nullptr) {
94 LOG(ERROR) << "Failed to parse command line.";
95 return false;
96 }
97 if (!cmd->Init(*ct) || cmd->GetCommandType() == CommandType::LAST || globalParams->env == nullptr) {
98 continue;
99 }
100 if (!retryCmd.empty() && globalParams->env->IsRetry()) {
101 if (*ct == retryCmd) {
102 retryCmd.clear();
103 }
104 if (cmd->GetCommandType() != CommandType::NEW) {
105 LOG(INFO) << "Retry: Command " << *ct << " passed";
106 continue;
107 }
108 }
109 if (!CommandsExecute(fd, *cmd)) {
110 LOG(ERROR) << "Running command : " << cmd->GetArgumentByPos(0) << " fail";
111 return false;
112 }
113 if (initBlock == 0) {
114 initBlock = globalParams->written;
115 }
116 if (totalSize != 0 && globalParams->env != nullptr && NeedSetProgress(cmd->GetCommandType())) {
117 globalParams->env->PostMessage("set_progress",
118 std::to_string((static_cast<double>(globalParams->written) - initBlock) / totalSize));
119 }
120 }
121 return true;
122 }
123
Init()124 void TransferManager::Init()
125 {
126 globalParams = std::make_unique<GlobalParams>();
127 globalParams->writerThreadInfo = std::make_unique<WriterThreadInfo>();
128 blocksetMap.clear();
129 }
130
RegisterForRetry(const std::string & cmd)131 bool TransferManager::RegisterForRetry(const std::string &cmd)
132 {
133 std::string path = globalParams->retryFile;
134 int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
135 if (fd == -1) {
136 LOG(ERROR) << "Failed to create";
137 return false;
138 }
139 bool ret = Utils::WriteStringToFile(fd, cmd);
140 if (ret == false) {
141 LOG(ERROR) << "Write retry flag error";
142 }
143 fsync(fd);
144 close(fd);
145 return ret;
146 }
147
ReloadForRetry() const148 std::string TransferManager::ReloadForRetry() const
149 {
150 std::string path = globalParams->retryFile;
151 int fd = open(path.c_str(), O_RDONLY);
152 if (fd < 0) {
153 LOG(ERROR) << "Failed to open";
154 return "";
155 }
156 (void)lseek(fd, 0, SEEK_SET);
157 std::string cmd = "";
158 if (!Utils::ReadFileToString(fd, cmd)) {
159 LOG(ERROR) << "Error to read retry flag";
160 }
161 close(fd);
162 return cmd;
163 }
164
NeedSetProgress(const CommandType & type)165 bool TransferManager::NeedSetProgress(const CommandType &type)
166 {
167 return type == CommandType::NEW ||
168 type == CommandType::IMGDIFF ||
169 type == CommandType::BSDIFF ||
170 type == CommandType::ZERO;
171 }
172
CheckResult(const CommandResult result,const std::string & cmd,const CommandType & type)173 bool TransferManager::CheckResult(const CommandResult result, const std::string &cmd, const CommandType &type)
174 {
175 switch (result) {
176 case SUCCESS:
177 if (type != CommandType::NEW) {
178 RegisterForRetry(cmd);
179 }
180 break;
181 case NEED_RETRY:
182 LOG(INFO) << "Running command need retry!";
183 if (globalParams->env != nullptr) {
184 globalParams->env->PostMessage("retry_update", cmd);
185 }
186 return false;
187 case FAILED:
188 default:
189 LOG(ERROR) << "Running command failed";
190 return false;
191 }
192 return true;
193 }
194 } // namespace Updater
195