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