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