• 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.SetSrcFileDescriptor(fd);
39     cmd.SetTargetFileDescriptor(fd);
40     CommandFunction* cf = CommandFunctionFactory::GetInstance().GetCommandFunction(cmd.GetCommandHead());
41     if (cf == nullptr) {
42         LOG(ERROR) << "Failed to get cmd exec";
43         return false;
44     }
45     CommandResult ret = cf->Execute(cmd);
46     if (!cmd.GetTransferParams()->canWrite) {
47         return ret == SUCCESS;
48     }
49     if (!CheckResult(ret, cmd.GetCommandLine(), cmd.GetCommandType())) {
50         return false;
51     }
52     return true;
53 }
54 
JudgeBlockVerifyCmdType(Command & cmd)55 static bool JudgeBlockVerifyCmdType(Command &cmd)
56 {
57     if (cmd.GetCommandType() == CommandType::NEW ||
58         cmd.GetCommandType() == CommandType::ERASE ||
59         cmd.GetCommandType() == CommandType::FREE ||
60         cmd.GetCommandType() == CommandType::ZERO) {
61             return false;
62         }
63     return true;
64 }
65 
InitCommandParser(std::vector<std::string>::const_iterator ct,std::string & retryCmd)66 std::vector<std::string>::const_iterator TransferManager::InitCommandParser(std::vector<std::string>::const_iterator ct,
67     std::string &retryCmd)
68 {
69     transferParams_->version = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
70     transferParams_->blockCount = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
71     transferParams_->maxEntries = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
72     transferParams_->maxBlocks = Utils::String2Int<size_t>(*ct++, Utils::N_DEC);
73     if (transferParams_->env != nullptr && transferParams_->env->IsRetry()) {
74         retryCmd = ReloadForRetry();
75     }
76     return ct;
77 }
78 
CommandParserPreCheck(const std::vector<std::string> & context)79 bool TransferManager::CommandParserPreCheck(const std::vector<std::string> &context)
80 {
81     if (context.size() < 1) {
82         LOG(ERROR) << "too small context in transfer file";
83         return false;
84     }
85     if (transferParams_ == nullptr) {
86         LOG(ERROR) << "transferParams_ is nullptr";
87         return false;
88     }
89     return true;
90 }
91 
CommandsParser(int fd,const std::vector<std::string> & context)92 bool TransferManager::CommandsParser(int fd, const std::vector<std::string> &context)
93 {
94     if (!CommandParserPreCheck(context)) {
95         return false;
96     }
97 
98     std::string retryCmd = "";
99     std::vector<std::string>::const_iterator ct = context.begin();
100     ct = InitCommandParser(ct, retryCmd);
101     size_t totalSize = transferParams_->blockCount;
102     size_t initBlock = 0;
103     for (; ct != context.end(); ct++) {
104         std::unique_ptr<Command> cmd = std::make_unique<Command>(transferParams_.get());
105         if (cmd == nullptr) {
106             LOG(ERROR) << "Failed to parse command line.";
107             return false;
108         }
109         if (!cmd->Init(*ct) || transferParams_->env == nullptr) {
110             continue;
111         }
112         if (!retryCmd.empty() && transferParams_->env->IsRetry()) {
113             if (*ct == retryCmd) {
114                 retryCmd.clear();
115             }
116             if (cmd->GetCommandType() != CommandType::NEW) {
117                 LOG(INFO) << "Retry: Command " << *ct << " passed";
118                 continue;
119             }
120         }
121         if (!transferParams_->canWrite && !JudgeBlockVerifyCmdType(*cmd)) {
122             continue;
123         }
124         if (!CommandsExecute(fd, *cmd)) {
125             LOG(ERROR) << "Running command : " << cmd->GetCommandLine() << " fail";
126             return false;
127         }
128         if (!transferParams_->canWrite) {
129             continue;
130         }
131         if (initBlock == 0) {
132             initBlock = transferParams_->written;
133         }
134         if (totalSize != 0 && (transferParams_->written - initBlock) > 0) {
135             UpdateProgress(initBlock, totalSize);
136         }
137     }
138     if (fabs(Uscript::GetScriptProportion() - 1.0f) < 1e-6) {
139         FillUpdateProgress();
140     }
141     return true;
142 }
143 
UpdateProgress(size_t & initBlock,size_t totalSize)144 void TransferManager::UpdateProgress(size_t &initBlock, size_t totalSize)
145 {
146     float p = static_cast<float>(transferParams_->written - initBlock) / totalSize\
147         * Uscript::GetScriptProportion() * Uscript::GetTotalProportion();
148     SetUpdateProgress(p);
149     initBlock = transferParams_->written;
150 }
151 
RegisterForRetry(const std::string & cmd)152 bool TransferManager::RegisterForRetry(const std::string &cmd)
153 {
154     std::string path = transferParams_->retryFile;
155     int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
156     if (fd == -1) {
157         LOG(ERROR) << "Failed to create";
158         return false;
159     }
160     bool ret = Utils::WriteStringToFile(fd, cmd);
161     if (ret == false) {
162         LOG(ERROR) << "Write retry flag error";
163     }
164     fsync(fd);
165     close(fd);
166     return ret;
167 }
168 
ReloadForRetry() const169 std::string TransferManager::ReloadForRetry() const
170 {
171     std::string path = transferParams_->retryFile;
172     int fd = open(path.c_str(), O_RDONLY);
173     if (fd < 0) {
174         LOG(ERROR) << "Failed to open";
175         return "";
176     }
177     (void)lseek(fd, 0, SEEK_SET);
178     std::string cmd = "";
179     if (!Utils::ReadFileToString(fd, cmd)) {
180         LOG(ERROR) << "Error to read retry flag";
181     }
182     close(fd);
183     return cmd;
184 }
185 
CheckResult(const CommandResult result,const std::string & cmd,const CommandType & type)186 bool TransferManager::CheckResult(const CommandResult result, const std::string &cmd, const CommandType &type)
187 {
188     switch (result) {
189         case SUCCESS:
190             if (type != CommandType::NEW) {
191                 RegisterForRetry(cmd);
192             }
193             break;
194         case NEED_RETRY:
195             LOG(INFO) << "IO failed. Running command need retry!";
196             if (transferParams_->env != nullptr) {
197                 transferParams_->env->PostMessage("retry_update", IO_FAILED_REBOOT);
198             }
199             return false;
200         case FAILED:
201             LOG(INFO) << "Block update failed. Running command need retry!";
202             if (transferParams_->env != nullptr) {
203                 transferParams_->env->PostMessage("retry_update", BLOCK_UPDATE_FAILED_REBOOT);
204             }
205             return false;
206         default:
207             LOG(ERROR) << "Running command failed";
208             return false;
209     }
210     return true;
211 }
212 } // namespace Updater
213