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 "pkg_manager.h"
19 #include "script_instructionhelper.h"
20 #include "script_interpreter.h"
21 #include "script_utils.h"
22 #include "thread_pool.h"
23
24 using namespace hpackage;
25
26 namespace uscript {
27 const std::string LOAD_SCRIPT_NAME = "loadScript.us";
28 const std::string REGISTER_CMD_SCRIPT_NAME = "registerCmd.us";
29
30 static ScriptManagerImpl* g_scriptManager = nullptr;
GetScriptManager(UScriptEnv * env)31 ScriptManager* ScriptManager::GetScriptManager(UScriptEnv *env)
32 {
33 USCRIPT_CHECK(env != nullptr, return nullptr, "Env null");
34
35 if (g_scriptManager == nullptr) {
36 g_scriptManager = new ScriptManagerImpl(env);
37 (void)g_scriptManager->Init();
38 }
39 return g_scriptManager;
40 }
41
ReleaseScriptManager()42 void ScriptManager::ReleaseScriptManager()
43 {
44 if (g_scriptManager != nullptr) {
45 delete g_scriptManager;
46 }
47 g_scriptManager = nullptr;
48 }
49
~ScriptManagerImpl()50 ScriptManagerImpl::~ScriptManagerImpl()
51 {
52 if (threadPool_) {
53 ThreadPool::Destroy();
54 threadPool_ = nullptr;
55 }
56 for (int i = 0; i < MAX_PRIORITY; i++) {
57 scriptFiles_[i].clear();
58 }
59 auto iter1 = scriptInstructions_.begin();
60 while (iter1 != scriptInstructions_.end()) {
61 UScriptInstructionPtr inst = (*iter1).second;
62 delete inst;
63 iter1 = scriptInstructions_.erase(iter1);
64 }
65 scriptInstructions_.clear();
66 ScriptInstructionHelper::ReleaseBasicInstructionHelper();
67 }
68
Init()69 int32_t ScriptManagerImpl::Init()
70 {
71 USCRIPT_CHECK(scriptEnv_ != nullptr, return USCRIPT_INVALID_PARAM, "Env null");
72
73 threadPool_ = ThreadPool::CreateThreadPool(MAX_PRIORITY);
74 USCRIPT_CHECK(threadPool_ != nullptr, return USCRIPT_INVALID_PARAM, "Failed to create thread pool");
75
76 // Register system reserved instructions
77 ScriptInstructionHelper* helper = ScriptInstructionHelper::GetBasicInstructionHelper(this);
78 USCRIPT_CHECK(helper != nullptr, return USCRIPT_INVALID_PARAM, "Failed to get helper");
79 helper->RegisterInstructions();
80
81 // Register customized instructions
82 RegisterInstruction(*helper);
83
84 PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
85 USCRIPT_CHECK(manager != nullptr, return USCRIPT_INVALID_PARAM, "Failed to get pkg manager");
86
87 // Register other instructions from scripts
88 int32_t ret = USCRIPT_SUCCESS;
89 const FileInfo *info = manager->GetFileInfo(REGISTER_CMD_SCRIPT_NAME);
90 if (info != nullptr) {
91 ret = ExtractAndExecuteScript(manager, REGISTER_CMD_SCRIPT_NAME);
92 }
93 // Collect scripts
94 ret |= ExtractAndExecuteScript(manager, LOAD_SCRIPT_NAME);
95 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to extract and execute script ");
96 return USCRIPT_SUCCESS;
97 }
98
RegisterInstruction(ScriptInstructionHelper & helper)99 int32_t ScriptManagerImpl::RegisterInstruction(ScriptInstructionHelper &helper)
100 {
101 uscript::UScriptInstructionFactoryPtr factory = scriptEnv_->GetInstructionFactory();
102 USCRIPT_CHECK(factory != nullptr, return USCRIPT_SUCCESS, "None factory");
103
104 for (auto instrName : scriptEnv_->GetInstructionNames()) {
105 // Create instructions and register it.
106 UScriptInstructionPtr instr = nullptr;
107 int32_t ret = factory->CreateInstructionInstance(instr, instrName);
108 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to create instruction for %s", instrName.c_str());
109 helper.AddInstruction(instrName, instr);
110 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to add instruction for %s", instrName.c_str());
111 }
112 return USCRIPT_SUCCESS;
113 }
114
ExtractAndExecuteScript(PkgManager::PkgManagerPtr manager,const std::string & scriptName)115 int32_t ScriptManagerImpl::ExtractAndExecuteScript(PkgManager::PkgManagerPtr manager,
116 const std::string &scriptName)
117 {
118 PkgManager::StreamPtr outStream = nullptr;
119 int32_t ret = manager->CreatePkgStream(outStream, scriptName, 0, PkgStream::PkgStreamType_Write);
120 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to create script stream %s", scriptName.c_str());
121 ret = manager->ExtractFile(scriptName, outStream);
122 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to extract script stream %s", scriptName.c_str());
123
124 ret = ScriptInterpreter::ExecuteScript(this, outStream);
125 manager->ClosePkgStream(outStream);
126 USCRIPT_CHECK(ret == USCRIPT_SUCCESS, return ret, "Failed to ExecuteScript %s", scriptName.c_str());
127 return ret;
128 }
129
ExecuteScript(int32_t priority)130 int32_t ScriptManagerImpl::ExecuteScript(int32_t priority)
131 {
132 USCRIPT_CHECK(priority < MAX_PRIORITY && priority >= 0,
133 return USCRIPT_INVALID_PRIORITY, "ExecuteScript priority not support %d", priority);
134 PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
135 USCRIPT_CHECK(manager != nullptr, return USCRIPT_INVALID_PARAM, "Failed to get pkg manager");
136 if (scriptFiles_[priority].size() == 0) {
137 return USCRIPT_SUCCESS;
138 }
139
140 // Execute scripts
141 int32_t threadNumber = threadPool_->GetThreadNumber();
142 Task task;
143 int32_t ret = USCRIPT_SUCCESS;
144 int32_t retCode = USCRIPT_SUCCESS;
145 task.workSize = threadNumber;
146 task.processor = [&](int iter) {
147 for (size_t i = iter; i < scriptFiles_[priority].size(); i += threadNumber) {
148 ret = ExtractAndExecuteScript(manager, scriptFiles_[priority][i]);
149 if (ret != USCRIPT_SUCCESS) {
150 USCRIPT_LOGE("Failed to execute script %s", scriptFiles_[priority][i].c_str());
151 retCode = ret;
152 }
153 }
154 };
155 ThreadPool::AddTask(std::move(task));
156 return retCode;
157 }
158
AddInstruction(const std::string & instrName,const UScriptInstructionPtr instruction)159 int32_t ScriptManagerImpl::AddInstruction(const std::string &instrName, const UScriptInstructionPtr instruction)
160 {
161 USCRIPT_LOGI("AddInstruction instrName: %s ", instrName.c_str());
162 if (scriptInstructions_.find(instrName) != scriptInstructions_.end()) {
163 USCRIPT_LOGW("Instruction: %s exist", instrName.c_str());
164 // New instruction has the same name
165 // with already registered instruction,
166 // just override it.
167 delete scriptInstructions_[instrName];
168 }
169 scriptInstructions_[instrName] = instruction;
170 return USCRIPT_SUCCESS;
171 }
172
AddScript(const std::string & scriptName,int32_t priority)173 int32_t ScriptManagerImpl::AddScript(const std::string &scriptName, int32_t priority)
174 {
175 USCRIPT_CHECK(priority < MAX_PRIORITY, return USCRIPT_INVALID_PRIORITY, "Invalid priority %d", priority);
176
177 PkgManager::PkgManagerPtr manager = scriptEnv_->GetPkgManager();
178 USCRIPT_CHECK(manager != nullptr, return USCRIPT_INVALID_PARAM, "Failed to get pkg manager");
179
180 if (manager->GetFileInfo(scriptName) == nullptr) {
181 USCRIPT_LOGE("Failed to access script %s", scriptName.c_str());
182 return USCRIPT_SUCCESS;
183 }
184 scriptFiles_[priority].push_back(scriptName);
185 return USCRIPT_SUCCESS;
186 }
187
FindInstruction(const std::string & instrName)188 UScriptInstruction* ScriptManagerImpl::FindInstruction(const std::string &instrName)
189 {
190 if (scriptInstructions_.find(instrName) == scriptInstructions_.end()) {
191 return nullptr;
192 }
193 return scriptInstructions_[instrName];
194 }
195
GetScriptEnv(const std::string & instrName) const196 UScriptEnv* ScriptManagerImpl::GetScriptEnv(const std::string &instrName) const
197 {
198 return scriptEnv_;
199 }
200 } // namespace uscript
201