• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "script_manager_impl.h"
16 #include <cstring>
17 #include <dlfcn.h>
18 #include "dump.h"
19 #include "pkg_manager.h"
20 #include "script_instructionhelper.h"
21 #include "script_interpreter.h"
22 #include "script_utils.h"
23 #include "thread_pool.h"
24 #include "updater_const.h"
25 #include "utils.h"
26 
27 using namespace Hpackage;
28 
29 namespace Uscript {
30 constexpr const char *LOAD_SCRIPT_NAME = "loadScript.us";
31 constexpr const char *REGISTER_CMD_SCRIPT_NAME = "registerCmd.us";
32 
33 static ScriptManagerImpl* g_scriptManager = nullptr;
GetScriptManager(UScriptEnv * env,const Hpackage::HashDataVerifier * verifier)34 ScriptManager* ScriptManager::GetScriptManager(UScriptEnv *env, const Hpackage::HashDataVerifier *verifier)
35 {
36     if (env == nullptr || verifier == nullptr) {
37         USCRIPT_LOGE("Env or verifier is null");
38         return nullptr;
39     }
40     if (g_scriptManager != nullptr) {
41         return g_scriptManager;
42     }
43     g_scriptManager = new (std::nothrow) ScriptManagerImpl(env, verifier);
44     if (g_scriptManager == nullptr) {
45         USCRIPT_LOGE("Create g_scriptManager failed");
46         return nullptr;
47     }
48     if (g_scriptManager->Init() != USCRIPT_SUCCESS) {
49         USCRIPT_LOGE("g_scriptManager init failed");
50         return nullptr;
51     }
52     return g_scriptManager;
53 }
54 
ReleaseScriptManager()55 void ScriptManager::ReleaseScriptManager()
56 {
57     if (g_scriptManager != nullptr) {
58         delete g_scriptManager;
59     }
60     g_scriptManager = nullptr;
61 }
62 
~ScriptManagerImpl()63 ScriptManagerImpl::~ScriptManagerImpl()
64 {
65     if (threadPool_) {
66         ThreadPool::Destroy();
67         threadPool_ = nullptr;
68     }
69     for (int i = 0; i < MAX_PRIORITY; i++) {
70         scriptFiles_[i].clear();
71     }
72     auto iter1 = scriptInstructions_.begin();
73     while (iter1 != scriptInstructions_.end()) {
74         UScriptInstructionPtr inst = (*iter1).second;
75         delete inst;
76         iter1 = scriptInstructions_.erase(iter1);
77     }
78     scriptInstructions_.clear();
79     ScriptInstructionHelper::ReleaseBasicInstructionHelper();
80 }
81 
Init()82 int32_t ScriptManagerImpl::Init()
83 {
84     if (scriptEnv_ == nullptr) {
85         USCRIPT_LOGE("Env null");
86         return USCRIPT_INVALID_PARAM;
87     }
88 
89     threadPool_ = ThreadPool::CreateThreadPool(MAX_PRIORITY);
90     if (threadPool_ == nullptr) {
91         USCRIPT_LOGE("Failed to create thread pool");
92         return USCRIPT_INVALID_PARAM;
93     }
94 
95     // Register system reserved instructions
96     ScriptInstructionHelper* helper = ScriptInstructionHelper::GetBasicInstructionHelper(this);
97     if (helper == nullptr) {
98         USCRIPT_LOGE("Failed to get helper");
99         return USCRIPT_INVALID_PARAM;
100     }
101     helper->RegisterInstructions();
102 
103     // Register customized instructions
104     RegisterInstruction(*helper);
105 
106     PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
107     if (manager == nullptr) {
108         USCRIPT_LOGE("Failed to get pkg manager");
109         return USCRIPT_INVALID_PARAM;
110     }
111 
112     // Register other instructions from scripts
113     int32_t ret = USCRIPT_SUCCESS;
114     const FileInfo *info = manager->GetFileInfo(REGISTER_CMD_SCRIPT_NAME);
115     if (info != nullptr) {
116         ret = ExtractAndExecuteScript(manager, REGISTER_CMD_SCRIPT_NAME);
117     }
118     if (ret != USCRIPT_SUCCESS) {
119         USCRIPT_LOGE("Failed to extract and execute script ");
120         return ret;
121     }
122 
123     // Collect scripts
124     ret = ExtractAndExecuteScript(manager, LOAD_SCRIPT_NAME);
125     if (ret != USCRIPT_SUCCESS) {
126         USCRIPT_LOGE("Failed to extract and execute script ");
127         return ret;
128     }
129     return USCRIPT_SUCCESS;
130 }
131 
RegisterInstruction(ScriptInstructionHelper & helper)132 int32_t ScriptManagerImpl::RegisterInstruction(ScriptInstructionHelper &helper)
133 {
134     Uscript::UScriptInstructionFactoryPtr factory = scriptEnv_->GetInstructionFactory();
135     if (factory == nullptr) {
136         USCRIPT_LOGE("None factory");
137         return USCRIPT_SUCCESS;
138     }
139 
140     for (auto instrName : scriptEnv_->GetInstructionNames()) {
141         // Create instructions and register it.
142         UScriptInstructionPtr instr = nullptr;
143         int32_t ret = factory->CreateInstructionInstance(instr, instrName);
144         if (ret != USCRIPT_SUCCESS) {
145             USCRIPT_LOGE("Failed to create instruction for %s", instrName.c_str());
146             return ret;
147         }
148         helper.AddInstruction(instrName, instr);
149         if (ret != USCRIPT_SUCCESS) {
150             USCRIPT_LOGE("Failed to add instruction for %s", instrName.c_str());
151             return ret;
152         }
153     }
154     return USCRIPT_SUCCESS;
155 }
156 
ExtractAndExecuteScript(PkgManager::PkgManagerPtr manager,const std::string & scriptName)157 int32_t ScriptManagerImpl::ExtractAndExecuteScript(PkgManager::PkgManagerPtr manager,
158     const std::string &scriptName)
159 {
160     Updater::UPDATER_INIT_RECORD;
161     PkgManager::StreamPtr outStream = nullptr;
162     const std::string path = Updater::Utils::IsUpdaterMode() ? "/tmp" : Updater::UPDATER_PATH;
163     const FileInfo *info = manager->GetFileInfo(scriptName);
164     if (info == nullptr) {
165         USCRIPT_LOGE("Error to get file info");
166         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
167         return USCRIPT_INVALID_PARAM;
168     }
169     int32_t ret = manager->CreatePkgStream(outStream, path + "/" + scriptName,
170         info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
171     if (ret != USCRIPT_SUCCESS) {
172         USCRIPT_LOGE("Failed to create script stream %s", scriptName.c_str());
173         UPDATER_LAST_WORD(ret);
174         return ret;
175     }
176     ret = manager->ExtractFile(scriptName, outStream);
177     if (ret != USCRIPT_SUCCESS) {
178         manager->ClosePkgStream(outStream);
179         USCRIPT_LOGE("Failed to extract script stream %s", scriptName.c_str());
180         UPDATER_LAST_WORD(ret);
181         return ret;
182     }
183     if (scriptVerifier_ == nullptr || !scriptVerifier_->VerifyHashData(scriptName, outStream)) {
184         manager->ClosePkgStream(outStream);
185         USCRIPT_LOGE("verify script %s by hash signed data failed", scriptName.c_str());
186         UPDATER_LAST_WORD(ret);
187         return USCRIPT_INVALID_SCRIPT;
188     }
189     ret = ScriptInterpreter::ExecuteScript(this, outStream);
190     manager->ClosePkgStream(outStream);
191     if (ret != USCRIPT_SUCCESS) {
192         USCRIPT_LOGE("Failed to ExecuteScript %s", scriptName.c_str());
193         return ret;
194     }
195     return ret;
196 }
197 
ExecuteScript(int32_t priority)198 int32_t ScriptManagerImpl::ExecuteScript(int32_t priority)
199 {
200     if (priority >= MAX_PRIORITY || priority < 0) {
201         USCRIPT_LOGE("ExecuteScript priority not support %d", priority);
202         UPDATER_LAST_WORD(USCRIPT_INVALID_PRIORITY, priority);
203         return USCRIPT_INVALID_PRIORITY;
204     }
205     PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
206     if (manager == nullptr) {
207         USCRIPT_LOGE("Failed to get pkg manager");
208         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
209         return USCRIPT_INVALID_PARAM;
210     }
211     if (scriptFiles_[priority].size() == 0) {
212         return USCRIPT_SUCCESS;
213     }
214 
215     // Execute scripts
216     int32_t threadNumber = threadPool_->GetThreadNumber();
217     Task task;
218     int32_t ret = USCRIPT_SUCCESS;
219     int32_t retCode = USCRIPT_SUCCESS;
220     task.workSize = threadNumber;
221     task.processor = [&](int iter) {
222         for (size_t i = static_cast<size_t>(iter); i < scriptFiles_[priority].size();
223             i += static_cast<size_t>(threadNumber)) {
224             ret = ExtractAndExecuteScript(manager, scriptFiles_[priority][i]);
225             if (ret != USCRIPT_SUCCESS) {
226                 USCRIPT_LOGE("Failed to execute script %s", scriptFiles_[priority][i].c_str());
227                 retCode = ret;
228             }
229         }
230     };
231     ThreadPool::AddTask(std::move(task));
232     return retCode;
233 }
234 
AddInstruction(const std::string & instrName,const UScriptInstructionPtr instruction)235 int32_t ScriptManagerImpl::AddInstruction(const std::string &instrName, const UScriptInstructionPtr instruction)
236 {
237     USCRIPT_LOGI("AddInstruction instrName: %s ", instrName.c_str());
238     if (scriptInstructions_.find(instrName) != scriptInstructions_.end()) {
239         USCRIPT_LOGW("Instruction: %s exist", instrName.c_str());
240         // New instruction has the same name
241         // with already registered instruction,
242         // just override it.
243         delete scriptInstructions_[instrName];
244     }
245     scriptInstructions_[instrName] = instruction;
246     return USCRIPT_SUCCESS;
247 }
248 
AddScript(const std::string & scriptName,int32_t priority)249 int32_t ScriptManagerImpl::AddScript(const std::string &scriptName, int32_t priority)
250 {
251     Updater::UPDATER_INIT_RECORD;
252     if (priority < 0 || priority >= MAX_PRIORITY) {
253         USCRIPT_LOGE("Invalid priority %d", priority);
254         UPDATER_LAST_WORD(USCRIPT_INVALID_PRIORITY);
255         return USCRIPT_INVALID_PRIORITY;
256     }
257 
258     PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
259     if (manager == nullptr) {
260         USCRIPT_LOGE("Failed to get pkg manager");
261         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
262         return USCRIPT_INVALID_PARAM;
263     }
264 
265     if (manager->GetFileInfo(scriptName) == nullptr) {
266         USCRIPT_LOGE("Failed to access script %s", scriptName.c_str());
267         UPDATER_LAST_WORD(USCRIPT_INVALID_SCRIPT);
268         return USCRIPT_INVALID_SCRIPT;
269     }
270     scriptFiles_[priority].push_back(scriptName);
271     return USCRIPT_SUCCESS;
272 }
273 
FindInstruction(const std::string & instrName)274 UScriptInstruction* ScriptManagerImpl::FindInstruction(const std::string &instrName)
275 {
276     if (scriptInstructions_.find(instrName) == scriptInstructions_.end()) {
277         return nullptr;
278     }
279     return scriptInstructions_[instrName];
280 }
281 
GetScriptEnv(const std::string & instrName) const282 UScriptEnv* ScriptManagerImpl::GetScriptEnv(const std::string &instrName) const
283 {
284     return scriptEnv_;
285 }
286 } // namespace Uscript
287