• 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 "applypatch/data_writer.h"
21 #include "applypatch/partition_record.h"
22 #include "dump.h"
23 #include "log.h"
24 #include "pkg_manager.h"
25 #ifdef UPDATER_USE_PTABLE
26 #include "ptable_manager.h"
27 #endif
28 #include "script_instruction.h"
29 #include "script_manager.h"
30 #include "slot_info/slot_info.h"
31 #include "update_image_block.h"
32 #include "update_image_patch.h"
33 #include "update_partitions.h"
34 #include "updater_main.h"
35 #include "updater/updater_const.h"
36 
37 using namespace Uscript;
38 using namespace Hpackage;
39 using namespace Updater;
40 
41 namespace Updater {
42 size_t UScriptInstructionRawImageWrite::totalSize_ = 0;
43 size_t UScriptInstructionRawImageWrite::readSize_ = 0;
44 
~UpdaterEnv()45 UpdaterEnv::~UpdaterEnv()
46 {
47     if (factory_ != nullptr) {
48         delete factory_;
49         factory_ = nullptr;
50     }
51 }
52 
PostMessage(const std::string & cmd,std::string content)53 void UpdaterEnv::PostMessage(const std::string &cmd, std::string content)
54 {
55     if (postMessage_ != nullptr) {
56         postMessage_(cmd.c_str(), content.c_str());
57     }
58 }
59 
GetInstructionFactory()60 UScriptInstructionFactoryPtr UpdaterEnv::GetInstructionFactory()
61 {
62     if (factory_ == nullptr) {
63         factory_ = new UpdaterInstructionFactory();
64     }
65     return factory_;
66 }
67 
GetInstructionNames() const68 const std::vector<std::string> UpdaterEnv::GetInstructionNames() const
69 {
70     static std::vector<std::string> updaterCmds = {
71         "sha_check", "first_block_check", "block_update",
72         "raw_image_write", "update_partitions", "image_patch",
73         "image_sha_check"
74     };
75     return updaterCmds;
76 }
77 
CreateInstructionInstance(UScriptInstructionPtr & instr,const std::string & name)78 int32_t UpdaterInstructionFactory::CreateInstructionInstance(UScriptInstructionPtr& instr,
79     const std::string& name)
80 {
81     if (name == "sha_check") {
82         instr = new UScriptInstructionShaCheck();
83     } else if (name == "first_block_check") {
84         instr = new UScriptInstructionBlockCheck();
85     } else if (name == "block_update") {
86         instr = new UScriptInstructionBlockUpdate();
87     } else if (name == "raw_image_write") {
88         instr = new UScriptInstructionRawImageWrite();
89     } else if (name == "update_partitions") {
90         instr = new UpdatePartitions();
91     } else if (name == "image_patch") {
92         instr = new USInstrImagePatch();
93     }  else if (name == "image_sha_check") {
94         instr = new USInstrImageShaCheck();
95     }
96     return USCRIPT_SUCCESS;
97 }
98 
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)99 int UScriptInstructionRawImageWrite::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
100                                                             bool isFinish, const void* context)
101 {
102     void *p = const_cast<void *>(context);
103     DataWriter *writer = static_cast<DataWriter *>(p);
104     if (writer == nullptr) {
105         LOG(ERROR) << "Data writer is null";
106         return PKG_INVALID_STREAM;
107     }
108 
109     // maybe extract from package is finished. just return.
110     if (buffer.buffer == nullptr || size == 0) {
111         return PKG_SUCCESS;
112     }
113 
114     bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, nullptr);
115     if (!ret) {
116         LOG(ERROR) << "Write " << size << " byte(s) failed";
117         return PKG_INVALID_STREAM;
118     }
119 
120     if (totalSize_ != 0) {
121         readSize_ += size;
122         writer->GetUpdaterEnv()->PostMessage("set_progress", std::to_string((float)readSize_ / totalSize_));
123     }
124 
125     return PKG_SUCCESS;
126 }
127 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)128 int32_t UScriptInstructionRawImageWrite::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
129 {
130     std::string partitionName;
131     int32_t ret = context.GetParam(0, partitionName);
132     UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to get partitionName", return ret);
133 
134     if (env.IsRetry()) {
135         LOG(DEBUG) << "Retry updater, check if current partition updated already during last time";
136         bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(partitionName);
137         if (isUpdated) {
138             LOG(INFO) << partitionName << " already updated, skip";
139             return USCRIPT_SUCCESS;
140         }
141     }
142     LOG(INFO) << "UScriptInstructionRawImageWrite::Execute " << partitionName;
143     UPDATER_ERROR_CHECK(env.GetPkgManager() != nullptr, "Error to get pkg manager", return USCRIPT_ERROR_EXECUTE);
144 
145     std::string writePath;
146     uint64_t offset = 0;
147     uint64_t partitionSize = 0;
148     if (GetWritePathAndOffset(partitionName, writePath, offset, partitionSize) != USCRIPT_SUCCESS) {
149         LOG(ERROR) << "Get partition:%s WritePathAndOffset fail \'" <<
150             partitionName.substr(1, partitionName.size()) << "\'.";
151         return USCRIPT_ERROR_EXECUTE;
152     }
153 
154     std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
155         static_cast<UpdaterEnv *>(&env), offset);
156     UPDATER_ERROR_CHECK(writer != nullptr, "Error to create writer", return USCRIPT_ERROR_EXECUTE);
157 
158     // Extract partition information
159     Hpackage::PkgManager::StreamPtr outStream = nullptr;
160     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
161     UPDATER_ERROR_CHECK(info != nullptr, "Error to get file info",
162         DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
163     totalSize_ = info->unpackedSize;
164 #ifdef UPDATER_USE_PTABLE
165     UPDATER_ERROR_CHECK(partitionSize >= totalSize_,
166         "partition size: " << partitionSize << " is short than image size: " << totalSize_,
167         DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
168 #endif
169 
170     ret = env.GetPkgManager()->CreatePkgStream(outStream,
171         partitionName, RawImageWriteProcessor, writer.get());
172     UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS && outStream != nullptr, "Error to create output stream",
173         DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
174 
175     ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
176     UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to extract file",
177         env.GetPkgManager()->ClosePkgStream(outStream);
178         DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
179 
180     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(partitionName, true);
181     ret = USCRIPT_SUCCESS;
182     env.GetPkgManager()->ClosePkgStream(outStream);
183     DataWriter::ReleaseDataWriter(writer);
184     totalSize_ = 0;
185     readSize_ = 0;
186     LOG(INFO)<<"UScriptInstructionRawImageWrite  finish";
187     return ret;
188 }
189 
ExecUpdate(PkgManager::PkgManagerPtr pkgManager,int retry,PostMessageFunction postMessage)190 int ExecUpdate(PkgManager::PkgManagerPtr pkgManager, int retry, PostMessageFunction postMessage)
191 {
192     UpdaterEnv* env = new UpdaterEnv(pkgManager, postMessage, retry);
193     if (env == nullptr) {
194         LOG(ERROR) << "Fail to creat env";
195         UPDATER_LAST_WORD(EXIT_PARSE_SCRIPT_ERROR);
196         return EXIT_PARSE_SCRIPT_ERROR;
197     }
198     int ret = 0;
199     ScriptManager* scriptManager = ScriptManager::GetScriptManager(env);
200     if (scriptManager == nullptr) {
201         LOG(ERROR) << "Fail to creat scriptManager";
202         ScriptManager::ReleaseScriptManager();
203         delete env;
204         UPDATER_LAST_WORD(EXIT_PARSE_SCRIPT_ERROR);
205         return EXIT_PARSE_SCRIPT_ERROR;
206     }
207 
208     UpdaterInit::GetInstance().InvokeEvent(UPDATER_BINARY_INIT_DONE_EVENT);
209 
210     for (int32_t i = 0; i < ScriptManager::MAX_PRIORITY; i++) {
211         ret = scriptManager->ExecuteScript(i);
212         if (ret != USCRIPT_SUCCESS) {
213             LOG(ERROR) << "Fail to execute script";
214             UPDATER_LAST_WORD(ret);
215             break;
216         }
217     }
218     ScriptManager::ReleaseScriptManager();
219     delete env;
220     return ret;
221 }
222 
GetWritePathAndOffset(const std::string & partitionName,std::string & writePath,uint64_t & offset,uint64_t & partitionSize)223 int UScriptInstructionRawImageWrite::GetWritePathAndOffset(const std::string &partitionName, std::string &writePath,
224     uint64_t &offset, uint64_t &partitionSize)
225 {
226 #ifdef UPDATER_USE_PTABLE
227     PackagePtable& packagePtb = PackagePtable::GetInstance();
228     Ptable::PtnInfo ptnInfo;
229     if (!packagePtb.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 #endif
254 #endif
255     return USCRIPT_SUCCESS;
256 }
257 
ProcessUpdater(bool retry,int pipeFd,const std::string & packagePath,const std::string & keyPath)258 int ProcessUpdater(bool retry, int pipeFd, const std::string &packagePath, const std::string &keyPath)
259 {
260     UPDATER_INIT_RECORD;
261     UpdaterInit::GetInstance().InvokeEvent(UPDATER_BINARY_INIT_EVENT);
262     Dump::GetInstance().RegisterDump("DumpHelperLog", std::make_unique<DumpHelperLog>());
263     FILE *pipeWrite = fdopen(pipeFd, "w");
264     if (pipeWrite == nullptr) {
265         LOG(ERROR) << "Fail to fdopen";
266         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
267         return EXIT_INVALID_ARGS;
268     }
269     // line buffered, make sure parent read per line.
270     setlinebuf(pipeWrite);
271     PkgManager::PkgManagerPtr pkgManager = PkgManager::GetPackageInstance();
272     if (pkgManager == nullptr) {
273         LOG(ERROR) << "Fail to GetPackageInstance";
274         fclose(pipeWrite);
275         pipeWrite = nullptr;
276         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
277         return EXIT_INVALID_ARGS;
278     }
279 
280     std::vector<std::string> components;
281     int32_t ret = pkgManager->LoadPackage(packagePath, keyPath, components);
282     if (ret != PKG_SUCCESS) {
283         LOG(ERROR) << "Fail to load package";
284         fclose(pipeWrite);
285         pipeWrite = nullptr;
286         PkgManager::ReleasePackageInstance(pkgManager);
287         UPDATER_LAST_WORD(EXIT_INVALID_ARGS);
288         return EXIT_INVALID_ARGS;
289     }
290 #ifdef UPDATER_USE_PTABLE
291     PackagePtable& packagePtb = PackagePtable::GetInstance();
292     packagePtb.LoadPartitionInfo(pkgManager);
293 #endif
294 
295     ret = Updater::ExecUpdate(pkgManager, retry,
296         [&pipeWrite](const char *cmd, const char *content) {
297             if (pipeWrite != nullptr) {
298                 fprintf(pipeWrite, "%s:%s\n", cmd, content);
299             }
300         });
301     PkgManager::ReleasePackageInstance(pkgManager);
302 #ifndef UPDATER_UT
303     fclose(pipeWrite);
304     pipeWrite = nullptr;
305     if (ret == 0) {
306         SetActiveSlot();
307     }
308 #endif
309     return ret;
310 }
311 } // Updater