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