1 /*
2 * Copyright (c) 2023 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 <cstdint>
17 #include <fstream>
18 #include <memory>
19 #include <string>
20 #include <utility>
21
22 #include "gtest/gtest.h"
23
24 #include "ecmascript/napi/include/jsnapi.h"
25 #include "ecmascript/ohos/ohos_pkg_args.h"
26 #include "ecmascript/ohos/enable_aot_list_helper.h"
27 #include "ecmascript/ohos/tests/mock/mock_enable_aot_list_helper.h"
28 #include "ecmascript/platform/file.h"
29 #include "ecmascript/tests/test_helper.h"
30
31 using namespace panda;
32 using namespace panda::ecmascript;
33 using namespace panda::ecmascript::kungfu;
34
35 namespace panda::test {
36 class OhosTest : public testing::Test {
37 public:
SetUpTestCase()38 static void SetUpTestCase()
39 {
40 GTEST_LOG_(INFO) << "SetUpTestCase";
41 }
42
TearDownTestCase()43 static void TearDownTestCase()
44 {
45 GTEST_LOG_(INFO) << "TearDownCase";
46 }
47
SetUp()48 void SetUp() override
49 {
50 runtimeOptions_.SetPGOProfilerPath("");
51 runtimeOptions_.SetTargetCompilerMode("partial");
52 runtimeOptions_.SetAOTOutputFile("/data/local/ark-cache/com.ohos.test/arm64/phone");
53 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson("/data/local/ark-profile/100/com.ohos.test"));
54 runtimeOptions_.SetCompilerFrameworkAbcPath("/etc/abc/framework");
55 runtimeOptions_.SetCompilerEnableExternalPkg(true);
56 runtimeOptions_.SetCompilerExternalPkgJsonInfo(BuildOhosExternalPkgJson());
57 vm_ = JSNApi::CreateEcmaVM(runtimeOptions_);
58 ASSERT(vm_ != nullptr);
59 vm_->GetJSThread()->ManagedCodeBegin();
60 }
61
TearDown()62 void TearDown() override
63 {
64 vm_->GetJSThread()->ManagedCodeEnd();
65 ohos::EnableAotJitListHelper::GetInstance()->Clear();
66 JSNApi::DestroyJSVM(vm_);
67 vm_ = nullptr;
68 }
69
BuildOhosExternalPkgJson()70 static std::string BuildOhosExternalPkgJson()
71 {
72 return "[" + BuildOhosPkgJson("", TEST_BUNDLE_NAME, "entry1") + ", " +
73 BuildOhosPkgJson("", TEST_BUNDLE_NAME, "entry2") + "]";
74 }
75
BuildOhosPkgJson(const std::string & pgoDir,const std::string & bundleName=TEST_BUNDLE_NAME,const std::string & moduleName="entry")76 static std::string BuildOhosPkgJson(const std::string &pgoDir, const std::string &bundleName = TEST_BUNDLE_NAME,
77 const std::string &moduleName = "entry")
78 {
79 std::string pkgJson;
80 pkgJson += R"({"bundleName": ")" + bundleName + "\"";
81 pkgJson += R"(,"moduleName": ")" + moduleName + "\"";
82 pkgJson += R"(,"pkgPath": "/data/app/el1/bundle/public/com.ohos.test/entry.hap","abcName": "ets/modules.abc")";
83 pkgJson += R"(,"abcOffset": "0x6bb3c","abcSize": "0x51adfc")";
84 if (!pgoDir.empty()) {
85 pkgJson += R"(,"pgoDir": ")" + pgoDir + "\"";
86 }
87 return pkgJson + "}";
88 }
89
90 protected:
91 static constexpr const char *TEST_BUNDLE_NAME = "com.ohos.test";
92 JSRuntimeOptions runtimeOptions_;
93 EcmaVM *vm_ {nullptr};
94 };
95
HWTEST_F_L0(OhosTest,AotWhiteListTest)96 HWTEST_F_L0(OhosTest, AotWhiteListTest)
97 {
98 const char *whiteListTestDir = "ohos-whiteList/";
99 const char *enableListName = "ohos-whiteList/app_aot_jit_enable_list.conf";
100 std::string bundleScope = "com.bundle.scope.test";
101 std::string bundleScope1 = "com.bundle.scope.test1";
102 std::string bundleScope2 = "com.bundle.scope.test2";
103 mkdir(whiteListTestDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
104 std::ofstream file(enableListName);
105 file << bundleScope << std::endl;
106 file << bundleScope1 << ":aot" << std::endl;
107 file << bundleScope2 << ":jit" << std::endl;
108
109 file.close();
110 auto helper = std::make_unique<ohos::EnableAotJitListHelper>(enableListName);
111 ASSERT_TRUE(helper->IsEnableAot(bundleScope));
112 ASSERT_TRUE(helper->IsEnableJit(bundleScope));
113 ASSERT_TRUE(helper->IsEnableAot(bundleScope1));
114 ASSERT_FALSE(helper->IsEnableJit(bundleScope1));
115 ASSERT_FALSE(helper->IsEnableAot(bundleScope2));
116 ASSERT_TRUE(helper->IsEnableJit(bundleScope2));
117 unlink(enableListName);
118 rmdir(whiteListTestDir);
119 }
120
HWTEST_F_L0(OhosTest,AotWhiteListPassBy)121 HWTEST_F_L0(OhosTest, AotWhiteListPassBy)
122 {
123 const char *enableListName = "ohos-AotWhiteListPassBy/app_aot_jit_enable_list.conf";
124 std::string bundleScope = "com.bundle.scope.test";
125
126 auto helper = std::make_unique<ohos::EnableAotJitListHelper>(enableListName);
127 ASSERT_FALSE(helper->IsEnableAot(bundleScope));
128 ASSERT_FALSE(helper->IsEnableJit(bundleScope));
129 }
130
HWTEST_F_L0(OhosTest,OhosPkgArgsParse)131 HWTEST_F_L0(OhosTest, OhosPkgArgsParse)
132 {
133 const char *pgoDir = "ohos-OhosPkgArgsParse";
134 std::string runtimeAp = std::string(pgoDir) + "/rt_entry.ap";
135 mkdir(pgoDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
136 std::ofstream file(runtimeAp);
137 file.close();
138
139 arg_list_t pandaFileNames {};
140 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
141 PGOProfilerDecoder decoder;
142
143 runtimeOptions_.SetPGOProfilerPath(runtimeAp);
144 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson(""));
145
146 CompilationOptions cOptions(runtimeOptions_);
147 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
148 OhosPkgArgs::ParseArgs(preProcessor, cOptions);
149
150 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetBundleName(), TEST_BUNDLE_NAME);
151 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetModuleName(), "entry");
152 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetPath(), "/data/app/el1/bundle/public/com.ohos.test/entry.hap");
153 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetSize(), 0x51adfc);
154 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetOffset(), 0x6bb3c);
155 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetPgoDir(), pgoDir);
156
157 ASSERT_EQ(preProcessor.GetPkgsArgs().size(), 3);
158
159 unlink(runtimeAp.c_str());
160 rmdir(pgoDir);
161 }
162
HWTEST_F_L0(OhosTest,OhosPkgArgsParsePgoDir)163 HWTEST_F_L0(OhosTest, OhosPkgArgsParsePgoDir)
164 {
165 arg_list_t pandaFileNames {};
166 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
167 PGOProfilerDecoder decoder;
168 CompilationOptions cOptions(runtimeOptions_);
169 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
170 OhosPkgArgs::ParseArgs(preProcessor, cOptions);
171
172 ASSERT_EQ(preProcessor.GetMainPkgArgs()->GetPgoDir(), "/data/local/ark-profile/100/com.ohos.test");
173 }
174
HWTEST_F_L0(OhosTest,UseBaselineApFromPgoDir)175 HWTEST_F_L0(OhosTest, UseBaselineApFromPgoDir)
176 {
177 const char *pgoDir = "ohos-UseBaselineApFromPgoDir";
178 std::string baselineAp = std::string(pgoDir) + "/entry.ap";
179 std::string runtimeAp = std::string(pgoDir) + "/rt_entry.ap";
180 std::string mergedAp = std::string(pgoDir) + "/merged_entry.ap";
181 mkdir(pgoDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
182 std::ofstream file(baselineAp);
183 file.close();
184 file.open(runtimeAp);
185 file.close();
186 // do not add to white list
187
188 arg_list_t pandaFileNames {};
189 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
190 PGOProfilerDecoder decoder;
191 CompilationOptions cOptions(runtimeOptions_);
192 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
193 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson(pgoDir));
194 // Input format is correct, but there is no available ap file for pgoDir, return success.
195 ASSERT_TRUE(preProcessor.HandleTargetCompilerMode(cOptions));
196
197 ASSERT_FALSE(cOptions.profilerIn_.empty());
198 unlink(runtimeAp.c_str());
199 unlink(baselineAp.c_str());
200 unlink(mergedAp.c_str());
201 rmdir(pgoDir);
202 }
203
HWTEST_F_L0(OhosTest,UseRuntimeApWhenOnlyRuntimeExits)204 HWTEST_F_L0(OhosTest, UseRuntimeApWhenOnlyRuntimeExits)
205 {
206 const char *pgoDir = "ohos-UseRuntimeApWhenOnlyRuntimeExits";
207 std::string baselineAp = std::string(pgoDir) + "/entry.ap";
208 std::string runtimeAp = std::string(pgoDir) + "/rt_entry.ap";
209 std::string mergedAp = std::string(pgoDir) + "/merged_entry.ap";
210 mkdir(pgoDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
211 std::ofstream file(baselineAp);
212 file.close();
213 file.open(runtimeAp);
214 file.close();
215
216 arg_list_t pandaFileNames {};
217 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
218 PGOProfilerDecoder decoder;
219 CompilationOptions cOptions(runtimeOptions_);
220 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
221 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson(pgoDir));
222 ASSERT_TRUE(FileExist(runtimeAp.c_str()));
223 ASSERT_TRUE(preProcessor.HandleTargetCompilerMode(cOptions));
224
225 ASSERT_EQ(cOptions.profilerIn_, mergedAp);
226 ASSERT_TRUE(FileExist(mergedAp.c_str()));
227 ASSERT_TRUE(FileExist(baselineAp.c_str()));
228 ASSERT_FALSE(FileExist(runtimeAp.c_str()));
229 unlink(runtimeAp.c_str());
230 unlink(baselineAp.c_str());
231 unlink(mergedAp.c_str());
232 rmdir(pgoDir);
233 }
234
HWTEST_F_L0(OhosTest,UseMergedApWhenOnlyMergedExist)235 HWTEST_F_L0(OhosTest, UseMergedApWhenOnlyMergedExist)
236 {
237 const char *pgoDir = "ohos-UseMergedApWhenOnlyMergedExist";
238 std::string baselineAp = std::string(pgoDir) + "/entry.ap";
239 std::string mergedAp = std::string(pgoDir) + "/merged_entry.ap";
240 mkdir(pgoDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
241 std::ofstream file(baselineAp);
242 file.close();
243 file.open(mergedAp);
244 file.close();
245
246 arg_list_t pandaFileNames {};
247 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
248 PGOProfilerDecoder decoder;
249 CompilationOptions cOptions(runtimeOptions_);
250 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
251 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson(pgoDir));
252 ASSERT_TRUE(preProcessor.HandleTargetCompilerMode(cOptions));
253
254 ASSERT_EQ(cOptions.profilerIn_, mergedAp);
255 ASSERT_TRUE(FileExist(mergedAp.c_str()));
256 ASSERT_TRUE(FileExist(baselineAp.c_str()));
257 unlink(baselineAp.c_str());
258 unlink(mergedAp.c_str());
259 rmdir(pgoDir);
260 }
261
HWTEST_F_L0(OhosTest,UseMergedApWhenBothRuntimeAndMergedExist)262 HWTEST_F_L0(OhosTest, UseMergedApWhenBothRuntimeAndMergedExist)
263 {
264 const char *pgoDir = "ohos-UseMergedApWhenBothRuntimeAndMergedExist";
265 std::string baselineAp = std::string(pgoDir) + "/entry.ap";
266 std::string runtimeAp = std::string(pgoDir) + "/rt_entry.ap";
267 std::string mergedAp = std::string(pgoDir) + "/merged_entry.ap";
268 mkdir(pgoDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
269 std::ofstream file(baselineAp);
270 file.close();
271 file.open(mergedAp);
272 file.close();
273 file.open(runtimeAp);
274 file.close();
275
276 arg_list_t pandaFileNames {};
277 std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
278 PGOProfilerDecoder decoder;
279 CompilationOptions cOptions(runtimeOptions_);
280 AotCompilerPreprocessor preProcessor(vm_, runtimeOptions_, pkgArgsMap, decoder, pandaFileNames);
281 runtimeOptions_.SetCompilerPkgJsonInfo(BuildOhosPkgJson(pgoDir));
282 ASSERT_TRUE(OhosPkgArgs::ParseArgs(preProcessor, cOptions));
283
284 ASSERT_EQ(cOptions.profilerIn_, mergedAp + ":" + runtimeAp);
285 ASSERT_TRUE(FileExist(mergedAp.c_str()));
286 ASSERT_TRUE(FileExist(baselineAp.c_str()));
287 unlink(baselineAp.c_str());
288 unlink(runtimeAp.c_str());
289 unlink(mergedAp.c_str());
290 rmdir(pgoDir);
291 }
292
HWTEST_F_L0(OhosTest,AotIsEnableArkProfileTrue)293 HWTEST_F_L0(OhosTest, AotIsEnableArkProfileTrue)
294 {
295 const char *whiteListTestDir = "ohos-whiteList/";
296 const char *enableListName = "ohos-whiteList/app_aot_jit_enable_list.conf";
297 std::string bundleScope = "com.bundle.scope.test";
298 std::string bundleScope1 = "com.bundle.scope.test1";
299 std::string bundleScope2 = "com.bundle.scope.test2";
300 mkdir(whiteListTestDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
301 ohos::EnableAotJitListHelper *helper = new MockEnableAotJitListHelper(enableListName);
302
303 ASSERT_TRUE(helper->IsEnableAot(bundleScope));
304 ASSERT_TRUE(helper->IsEnableAot(bundleScope1));
305 ASSERT_TRUE(helper->IsEnableAot(bundleScope2));
306
307 unlink(enableListName);
308 rmdir(whiteListTestDir);
309 }
310
HWTEST_F_L0(OhosTest,AotIsEnableArkProfileFalse)311 HWTEST_F_L0(OhosTest, AotIsEnableArkProfileFalse)
312 {
313 const char *whiteListTestDir = "ohos-whiteList/";
314 const char *enableListName = "ohos-whiteList/app_aot_jit_enable_list.conf";
315 std::string bundleScope = "com.bundle.scope.test";
316 std::string bundleScope1 = "com.bundle.scope.test1";
317 std::string bundleScope2 = "com.bundle.scope.test2";
318 mkdir(whiteListTestDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
319 std::ofstream file(enableListName);
320 file << bundleScope << std::endl;
321 file.close();
322 auto helper = std::make_unique<ohos::EnableAotJitListHelper>(enableListName);
323
324 ASSERT_TRUE(helper->IsEnableAot(bundleScope));
325 ASSERT_FALSE(helper->IsEnableAot(bundleScope1));
326 ASSERT_FALSE(helper->IsEnableAot(bundleScope2));
327
328 unlink(enableListName);
329 rmdir(whiteListTestDir);
330 }
331
332 } // namespace panda::test