• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "aot_compiler_impl.h"
17 
18 #include <cerrno>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <cstring>
22 #include <linux/capability.h>
23 #include <securec.h>
24 #include <sys/capability.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <thread>
29 
30 #include "aot_compiler_constants.h"
31 #include "aot_compiler_error_utils.h"
32 #include "aot_compiler_service.h"
33 #include "ecmascript/log_wrapper.h"
34 #include "hitrace_meter.h"
35 #ifdef CODE_SIGN_ENABLE
36 #include "local_code_sign_kit.h"
37 #endif
38 #include "system_ability_definition.h"
39 
40 namespace OHOS::ArkCompiler {
GetInstance()41 AotCompilerImpl& AotCompilerImpl::GetInstance()
42 {
43     static AotCompilerImpl aotCompiler;
44     return aotCompiler;
45 }
46 
FindArgsIdxToInteger(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,int32_t & bundleID)47 inline int32_t AotCompilerImpl::FindArgsIdxToInteger(const std::unordered_map<std::string, std::string> &argsMap,
48                                                      const std::string &keyName, int32_t &bundleID)
49 {
50     if (argsMap.find(keyName) == argsMap.end()) {
51         return ERR_AOT_COMPILER_PARAM_FAILED;
52     }
53     size_t sz;
54     bundleID = static_cast<int32_t>(std::stoi(argsMap.at(keyName), &sz));
55     if (sz < static_cast<size_t>(argsMap.at(keyName).size())) {
56         LOG_SA(ERROR) << "trigger exception as converting string to integer";
57         return ERR_AOT_COMPILER_PARAM_FAILED;
58     }
59     return ERR_OK;
60 }
61 
FindArgsIdxToString(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,std::string & bundleArg)62 inline int32_t AotCompilerImpl::FindArgsIdxToString(const std::unordered_map<std::string, std::string> &argsMap,
63                                                     const std::string &keyName, std::string &bundleArg)
64 {
65     if (argsMap.find(keyName) == argsMap.end()) {
66         return ERR_AOT_COMPILER_PARAM_FAILED;
67     }
68     bundleArg = argsMap.at(keyName);
69     return ERR_OK;
70 }
71 
PrepareArgs(const std::unordered_map<std::string,std::string> & argsMap)72 int32_t AotCompilerImpl::PrepareArgs(const std::unordered_map<std::string, std::string> &argsMap)
73 {
74     for (const auto &arg : argsMap) {
75         LOG_SA(DEBUG) << arg.first << ": " << arg.second;
76     }
77     std::string abcPath;
78     if ((FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_UID, hapArgs.bundleUid) != ERR_OK)   ||
79         (FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_GID, hapArgs.bundleGid) != ERR_OK)   ||
80         (FindArgsIdxToString(argsMap, ArgsIdx::AN_FILE_NAME, hapArgs.fileName) != ERR_OK)   ||
81         (FindArgsIdxToString(argsMap, ArgsIdx::APP_SIGNATURE, hapArgs.signature) != ERR_OK) ||
82         (FindArgsIdxToString(argsMap, ArgsIdx::ABC_PATH, abcPath) != ERR_OK)) {
83         LOG_SA(ERROR) << "aot compiler Args parsing error";
84         return ERR_AOT_COMPILER_PARAM_FAILED;
85     }
86     hapArgs.argVector.clear();
87     hapArgs.argVector.emplace_back(Cmds::ARK_AOT_COMPILER);
88     for (auto &argPair : argsMap) {
89         if (AotArgsSet.find(argPair.first) != AotArgsSet.end()) {
90             hapArgs.argVector.emplace_back(Symbols::PREFIX + argPair.first + Symbols::EQ + argPair.second);
91         }
92     }
93     hapArgs.argVector.emplace_back(abcPath);
94     return ERR_OK;
95 }
96 
DropCapabilities(const int32_t & bundleUid,const int32_t & bundleGid) const97 void AotCompilerImpl::DropCapabilities(const int32_t &bundleUid, const int32_t &bundleGid) const
98 {
99     LOG_SA(INFO) << "begin to drop capabilities";
100     if (setuid(bundleUid)) {
101         LOG_SA(ERROR) << "dropCapabilities setuid failed : " << strerror(errno);
102         exit(-1);
103     }
104     if (setgid(bundleGid)) {
105         LOG_SA(ERROR) << "dropCapabilities setgid failed : " << strerror(errno);
106         exit(-1);
107     }
108     struct __user_cap_header_struct capHeader;
109     if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) {
110         LOG_SA(ERROR) << "memset_s capHeader failed : " << strerror(errno);
111         exit(-1);
112     }
113     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
114     capHeader.pid = 0;
115 
116     struct __user_cap_data_struct capData[2];
117     if (memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK) {
118         LOG_SA(ERROR) << "memset_s capData failed : " << strerror(errno);
119         exit(-1);
120     }
121     if (capset(&capHeader, capData) != 0) {
122         LOG_SA(ERROR) << "capset failed : " << strerror(errno);
123         exit(-1);
124     }
125     LOG_SA(INFO) << "drop capabilities success";
126 }
127 
ExecuteInChildProcess(const std::vector<std::string> & aotVector) const128 void AotCompilerImpl::ExecuteInChildProcess(const std::vector<std::string> &aotVector) const
129 {
130     std::vector<const char*> argv;
131     argv.reserve(aotVector.size() + 1);
132     for (auto &arg : aotVector) {
133         argv.emplace_back(arg.c_str());
134     }
135     LOG_SA(INFO) << "ark_aot_compiler argv size : " << argv.size();
136     for (const auto &arg : argv) {
137         LOG_SA(INFO) << arg;
138     }
139     argv.emplace_back(nullptr);
140     LOG_SA(INFO) << "begin to execute ark_aot_compiler";
141     execv(argv[0], const_cast<char* const*>(argv.data()));
142     LOG_SA(ERROR) << "execv failed : " << strerror(errno);
143     exit(-1);
144 }
145 
PrintAOTCompilerResult(const int compilerStatus)146 int32_t AotCompilerImpl::PrintAOTCompilerResult(const int compilerStatus)
147 {
148     if (RetInfoOfCompiler.find(compilerStatus) == RetInfoOfCompiler.end()) {
149         LOG_SA(ERROR) << OtherInfoOfCompiler.mesg;
150         return OtherInfoOfCompiler.retCode;
151     }
152     if (RetInfoOfCompiler.at(compilerStatus).retCode == ERR_AOT_COMPILER_CALL_FAILED) {
153         LOG_SA(ERROR) << RetInfoOfCompiler.at(compilerStatus).mesg;
154     } else {
155         LOG_SA(INFO) << RetInfoOfCompiler.at(compilerStatus).mesg;
156     }
157     return RetInfoOfCompiler.at(compilerStatus).retCode;
158 }
159 
ExecuteInParentProcess(const pid_t childPid,int32_t & ret)160 void AotCompilerImpl::ExecuteInParentProcess(const pid_t childPid, int32_t &ret)
161 {
162     {
163         std::lock_guard<std::mutex> lock(stateMutex_);
164         InitState(childPid);
165     }
166     int status;
167     int waitRet = waitpid(childPid, &status, 0);
168     if (waitRet == -1) {
169         LOG_SA(ERROR) << "waitpid failed";
170         ret = ERR_AOT_COMPILER_CALL_FAILED;
171     } else if (WIFEXITED(status)) {
172         int exitStatus = WEXITSTATUS(status);
173         LOG_SA(INFO) << "child process exited with status: " << exitStatus;
174         ret = PrintAOTCompilerResult(exitStatus);
175     } else if (WIFSIGNALED(status)) {
176         int signalNumber = WTERMSIG(status);
177         LOG_SA(WARN) << "child process terminated by signal: " << signalNumber;
178         ret = signalNumber == SIGKILL ? ERR_AOT_COMPILER_CALL_CANCELLED : ERR_AOT_COMPILER_CALL_CRASH;
179     } else if (WIFSTOPPED(status)) {
180         int signalNumber = WSTOPSIG(status);
181         LOG_SA(WARN) << "child process was stopped by signal: " << signalNumber;
182         ret = ERR_AOT_COMPILER_CALL_FAILED;
183     } else if (WIFCONTINUED(status)) {
184         LOG_SA(WARN) << "child process was resumed";
185         ret = ERR_AOT_COMPILER_CALL_FAILED;
186     } else {
187         LOG_SA(WARN) << "unknown";
188         ret = ERR_AOT_COMPILER_CALL_FAILED;
189     }
190     {
191         std::lock_guard<std::mutex> lock(stateMutex_);
192         ResetState();
193     }
194 }
195 
VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string,std::string> & argsMap)196 bool AotCompilerImpl::VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string, std::string> &argsMap)
197 {
198     auto targetCompilerMode = argsMap.find(ArgsIdx::TARGET_COMPILER_MODE);
199     if (targetCompilerMode == argsMap.end() || targetCompilerMode->second.empty()) {
200         return false;
201     }
202     auto compilerPkgInfo = argsMap.find(ArgsIdx::COMPILER_PKG_INFO);
203     if (compilerPkgInfo == argsMap.end() || compilerPkgInfo->second.empty()) {
204         return false;
205     }
206     return true;
207 }
208 
EcmascriptAotCompiler(const std::unordered_map<std::string,std::string> & argsMap,std::vector<int16_t> & sigData)209 int32_t AotCompilerImpl::EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap,
210                                                std::vector<int16_t> &sigData)
211 {
212 #ifdef CODE_SIGN_ENABLE
213     if (!allowAotCompiler_) {
214         return ERR_AOT_COMPILER_CONNECT_FAILED;
215     }
216     std::lock_guard<std::mutex> lock(mutex_);
217     if (!VerifyCompilerModeAndPkgInfo(argsMap)) {
218         LOG_SA(ERROR) << "aot compiler mode or pkginfo arguments error";
219         return ERR_AOT_COMPILER_PARAM_FAILED;
220     }
221     if (argsMap.empty() || (PrepareArgs(argsMap) != ERR_OK)) {
222         LOG_SA(ERROR) << "aot compiler arguments error";
223         return ERR_AOT_COMPILER_PARAM_FAILED;
224     }
225     int32_t ret = ERR_OK;
226     LOG_SA(INFO) << "begin to fork";
227     pid_t pid = fork();
228     if (pid == -1) {
229         LOG_SA(ERROR) << "fork process failed : " << strerror(errno);
230         return ERR_AOT_COMPILER_CALL_FAILED;
231     } else if (pid == 0) {
232         DropCapabilities(hapArgs.bundleUid, hapArgs.bundleGid);
233         ExecuteInChildProcess(hapArgs.argVector);
234     } else {
235         ExecuteInParentProcess(pid, ret);
236     }
237     if (ret == ERR_OK_NO_AOT_FILE) {
238         return ERR_OK;
239     }
240     return ret ? ret : AOTLocalCodeSign(hapArgs.fileName, hapArgs.signature, sigData);
241 #else
242     LOG_SA(ERROR) << "no need to AOT compile when code signature disable";
243     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
244 #endif
245 }
246 
GetAOTVersion(std::string & sigData)247 int32_t AotCompilerImpl::GetAOTVersion(std::string& sigData)
248 {
249     LOG_SA(INFO) << "AotCompilerImpl::GetAOTVersion";
250     sigData = panda::ecmascript::AOTFileVersion::GetAOTVersion();
251 
252     return ERR_OK;
253 }
254 
NeedReCompile(const std::string & args,bool & sigData)255 int32_t AotCompilerImpl::NeedReCompile(const std::string& args, bool& sigData)
256 {
257     LOG_SA(INFO) << "AotCompilerImpl::NeedReCompile";
258     sigData = panda::ecmascript::AOTFileVersion::CheckAOTVersion(args);
259     return ERR_OK;
260 }
261 
AOTLocalCodeSign(const std::string & fileName,const std::string & appSignature,std::vector<int16_t> & sigData)262 int32_t AotCompilerImpl::AOTLocalCodeSign(const std::string &fileName, const std::string &appSignature,
263                                           std::vector<int16_t> &sigData)
264 {
265 #ifdef CODE_SIGN_ENABLE
266     Security::CodeSign::ByteBuffer sig;
267     if (Security::CodeSign::LocalCodeSignKit::SignLocalCode(appSignature, fileName, sig)
268                         != CommonErrCode::CS_SUCCESS) {
269         LOG_SA(ERROR) << "failed to sign the aot file";
270         return ERR_AOT_COMPILER_SIGNATURE_FAILED;
271     }
272     LOG_SA(DEBUG) << "aot file local sign success";
273     uint8_t *dataPtr = sig.GetBuffer();
274     for (uint32_t i = 0; i < sig.GetSize(); ++i) {
275         sigData.emplace_back(static_cast<int16_t>(dataPtr[i]));
276     }
277     return ERR_OK;
278 #else
279     LOG_SA(ERROR) << "no need to AOT local code sign when code signature disable";
280     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
281 #endif
282 }
283 
StopAotCompiler()284 int32_t AotCompilerImpl::StopAotCompiler()
285 {
286     LOG_SA(INFO) << "begin to stop AOT";
287     std::lock_guard<std::mutex> lock(stateMutex_);
288     if (!state_.running) {
289         LOG_SA(INFO) << "AOT not running, return directly";
290         return ERR_AOT_COMPILER_STOP_FAILED;
291     }
292     if (state_.childPid <= 0) {
293         LOG_SA(ERROR) << "invalid child pid";
294         return ERR_AOT_COMPILER_STOP_FAILED;
295     }
296     LOG_SA(INFO) << "begin to kill child process : " << state_.childPid;
297     auto result = kill(state_.childPid, SIGKILL);
298     int32_t ret = ERR_OK;
299     if (result != 0) {
300         LOG_SA(INFO) << "kill child process failed: " << result;
301         ret = ERR_AOT_COMPILER_STOP_FAILED;
302     } else {
303         LOG_SA(INFO) << "kill child process success";
304     }
305     ResetState();
306     return ret;
307 }
308 
HandlePowerDisconnected()309 void AotCompilerImpl::HandlePowerDisconnected()
310 {
311     LOG_SA(INFO) << "AotCompilerImpl::HandlePowerDisconnected";
312     PauseAotCompiler();
313     std::thread([]() {
314         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
315         sleep(30);  // wait for 30 seconds
316         AotCompilerImpl::GetInstance().AllowAotCompiler();
317     }).detach();
318 }
319 
HandleScreenOn()320 void AotCompilerImpl::HandleScreenOn()
321 {
322     LOG_SA(INFO) << "AotCompilerImpl::HandleScreenOn";
323     PauseAotCompiler();
324     std::thread([]() {
325         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
326         sleep(40);  // wait for 40 seconds
327         AotCompilerImpl::GetInstance().AllowAotCompiler();
328     }).detach();
329 }
330 
PauseAotCompiler()331 void AotCompilerImpl::PauseAotCompiler()
332 {
333     LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
334     allowAotCompiler_ = false;
335 }
336 
AllowAotCompiler()337 void AotCompilerImpl::AllowAotCompiler()
338 {
339     LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
340     allowAotCompiler_ = true;
341 }
342 
InitState(const pid_t childPid)343 void AotCompilerImpl::InitState(const pid_t childPid)
344 {
345     state_.running = true;
346     state_.childPid = childPid;
347 }
348 
ResetState()349 void AotCompilerImpl::ResetState()
350 {
351     state_.running = false;
352     state_.childPid = -1;
353 }
354 } // namespace OHOS::ArkCompiler