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