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