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