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 "log.h"
23 #include "pkg_manager.h"
24 #include "script_instruction.h"
25 #include "script_manager.h"
26 #include "update_image_block.h"
27 #include "update_partitions.h"
28
29 using namespace uscript;
30 using namespace hpackage;
31 using namespace updater;
32
33 namespace updater {
34 size_t UScriptInstructionRawImageWrite::totalSize_ = 0;
35 size_t UScriptInstructionRawImageWrite::readSize_ = 0;
~UpdaterEnv()36 UpdaterEnv::~UpdaterEnv()
37 {
38 if (factory_ != nullptr) {
39 delete factory_;
40 factory_ = nullptr;
41 }
42 }
43
PostMessage(const std::string & cmd,std::string content)44 void UpdaterEnv::PostMessage(const std::string &cmd, std::string content)
45 {
46 if (postMessage_ != nullptr) {
47 postMessage_(cmd.c_str(), content.c_str());
48 }
49 }
50
GetInstructionFactory()51 UScriptInstructionFactoryPtr UpdaterEnv::GetInstructionFactory()
52 {
53 if (factory_ == nullptr) {
54 factory_ = new UpdaterInstructionFactory();
55 }
56 return factory_;
57 }
58
GetInstructionNames() const59 const std::vector<std::string> UpdaterEnv::GetInstructionNames() const
60 {
61 static std::vector<std::string> updaterCmds = {
62 "sparse_image_write", "sha_check", "first_block_check", "block_update",
63 "raw_image_write", "update_partitions"
64 };
65 return updaterCmds;
66 }
67
CreateInstructionInstance(UScriptInstructionPtr & instr,const std::string & name)68 int32_t UpdaterInstructionFactory::CreateInstructionInstance(UScriptInstructionPtr& instr,
69 const std::string& name)
70 {
71 if (name == "sparse_image_write") {
72 instr = new UScriptInstructionSparseImageWrite();
73 } else if (name == "sha_check") {
74 instr = new UScriptInstructionShaCheck();
75 } else if (name == "first_block_check") {
76 instr = new UScriptInstructionBlockCheck();
77 } else if (name == "block_update") {
78 instr = new UScriptInstructionBlockUpdate();
79 } else if (name == "raw_image_write") {
80 instr = new UScriptInstructionRawImageWrite();
81 } else if (name == "update_partitions") {
82 instr = new UpdatePartitions();
83 }
84 return USCRIPT_SUCCESS;
85 }
86
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)87 int UScriptInstructionRawImageWrite::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
88 bool isFinish, const void* context)
89 {
90 void *p = const_cast<void *>(context);
91 DataWriter *writer = static_cast<DataWriter *>(p);
92 if (writer == nullptr) {
93 LOG(ERROR) << "Data writer is null";
94 return PKG_INVALID_STREAM;
95 }
96
97 // maybe extract from package is finished. just return.
98 if (buffer.buffer == nullptr || size == 0) {
99 return PKG_SUCCESS;
100 }
101
102 bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, WRITE_RAW, "");
103 if (!ret) {
104 LOG(ERROR) << "Write " << size << " byte(s) failed";
105 return PKG_INVALID_STREAM;
106 }
107
108 if (totalSize_ != 0) {
109 readSize_ += size;
110 writer->GetUpdaterEnv()->PostMessage("set_progress", std::to_string((float)readSize_ / totalSize_));
111 writer->GetUpdaterEnv()->PostMessage("data", std::to_string(size));
112 }
113
114 return PKG_SUCCESS;
115 }
116
Execute(uscript::UScriptEnv & env,uscript::UScriptContext & context)117 int32_t UScriptInstructionRawImageWrite::Execute(uscript::UScriptEnv &env, uscript::UScriptContext &context)
118 {
119 std::string partitionName;
120 int32_t ret = context.GetParam(0, partitionName);
121 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to get partitionName", return ret);
122 std::string imageFilename;
123 ret = context.GetParam(1, imageFilename);
124 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to get imageFilename", return ret);
125
126 if (env.IsRetry()) {
127 LOG(DEBUG) << "Retry updater, check if current partition updated already during last time";
128 bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(partitionName);
129 if (isUpdated) {
130 LOG(INFO) << partitionName << " already updated, skip";
131 return USCRIPT_SUCCESS;
132 }
133 }
134 LOG(INFO) << "UScriptInstructionRawImageWrite::Execute " << partitionName;
135 UPDATER_ERROR_CHECK(env.GetPkgManager() != nullptr, "Error to get pkg manager", return USCRIPT_ERROR_EXECUTE);
136
137 std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, partitionName,
138 static_cast<UpdaterEnv *>(&env));
139 UPDATER_ERROR_CHECK(writer != nullptr, "Error to create writer", return USCRIPT_ERROR_EXECUTE);
140
141 // Extract partition information
142 hpackage::PkgManager::StreamPtr outStream = nullptr;
143 const FileInfo *info = env.GetPkgManager()->GetFileInfo(imageFilename);
144 UPDATER_ERROR_CHECK(info != nullptr, "Error to get file info",
145 DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
146 totalSize_ = info->unpackedSize;
147 ret = env.GetPkgManager()->CreatePkgStream(outStream,
148 imageFilename, RawImageWriteProcessor, writer.get());
149 UPDATER_ERROR_CHECK(outStream != nullptr, "Error to create output stream",
150 DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
151
152 ret = env.GetPkgManager()->ExtractFile(imageFilename, outStream);
153 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to extract file",
154 env.GetPkgManager()->ClosePkgStream(outStream);
155 DataWriter::ReleaseDataWriter(writer); return USCRIPT_ERROR_EXECUTE);
156
157 PartitionRecord::GetInstance().RecordPartitionUpdateStatus(partitionName, true);
158 ret = USCRIPT_SUCCESS;
159 env.GetPkgManager()->ClosePkgStream(outStream);
160 DataWriter::ReleaseDataWriter(writer);
161 totalSize_ = 0;
162 readSize_ = 0;
163 LOG(INFO)<<"UScriptInstructionRawImageWrite finish";
164 return ret;
165 }
166
Execute(uscript::UScriptEnv & env,uscript::UScriptContext & context)167 int32_t UScriptInstructionSparseImageWrite::Execute(uscript::UScriptEnv &env, uscript::UScriptContext &context)
168 {
169 std::string partitionName;
170 int32_t ret = context.GetParam(0, partitionName);
171 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to get param", return ret);
172
173 if (env.IsRetry()) {
174 LOG(DEBUG) << "Retry updater, check if current partition updated already during last time.";
175 bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(partitionName);
176 if (isUpdated) {
177 LOG(INFO) << partitionName << " already updated, skip";
178 return USCRIPT_SUCCESS;
179 }
180 }
181 LOG(INFO) << "UScriptInstructionSparseImageWrite::Execute " << partitionName;
182 UPDATER_ERROR_CHECK(env.GetPkgManager() != nullptr, "Error to get pkg manager", return USCRIPT_ERROR_EXECUTE);
183
184 hpackage::PkgManager::StreamPtr outStream = nullptr;
185 const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
186 UPDATER_ERROR_CHECK(info != nullptr, "Error to get file info", return USCRIPT_ERROR_EXECUTE);
187
188 ret = env.GetPkgManager()->CreatePkgStream(outStream,
189 partitionName, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
190 UPDATER_ERROR_CHECK(outStream != nullptr, "Error to create output stream", return USCRIPT_ERROR_EXECUTE);
191
192 ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
193 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to extract file",
194 env.GetPkgManager()->ClosePkgStream(outStream); return USCRIPT_ERROR_EXECUTE);
195 std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_SPARSE, partitionName);
196 UPDATER_ERROR_CHECK(writer != nullptr, "Error to create writer",
197 env.GetPkgManager()->ClosePkgStream(outStream); return USCRIPT_ERROR_EXECUTE);
198
199 size_t size = 0;
200 uint8_t* buffer = nullptr;
201 outStream->GetBuffer(buffer, size);
202
203 ret = writer->Write(buffer, size, WRITE_SPARSE, partitionName);
204 if (ret != true) {
205 LOG(ERROR) << "writer " << partitionName.substr(1, partitionName.size()) << " failed ";
206 ret = USCRIPT_ERROR_EXECUTE;
207 } else {
208 PartitionRecord::GetInstance().RecordPartitionUpdateStatus(partitionName, true);
209 ret = USCRIPT_SUCCESS;
210 }
211
212 env.GetPkgManager()->ClosePkgStream(outStream);
213 DataWriter::ReleaseDataWriter(writer);
214 return ret;
215 }
216
ExecUpdate(PkgManager::PkgManagerPtr pkgManager,int retry,PostMessageFunction postMessage)217 int ExecUpdate(PkgManager::PkgManagerPtr pkgManager, int retry, PostMessageFunction postMessage)
218 {
219 UpdaterEnv* env = new UpdaterEnv(pkgManager, postMessage, retry);
220 UPDATER_ERROR_CHECK(env != nullptr, "Fail to create env", return EXIT_PARSE_SCRIPT_ERROR);
221 int ret = 0;
222 ScriptManager* scriptManager = ScriptManager::GetScriptManager(env);
223 UPDATER_ERROR_CHECK(scriptManager != nullptr, "Fail to create scriptManager",
224 ScriptManager::ReleaseScriptManager();
225 delete env;
226 return EXIT_PARSE_SCRIPT_ERROR);
227 for (int32_t i = 0; i < ScriptManager::MAX_PRIORITY; i++) {
228 ret = scriptManager->ExecuteScript(i);
229 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Fail to execute script", break);
230 }
231 ScriptManager::ReleaseScriptManager();
232 delete env;
233 return ret;
234 }
235 } // updater
236
ProcessUpdater(bool retry,int pipeFd,const std::string & packagePath,const std::string & keyPath)237 int ProcessUpdater(bool retry, int pipeFd, const std::string &packagePath, const std::string &keyPath)
238 {
239 FILE *pipeWrite = fdopen(pipeFd, "w");
240 UPDATER_ERROR_CHECK(pipeWrite != nullptr, "Fail to fdopen", return EXIT_INVALID_ARGS);
241 // line buffered, make sure parent read per line.
242 setlinebuf(pipeWrite);
243 PkgManager::PkgManagerPtr pkgManager = PkgManager::GetPackageInstance();
244 UPDATER_ERROR_CHECK(pkgManager != nullptr,
245 "Fail to GetPackageInstance", fclose(pipeWrite); pipeWrite = nullptr; return EXIT_INVALID_ARGS);
246
247 std::vector<std::string> components;
248 int32_t ret = pkgManager->LoadPackage(packagePath, keyPath, components);
249 UPDATER_ERROR_CHECK(ret == PKG_SUCCESS, "Fail to load package",
250 PkgManager::ReleasePackageInstance(pkgManager);
251 return EXIT_INVALID_ARGS);
252
253 ret = updater::ExecUpdate(pkgManager, retry,
254 [&pipeWrite](const char *cmd, const char *content) {
255 if (pipeWrite != nullptr) {
256 fprintf(pipeWrite, "%s:%s\n", cmd, content);
257 }
258 });
259 PkgManager::ReleasePackageInstance(pkgManager);
260 #ifndef UPDATER_UT
261 fclose(pipeWrite);
262 pipeWrite = nullptr;
263 #endif
264 return ret;
265 }
266