• 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 #include "update_processor.h"
16 #include <cstdio>
17 #include <memory>
18 #include <string>
19 #include <unistd.h>
20 #include <pthread.h>
21 #include "securec.h"
22 #include "applypatch/data_writer.h"
23 #include "applypatch/partition_record.h"
24 #include "applypatch/update_progress.h"
25 #include "dump.h"
26 #include "log.h"
27 #include "package/hash_data_verifier.h"
28 #include "pkg_manager.h"
29 #ifdef UPDATER_USE_PTABLE
30 #include "ptable_manager.h"
31 #endif
32 #include "script_instruction.h"
33 #include "script_manager.h"
34 #include "slot_info/slot_info.h"
35 #include "update_image_block.h"
36 #include "update_image_patch.h"
37 #include "update_partitions.h"
38 #include "updater_main.h"
39 #include "updater/updater_const.h"
40 #include "update_bin/bin_process.h"
41 
42 using namespace Uscript;
43 using namespace Hpackage;
44 using namespace Updater;
45 
46 namespace Updater {
47 size_t UScriptInstructionRawImageWrite::totalSize_ = 0;
48 size_t UScriptInstructionRawImageWrite::readSize_ = 0;
49 size_t UScriptInstructionUpdateFromBin::stashDataSize_ = 0;
50 
~UpdaterEnv()51 UpdaterEnv::~UpdaterEnv()
52 {
53     if (factory_ != nullptr) {
54         delete factory_;
55         factory_ = nullptr;
56     }
57 }
58 
PostMessage(const std::string & cmd,std::string content)59 void UpdaterEnv::PostMessage(const std::string &cmd, std::string content)
60 {
61     if (postMessage_ != nullptr) {
62         std::lock_guard<std::mutex> lock(messageLock_);
63         postMessage_(cmd.c_str(), content.c_str());
64     }
65 }
66 
GetInstructionFactory()67 UScriptInstructionFactoryPtr UpdaterEnv::GetInstructionFactory()
68 {
69     if (factory_ == nullptr) {
70         factory_ = new UpdaterInstructionFactory();
71     }
72     return factory_;
73 }
74 
GetInstructionNames() const75 const std::vector<std::string> UpdaterEnv::GetInstructionNames() const
76 {
77     static std::vector<std::string> updaterCmds = {
78         "sha_check", "first_block_check", "block_update",
79         "raw_image_write", "update_partitions", "image_patch",
80         "image_sha_check", "pkg_extract", "update_from_bin"
81     };
82     return updaterCmds;
83 }
84 
CreateInstructionInstance(UScriptInstructionPtr & instr,const std::string & name)85 int32_t UpdaterInstructionFactory::CreateInstructionInstance(UScriptInstructionPtr& instr,
86     const std::string& name)
87 {
88     if (name == "sha_check") {
89         instr = new UScriptInstructionShaCheck();
90     } else if (name == "first_block_check") {
91         instr = new UScriptInstructionBlockCheck();
92     } else if (name == "block_update") {
93         instr = new UScriptInstructionBlockUpdate();
94     } else if (name == "raw_image_write") {
95         instr = new UScriptInstructionRawImageWrite();
96     } else if (name == "update_partitions") {
97         instr = new UpdatePartitions();
98     } else if (name == "image_patch") {
99         instr = new USInstrImagePatch();
100     } else if (name == "image_sha_check") {
101         instr = new USInstrImageShaCheck();
102     } else if (name == "pkg_extract") {
103         instr = new UScriptInstructionPkgExtract();
104     } else if (name == "update_from_bin") {
105         instr = new UScriptInstructionBinFlowWrite();
106     }
107     return USCRIPT_SUCCESS;
108 }
109 
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)110 int UScriptInstructionRawImageWrite::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
111                                                             bool isFinish, const void* context)
112 {
113     void *p = const_cast<void *>(context);
114     DataWriter *writer = static_cast<DataWriter *>(p);
115     if (writer == nullptr) {
116         LOG(ERROR) << "Data writer is null";
117         return PKG_INVALID_STREAM;
118     }
119 
120     // maybe extract from package is finished. just return.
121     if (buffer.buffer == nullptr || size == 0) {
122         return PKG_SUCCESS;
123     }
124 
125     bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, nullptr);
126     if (!ret) {
127         LOG(ERROR) << "Write " << size << " byte(s) failed";
128         return PKG_INVALID_STREAM;
129     }
130 
131     if (totalSize_ != 0) {
132         readSize_ += size;
133         writer->GetUpdaterEnv()->PostMessage("set_progress", std::to_string((float)readSize_ / totalSize_));
134     }
135 
136     return PKG_SUCCESS;
137 }
138 
WriteRawImage(const std::string & partitionName,const std::unique_ptr<DataWriter> & writer,uint64_t partitionSize,Uscript::UScriptEnv & env)139 bool UScriptInstructionRawImageWrite::WriteRawImage(const std::string &partitionName, const std::unique_ptr<DataWriter> &writer,
140     [[maybe_unused]] uint64_t partitionSize, Uscript::UScriptEnv &env)
141 {
142     UPDATER_INIT_RECORD;
143     // Extract partition information
144     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
145     if (info == nullptr) {
146         LOG(ERROR) << "Error to get file info";
147         UPDATER_LAST_WORD(false);
148         return false;
149     }
150     totalSize_ = info->unpackedSize;
151 #ifdef UPDATER_USE_PTABLE
152     if (partitionSize < totalSize_) {
153         LOG(ERROR) << "partition size: " << partitionSize << " is short than image size: " << totalSize_;
154         UPDATER_LAST_WORD(false);
155         return false;
156     }
157 #endif
158 
159     Hpackage::PkgManager::StreamPtr outStream = nullptr;
160     int ret = env.GetPkgManager()->CreatePkgStream(outStream,
161         partitionName, RawImageWriteProcessor, writer.get());
162     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
163         LOG(ERROR) << "Error to create output stream";
164         UPDATER_LAST_WORD(false);
165         return false;
166     }
167 
168     ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
169     if (ret != USCRIPT_SUCCESS) {
170         LOG(ERROR) << "Error to extract file";
171         env.GetPkgManager()->ClosePkgStream(outStream);
172         UPDATER_LAST_WORD(false);
173         return false;
174     }
175     env.GetPkgManager()->ClosePkgStream(outStream);
176     return true;
177 }
178 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)179 int32_t UScriptInstructionRawImageWrite::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
180 {
181     std::string partitionName;
182     int32_t ret = context.GetParam(0, partitionName);
183     if (ret != USCRIPT_SUCCESS) {
184         LOG(ERROR) << "Error to get partitionName";
185         UPDATER_LAST_WORD(ret);
186         return ret;
187     }
188 
189     if (env.IsRetry()) {
190         LOG(DEBUG) << "Retry updater, check if current partition updated already during last time";
191         bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(partitionName);
192         if (isUpdated) {
193             LOG(INFO) << partitionName << " already updated, skip";
194             return USCRIPT_SUCCESS;
195         }
196     }
197     LOG(INFO) << "UScriptInstructionRawImageWrite::Execute " << partitionName;
198     if (env.GetPkgManager() == nullptr) {
199         LOG(ERROR) << "Error to get pkg manager";
200         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
201         return USCRIPT_ERROR_EXECUTE;
202     }
203 
204     std::string writePath;
205     uint64_t offset = 0;
206     uint64_t partitionSize = 0;
207     if (GetWritePathAndOffset(partitionName, writePath, offset, partitionSize) != USCRIPT_SUCCESS) {
208         LOG(ERROR) << "Get partition:%s WritePathAndOffset fail \'" <<
209             partitionName.substr(1, partitionName.size()) << "\'.";
210         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
211         return USCRIPT_ERROR_EXECUTE;
212     }
213 
214     std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
215         static_cast<UpdaterEnv *>(&env), offset);
216     if (writer == nullptr) {
217         LOG(ERROR) << "Error to create writer";
218         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
219         return USCRIPT_ERROR_EXECUTE;
220     }
221     if (!WriteRawImage(partitionName, writer, partitionSize, env)) {
222         DataWriter::ReleaseDataWriter(writer);
223         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
224         return USCRIPT_ERROR_EXECUTE;
225     }
226     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(partitionName, true);
227     DataWriter::ReleaseDataWriter(writer);
228     totalSize_ = 0;
229     readSize_ = 0;
230     LOG(INFO) << "UScriptInstructionRawImageWrite finish";
231     return USCRIPT_SUCCESS;
232 }
233 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)234 int32_t UScriptInstructionPkgExtract::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
235 {
236     std::string pkgFileName;
237     int32_t ret = context.GetParam(0, pkgFileName);
238     if (ret != USCRIPT_SUCCESS) {
239         LOG(ERROR) << "Error to get pkgFileName";
240         UPDATER_LAST_WORD(ret);
241         return ret;
242     }
243 
244     std::string destPath;
245     ret = context.GetParam(1, destPath);
246     if (ret != USCRIPT_SUCCESS) {
247         LOG(ERROR) << "Error to get destPath";
248         UPDATER_LAST_WORD(ret);
249         return ret;
250     }
251 
252     LOG(INFO) << "UScriptInstructionPkgExtract::Execute " << pkgFileName;
253     PkgManager::PkgManagerPtr manager = env.GetPkgManager();
254     if (manager == nullptr) {
255         LOG(ERROR) << "Error to get pkg manager";
256         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
257         return USCRIPT_INVALID_PARAM;
258     }
259 
260     const FileInfo *info = manager->GetFileInfo(pkgFileName);
261     if (info == nullptr) {
262         LOG(ERROR) << "Error to get file info";
263         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
264         return USCRIPT_INVALID_PARAM;
265     }
266 
267     Hpackage::PkgManager::StreamPtr outStream = nullptr;
268     ret = manager->CreatePkgStream(outStream, destPath + "/" + pkgFileName, info->unpackedSize,
269         PkgStream::PkgStreamType_Write);
270     if (ret != USCRIPT_SUCCESS) {
271         LOG(ERROR) << "Error to create output stream";
272         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
273         return USCRIPT_ERROR_EXECUTE;
274     }
275 
276     ret = manager->ExtractFile(pkgFileName, outStream);
277     if (ret != USCRIPT_SUCCESS) {
278         LOG(ERROR) << "Error to extract file";
279         manager->ClosePkgStream(outStream);
280         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
281         return USCRIPT_ERROR_EXECUTE;
282     }
283 
284     manager->ClosePkgStream(outStream);
285     LOG(INFO)<<"UScriptInstructionPkgExtract finish";
286     return ret;
287 }
288 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)289 int32_t UScriptInstructionUpdateFromBin::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
290 {
291     std::string upgradeFileName;
292     int32_t ret = context.GetParam(0, upgradeFileName);
293     if (ret != USCRIPT_SUCCESS) {
294         LOG(ERROR) << "Error to get partitionName";
295         return ret;
296     }
297 
298     LOG(INFO) << "UScriptInstructionUpdateFromBin::Execute " << upgradeFileName;
299 
300     PkgManager::PkgManagerPtr pkgManager = env.GetPkgManager();
301     if (pkgManager == nullptr) {
302         LOG(ERROR) << "Error to get pkg manager";
303         return USCRIPT_INVALID_PARAM;
304     }
305 
306     RingBuffer ringBuffer;
307     if (!ringBuffer.Init(STASH_BUFFER_SIZE, BUFFER_NUM)) {
308         LOG(ERROR) << "Error to get ringbuffer";
309         return USCRIPT_INVALID_PARAM;
310     }
311 
312     PkgManager::StreamPtr outStream = nullptr;
313     ret = pkgManager->CreatePkgStream(outStream, upgradeFileName, UnCompressDataProducer, &ringBuffer);
314     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
315         LOG(ERROR) << "Error to create output stream";
316         return USCRIPT_INVALID_PARAM;
317     }
318 
319     ret = pkgManager->ExtractFile(upgradeFileName, outStream);
320     if (ret != USCRIPT_SUCCESS) {
321         LOG(ERROR) << "Error to extract" << upgradeFileName;
322         pkgManager->ClosePkgStream(outStream);
323         return USCRIPT_ERROR_EXECUTE;
324     }
325     pkgManager->ClosePkgStream(outStream);
326     return USCRIPT_ERROR_EXECUTE;
327 }
328 
UnCompressDataProducer(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)329 int UScriptInstructionUpdateFromBin::UnCompressDataProducer(const PkgBuffer &buffer, size_t size, size_t start,
330                                                             bool isFinish, const void* context)
331 {
332     static PkgBuffer stashBuffer(STASH_BUFFER_SIZE);
333     size_t bufferStart = 0;
334     void *p = const_cast<void *>(context);
335     RingBuffer *ringBuffer = static_cast<RingBuffer *>(p);
336     if (ringBuffer == nullptr) {
337         LOG(ERROR) << "ring buffer is nullptr";
338         return PKG_INVALID_STREAM;
339     }
340 
341     while (stashDataSize_ + size >= STASH_BUFFER_SIZE) {
342         size_t readLen = STASH_BUFFER_SIZE - stashDataSize_;
343         if (memcpy_s(stashBuffer.buffer + stashDataSize_, readLen, buffer.buffer + bufferStart, readLen) != 0) {
344                 return USCRIPT_ERROR_EXECUTE;
345         }
346         ringBuffer->Push(stashBuffer.buffer, STASH_BUFFER_SIZE);
347         stashDataSize_ = 0;
348         size -= readLen;
349         bufferStart += readLen;
350     }
351     if (size == 0 && stashDataSize_ == 0) {
352         return PKG_SUCCESS;
353     } else if (size == 0 || memcpy_s(stashBuffer.buffer + stashDataSize_, STASH_BUFFER_SIZE - stashDataSize_,
354         buffer.buffer + bufferStart, size) == 0) {
355         if (isFinish) {
356             ringBuffer->Push(stashBuffer.buffer, stashDataSize_ + size);
357             stashDataSize_ = 0;
358         } else {
359             stashDataSize_ += size;
360         }
361         return PKG_SUCCESS;
362     } else {
363         return USCRIPT_ERROR_EXECUTE;
364     }
365 }
366 
ExecUpdate(PkgManager::PkgManagerPtr pkgManager,int retry,const std::string & pkgPath,PostMessageFunction postMessage)367 int ExecUpdate(PkgManager::PkgManagerPtr pkgManager, int retry, const std::string &pkgPath,
368     PostMessageFunction postMessage)
369 {
370     Hpackage::HashDataVerifier scriptVerifier {pkgManager};
371     if (!scriptVerifier.LoadHashDataAndPkcs7(pkgPath)) {
372         LOG(ERROR) << "Fail to load hash data";
373         UPDATER_LAST_WORD(EXIT_VERIFY_SCRIPT_ERROR);
374         return EXIT_VERIFY_SCRIPT_ERROR;
375     }
376     UpdaterEnv* env = new (std::nothrow) UpdaterEnv(pkgManager, postMessage, retry);
377     if (env == nullptr) {
378         LOG(ERROR) << "Fail to creat env";
379         UPDATER_LAST_WORD(EXIT_PARSE_SCRIPT_ERROR);
380         return EXIT_PARSE_SCRIPT_ERROR;
381     }
382     int ret = 0;
383     ScriptManager* scriptManager = ScriptManager::GetScriptManager(env, &scriptVerifier);
384     if (scriptManager == nullptr) {
385         LOG(ERROR) << "Fail to creat scriptManager";
386         ScriptManager::ReleaseScriptManager();
387         delete env;
388         UPDATER_LAST_WORD(EXIT_PARSE_SCRIPT_ERROR);
389         return EXIT_PARSE_SCRIPT_ERROR;
390     }
391 
392     UpdaterInit::GetInstance().InvokeEvent(UPDATER_BINARY_INIT_DONE_EVENT);
393 
394     pthread_t thread;
395     ret = CreateProgressThread(env, thread);
396     if (ret != 0) {
397         LOG(ERROR) << "Fail to create progress thread";
398         ScriptManager::ReleaseScriptManager();
399         delete env;
400         env = nullptr;
401         UPDATER_LAST_WORD(USCRIPT_ERROR_CREATE_THREAD);
402         return USCRIPT_ERROR_CREATE_THREAD;
403     }
404 
405     for (int32_t i = 0; i < ScriptManager::MAX_PRIORITY; i++) {
406         ret = scriptManager->ExecuteScript(i);
407         if (ret != USCRIPT_SUCCESS) {
408             LOG(ERROR) << "Fail to execute script";
409             UPDATER_LAST_WORD(ret);
410             break;
411         }
412     }
413     SetProgressExitFlag(thread);
414     ScriptManager::ReleaseScriptManager();
415     delete env;
416     env = nullptr;
417     return ret;
418 }
419 
GetWritePathAndOffset(const std::string & partitionName,std::string & writePath,uint64_t & offset,uint64_t & partitionSize)420 int UScriptInstructionRawImageWrite::GetWritePathAndOffset(const std::string &partitionName, std::string &writePath,
421     uint64_t &offset, uint64_t &partitionSize)
422 {
423 #ifdef UPDATER_USE_PTABLE
424     DevicePtable& devicePtb = DevicePtable::GetInstance();
425     Ptable::PtnInfo ptnInfo;
426     if (!devicePtb.GetPartionInfoByName(partitionName, ptnInfo)) {
427         LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
428                 partitionName.substr(1, partitionName.size()) << "\'.";
429         return USCRIPT_ERROR_EXECUTE;
430     }
431     char lunIndexName = 'a' + ptnInfo.lun;
432     writePath = std::string(PREFIX_UFS_NODE) + lunIndexName;
433     offset = ptnInfo.startAddr;
434     partitionSize = ptnInfo.partitionSize;
435 #else
436     writePath = GetBlockDeviceByMountPoint(partitionName);
437     if (writePath.empty()) {
438         LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
439             partitionName.substr(1, partitionName.size()) << "\'.";
440         return USCRIPT_ERROR_EXECUTE;
441     }
442 
443 #ifndef UPDATER_UT
444     if (partitionName != "/userdata") {
445         std::string suffix = "";
446         GetPartitionSuffix(suffix);
447         writePath += suffix;
448     }
449     LOG(INFO) << "write partition path: " << writePath;
450 #endif
451 #endif
452     return USCRIPT_SUCCESS;
453 }
454 
ProcessUpdater(bool retry,int pipeFd,const std::string & packagePath,const std::string & keyPath)455 int ProcessUpdater(bool retry, int pipeFd, const std::string &packagePath, const std::string &keyPath)
456 {
457     UPDATER_INIT_RECORD;
458     UpdaterInit::GetInstance().InvokeEvent(UPDATER_BINARY_INIT_EVENT);
459     Dump::GetInstance().RegisterDump("DumpHelperLog", std::make_unique<DumpHelperLog>());
460     FILE *pipeWrite = fdopen(pipeFd, "w");
461     if (pipeWrite == nullptr) {
462         LOG(ERROR) << "Fail to fdopen";
463         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
464         return EXIT_INVALID_ARGS;
465     }
466     // line buffered, make sure parent read per line.
467     setlinebuf(pipeWrite);
468     PkgManager::PkgManagerPtr pkgManager = PkgManager::CreatePackageInstance();
469     if (pkgManager == nullptr) {
470         LOG(ERROR) << "pkgManager is nullptr";
471         fclose(pipeWrite);
472         pipeWrite = nullptr;
473         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
474         return EXIT_INVALID_ARGS;
475     }
476 
477     std::vector<std::string> components;
478     int32_t ret = pkgManager->LoadPackage(packagePath, keyPath, components);
479     if (ret != PKG_SUCCESS) {
480         LOG(ERROR) << "Fail to load package";
481         fclose(pipeWrite);
482         pipeWrite = nullptr;
483         PkgManager::ReleasePackageInstance(pkgManager);
484         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
485         return EXIT_INVALID_ARGS;
486     }
487 #ifdef UPDATER_USE_PTABLE
488     DevicePtable& devicePtb = DevicePtable::GetInstance();
489     devicePtb.LoadPartitionInfo();
490 #endif
491 
492     ret = Updater::ExecUpdate(pkgManager, retry, packagePath,
493         [&pipeWrite](const char *cmd, const char *content) {
494             if (pipeWrite != nullptr) {
495                 fprintf(pipeWrite, "%s:%s\n", cmd, content);
496                 fflush(pipeWrite);
497             }
498         });
499     PkgManager::ReleasePackageInstance(pkgManager);
500 #ifndef UPDATER_UT
501     fclose(pipeWrite);
502     pipeWrite = nullptr;
503     if (ret == 0) {
504         SetActiveSlot();
505     }
506 #endif
507     return ret;
508 }
509 } // Updater