• 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 <charconv>
19 #include <sys/capability.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <thread>
23 
24 #include "aot_compiler_constants.h"
25 #include "ecmascript/log_wrapper.h"
26 #ifdef CODE_SIGN_ENABLE
27 #include "local_code_sign_kit.h"
28 #endif
29 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
30 #include "base/startup/init/interfaces/innerkits/include/syspara/parameters.h"
31 #endif
32 
33 namespace OHOS::ArkCompiler {
GetInstance()34 AotCompilerImpl& AotCompilerImpl::GetInstance()
35 {
36     static AotCompilerImpl aotCompiler;
37     return aotCompiler;
38 }
39 
FindArgsIdxToInteger(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,int32_t & bundleID)40 int32_t AotCompilerImpl::FindArgsIdxToInteger(const std::unordered_map<std::string, std::string> &argsMap,
41                                               const std::string &keyName, int32_t &bundleID)
42 {
43     if (argsMap.find(keyName) == argsMap.end()) {
44         return ERR_AOT_COMPILER_PARAM_FAILED;
45     }
46     if (argsMap.at(keyName).empty() || !isdigit(argsMap.at(keyName).at(0))) {
47         return ERR_AOT_COMPILER_PARAM_FAILED;
48     }
49     const char* beginPtr = argsMap.at(keyName).data();
50     const char* endPtr = argsMap.at(keyName).data() + argsMap.at(keyName).size();
51     auto res = std::from_chars(beginPtr, endPtr, bundleID);
52     if ((res.ec != std::errc()) || (res.ptr != endPtr)) {
53         LOG_SA(ERROR) << "trigger exception as converting string to integer";
54         return ERR_AOT_COMPILER_PARAM_FAILED;
55     }
56     return ERR_OK;
57 }
58 
FindArgsIdxToString(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,std::string & bundleArg)59 int32_t AotCompilerImpl::FindArgsIdxToString(const std::unordered_map<std::string, std::string> &argsMap,
60                                              const std::string &keyName, std::string &bundleArg)
61 {
62     if (argsMap.find(keyName) == argsMap.end()) {
63         return ERR_AOT_COMPILER_PARAM_FAILED;
64     }
65     bundleArg = argsMap.at(keyName);
66     return ERR_OK;
67 }
68 
PrepareArgs(const std::unordered_map<std::string,std::string> & argsMap)69 int32_t AotCompilerImpl::PrepareArgs(const std::unordered_map<std::string, std::string> &argsMap)
70 {
71     for (const auto &arg : argsMap) {
72         LOG_SA(DEBUG) << arg.first << ": " << arg.second;
73     }
74     std::lock_guard<std::mutex> lock(hapArgsMutex_);
75     std::string abcPath;
76     if ((FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_UID, hapArgs_.bundleUid) != ERR_OK)   ||
77         (FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_GID, hapArgs_.bundleGid) != ERR_OK)   ||
78         (FindArgsIdxToString(argsMap, ArgsIdx::AN_FILE_NAME, hapArgs_.fileName) != ERR_OK)   ||
79         (FindArgsIdxToString(argsMap, ArgsIdx::APP_SIGNATURE, hapArgs_.signature) != ERR_OK) ||
80         (FindArgsIdxToString(argsMap, ArgsIdx::ABC_PATH, abcPath) != ERR_OK)) {
81         LOG_SA(ERROR) << "aot compiler Args parsing error";
82         return ERR_AOT_COMPILER_PARAM_FAILED;
83     }
84     hapArgs_.argVector.clear();
85     hapArgs_.argVector.emplace_back(Cmds::ARK_AOT_COMPILER);
86     // service process add aot compile args here
87     AddExpandArgs(hapArgs_.argVector);
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 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
94     SetEnableCodeCommentBySysParam();
95     SetAnFileMaxSizeBySysParam();
96 #endif
97     hapArgs_.argVector.emplace_back(abcPath);
98     return ERR_OK;
99 }
100 
101 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
SetAnFileMaxSizeBySysParam()102 void AotCompilerImpl::SetAnFileMaxSizeBySysParam()
103 {
104     int anFileMaxSize = OHOS::system::GetIntParameter<int>("ark.aot.compiler_an_file_max_size", -1);
105     if (anFileMaxSize >= 0) {
106         hapArgs_.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_AN_FILE_MAX_SIZE + Symbols::EQ +
107                                         std::to_string(anFileMaxSize));
108     }
109 }
110 
SetEnableCodeCommentBySysParam()111 void AotCompilerImpl::SetEnableCodeCommentBySysParam()
112 {
113     bool enableAotCodeComment = OHOS::system::GetBoolParameter("ark.aot.code_comment.enable", false);
114     if (enableAotCodeComment) {
115         hapArgs_.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_ENABLE_AOT_CODE_COMMENT + Symbols::EQ +
116                                         "true");
117         hapArgs_.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_LOG_OPT + Symbols::EQ + "allasm");
118     }
119 }
120 #endif
121 
GetBundleId(int32_t & bundleUid,int32_t & bundleGid) const122 void AotCompilerImpl::GetBundleId(int32_t &bundleUid, int32_t &bundleGid) const
123 {
124     std::lock_guard<std::mutex> lock(hapArgsMutex_);
125     bundleUid = hapArgs_.bundleUid;
126     bundleGid = hapArgs_.bundleGid;
127 }
128 
DropCapabilities() const129 void AotCompilerImpl::DropCapabilities() const
130 {
131     LOG_SA(INFO) << "begin to drop capabilities";
132     int32_t bundleUid = 0;
133     int32_t bundleGid = 0;
134     GetBundleId(bundleUid, bundleGid);
135     if (setgid(bundleGid)) {
136         LOG_SA(ERROR) << "dropCapabilities setgid failed : " << strerror(errno);
137         exit(-1);
138     }
139     if (setuid(bundleUid)) {
140         LOG_SA(ERROR) << "dropCapabilities setuid failed : " << strerror(errno);
141         exit(-1);
142     }
143     struct __user_cap_header_struct capHeader;
144     if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) {
145         LOG_SA(ERROR) << "memset_s capHeader failed : " << strerror(errno);
146         exit(-1);
147     }
148     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
149     capHeader.pid = 0;
150     struct __user_cap_data_struct capData[2];
151     if (memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK) {
152         LOG_SA(ERROR) << "memset_s capData failed : " << strerror(errno);
153         exit(-1);
154     }
155     if (capset(&capHeader, capData) != 0) {
156         LOG_SA(ERROR) << "capset failed : " << strerror(errno);
157         exit(-1);
158     }
159     LOG_SA(INFO) << "drop capabilities success";
160 }
161 
GetAotArgsVector(std::vector<const char * > & argv) const162 void AotCompilerImpl::GetAotArgsVector(std::vector<const char*> &argv) const
163 {
164     std::lock_guard<std::mutex> lock(hapArgsMutex_);
165     const std::vector<std::string> &aotVector = hapArgs_.argVector;
166     argv.reserve(aotVector.size() + 1);
167     for (auto &arg : aotVector) {
168         argv.emplace_back(arg.c_str());
169     }
170 }
171 
ExecuteInChildProcess() const172 void AotCompilerImpl::ExecuteInChildProcess() const
173 {
174     std::vector<const char*> argv;
175     GetAotArgsVector(argv);
176     LOG_SA(INFO) << "ark_aot_compiler argv size : " << argv.size();
177     for (const auto &arg : argv) {
178         LOG_SA(INFO) << arg;
179     }
180     argv.emplace_back(nullptr);
181     LOG_SA(INFO) << "begin to execute ark_aot_compiler";
182     execv(argv[0], const_cast<char* const*>(argv.data()));
183     LOG_SA(ERROR) << "execv failed : " << strerror(errno);
184     exit(-1);
185 }
186 
AddExpandArgs(std::vector<std::string> & argVector)187 void AotCompilerImpl::AddExpandArgs(std::vector<std::string> &argVector)
188 {
189     std::string thermalLevelArg = "--compiler-thermal-level=" + std::to_string(thermalLevel_);
190     argVector.emplace_back(thermalLevelArg);
191 }
192 
PrintAOTCompilerResult(const int compilerStatus) const193 int32_t AotCompilerImpl::PrintAOTCompilerResult(const int compilerStatus) const
194 {
195     if (RetInfoOfCompiler.find(compilerStatus) == RetInfoOfCompiler.end()) {
196         LOG_SA(ERROR) << OtherInfoOfCompiler.mesg;
197         return OtherInfoOfCompiler.retCode;
198     }
199     if (RetInfoOfCompiler.at(compilerStatus).retCode == ERR_AOT_COMPILER_CALL_FAILED) {
200         LOG_SA(ERROR) << RetInfoOfCompiler.at(compilerStatus).mesg;
201     } else {
202         LOG_SA(INFO) << RetInfoOfCompiler.at(compilerStatus).mesg;
203     }
204     return RetInfoOfCompiler.at(compilerStatus).retCode;
205 }
206 
ExecuteInParentProcess(const pid_t childPid,int32_t & ret)207 void AotCompilerImpl::ExecuteInParentProcess(const pid_t childPid, int32_t &ret)
208 {
209     {
210         std::lock_guard<std::mutex> lock(stateMutex_);
211         InitState(childPid);
212     }
213     int status;
214     int waitRet = waitpid(childPid, &status, 0);
215     if (waitRet == -1) {
216         LOG_SA(ERROR) << "waitpid failed";
217         ret = ERR_AOT_COMPILER_CALL_FAILED;
218     } else if (WIFEXITED(status)) {
219         int exitStatus = WEXITSTATUS(status);
220         LOG_SA(INFO) << "child process exited with status: " << exitStatus;
221         ret = PrintAOTCompilerResult(exitStatus);
222     } else if (WIFSIGNALED(status)) {
223         int signalNumber = WTERMSIG(status);
224         LOG_SA(WARN) << "child process terminated by signal: " << signalNumber;
225         ret = signalNumber == SIGKILL ? ERR_AOT_COMPILER_CALL_CANCELLED : ERR_AOT_COMPILER_CALL_CRASH;
226     } else if (WIFSTOPPED(status)) {
227         int signalNumber = WSTOPSIG(status);
228         LOG_SA(WARN) << "child process was stopped by signal: " << signalNumber;
229         ret = ERR_AOT_COMPILER_CALL_FAILED;
230     } else if (WIFCONTINUED(status)) {
231         LOG_SA(WARN) << "child process was resumed";
232         ret = ERR_AOT_COMPILER_CALL_FAILED;
233     } else {
234         LOG_SA(WARN) << "unknown";
235         ret = ERR_AOT_COMPILER_CALL_FAILED;
236     }
237     {
238         std::lock_guard<std::mutex> lock(stateMutex_);
239         ResetState();
240     }
241 }
242 
VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string,std::string> & argsMap)243 bool AotCompilerImpl::VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string, std::string> &argsMap)
244 {
245     auto targetCompilerMode = argsMap.find(ArgsIdx::TARGET_COMPILER_MODE);
246     if (targetCompilerMode == argsMap.end() || targetCompilerMode->second.empty()) {
247         return false;
248     }
249     auto compilerPkgInfo = argsMap.find(ArgsIdx::COMPILER_PKG_INFO);
250     if (compilerPkgInfo == argsMap.end() || compilerPkgInfo->second.empty()) {
251         return false;
252     }
253     return true;
254 }
255 
EcmascriptAotCompiler(const std::unordered_map<std::string,std::string> & argsMap,std::vector<int16_t> & sigData)256 int32_t AotCompilerImpl::EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap,
257                                                std::vector<int16_t> &sigData)
258 {
259 #ifdef CODE_SIGN_ENABLE
260     if (!allowAotCompiler_) {
261         LOG_SA(ERROR) << "aot compiler is not allowed now";
262         return ERR_AOT_COMPILER_CALL_CANCELLED;
263     }
264     if (!VerifyCompilerModeAndPkgInfo(argsMap)) {
265         LOG_SA(ERROR) << "aot compiler mode or pkginfo arguments error";
266         return ERR_AOT_COMPILER_PARAM_FAILED;
267     }
268     if (argsMap.empty() || (PrepareArgs(argsMap) != ERR_OK)) {
269         LOG_SA(ERROR) << "aot compiler arguments error";
270         return ERR_AOT_COMPILER_PARAM_FAILED;
271     }
272     int32_t ret = ERR_OK;
273     LOG_SA(INFO) << "begin to fork";
274     pid_t pid = fork();
275     if (pid == -1) {
276         LOG_SA(ERROR) << "fork process failed : " << strerror(errno);
277         return ERR_AOT_COMPILER_CALL_FAILED;
278     } else if (pid == 0) {
279         DropCapabilities();
280         ExecuteInChildProcess();
281     } else {
282         ExecuteInParentProcess(pid, ret);
283     }
284     if (ret == ERR_OK_NO_AOT_FILE) {
285         return ERR_OK;
286     }
287     return ret != ERR_OK ? ret : AOTLocalCodeSign(sigData);
288 #else
289     LOG_SA(ERROR) << "no need to AOT compile when code signature disable";
290     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
291 #endif
292 }
293 
GetAOTVersion(std::string & sigData)294 int32_t AotCompilerImpl::GetAOTVersion(std::string& sigData)
295 {
296     LOG_SA(INFO) << "AotCompilerImpl::GetAOTVersion";
297     sigData = panda::ecmascript::AOTFileVersion::GetAOTVersion();
298 
299     return ERR_OK;
300 }
301 
NeedReCompile(const std::string & args,bool & sigData)302 int32_t AotCompilerImpl::NeedReCompile(const std::string& args, bool& sigData)
303 {
304     LOG_SA(INFO) << "AotCompilerImpl::NeedReCompile";
305     sigData = panda::ecmascript::AOTFileVersion::CheckAOTVersion(args);
306     return ERR_OK;
307 }
308 
GetCodeSignArgs(std::string & appSignature,std::string & fileName) const309 void AotCompilerImpl::GetCodeSignArgs(std::string &appSignature, std::string &fileName) const
310 {
311     std::lock_guard<std::mutex> lock(hapArgsMutex_);
312     appSignature = hapArgs_.signature;
313     fileName = hapArgs_.fileName;
314 }
315 
AOTLocalCodeSign(std::vector<int16_t> & sigData) const316 int32_t AotCompilerImpl::AOTLocalCodeSign(std::vector<int16_t> &sigData) const
317 {
318 #ifdef CODE_SIGN_ENABLE
319     std::string appSignature;
320     std::string fileName;
321     GetCodeSignArgs(appSignature, fileName);
322     Security::CodeSign::ByteBuffer sig;
323     if (Security::CodeSign::LocalCodeSignKit::SignLocalCode(appSignature, fileName, sig)
324                         != CommonErrCode::CS_SUCCESS) {
325         LOG_SA(ERROR) << "failed to sign the aot file";
326         return ERR_AOT_COMPILER_SIGNATURE_FAILED;
327     }
328     LOG_SA(DEBUG) << "aot file local sign success";
329     uint8_t *dataPtr = sig.GetBuffer();
330     for (uint32_t i = 0; i < sig.GetSize(); ++i) {
331         sigData.emplace_back(static_cast<int16_t>(dataPtr[i]));
332     }
333     return ERR_OK;
334 #else
335     LOG_SA(ERROR) << "no need to AOT local code sign when code signature disable";
336     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
337 #endif
338 }
339 
StopAotCompiler()340 int32_t AotCompilerImpl::StopAotCompiler()
341 {
342     LOG_SA(INFO) << "begin to stop AOT";
343     std::lock_guard<std::mutex> lock(stateMutex_);
344     if (!state_.running) {
345         LOG_SA(INFO) << "AOT not running, return directly";
346         return ERR_AOT_COMPILER_STOP_FAILED;
347     }
348     if (state_.childPid <= 0) {
349         LOG_SA(ERROR) << "invalid child pid";
350         return ERR_AOT_COMPILER_STOP_FAILED;
351     }
352     LOG_SA(INFO) << "begin to kill child process : " << state_.childPid;
353     auto result = kill(state_.childPid, SIGKILL);
354     int32_t ret = RemoveAotFiles();
355     if (result != 0) {
356         LOG_SA(INFO) << "kill child process failed: " << result;
357         ret = ERR_AOT_COMPILER_STOP_FAILED;
358     } else {
359         LOG_SA(INFO) << "kill child process success";
360     }
361     ResetState();
362     return ret;
363 }
364 
RemoveAotFiles() const365 int32_t AotCompilerImpl::RemoveAotFiles() const
366 {
367     std::lock_guard<std::mutex> lock(hapArgsMutex_);
368     if (access(hapArgs_.fileName.c_str(), ERR_OK) != ERR_FAIL) {
369         auto delRes = std::remove(hapArgs_.fileName.c_str());
370         if (delRes != ERR_OK) {
371             LOG_SA(INFO) << "delete invalid aot file failed: " << delRes;
372             return ERR_AOT_COMPILER_STOP_FAILED;
373         } else {
374             LOG_SA(INFO) << "delete invalid aot file success";
375         }
376     }
377     return ERR_OK;
378 }
379 
HandlePowerDisconnected()380 void AotCompilerImpl::HandlePowerDisconnected()
381 {
382     LOG_SA(INFO) << "AotCompilerImpl::HandlePowerDisconnected";
383     PauseAotCompiler();
384     std::thread t([]() {
385         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
386         sleep(30);  // wait for 30 seconds
387         AotCompilerImpl::GetInstance().AllowAotCompiler();
388     });
389     if (t.joinable()) {
390         t.detach();
391     } else {
392         LOG_SA(ERROR) << "Failed to create thread for AotCompilerImpl::HandlePowerDisconnected";
393     }
394 }
395 
HandleScreenOn()396 void AotCompilerImpl::HandleScreenOn()
397 {
398     LOG_SA(INFO) << "AotCompilerImpl::HandleScreenOn";
399     PauseAotCompiler();
400     std::thread t([]() {
401         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
402         sleep(40);  // wait for 40 seconds
403         AotCompilerImpl::GetInstance().AllowAotCompiler();
404     });
405     if (t.joinable()) {
406         t.detach();
407     } else {
408         LOG_SA(ERROR) << "Failed to create thread for AotCompilerImpl::HandleScreenOn";
409     }
410 }
411 
HandleThermalLevelChanged(const int32_t level)412 void AotCompilerImpl::HandleThermalLevelChanged(const int32_t level)
413 {
414     LOG_SA(INFO) << "AotCompilerImpl::HandleThermalLevelChanged";
415     thermalLevel_ = level;
416     // thermal level >= 2, stop aot compile
417     if (thermalLevel_ >= AOT_COMPILE_STOP_LEVEL) {
418         PauseAotCompiler();
419     } else {
420         AllowAotCompiler();
421     }
422 }
423 
PauseAotCompiler()424 void AotCompilerImpl::PauseAotCompiler()
425 {
426     LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
427     allowAotCompiler_ = false;
428 }
429 
AllowAotCompiler()430 void AotCompilerImpl::AllowAotCompiler()
431 {
432     LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
433     allowAotCompiler_ = true;
434 }
435 
InitState(const pid_t childPid)436 void AotCompilerImpl::InitState(const pid_t childPid)
437 {
438     state_.running = true;
439     state_.childPid = childPid;
440 }
441 
ResetState()442 void AotCompilerImpl::ResetState()
443 {
444     state_.running = false;
445     state_.childPid = -1;
446 }
447 } // namespace OHOS::ArkCompiler