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