• 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 "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 = "";
263         GetPartitionSuffix(suffix);
264         writePath += suffix;
265     }
266     LOG(INFO) << "write partition path: " << writePath;
267 #else
268     writePath = "/data/updater" + partitionName;
269 #endif
270 #endif
271     return USCRIPT_SUCCESS;
272 }
273 
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)274 int RawImgProcessor::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
275                                             bool isFinish, const void* context)
276 {
277     void *p = const_cast<void *>(context);
278     DataWriter *writer = static_cast<DataWriter *>(p);
279     if (writer == nullptr) {
280         LOG(ERROR) << "Data writer is null";
281         return PKG_INVALID_STREAM;
282     }
283 
284     // maybe extract from package is finished. just return.
285     if (buffer.buffer == nullptr || size == 0) {
286         return PKG_SUCCESS;
287     }
288 
289     bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, nullptr);
290     if (!ret) {
291         LOG(ERROR) << "Write " << size << " byte(s) failed";
292         if (errno == EIO) {
293             writer->GetUpdaterEnv()->PostMessage(UPDATER_RETRY_TAG, IO_FAILED_REBOOT);
294         }
295         return PKG_INVALID_STREAM;
296     }
297 
298     UpdateProgress(size);
299     return PKG_SUCCESS;
300 }
301 
PreProcess(Uscript::UScriptEnv & env)302 int32_t SkipImgProcessor::PreProcess(Uscript::UScriptEnv &env)
303 {
304     std::string partitionName = name_;
305     LOG(INFO) << "SkipImgProcessor::PreProcess " << partitionName;
306     if (env.GetPkgManager() == nullptr) {
307         LOG(ERROR) << "Error to get pkg manager";
308         return USCRIPT_ERROR_EXECUTE;
309     }
310 
311     std::string writePath;
312     writer_ = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
313         static_cast<UpdaterEnv *>(&env), 0);
314     if (writer_ == nullptr) {
315         LOG(ERROR) << "Error to create writer";
316         return USCRIPT_ERROR_EXECUTE;
317     }
318 #ifdef UPDATER_UT
319     int fd = open(writePath.c_str(), O_RDWR | O_CREAT);
320     if (fd >= 0) {
321         close(fd);
322     }
323 #endif
324     return USCRIPT_SUCCESS;
325 }
326 
DoProcess(Uscript::UScriptEnv & env)327 int32_t SkipImgProcessor::DoProcess(Uscript::UScriptEnv &env)
328 {
329     std::string partitionName = name_;
330     // Extract partition information
331     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
332     if (info == nullptr) {
333         LOG(ERROR) << "Error to get file info";
334         return USCRIPT_ERROR_EXECUTE;
335     }
336 
337     PkgStream::ExtractFileProcessor processor =
338         [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
339             return this->SkipImageWriteProcessor(buffer, size, start, isFinish, context);
340         };
341 
342     Hpackage::PkgManager::StreamPtr outStream = nullptr;
343     int ret = env.GetPkgManager()->CreatePkgStream(outStream, partitionName, processor, writer_.get());
344     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
345         LOG(ERROR) << "Error to create output stream";
346         return USCRIPT_ERROR_EXECUTE;
347     }
348 
349     ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
350     if (ret != USCRIPT_SUCCESS) {
351         LOG(ERROR) << "Error to extract file";
352         env.GetPkgManager()->ClosePkgStream(outStream);
353         return USCRIPT_ERROR_EXECUTE;
354     }
355     env.GetPkgManager()->ClosePkgStream(outStream);
356     return USCRIPT_SUCCESS;
357 }
358 
SkipImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)359 int SkipImgProcessor::SkipImageWriteProcessor(const PkgBuffer &buffer, size_t size, [[maybe_unused]]size_t start,
360                                               [[maybe_unused]]bool isFinish, [[maybe_unused]]const void* context)
361 {
362     void *p = const_cast<void *>(context);
363     DataWriter *writer = static_cast<DataWriter *>(p);
364     if (writer == nullptr) {
365         LOG(ERROR) << "Data writer is null";
366         return PKG_INVALID_STREAM;
367     }
368 
369     // maybe extract from package is finished. just return.
370     if (buffer.buffer == nullptr || size == 0) {
371         return PKG_SUCCESS;
372     }
373 
374     UpdateProgress(size);
375     return PKG_SUCCESS;
376 }
377 
PostProcess(Uscript::UScriptEnv & env)378 int32_t SkipImgProcessor::PostProcess(Uscript::UScriptEnv &env)
379 {
380     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(name_, true);
381     DataWriter::ReleaseDataWriter(writer_);
382     totalSize_ = 0;
383     LOG(INFO) << name_ << " SkipImgProcess finish";
384     return USCRIPT_SUCCESS;
385 }
386 }