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 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 hapArgs.argVector.emplace_back(abcPath);
94 return ERR_OK;
95 }
96
DropCapabilities(const int32_t & bundleUid,const int32_t & bundleGid) const97 void AotCompilerImpl::DropCapabilities(const int32_t &bundleUid, const int32_t &bundleGid) const
98 {
99 LOG_SA(INFO) << "begin to drop capabilities";
100 if (setuid(bundleUid)) {
101 LOG_SA(ERROR) << "dropCapabilities setuid failed : " << strerror(errno);
102 exit(-1);
103 }
104 if (setgid(bundleGid)) {
105 LOG_SA(ERROR) << "dropCapabilities setgid failed : " << strerror(errno);
106 exit(-1);
107 }
108 struct __user_cap_header_struct capHeader;
109 if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) {
110 LOG_SA(ERROR) << "memset_s capHeader failed : " << strerror(errno);
111 exit(-1);
112 }
113 capHeader.version = _LINUX_CAPABILITY_VERSION_3;
114 capHeader.pid = 0;
115
116 struct __user_cap_data_struct capData[2];
117 if (memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK) {
118 LOG_SA(ERROR) << "memset_s capData failed : " << strerror(errno);
119 exit(-1);
120 }
121 if (capset(&capHeader, capData) != 0) {
122 LOG_SA(ERROR) << "capset failed : " << strerror(errno);
123 exit(-1);
124 }
125 LOG_SA(INFO) << "drop capabilities success";
126 }
127
ExecuteInChildProcess(const std::vector<std::string> & aotVector) const128 void AotCompilerImpl::ExecuteInChildProcess(const std::vector<std::string> &aotVector) const
129 {
130 std::vector<const char*> argv;
131 argv.reserve(aotVector.size() + 1);
132 for (auto &arg : aotVector) {
133 argv.emplace_back(arg.c_str());
134 }
135 LOG_SA(INFO) << "ark_aot_compiler argv size : " << argv.size();
136 for (const auto &arg : argv) {
137 LOG_SA(INFO) << arg;
138 }
139 argv.emplace_back(nullptr);
140 LOG_SA(INFO) << "begin to execute ark_aot_compiler";
141 execv(argv[0], const_cast<char* const*>(argv.data()));
142 LOG_SA(ERROR) << "execv failed : " << strerror(errno);
143 exit(-1);
144 }
145
PrintAOTCompilerResult(const int compilerStatus)146 int32_t AotCompilerImpl::PrintAOTCompilerResult(const int compilerStatus)
147 {
148 if (RetInfoOfCompiler.find(compilerStatus) == RetInfoOfCompiler.end()) {
149 LOG_SA(ERROR) << OtherInfoOfCompiler.mesg;
150 return OtherInfoOfCompiler.retCode;
151 }
152 if (RetInfoOfCompiler.at(compilerStatus).retCode == ERR_AOT_COMPILER_CALL_FAILED) {
153 LOG_SA(ERROR) << RetInfoOfCompiler.at(compilerStatus).mesg;
154 } else {
155 LOG_SA(INFO) << RetInfoOfCompiler.at(compilerStatus).mesg;
156 }
157 return RetInfoOfCompiler.at(compilerStatus).retCode;
158 }
159
ExecuteInParentProcess(const pid_t childPid,int32_t & ret)160 void AotCompilerImpl::ExecuteInParentProcess(const pid_t childPid, int32_t &ret)
161 {
162 {
163 std::lock_guard<std::mutex> lock(stateMutex_);
164 InitState(childPid);
165 }
166 int status;
167 int waitRet = waitpid(childPid, &status, 0);
168 if (waitRet == -1) {
169 LOG_SA(ERROR) << "waitpid failed";
170 ret = ERR_AOT_COMPILER_CALL_FAILED;
171 } else if (WIFEXITED(status)) {
172 int exitStatus = WEXITSTATUS(status);
173 LOG_SA(INFO) << "child process exited with status: " << exitStatus;
174 ret = PrintAOTCompilerResult(exitStatus);
175 } else if (WIFSIGNALED(status)) {
176 int signalNumber = WTERMSIG(status);
177 LOG_SA(WARN) << "child process terminated by signal: " << signalNumber;
178 ret = signalNumber == SIGKILL ? ERR_AOT_COMPILER_CALL_CANCELLED : ERR_AOT_COMPILER_CALL_CRASH;
179 } else if (WIFSTOPPED(status)) {
180 int signalNumber = WSTOPSIG(status);
181 LOG_SA(WARN) << "child process was stopped by signal: " << signalNumber;
182 ret = ERR_AOT_COMPILER_CALL_FAILED;
183 } else if (WIFCONTINUED(status)) {
184 LOG_SA(WARN) << "child process was resumed";
185 ret = ERR_AOT_COMPILER_CALL_FAILED;
186 } else {
187 LOG_SA(WARN) << "unknown";
188 ret = ERR_AOT_COMPILER_CALL_FAILED;
189 }
190 {
191 std::lock_guard<std::mutex> lock(stateMutex_);
192 ResetState();
193 }
194 }
195
VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string,std::string> & argsMap)196 bool AotCompilerImpl::VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string, std::string> &argsMap)
197 {
198 auto targetCompilerMode = argsMap.find(ArgsIdx::TARGET_COMPILER_MODE);
199 if (targetCompilerMode == argsMap.end() || targetCompilerMode->second.empty()) {
200 return false;
201 }
202 auto compilerPkgInfo = argsMap.find(ArgsIdx::COMPILER_PKG_INFO);
203 if (compilerPkgInfo == argsMap.end() || compilerPkgInfo->second.empty()) {
204 return false;
205 }
206 return true;
207 }
208
EcmascriptAotCompiler(const std::unordered_map<std::string,std::string> & argsMap,std::vector<int16_t> & sigData)209 int32_t AotCompilerImpl::EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap,
210 std::vector<int16_t> &sigData)
211 {
212 #ifdef CODE_SIGN_ENABLE
213 if (!allowAotCompiler_) {
214 return ERR_AOT_COMPILER_CONNECT_FAILED;
215 }
216 std::lock_guard<std::mutex> lock(mutex_);
217 if (!VerifyCompilerModeAndPkgInfo(argsMap)) {
218 LOG_SA(ERROR) << "aot compiler mode or pkginfo arguments error";
219 return ERR_AOT_COMPILER_PARAM_FAILED;
220 }
221 if (argsMap.empty() || (PrepareArgs(argsMap) != ERR_OK)) {
222 LOG_SA(ERROR) << "aot compiler arguments error";
223 return ERR_AOT_COMPILER_PARAM_FAILED;
224 }
225 int32_t ret = ERR_OK;
226 LOG_SA(INFO) << "begin to fork";
227 pid_t pid = fork();
228 if (pid == -1) {
229 LOG_SA(ERROR) << "fork process failed : " << strerror(errno);
230 return ERR_AOT_COMPILER_CALL_FAILED;
231 } else if (pid == 0) {
232 DropCapabilities(hapArgs.bundleUid, hapArgs.bundleGid);
233 ExecuteInChildProcess(hapArgs.argVector);
234 } else {
235 ExecuteInParentProcess(pid, ret);
236 }
237 if (ret == ERR_OK_NO_AOT_FILE) {
238 return ERR_OK;
239 }
240 return ret ? ret : AOTLocalCodeSign(hapArgs.fileName, hapArgs.signature, sigData);
241 #else
242 LOG_SA(ERROR) << "no need to AOT compile when code signature disable";
243 return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
244 #endif
245 }
246
GetAOTVersion(std::string & sigData)247 int32_t AotCompilerImpl::GetAOTVersion(std::string& sigData)
248 {
249 LOG_SA(INFO) << "AotCompilerImpl::GetAOTVersion";
250 sigData = panda::ecmascript::AOTFileVersion::GetAOTVersion();
251
252 return ERR_OK;
253 }
254
NeedReCompile(const std::string & args,bool & sigData)255 int32_t AotCompilerImpl::NeedReCompile(const std::string& args, bool& sigData)
256 {
257 LOG_SA(INFO) << "AotCompilerImpl::NeedReCompile";
258 sigData = panda::ecmascript::AOTFileVersion::CheckAOTVersion(args);
259 return ERR_OK;
260 }
261
AOTLocalCodeSign(const std::string & fileName,const std::string & appSignature,std::vector<int16_t> & sigData)262 int32_t AotCompilerImpl::AOTLocalCodeSign(const std::string &fileName, const std::string &appSignature,
263 std::vector<int16_t> &sigData)
264 {
265 #ifdef CODE_SIGN_ENABLE
266 Security::CodeSign::ByteBuffer sig;
267 if (Security::CodeSign::LocalCodeSignKit::SignLocalCode(appSignature, fileName, sig)
268 != CommonErrCode::CS_SUCCESS) {
269 LOG_SA(ERROR) << "failed to sign the aot file";
270 return ERR_AOT_COMPILER_SIGNATURE_FAILED;
271 }
272 LOG_SA(DEBUG) << "aot file local sign success";
273 uint8_t *dataPtr = sig.GetBuffer();
274 for (uint32_t i = 0; i < sig.GetSize(); ++i) {
275 sigData.emplace_back(static_cast<int16_t>(dataPtr[i]));
276 }
277 return ERR_OK;
278 #else
279 LOG_SA(ERROR) << "no need to AOT local code sign when code signature disable";
280 return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
281 #endif
282 }
283
StopAotCompiler()284 int32_t AotCompilerImpl::StopAotCompiler()
285 {
286 LOG_SA(INFO) << "begin to stop AOT";
287 std::lock_guard<std::mutex> lock(stateMutex_);
288 if (!state_.running) {
289 LOG_SA(INFO) << "AOT not running, return directly";
290 return ERR_AOT_COMPILER_STOP_FAILED;
291 }
292 if (state_.childPid <= 0) {
293 LOG_SA(ERROR) << "invalid child pid";
294 return ERR_AOT_COMPILER_STOP_FAILED;
295 }
296 LOG_SA(INFO) << "begin to kill child process : " << state_.childPid;
297 auto result = kill(state_.childPid, SIGKILL);
298 int32_t ret = ERR_OK;
299 if (result != 0) {
300 LOG_SA(INFO) << "kill child process failed: " << result;
301 ret = ERR_AOT_COMPILER_STOP_FAILED;
302 } else {
303 LOG_SA(INFO) << "kill child process success";
304 }
305 ResetState();
306 return ret;
307 }
308
HandlePowerDisconnected()309 void AotCompilerImpl::HandlePowerDisconnected()
310 {
311 LOG_SA(INFO) << "AotCompilerImpl::HandlePowerDisconnected";
312 PauseAotCompiler();
313 std::thread([]() {
314 (void)AotCompilerImpl::GetInstance().StopAotCompiler();
315 sleep(30); // wait for 30 seconds
316 AotCompilerImpl::GetInstance().AllowAotCompiler();
317 }).detach();
318 }
319
HandleScreenOn()320 void AotCompilerImpl::HandleScreenOn()
321 {
322 LOG_SA(INFO) << "AotCompilerImpl::HandleScreenOn";
323 PauseAotCompiler();
324 std::thread([]() {
325 (void)AotCompilerImpl::GetInstance().StopAotCompiler();
326 sleep(40); // wait for 40 seconds
327 AotCompilerImpl::GetInstance().AllowAotCompiler();
328 }).detach();
329 }
330
PauseAotCompiler()331 void AotCompilerImpl::PauseAotCompiler()
332 {
333 LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
334 allowAotCompiler_ = false;
335 }
336
AllowAotCompiler()337 void AotCompilerImpl::AllowAotCompiler()
338 {
339 LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
340 allowAotCompiler_ = true;
341 }
342
InitState(const pid_t childPid)343 void AotCompilerImpl::InitState(const pid_t childPid)
344 {
345 state_.running = true;
346 state_.childPid = childPid;
347 }
348
ResetState()349 void AotCompilerImpl::ResetState()
350 {
351 state_.running = false;
352 state_.childPid = -1;
353 }
354 } // namespace OHOS::ArkCompiler