• 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 "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