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