1 /*
2 * Copyright (c) 2023 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
16 #include "bin_process.h"
17 #include <string>
18 #include <thread>
19 #include "applypatch/partition_record.h"
20 #include "log.h"
21 #include "pkg_manager_impl.h"
22 #include "pkg_package/pkg_pkgfile.h"
23 #include "pkg_utils.h"
24 #include "ring_buffer/ring_buffer.h"
25 #include "script_manager.h"
26 #include "threadpool/thread_pool.h"
27 #include "scope_guard.h"
28 #include "securec.h"
29 #include "updater/updater_const.h"
30
31 using namespace std;
32 using namespace Hpackage;
33 using namespace Uscript;
34 using namespace Updater::Utils;
35
36 namespace Updater {
37 constexpr uint32_t STASH_BUFFER_SIZE = 4 * 1024 * 1024;
38 constexpr uint32_t MAX_BUFFER_NUM = 16;
39 constexpr uint8_t ES_IMAGE = 6;
40 constexpr uint8_t CS_IMAGE = 7;
41 constexpr uint8_t NEED_VERIFY_CS_IMAGE = 8;
42
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)43 int32_t UScriptInstructionBinFlowWrite::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
44 {
45 std::string upgradeFileName;
46 int32_t ret = context.GetParam(0, upgradeFileName);
47 if (ret != USCRIPT_SUCCESS) {
48 LOG(ERROR) << "Error to get bin file";
49 return ret;
50 }
51
52 LOG(INFO) << "UScriptInstructionUpdateFromZip::Execute " << upgradeFileName;
53 PkgManager::PkgManagerPtr pkgManager = env.GetPkgManager();
54 if (pkgManager == nullptr) {
55 LOG(ERROR) << "Error to get pkg manager";
56 return USCRIPT_INVALID_PARAM;
57 }
58
59 RingBuffer ringBuffer;
60 if (!ringBuffer.Init(STASH_BUFFER_SIZE, MAX_BUFFER_NUM)) {
61 LOG(ERROR) << "Error to get ringbuffer";
62 return USCRIPT_INVALID_PARAM;
63 }
64
65 fullUpdateProportion_ = GetScriptProportion();
66 stashBuffer_.data.resize(STASH_BUFFER_SIZE);
67 stashBuffer_.buffer = stashBuffer_.data.data();
68 PkgManager::StreamPtr binFlowStream = nullptr;
69 const FileInfo *info = pkgManager->GetFileInfo(upgradeFileName);
70 if (info == nullptr) {
71 LOG(ERROR) << "Get file info fail " << upgradeFileName;
72 return PKG_INVALID_FILE;
73 }
74 ret = pkgManager->CreatePkgStream(binFlowStream, upgradeFileName, info->unpackedSize, &ringBuffer);
75 if (ret != USCRIPT_SUCCESS || binFlowStream == nullptr) {
76 LOG(ERROR) << "Error to create output stream";
77 return USCRIPT_INVALID_PARAM;
78 }
79
80 std::thread consumer([this, &env, &context, binFlowStream] {
81 this->ProcessBinFile(env, context, binFlowStream);
82 });
83 std::thread producer([this, &env, &context, binFlowStream] {
84 this->ExtractBinFile(env, context, binFlowStream);
85 });
86 consumer.join();
87 producer.join();
88 if (isStopRun_) {
89 LOG(ERROR) << "Error to Execute bin file update";
90 env.PostMessage(UPDATER_RETRY_TAG, PROCESS_BIN_FAIL_RETRY);
91 return USCRIPT_ERROR_EXECUTE;
92 }
93 return USCRIPT_SUCCESS;
94 }
95
ExtractBinFile(Uscript::UScriptEnv & env,Uscript::UScriptContext & context,PkgManager::StreamPtr stream)96 int32_t UScriptInstructionBinFlowWrite::ExtractBinFile(Uscript::UScriptEnv &env, Uscript::UScriptContext &context,
97 PkgManager::StreamPtr stream)
98 {
99 ON_SCOPE_EXIT(failExecute) {
100 isStopRun_ = true;
101 stream->Stop();
102 };
103 std::string upgradeFileName;
104 int32_t ret = context.GetParam(0, upgradeFileName);
105 if (ret != USCRIPT_SUCCESS) {
106 LOG(ERROR) << "Error to get bin file";
107 return ret;
108 }
109
110 LOG(INFO) << "UScriptInstructionBinFlowWrite::ExtractBinFile " << upgradeFileName;
111 PkgManager::PkgManagerPtr pkgManager = env.GetPkgManager();
112 if (pkgManager == nullptr) {
113 LOG(ERROR) << "Error to get pkg manager";
114 return USCRIPT_INVALID_PARAM;
115 }
116
117 PkgManager::StreamPtr processStream = nullptr;
118 PkgStream::ExtractFileProcessor processor =
119 [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
120 return this->UnCompressDataProducer(buffer, size, start, isFinish, context);
121 };
122 ret = pkgManager->CreatePkgStream(processStream, upgradeFileName, processor, stream);
123 if (ret != USCRIPT_SUCCESS || processStream == nullptr) {
124 LOG(ERROR) << "Error to create output stream";
125 return USCRIPT_INVALID_PARAM;
126 }
127
128 ret = pkgManager->ExtractFile(upgradeFileName, processStream);
129 if (ret != USCRIPT_SUCCESS) {
130 LOG(ERROR) << "Error to extract" << upgradeFileName;
131 pkgManager->ClosePkgStream(processStream);
132 return USCRIPT_ERROR_EXECUTE;
133 }
134 pkgManager->ClosePkgStream(processStream);
135 CANCEL_SCOPE_EXIT_GUARD(failExecute);
136 return USCRIPT_SUCCESS;
137 }
138
UnCompressDataProducer(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)139 int32_t UScriptInstructionBinFlowWrite::UnCompressDataProducer(const PkgBuffer &buffer, size_t size, size_t start,
140 bool isFinish, const void *context)
141 {
142 if (isStopRun_) {
143 LOG(ERROR) << "recive stop single, UnCompressDataProducer stop run";
144 return USCRIPT_ERROR_EXECUTE;
145 }
146
147 void *p = const_cast<void *>(context);
148 PkgStream *flowStream = static_cast<PkgStream *>(p);
149 if (flowStream == nullptr) {
150 LOG(ERROR) << "ring buffer is nullptr";
151 return PKG_INVALID_STREAM;
152 }
153
154 if (buffer.buffer == nullptr && size == 0 && isFinish) {
155 // 最后一块数据
156 if (stashDataSize_ != 0) {
157 size_t writeOffset = flowStream->GetFileLength() - stashDataSize_;
158 if (flowStream->Write(stashBuffer_, stashDataSize_, writeOffset) != USCRIPT_SUCCESS) {
159 LOG(ERROR) << "UnCompress flowStream write fail";
160 return USCRIPT_ERROR_EXECUTE;
161 }
162 stashDataSize_ = 0;
163 }
164 LOG(INFO) << "extract finished, start";
165 return USCRIPT_SUCCESS;
166 }
167
168 if (buffer.buffer == nullptr || size == 0 || start < stashDataSize_) {
169 LOG(ERROR) << "invalid para, size: " << size << "start: " << start;
170 return USCRIPT_ERROR_EXECUTE;
171 }
172
173 size_t writeSize = 0;
174 size_t copyLen = 0;
175 // 缓存4M再写入数据流
176 while (size - writeSize > STASH_BUFFER_SIZE - stashDataSize_) {
177 copyLen = STASH_BUFFER_SIZE - stashDataSize_;
178 if (memcpy_s(stashBuffer_.buffer + stashDataSize_, copyLen, buffer.buffer + writeSize, copyLen) != EOK) {
179 return USCRIPT_ERROR_EXECUTE;
180 }
181
182 if (flowStream->Write(stashBuffer_, STASH_BUFFER_SIZE, start - stashDataSize_) != USCRIPT_SUCCESS) {
183 LOG(ERROR) << "UnCompress flowStream write fail";
184 return USCRIPT_ERROR_EXECUTE;
185 }
186 writeSize += copyLen;
187 stashDataSize_ = 0;
188 }
189
190 copyLen = size - writeSize;
191 if (memcpy_s(stashBuffer_.buffer + stashDataSize_, copyLen, buffer.buffer + writeSize, copyLen) != EOK) {
192 return USCRIPT_ERROR_EXECUTE;
193 }
194 stashDataSize_ += copyLen;
195 if (stashDataSize_ == STASH_BUFFER_SIZE) {
196 if (flowStream->Write(stashBuffer_, stashDataSize_, start - stashDataSize_ + copyLen) != USCRIPT_SUCCESS) {
197 LOG(ERROR) << "UnCompress flowStream write fail";
198 return USCRIPT_ERROR_EXECUTE;
199 }
200 stashDataSize_ = 0;
201 }
202 return PKG_SUCCESS;
203 }
204
ProcessBinFile(Uscript::UScriptEnv & env,Uscript::UScriptContext & context,PkgManager::StreamPtr stream)205 int32_t UScriptInstructionBinFlowWrite::ProcessBinFile(Uscript::UScriptEnv &env, Uscript::UScriptContext &context,
206 PkgManager::StreamPtr stream)
207 {
208 if (stream == nullptr) {
209 LOG(ERROR) << "Error to get file stream";
210 return USCRIPT_ERROR_EXECUTE;
211 }
212 ON_SCOPE_EXIT(failExecute) {
213 isStopRun_ = true;
214 stream->Stop();
215 };
216 std::string pkgFileName;
217 int32_t ret = context.GetParam(0, pkgFileName);
218 if (ret != USCRIPT_SUCCESS) {
219 LOG(ERROR) << "Error to get pkgFileName";
220 return ret;
221 }
222
223 LOG(INFO) << "UScriptInstructionBinFlowWrite::Execute " << pkgFileName;
224 PkgManager::PkgManagerPtr manager = env.GetPkgManager();
225 if (manager == nullptr) {
226 LOG(ERROR) << "Error to get pkg manager";
227 return USCRIPT_INVALID_PARAM;
228 }
229 std::vector<std::string> innerFileNames;
230 ret = manager->LoadPackageWithStream(pkgFileName, Utils::GetCertName(),
231 innerFileNames, PkgFile::PKG_TYPE_UPGRADE, stream);
232 if (ret != USCRIPT_SUCCESS) {
233 LOG(ERROR) << "Error to load flow data stream";
234 return USCRIPT_ERROR_EXECUTE;
235 }
236 LOG(INFO) << "Get binary tids";
237 std::vector<pid_t> tids = GetAllTids(getpid());
238 env.PostMessage("set_binary_tids", VectorToString(tids));
239 for (const auto &iter : innerFileNames) {
240 // 根据镜像名称获取分区名称和大小
241 std::string partitionName = iter;
242 const FileInfo *info = manager->GetFileInfo(partitionName);
243 if (info == nullptr) {
244 LOG(ERROR) << "Error to get file info";
245 return USCRIPT_ERROR_EXECUTE;
246 }
247
248 LOG(INFO) << " start process Component " << partitionName << " unpackedSize " << info->unpackedSize;
249 if (ComponentProcess(env, stream, partitionName, *info) != USCRIPT_SUCCESS) {
250 LOG(ERROR) << "Error to process " << partitionName;
251 return USCRIPT_ERROR_EXECUTE;
252 }
253 }
254 CANCEL_SCOPE_EXIT_GUARD(failExecute);
255 LOG(INFO)<<"UScriptInstructionBinFlowWrite finish";
256 return USCRIPT_SUCCESS;
257 }
258
IsMatchedCsEsIamge(const Hpackage::FileInfo & fileInfo)259 bool UScriptInstructionBinFlowWrite::IsMatchedCsEsIamge(const Hpackage::FileInfo &fileInfo)
260 {
261 if ((fileInfo.resType == ES_IMAGE && !Utils::IsEsDevice()) ||
262 (fileInfo.resType == CS_IMAGE && Utils::IsEsDevice())) {
263 LOG(INFO) << "not matched cs es image, skip write";
264 return false;
265 }
266 return true;
267 }
268
CheckEsDeviceUpdate(const Hpackage::FileInfo & fileInfo)269 bool UScriptInstructionBinFlowWrite::CheckEsDeviceUpdate(const Hpackage::FileInfo &fileInfo)
270 {
271 if (fileInfo.resType == NEED_VERIFY_CS_IMAGE && Utils::IsEsDevice()) {
272 LOG(ERROR) << "pkg just cs image, but device is es";
273 return false;
274 }
275 return true;
276 }
277
SetProportion(float proportion)278 void UScriptInstructionBinFlowWrite::SetProportion(float proportion)
279 {
280 fullUpdateProportion_ = proportion;
281 }
282
ComponentProcess(Uscript::UScriptEnv & env,PkgManager::StreamPtr stream,const std::string & name,const Hpackage::FileInfo & fileInfo)283 int32_t UScriptInstructionBinFlowWrite::ComponentProcess(Uscript::UScriptEnv &env, PkgManager::StreamPtr stream,
284 const std::string &name, const Hpackage::FileInfo &fileInfo)
285 {
286 size_t fileSize = fileInfo.unpackedSize;
287 // 根据镜像名获取组件处理类名
288 std::unique_ptr<ComponentProcessor> processor =
289 ComponentProcessorFactory::GetInstance().GetProcessor(name, fileSize);
290
291 if (env.IsRetry()) {
292 LOG(DEBUG) << "Retry updater, check if current partition updated already during last time";
293 bool isUpdated = PartitionRecord::GetInstance().IsPartitionUpdated(name);
294 if (isUpdated) {
295 LOG(INFO) << name << " already updated, skip";
296 processor.reset();
297 processor = std::make_unique<SkipImgProcessor>(name, fileSize);
298 }
299 }
300
301 if (!CheckEsDeviceUpdate(fileInfo)) {
302 LOG(ERROR) << "pkg just cs image, es device not allow update";
303 return USCRIPT_ERROR_EXECUTE;
304 }
305
306 if ((processor == nullptr && fileInfo.resType == UPGRADE_FILE_COMP_OTHER_TPYE) ||
307 !IsMatchedCsEsIamge(fileInfo)) {
308 LOG(INFO) << name << " comp is not register and comp file is not image, or not match cs es image, skip";
309 processor.reset();
310 processor = std::make_unique<SkipImgProcessor>(name, fileSize);
311 }
312
313 if (processor == nullptr) {
314 LOG(ERROR) << "GetProcessor failed, partition name: " << name;
315 return USCRIPT_ERROR_EXECUTE;
316 }
317 processor->SetPkgFileInfo(stream->GetReadOffset(), stream->GetFileLength(),
318 fullUpdateProportion_ * GetTotalProportion());
319 LOG(INFO) << "component read offset " << stream->GetReadOffset();
320
321 if (processor->PreProcess(env) != USCRIPT_SUCCESS) {
322 LOG(ERROR) << "Error to PreProcess " << name;
323 return USCRIPT_ERROR_EXECUTE;
324 }
325
326 if (processor->DoProcess(env) != USCRIPT_SUCCESS) {
327 LOG(ERROR) << "Error to DoProcess " << name;
328 return USCRIPT_ERROR_EXECUTE;
329 }
330
331 if (processor->PostProcess(env) != USCRIPT_SUCCESS) {
332 LOG(ERROR) << "Error to PostProcess " << name;
333 return USCRIPT_ERROR_EXECUTE;
334 }
335
336 return USCRIPT_SUCCESS;
337 }
338 } // namespace Updater
339