1 /*
2 * Copyright (c) 2021 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 #include <string>
16 #include <vector>
17
18 #include <fcntl.h>
19 #include <gtest/gtest.h>
20 #include "sys_event.h"
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "event.h"
26 #include "faultlog_util.h"
27 #include "faultlog_database.h"
28 #define private public
29 #include "faultlogger.h"
30 #undef private
31 #include "faultlog_info_ohos.h"
32 #include "faultlogger_adapter.h"
33 #include "faultlogger_service_ohos.h"
34 #include "file_util.h"
35 #include "hiview_global.h"
36 #include "hiview_platform.h"
37 #include "log_analyzer.h"
38 #include "sys_event.h"
39 #include "sys_event_dao.h"
40
41 using namespace testing::ext;
42 using namespace OHOS::HiviewDFX;
43 namespace OHOS {
44 namespace HiviewDFX {
45 class FaultloggerUnittest : public testing::Test {
46 public:
SetUp()47 void SetUp()
48 {
49 sleep(1);
50 };
TearDown()51 void TearDown(){};
52
CreateFaultloggerInstance() const53 std::shared_ptr<Faultlogger> CreateFaultloggerInstance() const
54 {
55 static std::unique_ptr<HiviewPlatform> platform = std::make_unique<HiviewPlatform>();
56 auto plugin = std::make_shared<Faultlogger>();
57 plugin->SetName("Faultlogger");
58 plugin->SetHandle(nullptr);
59 plugin->SetHiviewContext(platform.get());
60 plugin->OnLoad();
61 return plugin;
62 }
63 };
64
InitHiviewContext()65 static void InitHiviewContext()
66 {
67 OHOS::HiviewDFX::HiviewPlatform &platform = HiviewPlatform::GetInstance();
68 bool result = platform.InitEnvironment("/data/test/test_faultlogger_data/hiview_platform_config");
69 printf("InitHiviewContext result:%d\n", result);
70 }
71
72 /**
73 * @tc.name: dumpFileListTest001
74 * @tc.desc: dump with cmds, check the result
75 * @tc.type: FUNC
76 * @tc.require: SR000F7UQ6 AR000F83AF
77 */
78 HWTEST_F(FaultloggerUnittest, dumpFileListTest001, testing::ext::TestSize.Level3)
79 {
80 /**
81 * @tc.steps: step1. add multiple cmds to faultlogger
82 * @tc.expected: check the content size of the dump function
83 */
84 auto plugin = CreateFaultloggerInstance();
85 auto fd = open("/data/test/testFile", O_CREAT | O_WRONLY | O_TRUNC, 770);
86 if (fd < 0) {
87 printf("Fail to create test result file.\n");
88 return;
89 }
90
91 std::vector<std::string> cmds;
92 plugin->Dump(fd, cmds);
93 cmds.push_back("Faultlogger");
94 plugin->Dump(fd, cmds);
95 cmds.push_back("-l");
96 plugin->Dump(fd, cmds);
97 cmds.push_back("-f");
98 plugin->Dump(fd, cmds);
99 cmds.push_back("cppcrash-ModuleName-10-20201209103823");
100 plugin->Dump(fd, cmds);
101 cmds.push_back("-d");
102 plugin->Dump(fd, cmds);
103 cmds.push_back("-t");
104 plugin->Dump(fd, cmds);
105 cmds.push_back("20201209103823");
106 plugin->Dump(fd, cmds);
107 cmds.push_back("-m");
108 plugin->Dump(fd, cmds);
109 cmds.push_back("FAULTLOGGER");
110 plugin->Dump(fd, cmds);
111 close(fd);
112 fd = -1;
113
114 std::string result;
115 if (FileUtil::LoadStringFromFile("/data/test/testFile", result)) {
116 ASSERT_GT(result.length(), 0ul);
117 } else {
118 FAIL();
119 }
120 }
121
122 /**
123 * @tc.name: genCppCrashLogTest001
124 * @tc.desc: create cpp crash event and send it to faultlogger
125 * @tc.type: FUNC
126 * @tc.require: SR000F7UQ6 AR000F4380
127 */
128 HWTEST_F(FaultloggerUnittest, genCppCrashLogTest001, testing::ext::TestSize.Level3)
129 {
130 /**
131 * @tc.steps: step1. create a cpp crash event and pass it to faultlogger
132 * @tc.expected: the calling is success and the file has been created
133 */
134 auto plugin = CreateFaultloggerInstance();
135 FaultLogInfo info;
136 info.time = 1607161163;
137 info.id = 0;
138 info.pid = 7497;
139 info.faultLogType = 2;
140 info.module = "com.example.myapplication";
141 info.sectionMap["APPVERSION"] = "1.0";
142 info.sectionMap["FAULT_MESSAGE"] = "Nullpointer";
143 info.sectionMap["TRACEID"] = "0x1646145645646";
144 info.sectionMap["KEY_THREAD_INFO"] = "Test Thread Info";
145 info.sectionMap["REASON"] = "TestReason";
146 info.sectionMap["STACKTRACE"] = "#01 xxxxxx\n#02 xxxxxx\n";
147 plugin->AddFaultLog(info);
148 std::string timeStr = GetFormatedTime(info.time);
149 std::string fileName = "/data/log/faultlog/faultlogger/cppcrash-com.example.myapplication-0-" + timeStr;
150 bool exist = FileUtil::FileExists(fileName);
151 ASSERT_EQ(exist, true);
152 auto size = FileUtil::GetFileSize(fileName);
153 ASSERT_GT(size, 0ul);
154 auto parsedInfo = plugin->GetFaultLogInfo(fileName);
155 ASSERT_EQ(parsedInfo->module, "com.example.myapplication");
156 }
157
158 /**
159 * @tc.name: genCppCrashtoAnalysisFaultlog
160 * @tc.desc: create cpp crash event and check AnalysisFaultlog
161 * @tc.type: FUNC
162 * @tc.require: SR000F7UQ6 AR000F4380
163 */
164 HWTEST_F(FaultloggerUnittest, genCppCrashtoAnalysisFaultlog001, testing::ext::TestSize.Level3)
165 {
166 /**
167 * @tc.steps: step1. create a cpp crash event and pass it to faultlogger
168 * @tc.expected: AnalysisFaultlog return expected result
169 */
170 FaultLogInfo info;
171 info.time = 1607161163;
172 info.id = 0;
173 info.pid = 7497;
174 info.faultLogType = 2;
175 info.module = "com.example.testapplication";
176 info.reason = "TestReason";
177 std::map<std::string, std::string> eventInfos;
178 ASSERT_EQ(AnalysisFaultlog(info, eventInfos), false);
179 ASSERT_EQ(!eventInfos["fingerPrint"].empty(), true);
180 }
181
182 /**
183 * @tc.name: genjserrorLogTest002
184 * @tc.desc: create JS ERROR event and send it to faultlogger
185 * @tc.type: FUNC
186 * @tc.require: SR000F7UQ6 AR000F4380
187 */
188 HWTEST_F(FaultloggerUnittest, genjserrorLogTest002, testing::ext::TestSize.Level3)
189 {
190 /**
191 * @tc.steps: step1. create a jss_error event and pass it to faultlogger
192 * @tc.expected: the calling is success and the file has been created
193 */
194 SysEventCreator sysEventCreator("AAFWK", "JSERROR", SysEventCreator::FAULT);
195 sysEventCreator.SetKeyValue("SUMMARY", "Error message:is not callable\nStacktrace:");
196 sysEventCreator.SetKeyValue("name_", "JS_ERROR");
197 sysEventCreator.SetKeyValue("happenTime_", 1670248360359);
198 sysEventCreator.SetKeyValue("REASON", "TypeError");
199 sysEventCreator.SetKeyValue("tz_", "+0800");
200 sysEventCreator.SetKeyValue("pid_", 2413);
201 sysEventCreator.SetKeyValue("tid_", 2413);
202 sysEventCreator.SetKeyValue("what_", 3);
203 sysEventCreator.SetKeyValue("PACKAGE_NAME", "com.ohos.systemui");
204 sysEventCreator.SetKeyValue("VERSION", "1.0.0");
205 sysEventCreator.SetKeyValue("TYPE", 3);
206 sysEventCreator.SetKeyValue("VERSION", "1.0.0");
207
208 auto sysEvent = std::make_shared<SysEvent>("test", nullptr, sysEventCreator);
209 auto testPlugin = CreateFaultloggerInstance();
210 std::shared_ptr<Event> event = std::dynamic_pointer_cast<Event>(sysEvent);
211 bool result = testPlugin->OnEvent(event);
212 ASSERT_EQ(result, true);
213 }
214
215 /**
216 * @tc.name: SaveFaultLogInfoTest001
217 * @tc.desc: Test calling SaveFaultLogInfo Func
218 * @tc.type: FUNC
219 */
220 HWTEST_F(FaultloggerUnittest, SaveFaultLogInfoTest001, testing::ext::TestSize.Level3)
221 {
222 InitHiviewContext();
223 FaultLogDatabase *faultLogDb = new FaultLogDatabase();
224 FaultLogInfo info;
225 info.time = std::time(nullptr); // 3 : index of timestamp
226 info.pid = getpid();
227 info.id = 0;
228 info.faultLogType = 2;
229 info.module = "FaultloggerUnittest";
230 info.reason = "unittest for SaveFaultLogInfo";
231 info.summary = "summary for SaveFaultLogInfo";
232 info.sectionMap["APPVERSION"] = "1.0";
233 info.sectionMap["FAULT_MESSAGE"] = "abort";
234 info.sectionMap["TRACEID"] = "0x1646145645646";
235 info.sectionMap["KEY_THREAD_INFO"] = "Test Thread Info";
236 info.sectionMap["REASON"] = "TestReason";
237 info.sectionMap["STACKTRACE"] = "#01 xxxxxx\n#02 xxxxxx\n";
238 faultLogDb->SaveFaultLogInfo(info);
239
240 std::string cmd = "hisysevent -l | grep " + std::to_string(info.time);
241 FILE* fp = popen(cmd.c_str(), "r");
242 char buffer[1024] = {0};
243 if (fp != nullptr) {
244 fgets(buffer, sizeof(buffer), fp);
245 pclose(fp);
246 std::string str(buffer);
247 if (str.find(std::to_string(info.time).c_str()) != std::string::npos) {
248 printf("sucess!\r\n");
249 } else {
250 FAIL();
251 }
252 } else {
253 FAIL();
254 }
255 }
256
257 /**
258 * @tc.name: GetFaultInfoListTest001
259 * @tc.desc: Test calling GetFaultInfoList Func
260 * @tc.type: FUNC
261 */
262 HWTEST_F(FaultloggerUnittest, GetFaultInfoListTest001, testing::ext::TestSize.Level3)
263 {
264 InitHiviewContext();
265
266 std::string jsonStr = R"~({"domain_":"RELIABILITY","name_":"CPP_CRASH","type_":1,"time_":1501973701070,"tz_":
267 "+0800","pid_":1854,"tid_":1854,"uid_":0,"FAULT_TYPE":"2","PID":1854,"UID":0,"MODULE":"FaultloggerUnittest",
268 "REASON":"unittest for SaveFaultLogInfo","SUMMARY":"summary for SaveFaultLogInfo","LOG_PATH":"","VERSION":"",
269 "HAPPEN_TIME":"1501973701","PNAME":"/","FIRST_FRAME":"/","SECOND_FRAME":"/","LAST_FRAME":"/","FINGERPRINT":
270 "04c0d6f03c73da531f00eb112479a8a2f19f59fafba6a474dcbe455a13288f4d","level_":"CRITICAL","tag_":"STABILITY","id_":
271 "17165544771317691984","info_":"","seq_":447})~";
272 auto sysEvent = std::make_shared<SysEvent>("SysEventSource", nullptr, jsonStr);
273 ASSERT_TRUE(sysEvent->ParseJson() == 0);
274 EventStore::SysEventDao::Insert(sysEvent);
275 FaultLogDatabase *faultLogDb = new FaultLogDatabase();
276 std::list<FaultLogInfo> infoList = faultLogDb->GetFaultInfoList("FaultloggerUnittest", 0, 2, 10);
277 ASSERT_GT(infoList.size(), 0);
278 }
279
280 /**
281 * @tc.name: FaultLogManager::CreateTempFaultLogFile
282 * @tc.desc: Test calling CreateTempFaultLogFile Func
283 * @tc.type: FUNC
284 */
285 HWTEST_F(FaultloggerUnittest, FaultlogManager001, testing::ext::TestSize.Level3)
286 {
287 std::unique_ptr<FaultLogManager> faultLogManager = std::make_unique<FaultLogManager>(nullptr);
288 faultLogManager->Init();
289 int fd = faultLogManager->CreateTempFaultLogFile(1607161345, 0, 2, "FaultloggerUnittest");
290 ASSERT_GT(fd, 0);
291 }
292
293 /**
294 * @tc.name: FaultLogManager::SaveFaultInfoToRawDb
295 * @tc.desc: Test calling SaveFaultInfoToRawDb Func
296 * @tc.type: FUNC
297 */
298 HWTEST_F(FaultloggerUnittest, FaultLogManagerTest001, testing::ext::TestSize.Level3)
299 {
300 InitHiviewContext();
301
302 FaultLogInfo info;
303 info.time = std::time(nullptr); // 3 : index of timestamp
304 info.pid = getpid();
305 info.id = 0;
306 info.faultLogType = 2;
307 info.module = "FaultloggerUnittest1111";
308 info.reason = "unittest for SaveFaultLogInfo";
309 info.summary = "summary for SaveFaultLogInfo";
310 info.sectionMap["APPVERSION"] = "1.0";
311 info.sectionMap["FAULT_MESSAGE"] = "abort";
312 info.sectionMap["TRACEID"] = "0x1646145645646";
313 info.sectionMap["KEY_THREAD_INFO"] = "Test Thread Info";
314 info.sectionMap["REASON"] = "TestReason";
315 info.sectionMap["STACKTRACE"] = "#01 xxxxxx\n#02 xxxxxx\n";
316 std::unique_ptr<FaultLogManager> faultLogManager = std::make_unique<FaultLogManager>(nullptr);
317 faultLogManager->Init();
318 faultLogManager->SaveFaultInfoToRawDb(info);
319
320 std::string cmd = "hisysevent -l | grep " + std::to_string(info.time);
321 FILE* fp = popen(cmd.c_str(), "r");
322 char buffer[1024] = {0};
323 if (fp != nullptr) {
324 fgets(buffer, sizeof(buffer), fp);
325 pclose(fp);
326 std::string str(buffer);
327 if (str.find(std::to_string(info.time).c_str()) != std::string::npos) {
328 printf("sucess!\r\n");
329 } else {
330 FAIL();
331 }
332 } else {
333 FAIL();
334 }
335 }
336
337 /**
338 * @tc.name: FaultLogManager::SaveFaultLogToFile
339 * @tc.desc: Test calling SaveFaultLogToFile Func
340 * @tc.type: FUNC
341 */
342 HWTEST_F(FaultloggerUnittest, FaultLogManagerTest003, testing::ext::TestSize.Level3)
343 {
344 InitHiviewContext();
345
346 FaultLogInfo info;
347 std::unique_ptr<FaultLogManager> faultLogManager = std::make_unique<FaultLogManager>(nullptr);
348 faultLogManager->Init();
349 for (int i = 1; i < 7; i++) {
350 info.time = std::time(nullptr); // 3 : index of timestamp
351 info.pid = getpid();
352 info.id = 0;
353 info.faultLogType = i;
354 info.module = "FaultloggerUnittest1111";
355 info.reason = "unittest for SaveFaultLogInfo";
356 info.summary = "summary for SaveFaultLogInfo";
357 info.sectionMap["APPVERSION"] = "1.0";
358 info.sectionMap["FAULT_MESSAGE"] = "abort";
359 info.sectionMap["TRACEID"] = "0x1646145645646";
360 info.sectionMap["KEY_THREAD_INFO"] = "Test Thread Info";
361 info.sectionMap["REASON"] = "TestReason";
362 info.sectionMap["STACKTRACE"] = "#01 xxxxxx\n#02 xxxxxx\n";
363
364 std::string fileName = faultLogManager->SaveFaultLogToFile(info);
365 if (fileName.find("FaultloggerUnittest1111") == std::string::npos) {
366 FAIL();
367 }
368 }
369 }
370
371 /**
372 * @tc.name: faultLogManager GetFaultInfoListTest001
373 * @tc.desc: Test calling faultLogManager.GetFaultInfoList Func
374 * @tc.type: FUNC
375 */
376 HWTEST_F(FaultloggerUnittest, FaultLogManagerTest002, testing::ext::TestSize.Level3)
377 {
378 InitHiviewContext();
379
380 std::string jsonStr = R"~({"domain_":"RELIABILITY","name_":"CPP_CRASH","type_":1,"time_":1501973701070,"tz_":
381 "+0800","pid_":1854,"tid_":1854,"uid_":0,"FAULT_TYPE":"2","PID":1854,"UID":0,"MODULE":"FaultloggerUnittest",
382 "REASON":"unittest for SaveFaultLogInfo","SUMMARY":"summary for SaveFaultLogInfo","LOG_PATH":"","VERSION":"",
383 "HAPPEN_TIME":"1501973701","PNAME":"/","FIRST_FRAME":"/","SECOND_FRAME":"/","LAST_FRAME":"/","FINGERPRINT":
384 "04c0d6f03c73da531f00eb112479a8a2f19f59fafba6a474dcbe455a13288f4d","level_":"CRITICAL","tag_":"STABILITY","id_":
385 "17165544771317691984","info_":"","seq_":447})~";
386 auto sysEvent = std::make_shared<SysEvent>("SysEventSource", nullptr, jsonStr);
387 ASSERT_TRUE(sysEvent->ParseJson() == 0);
388 EventStore::SysEventDao::Insert(sysEvent);
389
390 std::unique_ptr<FaultLogManager> faultLogManager = std::make_unique<FaultLogManager>(nullptr);
391 auto isProcessedFault1 = faultLogManager->IsProcessedFault(1854, 0, 2);
392 ASSERT_EQ(isProcessedFault1, false);
393
394 faultLogManager->Init();
395
396 auto list = faultLogManager->GetFaultInfoList("FaultloggerUnittest", 0, 2, 10);
397 ASSERT_GT(list.size(), 0);
398
399 auto isProcessedFault2 = faultLogManager->IsProcessedFault(1854, 0, 2);
400 ASSERT_EQ(isProcessedFault2, true);
401
402 auto isProcessedFault3 = faultLogManager->IsProcessedFault(1855, 0, 2);
403 ASSERT_EQ(isProcessedFault3, false);
404
405 auto isProcessedFault4 = faultLogManager->IsProcessedFault(1855, 5, 2);
406 ASSERT_EQ(isProcessedFault4, false);
407 }
408
409 /**
410 * @tc.name: FaultLogUtilTest001
411 * @tc.desc: check ExtractInfoFromFileName Func
412 * @tc.type: FUNC
413 */
414 HWTEST_F(FaultloggerUnittest, FaultLogUtilTest001, testing::ext::TestSize.Level3)
415 {
416 std::string filename = "appfreeze-com.ohos.systemui-10006-20170805172159";
417 auto info = ExtractInfoFromFileName(filename);
418 ASSERT_EQ(info.pid, 0);
419 ASSERT_EQ(info.faultLogType, FaultLogType::APP_FREEZE); // 4 : APP_FREEZE
420 ASSERT_EQ(info.module, "com.ohos.systemui");
421 ASSERT_EQ(info.id, 10006); // 10006 : test uid
422 }
423
424 /**
425 * @tc.name: FaultLogUtilTest002
426 * @tc.desc: check ExtractInfoFromTempFile Func
427 * @tc.type: FUNC
428 */
429 HWTEST_F(FaultloggerUnittest, FaultLogUtilTest002, testing::ext::TestSize.Level3)
430 {
431 std::string filename = "appfreeze-10006-20170805172159";
432 auto info = ExtractInfoFromTempFile(filename);
433 ASSERT_EQ(info.faultLogType, FaultLogType::APP_FREEZE); // 4 : APP_FREEZE
434 ASSERT_EQ(info.pid, 10006); // 10006 : test uid
435
436 std::string filename3 = "jscrash-10006-20170805172159";
437 auto info3 = ExtractInfoFromTempFile(filename3);
438 ASSERT_EQ(info3.faultLogType, FaultLogType::JS_CRASH); // 3 : JS_CRASH
439 ASSERT_EQ(info3.pid, 10006); // 10006 : test uid
440
441 std::string filename4 = "cppcrash-10006-20170805172159";
442 auto info4 = ExtractInfoFromTempFile(filename4);
443 ASSERT_EQ(info4.faultLogType, FaultLogType::CPP_CRASH); // 2 : CPP_CRASH
444 ASSERT_EQ(info4.pid, 10006); // 10006 : test uid
445
446 std::string filename5 = "all-10006-20170805172159";
447 auto info5 = ExtractInfoFromTempFile(filename5);
448 ASSERT_EQ(info5.faultLogType, FaultLogType::ALL); // 0 : ALL
449 ASSERT_EQ(info5.pid, 10006); // 10006 : test uid
450
451 std::string filename6 = "other-10006-20170805172159";
452 auto info6 = ExtractInfoFromTempFile(filename6);
453 ASSERT_EQ(info6.faultLogType, -1); // -1 : other
454 ASSERT_EQ(info6.pid, 10006); // 10006 : test uid
455 }
456
457 /**
458 * @tc.name: FaultloggerAdapter.StartService
459 * @tc.desc: Test calling FaultloggerAdapter.StartService Func
460 * @tc.type: FUNC
461 */
462 HWTEST_F(FaultloggerUnittest, FaultloggerAdapterTest001, testing::ext::TestSize.Level3)
463 {
464 InitHiviewContext();
465 FaultloggerAdapter::StartService(nullptr);
466 ASSERT_EQ(FaultloggerServiceOhos::GetOrSetFaultlogger(nullptr), nullptr);
467
468 Faultlogger faultlogger;
469 FaultloggerAdapter::StartService(&faultlogger);
470 ASSERT_EQ(FaultloggerServiceOhos::GetOrSetFaultlogger(nullptr), &faultlogger);
471 }
472
473 /**
474 * @tc.name: FaultloggerServiceOhos.StartService
475 * @tc.desc: Test calling FaultloggerServiceOhos.StartService Func
476 * @tc.type: FUNC
477 */
478 HWTEST_F(FaultloggerUnittest, FaultloggerServiceOhosTest001, testing::ext::TestSize.Level3)
479 {
480 InitHiviewContext();
481
482 auto service = CreateFaultloggerInstance();
483 FaultloggerServiceOhos serviceOhos;
484 FaultloggerServiceOhos::StartService(service.get());
485 ASSERT_EQ(FaultloggerServiceOhos::GetOrSetFaultlogger(nullptr), service.get());
486 FaultLogInfoOhos info;
487 info.time = std::time(nullptr); // 3 : index of timestamp
488 info.pid = getpid();
489 info.uid = 0;
490 info.faultLogType = 2;
491 info.module = "FaultloggerUnittest333";
492 info.reason = "unittest for SaveFaultLogInfo";
493 serviceOhos.AddFaultLog(info);
494 auto list = serviceOhos.QuerySelfFaultLog(2, 10);
495 ASSERT_NE(list, nullptr);
496 info.time = std::time(nullptr); // 3 : index of timestamp
497 info.pid = getpid();
498 info.uid = 10;
499 info.faultLogType = 2;
500 info.module = "FaultloggerUnittest333";
501 info.reason = "unittest for SaveFaultLogInfo";
502 serviceOhos.AddFaultLog(info);
503 list = serviceOhos.QuerySelfFaultLog(2, 10);
504 ASSERT_EQ(list, nullptr);
505 info.time = std::time(nullptr); // 3 : index of timestamp
506 info.pid = getpid();
507 info.uid = 0;
508 info.faultLogType = 2;
509 info.module = "FaultloggerUnittest333";
510 info.reason = "unittest for SaveFaultLogInfo";
511 serviceOhos.AddFaultLog(info);
512 list = serviceOhos.QuerySelfFaultLog(8, 10);
513 ASSERT_EQ(list, nullptr);
514
515 serviceOhos.Destroy();
516 }
517 } // namespace HiviewDFX
518 } // namespace OHOS
519