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