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