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 "hitrace_dump.h"
17
18 #include <iostream>
19 #include <memory>
20 #include <fstream>
21 #include <string>
22 #include <vector>
23
24 #include <unistd.h>
25 #include <cstdio>
26 #include "securec.h"
27
28 #include "hilog/log.h"
29 #include "parameters.h"
30 #include <gtest/gtest.h>
31
32 using namespace OHOS::HiviewDFX::Hitrace;
33 using namespace testing::ext;
34 using OHOS::HiviewDFX::HiLog;
35
36 namespace {
37
38 constexpr uint64_t HITRACE_TAG = 0xD002D33;
39 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_TAG, "HitraceTest"};
40
41 const std::string TAG_PROP = "debug.hitrace.tags.enableflags";
42 const std::string DEFAULT_OUTPUT_DIR = "/data/log/hitrace/";
43 const std::string LOG_DIR = "/data/log/";
44
45 std::string g_traceRootPath;
46
AddPair2Table(std::string outputFileName,int nowSec)47 void AddPair2Table(std::string outputFileName, int nowSec)
48 {
49 std::vector<std::pair<std::string, int>> traceFilesTable = GetTraceFilesTable();
50 traceFilesTable.push_back({outputFileName, nowSec});
51 SetTraceFilesTable(traceFilesTable);
52 }
53
CreateFile(std::string outputFileName)54 bool CreateFile(std::string outputFileName)
55 {
56 std::ofstream ofs;
57 ofs.open(outputFileName, std::ios::out | std::ios::trunc);
58 bool openRes = ofs.is_open();
59 ofs.close();
60 return openRes;
61 }
62
EraseFile(std::string outputFileName)63 void EraseFile(std::string outputFileName)
64 {
65 std::vector<std::pair<std::string, int>> traceFilesTable = GetTraceFilesTable();
66 for (auto iter = traceFilesTable.begin(); iter != traceFilesTable.end();) {
67 if (strcmp(iter->first.c_str(), outputFileName.c_str())) {
68 iter = traceFilesTable.erase(iter);
69 continue;
70 }
71 iter++;
72 }
73 SetTraceFilesTable(traceFilesTable);
74 }
75
TraverseFiles(std::vector<std::string> files,std::string outputFileName)76 bool TraverseFiles(std::vector<std::string> files, std::string outputFileName)
77 {
78 int i = 1;
79 bool isExists = false;
80 for (std::vector<std::string>::iterator iter = files.begin(); iter != files.end(); iter++) {
81 isExists |= (strcmp(iter->c_str(), outputFileName.c_str()) == 0);
82 HiLog::Info(LABEL, "ret.outputFile%{public}d: %{public}s", i++, iter->c_str());
83 }
84 return isExists;
85 }
86
87 class HitraceDumpTest : public testing::Test {
88 public:
89 static void SetUpTestCase(void);
90 static void TearDownTestCase(void);
SetUp()91 void SetUp() {}
TearDown()92 void TearDown() {}
93 };
94
SetUpTestCase()95 void HitraceDumpTest::SetUpTestCase()
96 {
97 const std::string debugfsDir = "/sys/kernel/debug/tracing/";
98 const std::string tracefsDir = "/sys/kernel/tracing/";
99 if (access((debugfsDir + "trace_marker").c_str(), F_OK) != -1) {
100 g_traceRootPath = debugfsDir;
101 } else if (access((tracefsDir + "trace_marker").c_str(), F_OK) != -1) {
102 g_traceRootPath = tracefsDir;
103 } else {
104 HiLog::Error(LABEL, "Error: Finding trace folder failed.");
105 }
106
107 /* Open CMD_MODE */
108 }
109
TearDownTestCase()110 void HitraceDumpTest::TearDownTestCase()
111 {
112 /* Close CMD_MODE */
113 }
114
115 /**
116 * @tc.name: GetTraceModeTest_001
117 * @tc.desc: test GetTraceMode() service mode
118 * @tc.type: FUNC
119 */
120 HWTEST_F(HitraceDumpTest, GetTraceModeTest_001, TestSize.Level0)
121 {
122 // check service mode
123 const std::vector<std::string> tagGroups = {"scene_performance"};
124 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
125 TraceMode serviceMode = GetTraceMode();
126 ASSERT_TRUE(serviceMode == TraceMode::SERVICE_MODE);
127
128 // check close mode
129 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
130 TraceMode closeMode = GetTraceMode();
131 ASSERT_TRUE(closeMode == TraceMode::CLOSE);
132 }
133
134 /**
135 * @tc.name: GetTraceModeTest_002
136 * @tc.desc: test GetTraceMode() cmd mode
137 * @tc.type: FUNC
138 */
139 HWTEST_F(HitraceDumpTest, GetTraceModeTest_002, TestSize.Level0)
140 {
141 // check cmd mode
142 std::string args = "tags:sched clockType:boot bufferSize:1024 overwrite:1";
143 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
144 TraceMode cmdMode = GetTraceMode();
145 ASSERT_TRUE(cmdMode == TraceMode::CMD_MODE);
146
147 // check close mode
148 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
149 TraceMode closeMode = GetTraceMode();
150 ASSERT_TRUE(closeMode == TraceMode::CLOSE);
151 }
152
153 /**
154 * @tc.name: DumpForServiceMode_001
155 * @tc.desc: The correct usage of grasping trace in SERVICE_MODE.
156 * @tc.type: FUNC
157 */
158 HWTEST_F(HitraceDumpTest, DumpForServiceMode_001, TestSize.Level0)
159 {
160 const std::vector<std::string> tagGroups = {"scene_performance"};
161 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
162
163 TraceRetInfo ret = DumpTrace();
164 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
165 ASSERT_TRUE(ret.outputFiles.size() > 0);
166 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
167 }
168
169 /**
170 * @tc.name: DumpForCmdMode_001
171 * @tc.desc: The correct usage of grasping trace in CMD_MODE.
172 * @tc.type: FUNC
173 */
174 HWTEST_F(HitraceDumpTest, DumpForCmdMode_001, TestSize.Level0)
175 {
176 std::string args = "tags:sched clockType:boot bufferSize:1024 overwrite:1";
177 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
178
179 ASSERT_TRUE(DumpTraceOn() == TraceErrorCode::SUCCESS);
180 sleep(1);
181
182 TraceRetInfo ret = DumpTraceOff();
183 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
184 ASSERT_TRUE(ret.outputFiles.size() > 0);
185
186 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
187 }
188
189 /**
190 * @tc.name: DumpForCmdMode_002
191 * @tc.desc: Specifies the path of the command in CMD_MODE.
192 * @tc.type: FUNC
193 */
194 HWTEST_F(HitraceDumpTest, DumpForCmdMode_002, TestSize.Level0)
195 {
196 std::string filePathName = "/data/local/tmp/mytrace.sys";
197 std::string args = "tags:sched clockType:boot bufferSize:1024 overwrite:1 output:" + filePathName;
198 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
199 ASSERT_TRUE(DumpTraceOn() == TraceErrorCode::SUCCESS);
200 sleep(1);
201
202 TraceRetInfo ret = DumpTraceOff();
203 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
204
205 ASSERT_TRUE(TraverseFiles(ret.outputFiles, filePathName));
206
207 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
208 }
209
210 /**
211 * @tc.name: DumpForCmdMode_003
212 * @tc.desc: Invalid args verification in CMD_MODE.
213 * @tc.type: FUNC
214 */
215 HWTEST_F(HitraceDumpTest, DumpForCmdMode_003, TestSize.Level0)
216 {
217 std::string args = "tags:hdcc clockType:boot bufferSize:1024 overwrite:1 ";
218 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::TAG_ERROR);
219
220 args = "tags:hdcc clockType:boot bufferSize:1024 overwrite:1 descriptions:123";
221 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::TAG_ERROR);
222
223 ASSERT_TRUE(CloseTrace() == TraceErrorCode::CALL_ERROR);
224 }
225
226 /**
227 * @tc.name: DumpForCmdMode_004
228 * @tc.desc: The CMD_MODE cannot be interrupted by the SERVICE_MODE.
229 * @tc.type: FUNC
230 */
231 HWTEST_F(HitraceDumpTest, DumpForCmdMode_004, TestSize.Level0)
232 {
233 std::string args = "tags:memory clockType:boot1 bufferSize:1024 overwrite:0";
234 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
235
236 const std::vector<std::string> tagGroups = {"scene_performance"};
237 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::TRACE_IS_OCCUPIED);
238
239 ASSERT_TRUE(DumpTraceOn() == TraceErrorCode::SUCCESS);
240 sleep(1);
241
242 TraceRetInfo ret = DumpTraceOff();
243 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
244 ASSERT_TRUE(ret.outputFiles.size() > 0);
245
246 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
247
248 args = "tags:memory clockType: bufferSize:1024 overwrite:1";
249 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
250 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
251
252 args = "tags:memory clockType:perf bufferSize:1024 overwrite:1";
253 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
254 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
255 }
256
257 /**
258 * @tc.name: DumpForCmdMode_005
259 * @tc.desc: Enable the cmd mode in non-close mode.
260 * @tc.type: FUNC
261 */
262 HWTEST_F(HitraceDumpTest, DumpForCmdMode_005, TestSize.Level0)
263 {
264 const std::vector<std::string> tagGroups = {"scene_performance"};
265 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
266 std::string args = "tags:sched clockType:boot bufferSize:1024 overwrite:1";
267 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::CALL_ERROR);
268 ASSERT_TRUE(DumpTraceOn() == TraceErrorCode::CALL_ERROR);
269
270 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
271 }
272
273 /**
274 * @tc.name: DumpForCmdMode_006
275 * @tc.desc: Test the CMD_MODE when there's extra space in args.
276 * @tc.type: FUNC
277 */
278 HWTEST_F(HitraceDumpTest, DumpForCmdMode_006, TestSize.Level0)
279 {
280 std::string args = "tags: sched clockType: boot bufferSize:1024 overwrite: 1";
281 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
282
283 ASSERT_TRUE(DumpTraceOn() == TraceErrorCode::SUCCESS);
284 sleep(1);
285
286 TraceRetInfo ret = DumpTraceOff();
287 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
288 ASSERT_TRUE(ret.outputFiles.size() > 0);
289
290 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
291 }
292
293 /**
294 * @tc.name: ParammeterCheck_001
295 * @tc.desc: Check parameter after interface call.
296 * @tc.type: FUNC
297 */
298 HWTEST_F(HitraceDumpTest, ParammeterCheck_001, TestSize.Level0)
299 {
300 const std::vector<std::string> tagGroups = {"scene_performance"};
301 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
302
303 // ckeck Property("debug.hitrace.tags.enableflags")
304 uint64_t openTags = OHOS::system::GetUintParameter<uint64_t>(TAG_PROP, 0);
305 ASSERT_TRUE(openTags > 0);
306
307 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
308
309 // ckeck Property("debug.hitrace.tags.enableflags")
310 uint64_t closeTags = OHOS::system::GetUintParameter<uint64_t>(TAG_PROP, 0);
311 ASSERT_TRUE(closeTags == 0);
312 }
313
314 /**
315 * @tc.name: DumpForServiceMode_002
316 * @tc.desc: Verify if files can be returned as expected in Service_MODE.
317 * @tc.type: FUNC
318 */
319 HWTEST_F(HitraceDumpTest, DumpForServiceMode_002, TestSize.Level0)
320 {
321 const std::vector<std::string> tagGroups = {"scene_performance"};
322 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
323 ASSERT_TRUE(access(DEFAULT_OUTPUT_DIR.c_str(), F_OK) == 0) << "/data/log/hitrace not exists.";
324
325 struct timeval now = {0, 0};
326 gettimeofday(&now, nullptr);
327 int nowSec = now.tv_sec;
328 int nowUsec = now.tv_usec;
329 nowSec--;
330 std::string outputFileName = DEFAULT_OUTPUT_DIR + "trace_" + std::to_string(nowSec)
331 + "_" + std::to_string(nowUsec) + ".sys";
332 ASSERT_TRUE(CreateFile(outputFileName)) << "create log file failed.";
333 HiLog::Info(LABEL, "outputFileName: %{public}s", outputFileName.c_str());
334 AddPair2Table(outputFileName, nowSec);
335
336 TraceRetInfo ret = DumpTrace();
337 // Remove outputFileName in g_hitraceFilesTable
338 EraseFile(outputFileName);
339 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
340 ASSERT_TRUE(TraverseFiles(ret.outputFiles, outputFileName)) << "file created by user is not exists.";
341 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
342 }
343
344 /**
345 * @tc.name: DumpForServiceMode_003
346 * @tc.desc: Verify if files can be deleted in Service_MODE.
347 * @tc.type: FUNC
348 */
349 HWTEST_F(HitraceDumpTest, DumpForServiceMode_003, TestSize.Level0)
350 {
351 const std::vector<std::string> tagGroups = {"scene_performance"};
352 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
353 ASSERT_TRUE(access(DEFAULT_OUTPUT_DIR.c_str(), F_OK) == 0) << "/data/log/hitrace not exists.";
354
355 struct timeval now = {0, 0};
356 gettimeofday(&now, nullptr);
357 int nowSec = now.tv_sec;
358 int nowUsec = now.tv_usec;
359 nowSec = nowSec - 1900;
360 std::string outputFileName = DEFAULT_OUTPUT_DIR + "trace_" + std::to_string(nowSec)
361 + "_" + std::to_string(nowUsec) + ".sys";
362 ASSERT_TRUE(CreateFile(outputFileName)) << "create log file failed.";
363 HiLog::Info(LABEL, "outputFileName: %{public}s", outputFileName.c_str());
364 AddPair2Table(outputFileName, nowSec);
365
366 TraceRetInfo ret = DumpTrace();
367 ASSERT_TRUE(ret.errorCode == TraceErrorCode::SUCCESS);
368 ASSERT_FALSE(TraverseFiles(ret.outputFiles, outputFileName))
369 << "Returned files that should have been deleted half an hour ago.";
370 ASSERT_TRUE(access(outputFileName.c_str(), F_OK) < 0) << "The file was not deleted half an hour ago";
371 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
372 }
373 /**
374 * @tc.name: DumpForServiceMode_004
375 * @tc.desc: Invalid parameter verification in CMD_MODE.
376 * @tc.type: FUNC
377 */
378 HWTEST_F(HitraceDumpTest, DumpForServiceMode_004, TestSize.Level0)
379 {
380 const std::vector<std::string> tagGroups;
381 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::TAG_ERROR);
382
383 const std::vector<std::string> tagGroups1 = {"scene_performance1"};
384 ASSERT_TRUE(OpenTrace(tagGroups1) == TraceErrorCode::TAG_ERROR);
385 ASSERT_TRUE(DumpTrace().errorCode == TraceErrorCode::CALL_ERROR);
386
387 ASSERT_TRUE(CloseTrace() == TraceErrorCode::CALL_ERROR);
388 }
389
390 /**
391 * @tc.name: DumpForServiceMode_005
392 * @tc.desc: Enable the service mode in CMD_MODE.
393 * @tc.type: FUNC
394 */
395 HWTEST_F(HitraceDumpTest, DumpForServiceMode_005, TestSize.Level0)
396 {
397 std::string args = "tags:sched clockType:boot bufferSize:1024 overwrite:1";
398 ASSERT_TRUE(OpenTrace(args) == TraceErrorCode::SUCCESS);
399
400 const std::vector<std::string> tagGroups = {"scene_performance"};
401 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::TRACE_IS_OCCUPIED);
402
403 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
404
405 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::SUCCESS);
406
407 ASSERT_TRUE(OpenTrace(tagGroups) == TraceErrorCode::CALL_ERROR);
408
409 ASSERT_TRUE(CloseTrace() == TraceErrorCode::SUCCESS);
410 }
411 } // namespace
412