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