• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <charconv>
19 #include <sys/capability.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <thread>
23 
24 #include "aot_compiler_constants.h"
25 #include "ecmascript/log_wrapper.h"
26 #ifdef CODE_SIGN_ENABLE
27 #include "local_code_sign_kit.h"
28 #endif
29 #ifdef ENABLE_HISYSEVENT
30 #include "ecmascript/compiler/aot_compiler_stats.h"
31 #endif
32 
33 namespace OHOS::ArkCompiler {
GetInstance()34 AotCompilerImpl& AotCompilerImpl::GetInstance()
35 {
36     static AotCompilerImpl aotCompiler;
37     return aotCompiler;
38 }
39 
DropCapabilities() const40 void AotCompilerImpl::DropCapabilities() const
41 {
42     LOG_SA(INFO) << "begin to drop capabilities";
43     int32_t bundleUid = 0;
44     int32_t bundleGid = 0;
45     argsHandler_->GetBundleId(bundleUid, bundleGid);
46     if (setgid(bundleGid)) {
47         LOG_SA(ERROR) << "dropCapabilities setgid failed : " << strerror(errno);
48         exit(-1);
49     }
50     if (setuid(bundleUid)) {
51         LOG_SA(ERROR) << "dropCapabilities setuid failed : " << strerror(errno);
52         exit(-1);
53     }
54     struct __user_cap_header_struct capHeader;
55     if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) {
56         LOG_SA(ERROR) << "memset_s capHeader failed : " << strerror(errno);
57         exit(-1);
58     }
59     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
60     capHeader.pid = 0;
61     struct __user_cap_data_struct capData[2];
62     if (memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK) {
63         LOG_SA(ERROR) << "memset_s capData failed : " << strerror(errno);
64         exit(-1);
65     }
66     if (capset(&capHeader, capData) != 0) {
67         LOG_SA(ERROR) << "capset failed : " << strerror(errno);
68         exit(-1);
69     }
70     LOG_SA(INFO) << "drop capabilities success";
71 }
ExecuteInChildProcess() const72 void AotCompilerImpl::ExecuteInChildProcess() const
73 {
74     std::vector<const char*> argv = argsHandler_->GetAotArgs();
75     LOG_SA(INFO) << "ark_aot_compiler argv size : " << argv.size();
76     for (const auto &arg : argv) {
77         LOG_SA(INFO) << arg;
78     }
79     argv.emplace_back(nullptr);
80     LOG_SA(INFO) << "begin to execute ark_aot_compiler";
81     execv(argv[0], const_cast<char* const*>(argv.data()));
82     LOG_SA(ERROR) << "execv failed : " << strerror(errno);
83     exit(-1);
84 }
85 
PrintAOTCompilerResult(const int compilerStatus) const86 int32_t AotCompilerImpl::PrintAOTCompilerResult(const int compilerStatus) const
87 {
88     if (RetInfoOfCompiler.find(compilerStatus) == RetInfoOfCompiler.end()) {
89         LOG_SA(ERROR) << OtherInfoOfCompiler.mesg;
90         return OtherInfoOfCompiler.retCode;
91     }
92     if (RetInfoOfCompiler.at(compilerStatus).retCode == ERR_AOT_COMPILER_CALL_FAILED) {
93         LOG_SA(ERROR) << RetInfoOfCompiler.at(compilerStatus).mesg;
94     } else {
95         LOG_SA(INFO) << RetInfoOfCompiler.at(compilerStatus).mesg;
96     }
97     return RetInfoOfCompiler.at(compilerStatus).retCode;
98 }
99 
ExecuteInParentProcess(const pid_t childPid,int32_t & ret)100 void AotCompilerImpl::ExecuteInParentProcess(const pid_t childPid, int32_t &ret)
101 {
102     {
103         std::lock_guard<std::mutex> lock(stateMutex_);
104         InitState(childPid);
105     }
106     int status;
107     int waitRet = waitpid(childPid, &status, 0);
108     if (waitRet == -1) {
109         LOG_SA(ERROR) << "waitpid failed";
110         ret = ERR_AOT_COMPILER_CALL_FAILED;
111     } else if (WIFEXITED(status)) {
112         int exitStatus = WEXITSTATUS(status);
113         LOG_SA(INFO) << "child process exited with status: " << exitStatus;
114         ret = PrintAOTCompilerResult(exitStatus);
115     } else if (WIFSIGNALED(status)) {
116         int signalNumber = WTERMSIG(status);
117         LOG_SA(WARN) << "child process terminated by signal: " << signalNumber;
118         ret = signalNumber == SIGKILL ? ERR_AOT_COMPILER_CALL_CANCELLED : ERR_AOT_COMPILER_CALL_CRASH;
119     } else if (WIFSTOPPED(status)) {
120         int signalNumber = WSTOPSIG(status);
121         LOG_SA(WARN) << "child process was stopped by signal: " << signalNumber;
122         ret = ERR_AOT_COMPILER_CALL_FAILED;
123     } else if (WIFCONTINUED(status)) {
124         LOG_SA(WARN) << "child process was resumed";
125         ret = ERR_AOT_COMPILER_CALL_FAILED;
126     } else {
127         LOG_SA(WARN) << "unknown";
128         ret = ERR_AOT_COMPILER_CALL_FAILED;
129     }
130     {
131         std::lock_guard<std::mutex> lock(stateMutex_);
132         ResetState();
133     }
134 }
135 
IsSystemComponent(const std::unordered_map<std::string,std::string> & argsMap)136 bool AotCompilerImpl::IsSystemComponent(const std::unordered_map<std::string, std::string> &argsMap)
137 {
138     auto isSystemComponent = argsMap.find(ArgsIdx::IS_SYSTEM_COMPONENT);
139     if (isSystemComponent != argsMap.end() && isSystemComponent->second != BOOLEAN_FALSE) {
140         return true;
141     }
142     return false;
143 }
144 
VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string,std::string> & argsMap)145 bool AotCompilerImpl::VerifyCompilerModeAndPkgInfo(const std::unordered_map<std::string, std::string> &argsMap)
146 {
147     auto targetCompilerMode = argsMap.find(ArgsIdx::TARGET_COMPILER_MODE);
148     if (targetCompilerMode == argsMap.end() || targetCompilerMode->second.empty()) {
149         return false;
150     }
151     auto compilerPkgInfo = argsMap.find(ArgsIdx::COMPILER_PKG_INFO);
152     if (compilerPkgInfo == argsMap.end() || compilerPkgInfo->second.empty()) {
153         return false;
154     }
155     return true;
156 }
157 
EcmascriptAotCompiler(const std::unordered_map<std::string,std::string> & argsMap,std::vector<int16_t> & sigData)158 int32_t AotCompilerImpl::EcmascriptAotCompiler(const std::unordered_map<std::string, std::string> &argsMap,
159                                                std::vector<int16_t> &sigData)
160 {
161 #ifdef CODE_SIGN_ENABLE
162     if (!allowAotCompiler_) {
163         LOG_SA(ERROR) << "aot compiler is not allowed now";
164         return ERR_AOT_COMPILER_CALL_CANCELLED;
165     }
166     if (!VerifyCompilerModeAndPkgInfo(argsMap) && !IsSystemComponent(argsMap)) {
167         LOG_SA(ERROR) << "aot compiler mode or pkginfo arguments error";
168         return ERR_AOT_COMPILER_PARAM_FAILED;
169     }
170 
171     argsHandler_ = std::make_unique<AOTArgsHandler>(argsMap);
172     if (argsHandler_->Handle(thermalLevel_) != ERR_OK) {
173         return ERR_AOT_COMPILER_PARAM_FAILED;
174     }
175 
176     int32_t ret = ERR_OK;
177     LOG_SA(INFO) << "begin to fork";
178     pid_t pid = fork();
179     if (pid == -1) {
180         LOG_SA(ERROR) << "fork process failed : " << strerror(errno);
181         return ERR_AOT_COMPILER_CALL_FAILED;
182     } else if (pid == 0) {
183         DropCapabilities();
184         ExecuteInChildProcess();
185     } else {
186         ExecuteInParentProcess(pid, ret);
187     }
188     if (ret == ERR_OK_NO_AOT_FILE) {
189         return ERR_OK;
190     }
191     SendSysEvent(argsMap);
192     return ret != ERR_OK ? ret : AOTLocalCodeSign(sigData);
193 #else
194     LOG_SA(ERROR) << "no need to AOT compile when code signature disable";
195     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
196 #endif
197 }
198 
SendSysEvent(const std::unordered_map<std::string,std::string> & argsMap) const199 int32_t AotCompilerImpl::SendSysEvent(const std::unordered_map<std::string, std::string> &argsMap) const
200 {
201 #ifdef ENABLE_HISYSEVENT
202     panda::ecmascript::AotCompilerStats aotCompilerStats;
203     return aotCompilerStats.SendDataPartitionSysEvent(ParseArkCacheFromArgs(argsMap));
204 #endif
205     return 0;
206 }
207 
ParseArkCacheFromArgs(const std::unordered_map<std::string,std::string> & argsMap) const208 std::string AotCompilerImpl::ParseArkCacheFromArgs(const std::unordered_map<std::string, std::string> &argsMap) const
209 {
210     if (argsMap.find(ArgsIdx::AOT_FILE) == argsMap.end()) {
211         LOG_SA(ERROR) << "aot compiler SendSysEvent parsing an or ap path error";
212         return "";
213     }
214     std::string aotFile = argsMap.at(ArgsIdx::AOT_FILE);
215     auto index = aotFile.find_last_of('/');
216     if (index == std::string::npos) {
217         LOG_SA(ERROR) << "ark-cache path find / error";
218         return "";
219     }
220     return aotFile.substr(0, index);
221 }
222 
GetAOTVersion(std::string & sigData)223 int32_t AotCompilerImpl::GetAOTVersion(std::string& sigData)
224 {
225     LOG_SA(INFO) << "AotCompilerImpl::GetAOTVersion";
226     sigData = panda::ecmascript::AOTFileVersion::GetAOTVersion();
227 
228     return ERR_OK;
229 }
230 
NeedReCompile(const std::string & args,bool & sigData)231 int32_t AotCompilerImpl::NeedReCompile(const std::string& args, bool& sigData)
232 {
233     LOG_SA(INFO) << "AotCompilerImpl::NeedReCompile";
234     sigData = panda::ecmascript::AOTFileVersion::CheckAOTVersion(args);
235     return ERR_OK;
236 }
237 
AOTLocalCodeSign(std::vector<int16_t> & sigData) const238 int32_t AotCompilerImpl::AOTLocalCodeSign(std::vector<int16_t> &sigData) const
239 {
240 #ifdef CODE_SIGN_ENABLE
241     std::string appSignature = argsHandler_->GetCodeSignArgs();
242     std::string fileName = argsHandler_->GetFileName();
243     Security::CodeSign::ByteBuffer sig;
244     if (Security::CodeSign::LocalCodeSignKit::SignLocalCode(appSignature, fileName, sig)
245                         != CommonErrCode::CS_SUCCESS) {
246         LOG_SA(ERROR) << "failed to sign the aot file";
247         return ERR_AOT_COMPILER_SIGNATURE_FAILED;
248     }
249     LOG_SA(INFO) << "aot file local sign success";
250     uint8_t *dataPtr = sig.GetBuffer();
251     for (uint32_t i = 0; i < sig.GetSize(); ++i) {
252         sigData.emplace_back(static_cast<int16_t>(dataPtr[i]));
253     }
254     return ERR_OK;
255 #else
256     LOG_SA(ERROR) << "no need to AOT local code sign when code signature disable";
257     return ERR_AOT_COMPILER_SIGNATURE_DISABLE;
258 #endif
259 }
260 
StopAotCompiler()261 int32_t AotCompilerImpl::StopAotCompiler()
262 {
263     LOG_SA(INFO) << "begin to stop AOT";
264     std::lock_guard<std::mutex> lock(stateMutex_);
265     if (!state_.running) {
266         LOG_SA(INFO) << "AOT not running, return directly";
267         return ERR_AOT_COMPILER_STOP_FAILED;
268     }
269     if (state_.childPid <= 0) {
270         LOG_SA(ERROR) << "invalid child pid";
271         return ERR_AOT_COMPILER_STOP_FAILED;
272     }
273     LOG_SA(INFO) << "begin to kill child process : " << state_.childPid;
274     auto result = kill(state_.childPid, SIGKILL);
275     int32_t ret = RemoveAotFiles();
276     if (result != 0) {
277         LOG_SA(INFO) << "kill child process failed: " << result;
278         ret = ERR_AOT_COMPILER_STOP_FAILED;
279     } else {
280         LOG_SA(INFO) << "kill child process success";
281     }
282     ResetState();
283     return ret;
284 }
285 
RemoveAotFiles() const286 int32_t AotCompilerImpl::RemoveAotFiles() const
287 {
288     std::string fileName = argsHandler_->GetFileName();
289     if (access(fileName.c_str(), ERR_OK) != ERR_FAIL) {
290         auto delRes = std::remove(fileName.c_str());
291         if (delRes != ERR_OK) {
292             LOG_SA(INFO) << "delete invalid aot file failed: " << delRes;
293             return ERR_AOT_COMPILER_STOP_FAILED;
294         } else {
295             LOG_SA(INFO) << "delete invalid aot file success";
296         }
297     }
298     return ERR_OK;
299 }
300 
HandlePowerDisconnected()301 void AotCompilerImpl::HandlePowerDisconnected()
302 {
303     LOG_SA(INFO) << "AotCompilerImpl::HandlePowerDisconnected";
304     PauseAotCompiler();
305     std::thread t([]() {
306         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
307         sleep(30);  // wait for 30 seconds
308         AotCompilerImpl::GetInstance().AllowAotCompiler();
309     });
310     if (t.joinable()) {
311         t.detach();
312     } else {
313         LOG_SA(ERROR) << "Failed to create thread for AotCompilerImpl::HandlePowerDisconnected";
314     }
315 }
316 
HandleScreenOn()317 void AotCompilerImpl::HandleScreenOn()
318 {
319     LOG_SA(INFO) << "AotCompilerImpl::HandleScreenOn";
320     PauseAotCompiler();
321     std::thread t([]() {
322         (void)AotCompilerImpl::GetInstance().StopAotCompiler();
323         sleep(40);  // wait for 40 seconds
324         AotCompilerImpl::GetInstance().AllowAotCompiler();
325     });
326     if (t.joinable()) {
327         t.detach();
328     } else {
329         LOG_SA(ERROR) << "Failed to create thread for AotCompilerImpl::HandleScreenOn";
330     }
331 }
332 
HandleThermalLevelChanged(const int32_t level)333 void AotCompilerImpl::HandleThermalLevelChanged(const int32_t level)
334 {
335     LOG_SA(INFO) << "AotCompilerImpl::HandleThermalLevelChanged";
336     thermalLevel_ = level;
337     // thermal level >= 2, stop aot compile
338     if (thermalLevel_ >= AOT_COMPILE_STOP_LEVEL) {
339         PauseAotCompiler();
340     } else {
341         AllowAotCompiler();
342     }
343 }
344 
PauseAotCompiler()345 void AotCompilerImpl::PauseAotCompiler()
346 {
347     LOG_SA(INFO) << "AotCompilerImpl::PauseAotCompiler";
348     allowAotCompiler_ = false;
349 }
350 
AllowAotCompiler()351 void AotCompilerImpl::AllowAotCompiler()
352 {
353     LOG_SA(INFO) << "AotCompilerImpl::AllowAotCompiler";
354     allowAotCompiler_ = true;
355 }
356 
InitState(const pid_t childPid)357 void AotCompilerImpl::InitState(const pid_t childPid)
358 {
359     state_.running = true;
360     state_.childPid = childPid;
361 }
362 
ResetState()363 void AotCompilerImpl::ResetState()
364 {
365     state_.running = false;
366     state_.childPid = -1;
367 }
368 } // namespace OHOS::ArkCompiler
369