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_args_handler.h"
17
18 #include <charconv>
19 #include <cstdio>
20 #include <fstream>
21 #include <nlohmann/json.hpp>
22
23 #include "aot_args_list.h"
24 #include "aot_compiler_constants.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "ecmascript/platform/file.h"
27
28 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
29 #include "parameters.h"
30 #endif
31
32 namespace OHOS::ArkCompiler {
33 const std::string AOT_FILE = "aot-file";
34
35 const std::string STATIC_BOOT_PANDA_FILES = "boot-panda-files";
36 const std::string STATIC_PAOC_PANDA_FILES = "paoc-panda-files";
37 const std::string STATIC_PAOC_LOCATION = "paoc-location";
38 const std::string STATIC_PAOC_OUTPUT = "paoc-output";
39 const std::string STATIC_BOOT_PATH = "/system/framework/bootpath.json";
40
41 const std::string ARKTS_DYNAMIC = "dynamic";
42 const std::string ARKTS_STATIC = "static";
43 const std::string AN_FILE_NAME = "anFileName";
44 const std::string ARKTS_HYBRID = "hybrid";
45
46 const std::string AN_SUFFIX = ".an";
47 const std::string APP_SANBOX_PATH_PREFIX = "/data/storage/el1/bundle/";
48 const std::string ETS_PATH = "/ets";
49 const std::string OWNERID_SHARED_TAG = "SHARED_LIB_ID";
50
51 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
52 // Default closed, open on qiangji
53 const bool ARK_AOT_ENABLE_STATIC_COMPILER_DEFAULT_VALUE = false;
54 #endif
55
AOTArgsHandler(const std::unordered_map<std::string,std::string> & argsMap)56 AOTArgsHandler::AOTArgsHandler(const std::unordered_map<std::string, std::string> &argsMap) : argsMap_(argsMap)
57 {
58 parser_ = *AOTArgsParserFactory::GetParser(argsMap);
59 }
60
Handle(int32_t thermalLevel)61 int32_t AOTArgsHandler::Handle(int32_t thermalLevel)
62 {
63 if (argsMap_.empty()) {
64 LOG_SA(ERROR) << "pass empty args to aot sa";
65 return ERR_AOT_COMPILER_PARAM_FAILED;
66 }
67
68 std::lock_guard<std::mutex> lock(hapArgsMutex_);
69 int32_t ret = parser_->Parse(argsMap_, hapArgs_, thermalLevel);
70 return ret;
71 }
72
GetAotArgs() const73 std::vector<const char*> AOTArgsHandler::GetAotArgs() const
74 {
75 std::lock_guard<std::mutex> lock(hapArgsMutex_);
76 std::vector<const char*> argv;
77 argv.reserve(hapArgs_.argVector.size() + 1); // 1: for nullptr
78 for (auto &arg : hapArgs_.argVector) {
79 argv.emplace_back(arg.c_str());
80 }
81
82 return argv;
83 }
84
GetBundleId(int32_t & bundleUid,int32_t & bundleGid) const85 void AOTArgsHandler::GetBundleId(int32_t &bundleUid, int32_t &bundleGid) const
86 {
87 std::lock_guard<std::mutex> lock(hapArgsMutex_);
88 bundleUid = hapArgs_.bundleUid;
89 bundleGid = hapArgs_.bundleGid;
90 }
91
GetFileName() const92 std::string AOTArgsHandler::GetFileName() const
93 {
94 std::lock_guard<std::mutex> lock(hapArgsMutex_);
95 return hapArgs_.fileName;
96 }
97
GetCodeSignArgs() const98 std::string AOTArgsHandler::GetCodeSignArgs() const
99 {
100 std::lock_guard<std::mutex> lock(hapArgsMutex_);
101 return hapArgs_.signature;
102 }
103
FindArgsIdxToInteger(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,int32_t & bundleID)104 int32_t AOTArgsParserBase::FindArgsIdxToInteger(const std::unordered_map<std::string, std::string> &argsMap,
105 const std::string &keyName, int32_t &bundleID)
106 {
107 if (argsMap.find(keyName) == argsMap.end()) {
108 return ERR_AOT_COMPILER_PARAM_FAILED;
109 }
110
111 if (argsMap.at(keyName).empty() || !isdigit(argsMap.at(keyName).at(0))) {
112 return ERR_AOT_COMPILER_PARAM_FAILED;
113 }
114
115 const char* beginPtr = argsMap.at(keyName).data();
116 const char* endPtr = argsMap.at(keyName).data() + argsMap.at(keyName).size();
117 auto res = std::from_chars(beginPtr, endPtr, bundleID);
118 if ((res.ec != std::errc()) || (res.ptr != endPtr)) {
119 LOG_SA(ERROR) << "trigger exception as converting string to integer";
120 return ERR_AOT_COMPILER_PARAM_FAILED;
121 }
122 return ERR_OK;
123 }
124
FindArgsIdxToString(const std::unordered_map<std::string,std::string> & argsMap,const std::string & keyName,std::string & bundleArg)125 int32_t AOTArgsParserBase::FindArgsIdxToString(const std::unordered_map<std::string, std::string> &argsMap,
126 const std::string &keyName, std::string &bundleArg)
127 {
128 if (argsMap.find(keyName) == argsMap.end()) {
129 return ERR_AOT_COMPILER_PARAM_FAILED;
130 }
131
132 bundleArg = argsMap.at(keyName);
133 return ERR_OK;
134 }
135
Parse(const std::unordered_map<std::string,std::string> & argsMap,HapArgs & hapArgs,int32_t thermalLevel)136 int32_t AOTArgsParser::Parse(const std::unordered_map<std::string, std::string> &argsMap, HapArgs &hapArgs,
137 int32_t thermalLevel)
138 {
139 std::string abcPath;
140 if ((FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_UID, hapArgs.bundleUid) != ERR_OK) ||
141 (FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_GID, hapArgs.bundleGid) != ERR_OK) ||
142 (FindArgsIdxToString(argsMap, ArgsIdx::AN_FILE_NAME, hapArgs.fileName) != ERR_OK) ||
143 (FindArgsIdxToString(argsMap, ArgsIdx::APP_SIGNATURE, hapArgs.signature) != ERR_OK) ||
144 (FindArgsIdxToString(argsMap, ArgsIdx::ABC_PATH, abcPath) != ERR_OK)) {
145 LOG_SA(ERROR) << "aot compiler args parsing error";
146 return ERR_AOT_COMPILER_PARAM_FAILED;
147 }
148
149 hapArgs.argVector.clear();
150 hapArgs.argVector.emplace_back(AOT_EXE);
151
152 // service process add aot compile args here
153 AddExpandArgs(hapArgs.argVector, thermalLevel);
154
155 for (auto &argPair : argsMap) {
156 if (aotArgsList.find(argPair.first) != aotArgsList.end()) {
157 hapArgs.argVector.emplace_back(Symbols::PREFIX + argPair.first + Symbols::EQ + argPair.second);
158 }
159 }
160
161 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
162 SetEnableCodeCommentBySysParam(hapArgs);
163 SetAnFileMaxSizeBySysParam(hapArgs);
164 #endif
165
166 hapArgs.argVector.emplace_back(abcPath);
167 return ERR_OK;
168 }
169
170 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
SetAnFileMaxSizeBySysParam(HapArgs & hapArgs)171 void AOTArgsParser::SetAnFileMaxSizeBySysParam(HapArgs &hapArgs)
172 {
173 int anFileMaxSize = OHOS::system::GetIntParameter<int>("ark.aot.compiler_an_file_max_size", -1);
174 if (anFileMaxSize >= 0) {
175 hapArgs.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_AN_FILE_MAX_SIZE + Symbols::EQ +
176 std::to_string(anFileMaxSize));
177 }
178 }
179
SetEnableCodeCommentBySysParam(HapArgs & hapArgs)180 void AOTArgsParser::SetEnableCodeCommentBySysParam(HapArgs &hapArgs)
181 {
182 bool enableAotCodeComment = OHOS::system::GetBoolParameter("ark.aot.code_comment.enable", false);
183 if (enableAotCodeComment) {
184 hapArgs.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_ENABLE_AOT_CODE_COMMENT + Symbols::EQ +
185 "true");
186 hapArgs.argVector.emplace_back(Symbols::PREFIX + ArgsIdx::COMPILER_LOG_OPT + Symbols::EQ + "allasm");
187 }
188 }
189
IsEnableStaticCompiler()190 bool AOTArgsParserBase::IsEnableStaticCompiler()
191 {
192 return OHOS::system::GetBoolParameter("ark.aot.enable_static_compiler",
193 ARK_AOT_ENABLE_STATIC_COMPILER_DEFAULT_VALUE);
194 }
195 #endif
196
AddExpandArgs(std::vector<std::string> & argVector,int32_t thermalLevel)197 void AOTArgsParser::AddExpandArgs(std::vector<std::string> &argVector, int32_t thermalLevel)
198 {
199 std::string thermalLevelArg = "--compiler-thermal-level=" + std::to_string(thermalLevel);
200 argVector.emplace_back(thermalLevelArg);
201 }
202
Parse(const std::unordered_map<std::string,std::string> & argsMap,HapArgs & hapArgs,int32_t thermalLevel)203 int32_t StaticAOTArgsParser::Parse(const std::unordered_map<std::string, std::string> &argsMap,
204 HapArgs &hapArgs, [[maybe_unused]] int32_t thermalLevel)
205 {
206 std::string abcPath;
207 if ((FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_UID, hapArgs.bundleUid) != ERR_OK) ||
208 (FindArgsIdxToInteger(argsMap, ArgsIdx::BUNDLE_GID, hapArgs.bundleGid) != ERR_OK) ||
209 (FindArgsIdxToString(argsMap, ArgsIdx::AN_FILE_NAME, hapArgs.fileName) != ERR_OK) ||
210 (FindArgsIdxToString(argsMap, ArgsIdx::APP_SIGNATURE, hapArgs.signature) != ERR_OK) ||
211 (FindArgsIdxToString(argsMap, ArgsIdx::ABC_PATH, abcPath) != ERR_OK)) {
212 LOG_SA(ERROR) << "aot compiler args parsing error";
213 return ERR_AOT_COMPILER_PARAM_FAILED;
214 }
215
216 hapArgs.argVector.clear();
217 hapArgs.argVector.emplace_back(STATIC_AOT_EXE);
218
219 for (auto &defaultArg : staticAOTDefaultArgs) {
220 hapArgs.argVector.emplace_back(defaultArg);
221 }
222
223 std::string bootfiles;
224 if (!ParseBootPandaFiles(bootfiles)) {
225 return ERR_AOT_COMPILER_PARAM_FAILED;
226 }
227 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_BOOT_PANDA_FILES + Symbols::EQ + bootfiles);
228
229 std::string anfilePath;
230 for (auto &argPair : argsMap) {
231 // for 1.2, replace aot-file by paoc-output
232 if (argPair.first == AOT_FILE) {
233 anfilePath = argPair.second;
234 std::string anFileName = anfilePath + AN_SUFFIX;
235 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_PAOC_OUTPUT + Symbols::EQ + anFileName);
236 continue;
237 }
238
239 if (staticAOTArgsList.find(argPair.first) != staticAOTArgsList.end()) {
240 hapArgs.argVector.emplace_back(Symbols::PREFIX + argPair.first + Symbols::EQ + argPair.second);
241 }
242 }
243
244 std::string location = ParseLocation(anfilePath);
245 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_PAOC_LOCATION + Symbols::EQ + location);
246 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_PAOC_PANDA_FILES + Symbols::EQ + abcPath);
247
248 return ERR_OK;
249 }
250
ParseBootPandaFiles(std::string & bootfiles)251 bool StaticAOTArgsParser::ParseBootPandaFiles(std::string &bootfiles)
252 {
253 std::ifstream inFile;
254 inFile.open(STATIC_BOOT_PATH, std::ios::in);
255 if (!inFile.is_open()) {
256 LOG_SA(ERROR) << "read json error";
257 return false;
258 }
259 nlohmann::json jsonObject = nlohmann::json::parse(inFile);
260 if (jsonObject.is_discarded()) {
261 LOG_SA(ERROR) << "json discarded error";
262 inFile.close();
263 return false;
264 }
265
266 if (jsonObject.is_null() || jsonObject.empty()) {
267 LOG_SA(ERROR) << "invalid json";
268 inFile.close();
269 return false;
270 }
271
272 for (const auto &[key, value] : jsonObject.items()) {
273 if (!value.is_null() && value.is_string()) {
274 std::string jsonValue = value.get<std::string>();
275 if (jsonValue.empty()) {
276 LOG_SA(ERROR) << "json value of " << key << " is empty";
277 continue;
278 }
279 if (!bootfiles.empty()) {
280 bootfiles += ":";
281 }
282 bootfiles += jsonValue.c_str();
283 }
284 }
285 inFile.close();
286 return true;
287 }
288
ParseLocation(std::string & anFilePath)289 std::string StaticAOTArgsParser::ParseLocation(std::string &anFilePath)
290 {
291 size_t pos = anFilePath.find_last_of("/");
292 if (pos == std::string::npos) {
293 LOG_SA(FATAL) << "aot sa parse invalid location";
294 }
295 std::string moduleName = anFilePath.substr(pos + 1);
296 std::string location = APP_SANBOX_PATH_PREFIX + moduleName + ETS_PATH;
297 return location;
298 }
299
GetParser(const std::unordered_map<std::string,std::string> & argsMap)300 std::optional<std::unique_ptr<AOTArgsParserBase>> AOTArgsParserFactory::GetParser(
301 const std::unordered_map<std::string, std::string> &argsMap)
302 {
303 #ifdef ENABLE_COMPILER_SERVICE_GET_PARAMETER
304 if (!AOTArgsParserBase::IsEnableStaticCompiler()) {
305 return std::make_unique<AOTArgsParser>();
306 }
307 #endif
308 int32_t isSystemComponent = 0;
309 if ((AOTArgsParserBase::FindArgsIdxToInteger(argsMap, ArgsIdx::IS_SYSTEM_COMPONENT, isSystemComponent) != ERR_OK)) {
310 LOG_SA(INFO) << "aot sa failed to get isSystemComponent";
311 }
312 if (isSystemComponent) {
313 return std::make_unique<StaticFrameworkAOTArgsParser>();
314 }
315 std::string arkTsMode;
316 if (AOTArgsParserBase::FindArgsIdxToString(argsMap, ArgsIdx::ARKTS_MODE, arkTsMode) != ERR_OK) {
317 LOG_SA(INFO) << "aot sa failed to get language version";
318 arkTsMode = ARKTS_DYNAMIC;
319 }
320
321 if (arkTsMode == ARKTS_DYNAMIC) {
322 LOG_SA(INFO) << "aot sa use default compiler";
323 return std::make_unique<AOTArgsParser>();
324 } else if (arkTsMode == ARKTS_STATIC || arkTsMode == ARKTS_HYBRID) {
325 LOG_SA(INFO) << "aot sa use static compiler";
326 return std::make_unique<StaticAOTArgsParser>();
327 }
328 LOG_SA(FATAL) << "aot sa get invalid code language version";
329 return std::nullopt;
330 }
331
IsFileExists(const std::string & fileName)332 bool StaticFrameworkAOTArgsParser::IsFileExists(const std::string &fileName)
333 {
334 std::string realPath;
335 if (!panda::ecmascript::RealPath(fileName, realPath)) {
336 LOG_SA(ERROR) << "get real path failed:" << fileName;
337 return false;
338 }
339 return panda::ecmascript::FileExist(realPath.c_str());
340 }
341
Parse(const std::unordered_map<std::string,std::string> & argsMap,HapArgs & hapArgs,int32_t thermalLevel)342 int32_t StaticFrameworkAOTArgsParser::Parse(const std::unordered_map<std::string, std::string> &argsMap,
343 HapArgs &hapArgs, [[maybe_unused]] int32_t thermalLevel)
344 {
345 std::string abcPath;
346 if ((FindArgsIdxToString(argsMap, ArgsIdx::ABC_PATH, abcPath) != ERR_OK) ||
347 (FindArgsIdxToString(argsMap, ArgsIdx::AN_FILE_NAME, hapArgs.fileName) != ERR_OK)) {
348 LOG_SA(ERROR) << "aot compiler args parsing error";
349 return ERR_AOT_COMPILER_PARAM_FAILED;
350 }
351
352 if (IsFileExists(hapArgs.fileName)) {
353 LOG_SA(INFO) << "framework's an is exist";
354 return ERR_AOT_COMPILER_CALL_CANCELLED;
355 }
356
357 hapArgs.argVector.clear();
358 hapArgs.argVector.emplace_back(STATIC_AOT_EXE);
359
360 hapArgs.signature = OWNERID_SHARED_TAG;
361
362 hapArgs.bundleUid = OID_SYSTEM;
363 hapArgs.bundleGid = OID_SYSTEM;
364
365 for (auto &defaultArg : staticFrameworkAOTDefaultArgs) {
366 hapArgs.argVector.emplace_back(defaultArg);
367 }
368
369 std::string fullBootfiles;
370 if (!ParseBootPandaFiles(fullBootfiles)) {
371 return ERR_AOT_COMPILER_PARAM_FAILED;
372 }
373 std::string bootfiles = ParseFrameworkBootPandaFiles(fullBootfiles, abcPath);
374 if (bootfiles.empty()) {
375 LOG_SA(ERROR) << "can not find paoc panda files ";
376 return ERR_AOT_COMPILER_PARAM_FAILED;
377 }
378 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_BOOT_PANDA_FILES + Symbols::EQ + bootfiles);
379
380 for (auto &argPair : argsMap) {
381 if (argPair.first == AN_FILE_NAME) {
382 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_PAOC_OUTPUT + Symbols::EQ + argPair.second);
383 }
384 }
385 hapArgs.argVector.emplace_back(Symbols::PREFIX + STATIC_PAOC_PANDA_FILES + Symbols::EQ + abcPath);
386 return ERR_OK;
387 }
388
ParseFrameworkBootPandaFiles(const std::string & bootfiles,const std::string & paocPandaFiles)389 std::string StaticFrameworkAOTArgsParser::ParseFrameworkBootPandaFiles(const std::string &bootfiles,
390 const std::string &paocPandaFiles)
391 {
392 size_t pos = bootfiles.find(paocPandaFiles);
393 std::string frameworkBootPandaFiles;
394 if (pos != std::string::npos) {
395 frameworkBootPandaFiles += bootfiles.substr(0, pos + paocPandaFiles.length());
396 }
397 return frameworkBootPandaFiles;
398 }
399 } // namespace OHOS::ArkCompiler
400