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