• 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     // service process add aot compile args here
89     AddExpandArgs(hapArgs.argVector);
90     for (auto &argPair : argsMap) {
91         if (AotArgsSet.find(argPair.first) != AotArgsSet.end()) {
92             hapArgs.argVector.emplace_back(Symbols::PREFIX + argPair.first + Symbols::EQ + argPair.second);
93         }
94     }
95     hapArgs.argVector.emplace_back(abcPath);
96     return ERR_OK;
97 }
98 
DropCapabilities(const int32_t & bundleUid,const int32_t & bundleGid) const99 void AotCompilerImpl::DropCapabilities(const int32_t &bundleUid, const int32_t &bundleGid) const
100 {
101     LOG_SA(INFO) << "begin to drop capabilities";
102     if (setuid(bundleUid)) {
103         LOG_SA(ERROR) << "dropCapabilities setuid failed : " << strerror(errno);
104         exit(-1);
105     }
106     if (setgid(bundleGid)) {
107         LOG_SA(ERROR) << "dropCapabilities setgid failed : " << strerror(errno);
108         exit(-1);
109     }
110     struct __user_cap_header_struct capHeader;
111     if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) {
112         LOG_SA(ERROR) << "memset_s capHeader failed : " << strerror(errno);
113         exit(-1);
114     }
115     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
116     capHeader.pid = 0;
117 
118     struct __user_cap_data_struct capData[2];
119     if (memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK) {
120         LOG_SA(ERROR) << "memset_s capData failed : " << strerror(errno);
121         exit(-1);
122     }
123     if (capset(&capHeader, capData) != 0) {
124         LOG_SA(ERROR) << "capset failed : " << strerror(errno);
125         exit(-1);
126     }
127     LOG_SA(INFO) << "drop capabilities success";
128 }
129 
ExecuteInChildProcess(const std::vector<std::string> & aotVector) const130 void AotCompilerImpl::ExecuteInChildProcess(const std::vector<std::string> &aotVector) const
131 {
132     std::vector<const char*> argv;
133     argv.reserve(aotVector.size() + 1);
134     for (auto &arg : aotVector) {
135         argv.emplace_back(arg.c_str());
136     }
137     LOG_SA(INFO) << "ark_aot_compiler argv size : " << argv.size();
138     for (const auto &arg : argv) {
139         LOG_SA(INFO) << arg;
140     }
141     argv.emplace_back(nullptr);
142     LOG_SA(INFO) << "begin to execute ark_aot_compiler";
143     execv(argv[0], const_cast<char* const*>(argv.data()));
144     LOG_SA(ERROR) << "execv failed : " << strerror(errno);
145     exit(-1);
146 }
147 
AddExpandArgs(std::vector<std::string> & argVector)148 void AotCompilerImpl::AddExpandArgs(std::vector<std::string> &argVector)
149 {
150     std::string thermalLevelArg = "--compiler-thermal-level=" + std::to_string(thermalLevel_);
151     argVector.emplace_back(thermalLevelArg);
152 }
153 
PrintAOTCompilerResult(const int compilerStatus)154 int32_t AotCompilerImpl::PrintAOTCompilerResult(const int compilerStatus)
155 {
156     if (RetInfoOfCompiler.find(compilerStatus) == RetInfoOfCompiler.end()) {
157         LOG_SA(ERROR) << OtherInfoOfCompiler.mesg;
158         return OtherInfoOfCompiler.retCode;
159     }
160     if (RetInfoOfCompiler.at(compilerStatus).retCode == ERR_AOT_COMPILER_CALL_FAILED) {
161         LOG_SA(ERROR) << RetInfoOfCompiler.at(compilerStatus).mesg;
162     } else {
163         LOG_SA(INFO) << RetInfoOfCompiler.at(compilerStatus).mesg;
164     }
165     return RetInfoOfCompiler.at(compilerStatus).retCode;
166 }
167 
ExecuteInParentProcess(const pid_t childPid,int32_t & ret)168 void AotCompilerImpl::ExecuteInParentProcess(const pid_t childPid, int32_t &ret)
169 {
170     {
171         std::lock_guard<std::mutex> lock(stateMutex_);
172         InitState(childPid);
173     }
174     int status;
175     int waitRet = waitpid(childPid, &status, 0);
176     if (waitRet == -1) {
177         LOG_SA(ERROR) << "waitpid failed";
178         ret = ERR_AOT_COMPILER_CALL_FAILED;
179     } else if (WIFEXITED(status)) {
180         int exitStatus = WEXITSTATUS(status);
181         LOG_SA(INFO) << "child process exited with status: " << exitStatus;
182         ret = PrintAOTCompilerResult(exitStatus);
183     } else if (WIFSIGNALED(status)) {
184         int signalNumber = WTERMSIG(status);
185         LOG_SA(WARN) << "child process terminated by signal: " << signalNumber;
186         ret = signalNumber == SIGKILL ? ERR_AOT_COMPILER_CALL_CANCELLED : ERR_AOT_COMPILER_CALL_CRASH;
187     } else if (WIFSTOPPED(status)) {
188         int signalNumber = WSTOPSIG(status);
189         LOG_SA(WARN) << "child process was stopped by signal: " << signalNumber;
190         ret = ERR_AOT_COMPILER_CALL_FAILED;
191     } else if (WIFCONTINUED(status)) {
192         LOG_SA(WARN) << "child process was resumed";
193         ret = ERR_AOT_COMPILER_CALL_FAILED;
194     } else {
195         LOG_SA(WARN) << "unknown";
196         ret = ERR_AOT_COMPILER_CALL_FAILED;
197     }
198     {
199         std::lock_guard<std::mutex> lock(stateMutex_);
200         ResetState();
201     }
202 }
203 
VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string,std::string> & argsMap)204 bool AotCompilerImpl::VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string, std::string> &argsMap)
205 {
206     auto targetCompilerMode = argsMap.find(ArgsIdx::TARGET_COMPILER_MODE);
207     if (targetCompilerMode == argsMap.end() || targetCompilerMode->second.empty()) {
208         return false;
209     }
210     auto compilerPkgInfo = argsMap.find(ArgsIdx::COMPILER_PKG_INFO);
211     if (compilerPkgInfo == argsMap.end() || compilerPkgInfo->second.empty()) {
212         return false;
213     }
214     return true;
215 }
216 
EcmascriptAotCompiler(const std::unordered_map<std::string,std::string> & argsMap,std::vector<int16_t> & sigData)217 int32_t AotCompilerImpl::EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap,
218                                                std::vector<int16_t> &sigData)
219 {
220 #ifdef CODE_SIGN_ENABLE
221     if (!allowAotCompiler_) {
222         return ERR_AOT_COMPILER_CONNECT_FAILED;
223     }
224     std::lock_guard<std::mutex> lock(mutex_);
225     if (!VerifyCompilerModeAndPkgInfo(argsMap)) {
226         LOG_SA(ERROR) << "aot compiler mode or pkginfo arguments error";
227         return ERR_AOT_COMPILER_PARAM_FAILED;
228     }
229     if (argsMap.empty() || (PrepareArgs(argsMap) != ERR_OK)) {
230         LOG_SA(ERROR) << "aot compiler arguments error";
231         return ERR_AOT_COMPILER_PARAM_FAILED;
232     }
233     int32_t ret = ERR_OK;
234     LOG_SA(INFO) << "begin to fork";
235     pid_t pid = fork();
236     if (pid == -1) {
237         LOG_SA(ERROR) << "fork process failed : " << strerror(errno);
238         return ERR_AOT_COMPILER_CALL_FAILED;
239     } else if (pid == 0) {
240         DropCapabilities(hapArgs.bundleUid, hapArgs.bundleGid);
241         ExecuteInChildProcess(hapArgs.argVector);
242     } else {
243         ExecuteInParentProcess(pid, ret);
244     }
245     if (ret == ERR_OK_NO_AOT_FILE) {
246         return ERR_OK;
247     }
248     return ret ? ret : AOTLocalCodeSign(hapArgs.fileName, hapArgs.signature, sigData);
249 #else
250     LOG_SA(ERROR) << "no need to AOT compile when code signature disable";
251     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
252 #endif
253 }
254 
GetAOTVersion(std::string & sigData)255 int32_t AotCompilerImpl::GetAOTVersion(std::string& sigData)
256 {
257     LOG_SA(INFO) << "AotCompilerImpl::GetAOTVersion";
258     sigData = panda::ecmascript::AOTFileVersion::GetAOTVersion();
259 
260     return ERR_OK;
261 }
262 
NeedReCompile(const std::string & args,bool & sigData)263 int32_t AotCompilerImpl::NeedReCompile(const std::string& args, bool& sigData)
264 {
265     LOG_SA(INFO) << "AotCompilerImpl::NeedReCompile";
266     sigData = panda::ecmascript::AOTFileVersion::CheckAOTVersion(args);
267     return ERR_OK;
268 }
269 
AOTLocalCodeSign(const std::string & fileName,const std::string & appSignature,std::vector<int16_t> & sigData)270 int32_t AotCompilerImpl::AOTLocalCodeSign(const std::string &fileName, const std::string &appSignature,
271                                           std::vector<int16_t> &sigData)
272 {
273 #ifdef CODE_SIGN_ENABLE
274     Security::CodeSign::ByteBuffer sig;
275     if (Security::CodeSign::LocalCodeSignKit::SignLocalCode(appSignature, fileName, sig)
276                         != CommonErrCode::CS_SUCCESS) {
277         LOG_SA(ERROR) << "failed to sign the aot file";
278         return ERR_AOT_COMPILER_SIGNATURE_FAILED;
279     }
280     LOG_SA(DEBUG) << "aot file local sign success";
281     uint8_t *dataPtr = sig.GetBuffer();
282     for (uint32_t i = 0; i < sig.GetSize(); ++i) {
283         sigData.emplace_back(static_cast<int16_t>(dataPtr[i]));
284     }
285     return ERR_OK;
286 #else
287     LOG_SA(ERROR) << "no need to AOT local code sign when code signature disable";
288     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
289 #endif
290 }
291 
StopAotCompiler()292 int32_t AotCompilerImpl::StopAotCompiler()
293 {
294     LOG_SA(INFO) << "begin to stop AOT";
295     std::lock_guard<std::mutex> lock(stateMutex_);
296     if (!state_.running) {
297         LOG_SA(INFO) << "AOT not running, return directly";
298         return ERR_AOT_COMPILER_STOP_FAILED;
299     }
300     if (state_.childPid <= 0) {
301         LOG_SA(ERROR) << "invalid child pid";
302         return ERR_AOT_COMPILER_STOP_FAILED;
303     }
304     LOG_SA(INFO) << "begin to kill child process : " << state_.childPid;
305     auto result = kill(state_.childPid, SIGKILL);
306     int32_t ret = ERR_OK;
307     if (access(hapArgs.fileName.c_str(), ERR_OK) != ERR_FAIL) {
308         auto delRes = std::remove(hapArgs.fileName.c_str());
309         if (delRes != ERR_OK) {
310             LOG_SA(INFO) << "delete invalid aot file failed: " << delRes;
311             ret = ERR_AOT_COMPILER_STOP_FAILED;
312         } else {
313             LOG_SA(INFO) << "delete invalid aot file success";
314         }
315     }
316     if (result != 0) {
317         LOG_SA(INFO) << "kill child process failed: " << result;
318         ret = ERR_AOT_COMPILER_STOP_FAILED;
319     } else {
320         LOG_SA(INFO) << "kill child process success";
321     }
322     ResetState();
323     return ret;
324 }
325 
HandlePowerDisconnected()326 void AotCompilerImpl::HandlePowerDisconnected()
327 {
328     LOG_SA(INFO) << "AotCompilerImpl::HandlePowerDisconnected";
329     PauseAotCompiler();
330     std::thread([]() {
331         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
332         sleep(30);  // wait for 30 seconds
333         AotCompilerImpl::GetInstance().AllowAotCompiler();
334     }).detach();
335 }
336 
HandleScreenOn()337 void AotCompilerImpl::HandleScreenOn()
338 {
339     LOG_SA(INFO) << "AotCompilerImpl::HandleScreenOn";
340     PauseAotCompiler();
341     std::thread([]() {
342         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
343         sleep(40);  // wait for 40 seconds
344         AotCompilerImpl::GetInstance().AllowAotCompiler();
345     }).detach();
346 }
347 
HandleThermalLevelChanged(const int32_t level)348 void AotCompilerImpl::HandleThermalLevelChanged(const int32_t level)
349 {
350     LOG_SA(INFO) << "AotCompilerImpl::HandleThermalLevelChanged";
351     thermalLevel_ = level;
352     // thermal level >= 2, stop aot compile
353     if (thermalLevel_ >= AOT_COMPILE_STOP_LEVEL) {
354         PauseAotCompiler();
355     } else {
356         AllowAotCompiler();
357     }
358 }
359 
PauseAotCompiler()360 void AotCompilerImpl::PauseAotCompiler()
361 {
362     LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
363     allowAotCompiler_ = false;
364 }
365 
AllowAotCompiler()366 void AotCompilerImpl::AllowAotCompiler()
367 {
368     LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
369     allowAotCompiler_ = true;
370 }
371 
InitState(const pid_t childPid)372 void AotCompilerImpl::InitState(const pid_t childPid)
373 {
374     state_.running = true;
375     state_.childPid = childPid;
376 }
377 
ResetState()378 void AotCompilerImpl::ResetState()
379 {
380     state_.running = false;
381     state_.childPid = -1;
382 }
383 } // namespace OHOS::ArkCompiler