• 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 
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 }