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