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 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 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
FindArgsIdxToString(const std::unordered_map<std::string, std::string> &argsMap, const std::string &keyName, std::string &bundleArg)65 int32_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
PrepareArgs(const std::unordered_map<std::string, std::string> &argsMap)75 int32_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
GetBundleId(int32_t &bundleUid, int32_t &bundleGid) const103 void 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
DropCapabilities() const110 void 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
GetAotArgsVector(std::vector<const char*> &argv) const143 void 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
ExecuteInChildProcess() const153 void 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
AddExpandArgs(std::vector<std::string> &argVector)168 void 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
PrintAOTCompilerResult(const int compilerStatus) const174 int32_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
ExecuteInParentProcess(const pid_t childPid, int32_t &ret)188 void 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
EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap, std::vector<int16_t> &sigData)224 int32_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
GetAOTVersion(std::string& sigData)258 int32_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
NeedReCompile(const std::string& args, bool& sigData)266 int32_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
GetCodeSignArgs(std::string &appSignature, std::string &fileName) const273 void 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
AOTLocalCodeSign(std::vector<int16_t> &sigData) const280 int32_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
StopAotCompiler()304 int32_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
RemoveAotFiles() const329 int32_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
HandlePowerDisconnected()344 void 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
HandleScreenOn()355 void 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
HandleThermalLevelChanged(const int32_t level)366 void 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
PauseAotCompiler()378 void AotCompilerImpl::PauseAotCompiler()
379 {
380 LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
381 allowAotCompiler_ = false;
382 }
383
AllowAotCompiler()384 void AotCompilerImpl::AllowAotCompiler()
385 {
386 LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
387 allowAotCompiler_ = true;
388 }
389
InitState(const pid_t childPid)390 void AotCompilerImpl::InitState(const pid_t childPid)
391 {
392 state_.running = true;
393 state_.childPid = childPid;
394 }
395
ResetState()396 void AotCompilerImpl::ResetState()
397 {
398 state_.running = false;
399 state_.childPid = -1;
400 }
401 } // namespace OHOS::ArkCompiler