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