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
16 #include "component_processor.h"
17 #include <fcntl.h>
18 #include "applypatch/data_writer.h"
19 #include "applypatch/partition_record.h"
20 #include "dump.h"
21 #include "log.h"
22 #include "parameter.h"
23 #ifdef UPDATER_USE_PTABLE
24 #include "ptable_parse/ptable_manager.h"
25 #endif
26 #include "slot_info/slot_info.h"
27 #include "updater/updater_const.h"
28
29 using namespace std;
30 using namespace std::placeholders;
31 using namespace Hpackage;
32 using namespace Uscript;
33
34 namespace Updater {
35 REGISTER_PROCESSOR(VersionCheckProcessor, "version_list")
36 REGISTER_PROCESSOR(BoardIdCheckProcessor, "board_list")
37 REGISTER_PROCESSOR(RawImgProcessor, "uboot", "boot_linux", "ramdisk",
38 "system", "vendor", "resource", "updater", "userdata")
39
GetInstance()40 ComponentProcessorFactory &ComponentProcessorFactory::GetInstance()
41 {
42 static ComponentProcessorFactory instance;
43 return instance;
44 }
45
RegisterProcessor(Constructor constructor,std::vector<std::string> & nameList)46 void ComponentProcessorFactory::RegisterProcessor(Constructor constructor, std::vector<std::string> &nameList)
47 {
48 for (auto &iter : nameList) {
49 if (!m_constructorMap.emplace(iter, constructor).second) {
50 LOG(ERROR) << "emplace: " << iter.c_str() << " fail";
51 }
52 }
53 }
54
GetProcessor(const std::string & name,const uint8_t len) const55 std::unique_ptr<ComponentProcessor> ComponentProcessorFactory::GetProcessor(const std::string &name,
56 const uint8_t len) const
57 {
58 std::string partitionName = name;
59 std::transform(partitionName.begin(), partitionName.end(), partitionName.begin(), ::tolower);
60 partitionName.erase(std::remove(partitionName.begin(), partitionName.end(), '/'), partitionName.end());
61 std::string::size_type position = partitionName.find("_es");
62 if (position != partitionName.npos) {
63 partitionName = partitionName.substr(0, position);
64 }
65 auto it = m_constructorMap.find(partitionName);
66 if (it == m_constructorMap.end() || it->second == nullptr) {
67 LOG(WARNING) << "GetProcessor for: " << name.c_str() << " fail, use default raw write";
68 return std::make_unique<RawImgProcessor>(name, len);
69 }
70 return (*(it->second))(name, len);
71 }
72
DoProcess(Uscript::UScriptEnv & env)73 int32_t VersionCheckProcessor::DoProcess(Uscript::UScriptEnv &env)
74 {
75 PackagesInfoPtr pkginfomanager = PackagesInfo::GetPackagesInfoInstance();
76 if (pkginfomanager == nullptr) {
77 LOG(ERROR) << "Fail to pkginfomanager";
78 return PKG_INVALID_VERSION;
79 }
80
81 if (env.GetPkgManager() == nullptr || pkginfomanager == nullptr) {
82 return PKG_INVALID_VERSION;
83 }
84 const char *verPtr = GetDisplayVersion();
85 if (verPtr == nullptr) {
86 LOG(ERROR) << "Fail to GetDisplayVersion";
87 return PKG_INVALID_VERSION;
88 }
89 std::string verStr(verPtr);
90 LOG(INFO) << "current version:" << verStr;
91 int ret = -1;
92 std::vector<std::string> targetVersions = pkginfomanager->GetOTAVersion(env.GetPkgManager(), "/version_list", "");
93 for (size_t i = 0; i < targetVersions.size(); i++) {
94 LOG(INFO) << "Check version " << targetVersions[i];
95 ret = verStr.compare(targetVersions[i]);
96 if (ret == 0) {
97 LOG(INFO) << "Check version success";
98 break;
99 }
100 }
101 #ifndef UPDATER_UT
102 return ret;
103 #else
104 return USCRIPT_SUCCESS;
105 #endif
106 }
107
DoProcess(Uscript::UScriptEnv & env)108 int32_t BoardIdCheckProcessor::DoProcess(Uscript::UScriptEnv &env)
109 {
110 PackagesInfoPtr pkginfomanager = PackagesInfo::GetPackagesInfoInstance();
111 if (pkginfomanager == nullptr) {
112 LOG(ERROR) << "Fail to get pkginfomanager";
113 return PKG_INVALID_VERSION;
114 }
115
116 if (env.GetPkgManager() == nullptr) {
117 LOG(ERROR) << "Fail to GetPkgManager";
118 return PKG_INVALID_VERSION;
119 }
120
121 std::string localBoardId = Utils::GetLocalBoardId();
122 if (localBoardId.empty()) {
123 return 0;
124 }
125
126 int ret = -1;
127 std::vector<std::string> boardIdList = pkginfomanager->GetBoardID(env.GetPkgManager(), "/board_list", "");
128 for (size_t i = 0; i < boardIdList.size(); i++) {
129 LOG(INFO) << "Check BoardId " << boardIdList[i];
130 ret = localBoardId.compare(boardIdList[i]);
131 if (ret == 0) {
132 LOG(INFO) << "Check board list success ";
133 break;
134 }
135 }
136 #ifndef UPDATER_UT
137 return ret;
138 #else
139 return USCRIPT_SUCCESS;
140 #endif
141 }
142
PreProcess(Uscript::UScriptEnv & env)143 int32_t RawImgProcessor::PreProcess(Uscript::UScriptEnv &env)
144 {
145 UPDATER_INIT_RECORD;
146 std::string partitionName = name_;
147 LOG(INFO) << "RawImgProcessor::PreProcess " << partitionName;
148 if (env.GetPkgManager() == nullptr) {
149 LOG(ERROR) << "Error to get pkg manager";
150 UPDATER_LAST_WORD(partitionName, "Error to get pkg manager");
151 return USCRIPT_ERROR_EXECUTE;
152 }
153
154 std::string writePath;
155 uint64_t offset = 0;
156 uint64_t partitionSize = 0;
157 if (GetWritePathAndOffset(partitionName, writePath, offset, partitionSize) != USCRIPT_SUCCESS) {
158 LOG(ERROR) << "Get partition:%s WritePathAndOffset fail \'" <<
159 partitionName.substr(1, partitionName.size()) << "\'.";
160 UPDATER_LAST_WORD("WritePathAndOffset fail", partitionName);
161 return USCRIPT_ERROR_EXECUTE;
162 }
163 const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
164 if (info == nullptr) {
165 LOG(ERROR) << "Error to get file info";
166 UPDATER_LAST_WORD("Error to get file info");
167 return USCRIPT_ERROR_EXECUTE;
168 }
169 #ifdef UPDATER_USE_PTABLE
170 if (partitionSize < info->unpackedSize) {
171 LOG(ERROR) << "partition size: " << partitionSize << " is short than image size: " << totalSize_;
172 UPDATER_LAST_WORD(partitionName, partitionSize, totalSize_);
173 return USCRIPT_ERROR_EXECUTE;
174 }
175 #endif
176
177 writer_ = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
178 static_cast<UpdaterEnv *>(&env), offset);
179 if (writer_ == nullptr) {
180 LOG(ERROR) << "Error to create writer";
181 UPDATER_LAST_WORD(partitionName, "Error to create writer");
182 return USCRIPT_ERROR_EXECUTE;
183 }
184 #ifdef UPDATER_UT
185 int fd = open(writePath.c_str(), O_RDWR | O_CREAT);
186 if (fd >= 0) {
187 close(fd);
188 }
189 #endif
190 return USCRIPT_SUCCESS;
191 }
192
DoProcess(Uscript::UScriptEnv & env)193 int32_t RawImgProcessor::DoProcess(Uscript::UScriptEnv &env)
194 {
195 UPDATER_INIT_RECORD;
196 std::string partitionName = name_;
197 // Extract partition information
198 const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
199 if (info == nullptr) {
200 LOG(ERROR) << "Error to get file info";
201 UPDATER_LAST_WORD(partitionName, "Error to get file info");
202 return USCRIPT_ERROR_EXECUTE;
203 }
204
205 PkgStream::ExtractFileProcessor processor =
206 [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
207 return this->RawImageWriteProcessor(buffer, size, start, isFinish, context);
208 };
209
210 Hpackage::PkgManager::StreamPtr outStream = nullptr;
211 int ret = env.GetPkgManager()->CreatePkgStream(outStream, partitionName, processor, writer_.get());
212 if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
213 LOG(ERROR) << "Error to create output stream";
214 UPDATER_LAST_WORD(partitionName, "Error to create output stream");
215 return USCRIPT_ERROR_EXECUTE;
216 }
217
218 ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
219 if (ret != USCRIPT_SUCCESS) {
220 LOG(ERROR) << "Error to extract file";
221 env.GetPkgManager()->ClosePkgStream(outStream);
222 UPDATER_LAST_WORD(partitionName, "Error to extract file");
223 return USCRIPT_ERROR_EXECUTE;
224 }
225 env.GetPkgManager()->ClosePkgStream(outStream);
226 return USCRIPT_SUCCESS;
227 }
228
PostProcess(Uscript::UScriptEnv & env)229 int32_t RawImgProcessor::PostProcess(Uscript::UScriptEnv &env)
230 {
231 PartitionRecord::GetInstance().RecordPartitionUpdateStatus(name_, true);
232 DataWriter::ReleaseDataWriter(writer_);
233 totalSize_ = 0;
234 LOG(INFO) << "UScriptInstructionRawImageWrite finish";
235 return USCRIPT_SUCCESS;
236 }
237
GetWritePathAndOffset(const std::string & partitionName,std::string & writePath,uint64_t & offset,uint64_t & partitionSize)238 int RawImgProcessor::GetWritePathAndOffset(const std::string &partitionName, std::string &writePath,
239 uint64_t &offset, uint64_t &partitionSize)
240 {
241 #ifdef UPDATER_USE_PTABLE
242 DevicePtable &devicePtb = DevicePtable::GetInstance();
243 Ptable::PtnInfo ptnInfo;
244 if (!devicePtb.GetPartionInfoByName(partitionName, ptnInfo)) {
245 LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
246 partitionName.substr(1, partitionName.size()) << "\'.";
247 return USCRIPT_ERROR_EXECUTE;
248 }
249 writePath = ptnInfo.writePath;
250 offset = ptnInfo.startAddr;
251 partitionSize = ptnInfo.partitionSize;
252 #else
253 writePath = GetBlockDeviceByMountPoint(partitionName);
254 if (writePath.empty()) {
255 LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
256 partitionName.substr(1, partitionName.size()) << "\'.";
257 return USCRIPT_ERROR_EXECUTE;
258 }
259
260 #ifndef UPDATER_UT
261 if (partitionName != "/userdata") {
262 std::string suffix = Utils::GetUpdateSuffix();
263 writePath += suffix;
264 }
265 LOG(INFO) << "write partition path: " << writePath;
266 #else
267 writePath = "/data/updater" + partitionName;
268 #endif
269 #endif
270 return USCRIPT_SUCCESS;
271 }
272
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)273 int RawImgProcessor::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
274 bool isFinish, const void* context)
275 {
276 void *p = const_cast<void *>(context);
277 DataWriter *writer = static_cast<DataWriter *>(p);
278 if (writer == nullptr) {
279 LOG(ERROR) << "Data writer is null";
280 return PKG_INVALID_STREAM;
281 }
282
283 // maybe extract from package is finished. just return.
284 if (buffer.buffer == nullptr || size == 0) {
285 return PKG_SUCCESS;
286 }
287
288 bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, nullptr);
289 if (!ret) {
290 LOG(ERROR) << "Write " << size << " byte(s) failed";
291 if (errno == EIO) {
292 writer->GetUpdaterEnv()->PostMessage(UPDATER_RETRY_TAG, IO_FAILED_REBOOT);
293 }
294 return PKG_INVALID_STREAM;
295 }
296
297 UpdateProgress(size);
298 return PKG_SUCCESS;
299 }
300
PreProcess(Uscript::UScriptEnv & env)301 int32_t SkipImgProcessor::PreProcess(Uscript::UScriptEnv &env)
302 {
303 std::string partitionName = name_;
304 LOG(INFO) << "SkipImgProcessor::PreProcess " << partitionName;
305 if (env.GetPkgManager() == nullptr) {
306 LOG(ERROR) << "Error to get pkg manager";
307 return USCRIPT_ERROR_EXECUTE;
308 }
309
310 std::string writePath;
311 writer_ = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
312 static_cast<UpdaterEnv *>(&env), 0);
313 if (writer_ == nullptr) {
314 LOG(ERROR) << "Error to create writer";
315 return USCRIPT_ERROR_EXECUTE;
316 }
317 #ifdef UPDATER_UT
318 int fd = open(writePath.c_str(), O_RDWR | O_CREAT);
319 if (fd >= 0) {
320 close(fd);
321 }
322 #endif
323 return USCRIPT_SUCCESS;
324 }
325
DoProcess(Uscript::UScriptEnv & env)326 int32_t SkipImgProcessor::DoProcess(Uscript::UScriptEnv &env)
327 {
328 std::string partitionName = name_;
329 // Extract partition information
330 const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
331 if (info == nullptr) {
332 LOG(ERROR) << "Error to get file info";
333 return USCRIPT_ERROR_EXECUTE;
334 }
335
336 PkgStream::ExtractFileProcessor processor =
337 [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
338 return this->SkipImageWriteProcessor(buffer, size, start, isFinish, context);
339 };
340
341 Hpackage::PkgManager::StreamPtr outStream = nullptr;
342 int ret = env.GetPkgManager()->CreatePkgStream(outStream, partitionName, processor, writer_.get());
343 if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
344 LOG(ERROR) << "Error to create output stream";
345 return USCRIPT_ERROR_EXECUTE;
346 }
347
348 ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
349 if (ret != USCRIPT_SUCCESS) {
350 LOG(ERROR) << "Error to extract file";
351 env.GetPkgManager()->ClosePkgStream(outStream);
352 return USCRIPT_ERROR_EXECUTE;
353 }
354 env.GetPkgManager()->ClosePkgStream(outStream);
355 return USCRIPT_SUCCESS;
356 }
357
SkipImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)358 int SkipImgProcessor::SkipImageWriteProcessor(const PkgBuffer &buffer, size_t size, [[maybe_unused]]size_t start,
359 [[maybe_unused]]bool isFinish, [[maybe_unused]]const void* context)
360 {
361 void *p = const_cast<void *>(context);
362 DataWriter *writer = static_cast<DataWriter *>(p);
363 if (writer == nullptr) {
364 LOG(ERROR) << "Data writer is null";
365 return PKG_INVALID_STREAM;
366 }
367
368 // maybe extract from package is finished. just return.
369 if (buffer.buffer == nullptr || size == 0) {
370 return PKG_SUCCESS;
371 }
372
373 UpdateProgress(size);
374 return PKG_SUCCESS;
375 }
376
PostProcess(Uscript::UScriptEnv & env)377 int32_t SkipImgProcessor::PostProcess(Uscript::UScriptEnv &env)
378 {
379 PartitionRecord::GetInstance().RecordPartitionUpdateStatus(name_, true);
380 DataWriter::ReleaseDataWriter(writer_);
381 totalSize_ = 0;
382 LOG(INFO) << name_ << " SkipImgProcess finish";
383 return USCRIPT_SUCCESS;
384 }
385 }