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