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