1 /*
2 * Copyright (C) 2022-2024 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 <cinttypes>
17 #include <csignal>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <ctime>
22 #include <fcntl.h>
23 #include <fstream>
24 #include <getopt.h>
25 #include <iostream>
26 #include <map>
27 #include <memory>
28 #include <sstream>
29 #include <string>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <thread>
33 #include <unistd.h>
34 #include <map>
35 #include <vector>
36 #include <zlib.h>
37
38 #include "common_define.h"
39 #include "common_utils.h"
40 #include "hilog/log.h"
41 #include "hisysevent_c.h"
42 #include "hitrace_meter.h"
43 #include "parameters.h"
44 #include "securec.h"
45 #include "trace_collector_client.h"
46 #include "trace_json_parser.h"
47
48 using namespace OHOS::HiviewDFX::Hitrace;
49
50 #ifdef LOG_DOMAIN
51 #undef LOG_DOMAIN
52 #define LOG_DOMAIN 0xD002D33
53 #endif
54 #ifdef LOG_TAG
55 #undef LOG_TAG
56 #define LOG_TAG "Hitrace"
57 #endif
58
59 namespace {
60 struct TraceArgs {
61 std::string tags;
62 std::string tagGroups;
63 std::string clockType;
64 std::string level;
65 int bufferSize = 0;
66 int fileSize = 0;
67 bool overwrite = true;
68 std::string output;
69
70 int duration = 0;
71 bool isCompress = false;
72 };
73
74 struct TraceSysEventParams {
75 std::string opt;
76 std::string caller;
77 std::string tags;
78 int duration = 0;
79 int bufferSize = 0;
80 int fileSize = 0;
81 int fileLimit = 0;
82 std::string clockType;
83 bool isCompress = false;
84 bool isRaw = false;
85 bool isOverwrite = true;
86 int errorCode = 0;
87 std::string errorMessage;
88 };
89
90 enum RunningState {
91 /* Initial value */
92 STATE_NULL = 0,
93
94 /* Record a short trace */
95 RECORDING_SHORT_TEXT = 1, // --text
96 RECORDING_SHORT_RAW = 2, // --raw
97
98 /* Record a long trace */
99 RECORDING_LONG_BEGIN = 10, // --trace_begin
100 RECORDING_LONG_DUMP = 11, // --trace_dump
101 RECORDING_LONG_FINISH = 12, // --trace_finish
102 RECORDING_LONG_FINISH_NODUMP = 13, // --trace_finish_nodump
103 RECORDING_LONG_BEGIN_RECORD = 14, // --trace_begin --record
104 RECORDING_LONG_FINISH_RECORD = 15, // --trace_finish --record
105
106 /* Manipulating trace services in snapshot mode */
107 SNAPSHOT_START = 20, // --start_bgsrv
108 SNAPSHOT_DUMP = 21, // --dump_bgsrv
109 SNAPSHOT_STOP = 22, // --stop_bgsrv
110
111 /* Help Info */
112 SHOW_HELP = 31, // -h, --help
113 SHOW_LIST_CATEGORY = 32, // -l, --list_categories
114
115 /* Set system parameter */
116 SET_TRACE_LEVEL = 33, // --trace_level level
117 GET_TRACE_LEVEL = 34, // --trace_level
118 };
119
120 enum CmdErrorCode {
121 OPEN_ROOT_PATH_FAILURE = 2001,
122 OPEN_FILE_PATH_FAILURE = 2002,
123 TRACING_ON_CLOSED = 2003,
124 };
125
126 const std::map<RunningState, std::string> STATE_INFO = {
127 { STATE_NULL, "STATE_NULL" },
128 { RECORDING_SHORT_TEXT, "RECORDING_SHORT_TEXT" },
129 { RECORDING_SHORT_RAW, "RECORDING_SHORT_RAW" },
130 { RECORDING_LONG_BEGIN, "RECORDING_LONG_BEGIN" },
131 { RECORDING_LONG_DUMP, "RECORDING_LONG_DUMP" },
132 { RECORDING_LONG_FINISH_NODUMP, "RECORDING_LONG_FINISH_NODUMP" },
133 { RECORDING_LONG_BEGIN_RECORD, "RECORDING_LONG_BEGIN_RECORD" },
134 { RECORDING_LONG_FINISH_RECORD, "RECORDING_LONG_FINISH_RECORD" },
135 { SNAPSHOT_START, "SNAPSHOT_START" },
136 { SNAPSHOT_DUMP, "SNAPSHOT_DUMP" },
137 { SNAPSHOT_STOP, "SNAPSHOT_STOP" },
138 { SHOW_HELP, "SHOW_HELP" },
139 { SHOW_LIST_CATEGORY, "SHOW_LIST_CATEGORY" },
140 { SET_TRACE_LEVEL, "SET_TRACE_LEVEL"},
141 { GET_TRACE_LEVEL, "GET_TRACE_LEVEL"},
142 };
143
144 constexpr struct option LONG_OPTIONS[] = {
145 { "buffer_size", required_argument, nullptr, 0 },
146 { "trace_clock", required_argument, nullptr, 0 },
147 { "help", no_argument, nullptr, 0 },
148 { "output", required_argument, nullptr, 0 },
149 { "time", required_argument, nullptr, 0 },
150 { "text", no_argument, nullptr, 0 },
151 { "raw", no_argument, nullptr, 0 },
152 { "trace_begin", no_argument, nullptr, 0 },
153 { "trace_finish", no_argument, nullptr, 0 },
154 { "trace_finish_nodump", no_argument, nullptr, 0 },
155 { "record", no_argument, nullptr, 0 },
156 { "trace_dump", no_argument, nullptr, 0 },
157 { "list_categories", no_argument, nullptr, 0 },
158 { "overwrite", no_argument, nullptr, 0 },
159 { "start_bgsrv", no_argument, nullptr, 0 },
160 { "dump_bgsrv", no_argument, nullptr, 0 },
161 { "stop_bgsrv", no_argument, nullptr, 0 },
162 { "file_size", required_argument, nullptr, 0 },
163 { "trace_level", required_argument, nullptr, 0 },
164 { "get_level", no_argument, nullptr, 0 },
165 { nullptr, 0, nullptr, 0 },
166 };
167 const unsigned int CHUNK_SIZE = 65536;
168
169 // support customization of some parameters
170 const int KB_PER_MB = 1024;
171 const int MIN_BUFFER_SIZE = 256;
172 const int MAX_BUFFER_SIZE = 307200; // 300 MB
173 const int HM_MAX_BUFFER_SIZE = 1024 * KB_PER_MB; // 1024 MB
174 const int DEFAULT_BUFFER_SIZE = 18432; // 18 MB
175 constexpr unsigned int MAX_OUTPUT_LEN = 255;
176 const int PAGE_SIZE_KB = 4; // 4 KB
177 const int MIN_FILE_SIZE = 51200; // 50 MB
178 const int MAX_FILE_SIZE = 512000; // 500 MB
179
180 std::string g_traceRootPath;
181 std::shared_ptr<OHOS::HiviewDFX::UCollectClient::TraceCollector> g_traceCollector;
182 TraceArgs g_traceArgs;
183 TraceSysEventParams g_traceSysEventParams;
184 bool g_needSysEvent = false;
185 RunningState g_runningState = STATE_NULL;
186 }
187
188 #ifdef HITRACE_UNITTEST
Reset()189 void Reset()
190 {
191 optind = 0;
192 opterr = 1;
193 optopt = 0;
194 optarg = nullptr;
195 g_traceRootPath = "";
196 g_traceCollector = nullptr;
197 g_needSysEvent = false;
198 g_runningState = STATE_NULL;
199 g_traceSysEventParams = {};
200 g_traceArgs = {};
201 }
202 #endif
203
SetTraceSysEventParams()204 static void SetTraceSysEventParams()
205 {
206 g_needSysEvent = true;
207 g_traceSysEventParams.caller = "CMD";
208 }
209
ConsoleLog(const std::string & logInfo)210 static void ConsoleLog(const std::string& logInfo)
211 {
212 // get localtime
213 time_t currentTime;
214 time(¤tTime);
215 struct tm timeInfo = {};
216 const int bufferSize = 20;
217 char timeStr[bufferSize] = {0};
218 localtime_r(¤tTime, &timeInfo);
219 strftime(timeStr, bufferSize, "%Y/%m/%d %H:%M:%S", &timeInfo);
220 std::cout << timeStr << " " << logInfo << std::endl;
221 }
222
GetStateInfo(const RunningState state)223 static std::string GetStateInfo(const RunningState state)
224 {
225 if (STATE_INFO.find(state) == STATE_INFO.end()) {
226 ConsoleLog("error: running_state is invalid.");
227 return "";
228 }
229 return STATE_INFO.at(state);
230 }
231
WriteStrToFile(const std::string & filename,const std::string & str)232 static bool WriteStrToFile(const std::string& filename, const std::string& str)
233 {
234 std::ofstream out;
235 std::string inSpecPath =
236 OHOS::HiviewDFX::Hitrace::CanonicalizeSpecPath((g_traceRootPath + filename).c_str());
237 out.open(inSpecPath, std::ios::out);
238 if (out.fail()) {
239 ConsoleLog("error: open " + inSpecPath + " failed.");
240 return false;
241 }
242 out << str;
243 if (out.bad()) {
244 ConsoleLog("error: can not write " + inSpecPath);
245 out.close();
246 return false;
247 }
248 out.flush();
249 out.close();
250 return true;
251 }
252
SetFtraceEnabled(const std::string & path,bool enabled)253 static bool SetFtraceEnabled(const std::string& path, bool enabled)
254 {
255 return WriteStrToFile(path, enabled ? "1" : "0");
256 }
257
SetProperty(const std::string & property,const std::string & value)258 static bool SetProperty(const std::string& property, const std::string& value)
259 {
260 return SetPropertyInner(property, value);
261 }
262
SetTraceTagsEnabled(uint64_t tags)263 static bool SetTraceTagsEnabled(uint64_t tags)
264 {
265 std::string value = std::to_string(tags);
266 return SetProperty(TRACE_TAG_ENABLE_FLAGS, value);
267 }
268
ShowListCategory()269 static void ShowListCategory()
270 {
271 g_traceSysEventParams.opt = "ShowListCategory";
272 printf(" %18s description:\n", "tagName:");
273 auto traceTags = TraceJsonParser::Instance().GetAllTagInfos();
274 for (auto it = traceTags.begin(); it != traceTags.end(); ++it) {
275 printf(" %18s - %s\n", it->first.c_str(), it->second.description.c_str());
276 }
277 }
278
ShowHelp(const std::string & cmd)279 static void ShowHelp(const std::string& cmd)
280 {
281 g_traceSysEventParams.opt = "ShowHelp";
282 printf("usage: %s [options] [categories...]\n", cmd.c_str());
283 printf("options include:\n"
284 " -b N Set the size of the buffer (KB) for storing and reading traces.\n"
285 " The default buffer size is 18432 KB.\n"
286 " --buffer_size N Like \"-b N\".\n"
287 " -l List available hitrace categories.\n"
288 " --list_categories Like \"-l\".\n"
289 " -t N Set the hitrace running duration in seconds (5s by default), which depends on\n"
290 " the time required for analysis.\n"
291 " --time N Like \"-t N\".\n"
292 " --trace_clock clock Sets the type of the clock for adding a timestamp to a trace, which can be\n"
293 " boot (default), global, mono, uptime, or perf.\n"
294 " --trace_begin Start capturing traces.\n"
295 " --trace_dump Dump traces to a specified path (stdout by default).\n"
296 " --trace_finish Stop capturing traces and dumps traces to a specified path (stdout by default).\n"
297 " --trace_finish_nodump Stop capturing traces and not dumps traces.\n"
298 " --record Enable or disable long-term trace collection tasks in conjunction with\n"
299 " \"--trace_begin\" and \"--trace_finish\".\n"
300 " --overwrite Set the action to take when the buffer is full. If this option is used,\n"
301 " the latest traces are discarded; if this option is not used (default setting),\n"
302 " the earliest traces are discarded.\n"
303 " -o filename Specifies the name of the target file (stdout by default).\n"
304 " --output filename Like \"-o filename\".\n"
305 " -z Compresses a captured trace.\n"
306 " --text Specify the output format of trace as text.\n"
307 " --raw Specify the output format of trace as raw trace, the default format is text.\n"
308 " --start_bgsrv Enable trace_service in snapshot mode.\n"
309 " --dump_bgsrv Trigger the dump trace task of the trace_service.\n"
310 " --stop_bgsrv Disable trace_service in snapshot mode.\n"
311 " --file_size Sets the size of the raw trace (KB). The default file size is 102400 KB.\n"
312 " Only effective in raw trace mode\n"
313 " --trace_level level Set the system parameter \"persist.hitrace.level.threshold\", which can control\n"
314 " the level threshold of trace dotting. Valid values for \"level\" include\n"
315 " D or Debug, I or Info, C or Critical, M or Commercial.\n"
316 " --get_level Query the system parameter \"persist.hitrace.level.threshold\",\n"
317 " which can control the level threshold for trace dotting.\n"
318 );
319 }
320
CheckTraceLevel(const std::string & arg)321 static bool CheckTraceLevel(const std::string& arg)
322 {
323 static const std::map<std::string, std::string> traceLevels = {
324 {"D", "0"}, {"Debug", "0"},
325 {"I", "1"}, {"Info", "1"},
326 {"C", "2"}, {"Critical", "2"},
327 {"M", "3"}, {"Commercial", "3"}
328 };
329
330 auto it = traceLevels.find(arg);
331 if (it != traceLevels.end()) {
332 g_traceArgs.level = it->second;
333 return true;
334 } else {
335 ConsoleLog("error: trace level is illegal input. eg: \"--trace_level I\", \"--trace_level Info\".");
336 return false;
337 }
338 }
339
SetTraceLevel()340 static bool SetTraceLevel()
341 {
342 bool isSuccess = OHOS::system::SetParameter(TRACE_LEVEL_THRESHOLD, g_traceArgs.level);
343 if (!isSuccess) {
344 ConsoleLog("error: failed to set trace level.");
345 } else {
346 ConsoleLog("success to set trace level.");
347 }
348 return isSuccess;
349 }
350
GetTraceLevel()351 static bool GetTraceLevel()
352 {
353 std::string level = OHOS::system::GetParameter(TRACE_LEVEL_THRESHOLD, "");
354 static const std::map<std::string, std::string> traceLevels = {
355 {"0", "Debug"},
356 {"1", "Info"},
357 {"2", "Critical"},
358 {"3", "Commercial"},
359 };
360
361 auto it = traceLevels.find(level);
362 if (it != traceLevels.end()) {
363 ConsoleLog("the current trace level threshold is " + it->second);
364 return true;
365 } else {
366 ConsoleLog("error: get trace level threshold failed, level(" + level + ") cannot be parsed.");
367 return false;
368 }
369 }
370
371 template <typename T>
StrToNum(const std::string & sString,T & tX)372 inline bool StrToNum(const std::string& sString, T &tX)
373 {
374 std::istringstream iStream(sString);
375 iStream >> tX;
376 return !iStream.fail();
377 }
378
SetRunningState(const RunningState & setValue)379 static bool SetRunningState(const RunningState& setValue)
380 {
381 if (g_runningState != STATE_NULL) {
382 ConsoleLog("error: the parameter is set incorrectly, " + GetStateInfo(g_runningState) +
383 " and " + GetStateInfo(setValue) + " cannot coexist.");
384 return false;
385 }
386 g_runningState = setValue;
387 return true;
388 }
389
CheckOutputFile(const char * path)390 static bool CheckOutputFile(const char* path)
391 {
392 struct stat buf;
393 size_t len = strnlen(path, MAX_OUTPUT_LEN);
394 if (len == MAX_OUTPUT_LEN || len < 1 || (stat(path, &buf) == 0 && (buf.st_mode & S_IFDIR))) {
395 ConsoleLog("error: output file is illegal");
396 return false;
397 }
398 g_traceArgs.output = path;
399 return true;
400 }
401
CheckClock(const char * clock)402 static bool CheckClock(const char* clock)
403 {
404 if (clock == nullptr) {
405 return false;
406 }
407
408 static constexpr size_t maxLen = 6;
409 static constexpr size_t minLen = 4;
410 size_t len = strlen(clock);
411 if (len < minLen || len > maxLen) {
412 return false;
413 }
414
415 const char* c = clock;
416 while (*c != '\0') {
417 if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z')) {
418 ++c;
419 continue;
420 }
421 return false;
422 }
423 return true;
424 }
425
ParseLongOpt(const std::string & cmd,int optionIndex)426 static bool ParseLongOpt(const std::string& cmd, int optionIndex)
427 {
428 bool isTrue = true;
429 if (!strcmp(LONG_OPTIONS[optionIndex].name, "buffer_size")) {
430 int bufferSizeKB = 0;
431 int maxBufferSizeKB = MAX_BUFFER_SIZE;
432 if (IsHmKernel()) {
433 maxBufferSizeKB = HM_MAX_BUFFER_SIZE;
434 }
435 if (!StrToNum(optarg, bufferSizeKB)) {
436 ConsoleLog("error: buffer size is illegal input. eg: \"--buffer_size 18432\".");
437 isTrue = false;
438 } else if (bufferSizeKB < MIN_BUFFER_SIZE || bufferSizeKB > maxBufferSizeKB) {
439 ConsoleLog("error: buffer size must be from 256 KB to " + std::to_string(maxBufferSizeKB / KB_PER_MB) +
440 " MB. eg: \"--buffer_size 18432\".");
441 isTrue = false;
442 }
443 g_traceArgs.bufferSize = bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
444 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_clock")) {
445 if (CheckClock(optarg)) {
446 g_traceArgs.clockType = optarg;
447 } else {
448 ConsoleLog("error: \"--trace_clock\" is illegal input. eg: \"--trace_clock boot\".");
449 isTrue = false;
450 }
451 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "help")) {
452 isTrue = SetRunningState(SHOW_HELP);
453 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "time")) {
454 if (!StrToNum(optarg, g_traceArgs.duration)) {
455 ConsoleLog("error: the time is illegal input. eg: \"--time 5\".");
456 isTrue = false;
457 } else if (g_traceArgs.duration < 1) {
458 ConsoleLog("error: \"-t " + std::string(optarg) + "\" to be greater than zero. eg: \"--time 5\".");
459 isTrue = false;
460 }
461 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "list_categories")) {
462 isTrue = SetRunningState(SHOW_LIST_CATEGORY);
463 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "output")) {
464 isTrue = CheckOutputFile(optarg);
465 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "overwrite")) {
466 g_traceArgs.overwrite = false;
467 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_begin")) {
468 isTrue = SetRunningState(RECORDING_LONG_BEGIN);
469 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_finish")) {
470 isTrue = SetRunningState(RECORDING_LONG_FINISH);
471 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_finish_nodump")) {
472 isTrue = SetRunningState(RECORDING_LONG_FINISH_NODUMP);
473 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_dump")) {
474 isTrue = SetRunningState(RECORDING_LONG_DUMP);
475 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "record")) {
476 if (g_runningState == RECORDING_LONG_BEGIN) {
477 g_runningState = RECORDING_LONG_BEGIN_RECORD;
478 } else if (g_runningState == RECORDING_LONG_FINISH) {
479 g_runningState = RECORDING_LONG_FINISH_RECORD;
480 } else {
481 ConsoleLog("error: \"--record\" is set incorrectly. eg: \"--trace_begin --record\","
482 " \"--trace_finish --record\".");
483 isTrue = false;
484 }
485 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "start_bgsrv")) {
486 isTrue = SetRunningState(SNAPSHOT_START);
487 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "dump_bgsrv")) {
488 isTrue = SetRunningState(SNAPSHOT_DUMP);
489 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "stop_bgsrv")) {
490 isTrue = SetRunningState(SNAPSHOT_STOP);
491 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "text")) {
492 isTrue = SetRunningState(RECORDING_SHORT_TEXT);
493 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "raw")) {
494 isTrue = SetRunningState(RECORDING_SHORT_RAW);
495 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "file_size")) {
496 int fileSizeKB = 0;
497 if (!StrToNum(optarg, fileSizeKB)) {
498 ConsoleLog("error: file size is illegal input. eg: \"--file_size 102400\".");
499 isTrue = false;
500 } else if (fileSizeKB < MIN_FILE_SIZE || fileSizeKB > MAX_FILE_SIZE) {
501 ConsoleLog("error: file size must be from 50 MB to 500 MB. eg: \"--file_size 102400\".");
502 isTrue = false;
503 }
504 g_traceArgs.fileSize = fileSizeKB;
505 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "trace_level")) {
506 isTrue = SetRunningState(SET_TRACE_LEVEL);
507 if (!CheckTraceLevel(optarg)) {
508 isTrue = false;
509 }
510 } else if (!strcmp(LONG_OPTIONS[optionIndex].name, "get_level")) {
511 isTrue = SetRunningState(GET_TRACE_LEVEL);
512 }
513
514 return isTrue;
515 }
516
SetBufferSize()517 static bool SetBufferSize()
518 {
519 bool isTrue = true;
520 int bufferSizeKB = 0;
521 int maxBufferSizeKB = MAX_BUFFER_SIZE;
522 if (IsHmKernel()) {
523 maxBufferSizeKB = HM_MAX_BUFFER_SIZE;
524 }
525 if (!StrToNum(optarg, bufferSizeKB)) {
526 ConsoleLog("error: buffer size is illegal input. eg: \"--buffer_size 18432\".");
527 isTrue = false;
528 } else if (bufferSizeKB < MIN_BUFFER_SIZE || bufferSizeKB > maxBufferSizeKB) {
529 ConsoleLog("error: buffer size must be from 256 KB to " + std::to_string(maxBufferSizeKB / KB_PER_MB) +
530 " MB. eg: \"--buffer_size 18432\".");
531 isTrue = false;
532 }
533 g_traceArgs.bufferSize = bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
534 return isTrue;
535 }
536
ParseOpt(int opt,char ** argv,int optIndex)537 static bool ParseOpt(int opt, char** argv, int optIndex)
538 {
539 bool isTrue = true;
540 switch (opt) {
541 case 'b': {
542 isTrue = SetBufferSize();
543 break;
544 }
545 case 'h':
546 isTrue = SetRunningState(SHOW_HELP);
547 break;
548 case 'l':
549 isTrue = SetRunningState(SHOW_LIST_CATEGORY);
550 break;
551 case 't': {
552 if (!StrToNum(optarg, g_traceArgs.duration)) {
553 ConsoleLog("error: the time is illegal input. eg: \"--time 5\".");
554 isTrue = false;
555 } else if (g_traceArgs.duration < 1) {
556 ConsoleLog("error: \"-t " + std::string(optarg) + "\" to be greater than zero. eg: \"--time 5\".");
557 isTrue = false;
558 }
559 break;
560 }
561 case 'o': {
562 isTrue = CheckOutputFile(optarg);
563 break;
564 }
565 case 'z':
566 g_traceArgs.isCompress = true;
567 break;
568 case 0: // long options
569 isTrue = ParseLongOpt(argv[0], optIndex);
570 break;
571 case '?':
572 isTrue = false;
573 break;
574 default:
575 break;
576 }
577 return isTrue;
578 }
579
AddTagItems(int argc,char ** argv)580 static bool AddTagItems(int argc, char** argv)
581 {
582 auto traceTags = TraceJsonParser::Instance().GetAllTagInfos();
583 for (int i = optind; i < argc; i++) {
584 std::string tag = std::string(argv[i]);
585 if (traceTags.find(tag) == traceTags.end()) {
586 std::string errorInfo = "error: " + tag + " is not support category on this device.";
587 ConsoleLog(errorInfo);
588 return false;
589 }
590
591 if (i == optind) {
592 g_traceArgs.tags = tag;
593 } else {
594 g_traceArgs.tags += ("," + tag);
595 }
596 }
597 return true;
598 }
599
HandleOpt(int argc,char ** argv)600 static bool HandleOpt(int argc, char** argv)
601 {
602 bool isTrue = true;
603 int opt = 0;
604 int optionIndex = 0;
605 std::string shortOption = "b:c:hlo:t:z";
606 int argcSize = argc;
607 while (isTrue && argcSize-- > 0) {
608 opt = getopt_long(argc, argv, shortOption.c_str(), LONG_OPTIONS, &optionIndex);
609 if (opt < 0 && (!AddTagItems(argc, argv))) {
610 isTrue = false;
611 break;
612 }
613 isTrue = ParseOpt(opt, argv, optionIndex);
614 }
615
616 return isTrue;
617 }
618
StopTrace()619 static void StopTrace()
620 {
621 const int napTime = 10000;
622 usleep(napTime);
623 SetTraceTagsEnabled(0);
624 SetFtraceEnabled(TRACING_ON_NODE, false);
625 }
626
DumpCompressedTrace(int traceFd,int outFd)627 static void DumpCompressedTrace(int traceFd, int outFd)
628 {
629 z_stream zs { nullptr };
630 int flush = Z_NO_FLUSH;
631 ssize_t bytesWritten;
632 ssize_t bytesRead;
633 if (memset_s(&zs, sizeof(zs), 0, sizeof(zs)) != EOK) {
634 ConsoleLog("error: zip stream buffer init failed.");
635 return;
636 }
637 int ret = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
638 if (ret != Z_OK) {
639 ConsoleLog("error: initializing zlib failed ret " + std::to_string(ret));
640 return;
641 }
642 std::unique_ptr<uint8_t[]> in = std::make_unique<uint8_t[]>(CHUNK_SIZE);
643 std::unique_ptr<uint8_t[]> out = std::make_unique<uint8_t[]>(CHUNK_SIZE);
644 if (!in || !out) {
645 ConsoleLog("error: couldn't allocate buffers.");
646 return;
647 }
648 zs.next_out = reinterpret_cast<Bytef*>(out.get());
649 zs.avail_out = CHUNK_SIZE;
650
651 do {
652 if (zs.avail_in == 0 && flush == Z_NO_FLUSH) {
653 bytesRead = TEMP_FAILURE_RETRY(read(traceFd, in.get(), CHUNK_SIZE));
654 if (bytesRead == 0) {
655 flush = Z_FINISH;
656 } else if (bytesRead == -1) {
657 ConsoleLog("error: reading trace, errno " + std::to_string(errno));
658 break;
659 } else {
660 zs.next_in = reinterpret_cast<Bytef*>(in.get());
661 zs.avail_in = bytesRead;
662 }
663 }
664 if (zs.avail_out == 0) {
665 bytesWritten = TEMP_FAILURE_RETRY(write(outFd, out.get(), CHUNK_SIZE));
666 if (bytesWritten < static_cast<ssize_t>(CHUNK_SIZE)) {
667 ConsoleLog("error: writing deflated trace, errno " + std::to_string(errno));
668 break;
669 }
670 zs.next_out = reinterpret_cast<Bytef*>(out.get());
671 zs.avail_out = CHUNK_SIZE;
672 }
673 ret = deflate(&zs, flush);
674 if (flush == Z_FINISH && ret == Z_STREAM_END) {
675 size_t have = CHUNK_SIZE - zs.avail_out;
676 bytesWritten = TEMP_FAILURE_RETRY(write(outFd, out.get(), have));
677 if (bytesWritten < static_cast<ssize_t>(have)) {
678 ConsoleLog("error: writing deflated trace, errno " + std::to_string(errno));
679 }
680 break;
681 } else if (ret != Z_OK) {
682 if (ret == Z_ERRNO) {
683 ConsoleLog("error: deflate failed with errno " + std::to_string(errno));
684 } else {
685 ConsoleLog("error: deflate failed return " + std::to_string(ret));
686 }
687 break;
688 }
689 } while (ret == Z_OK);
690
691 ret = deflateEnd(&zs);
692 if (ret != Z_OK) {
693 ConsoleLog("error: cleaning up zlib return " + std::to_string(ret));
694 }
695 }
696
DumpTrace()697 static void DumpTrace()
698 {
699 std::string tracePath = g_traceRootPath + TRACE_NODE;
700 std::string traceSpecPath = CanonicalizeSpecPath(tracePath.c_str());
701 int traceFd = open(traceSpecPath.c_str(), O_RDONLY);
702 if (traceFd == -1) {
703 ConsoleLog("error: opening " + tracePath + ", errno: " + std::to_string(errno));
704 g_traceSysEventParams.errorCode = OPEN_ROOT_PATH_FAILURE;
705 g_traceSysEventParams.errorMessage = "error: opening " + tracePath + ", errno: " +
706 std::to_string(errno);
707 return;
708 }
709
710 int outFd = STDOUT_FILENO;
711 if (g_traceArgs.output.size() > 0) {
712 std::string outSpecPath = CanonicalizeSpecPath(g_traceArgs.output.c_str());
713 outFd = open(outSpecPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
714 }
715
716 if (outFd == -1) {
717 ConsoleLog("error: opening " + g_traceArgs.output + ", errno: " + std::to_string(errno));
718 g_traceSysEventParams.errorCode = OPEN_FILE_PATH_FAILURE;
719 g_traceSysEventParams.errorMessage = "error: opening " + g_traceArgs.output + ", errno: " +
720 std::to_string(errno);
721 close(traceFd);
722 return;
723 }
724
725 ssize_t bytesWritten;
726 ssize_t bytesRead;
727 if (g_traceArgs.isCompress) {
728 DumpCompressedTrace(traceFd, outFd);
729 } else {
730 const int blockSize = 4096;
731 char buffer[blockSize];
732 do {
733 bytesRead = TEMP_FAILURE_RETRY(read(traceFd, buffer, blockSize));
734 if ((bytesRead == 0) || (bytesRead == -1)) {
735 break;
736 }
737 bytesWritten = TEMP_FAILURE_RETRY(write(outFd, buffer, bytesRead));
738 if (bytesWritten > 0) {
739 g_traceSysEventParams.fileSize += bytesWritten;
740 }
741 } while (bytesWritten > 0);
742 }
743
744 g_traceSysEventParams.fileSize = g_traceSysEventParams.fileSize / KB_PER_MB;
745 if (outFd != STDOUT_FILENO) {
746 ConsoleLog("trace read done, output: " + g_traceArgs.output);
747 close(outFd);
748 }
749 close(traceFd);
750 }
751
ReloadTraceArgs()752 static std::string ReloadTraceArgs()
753 {
754 if (g_traceArgs.tags.size() == 0) {
755 ConsoleLog("error: tag is empty, please add.");
756 return "";
757 }
758 std::string args = "tags:" + g_traceArgs.tags;
759
760 if (g_traceArgs.bufferSize > 0) {
761 args += (" bufferSize:" + std::to_string(g_traceArgs.bufferSize));
762 } else {
763 args += (" bufferSize:" + std::to_string(DEFAULT_BUFFER_SIZE));
764 }
765
766 if (g_traceArgs.clockType.size() > 0) {
767 args += (" clockType:" + g_traceArgs.clockType);
768 }
769
770 if (g_traceArgs.overwrite) {
771 args += " overwrite:";
772 args += "1";
773 } else {
774 args += " overwrite:";
775 args += "0";
776 }
777
778 if (g_traceArgs.fileSize > 0) {
779 if (g_runningState == RECORDING_SHORT_RAW || g_runningState == RECORDING_LONG_BEGIN_RECORD) {
780 args += (" fileSize:" + std::to_string(g_traceArgs.fileSize));
781 } else {
782 ConsoleLog("warning: The current state does not support specifying the file size, file size: " +
783 std::to_string(g_traceArgs.fileSize) + " is invalid.");
784 }
785 }
786
787 if (g_runningState != RECORDING_SHORT_TEXT) {
788 ConsoleLog("args: " + args);
789 }
790 return args;
791 }
792
HandleRecordingShortRaw()793 static bool HandleRecordingShortRaw()
794 {
795 std::string args = ReloadTraceArgs();
796 if (g_traceArgs.output.size() > 0) {
797 ConsoleLog("warning: The current state does not support specifying the output file path, " +
798 g_traceArgs.output + " is invalid.");
799 }
800 auto openRet = g_traceCollector->OpenRecording(args);
801 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
802 ConsoleLog("error: OpenRecording failed, errorCode(" + std::to_string(openRet.retCode) +")");
803 return false;
804 }
805
806 auto recOnRet = g_traceCollector->RecordingOn();
807 if (recOnRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
808 ConsoleLog("error: RecordingOn failed, errorCode(" + std::to_string(recOnRet.retCode) +")");
809 g_traceCollector->Close();
810 return false;
811 }
812 ConsoleLog("start capture, please wait " + std::to_string(g_traceArgs.duration) + "s ...");
813 sleep(g_traceArgs.duration);
814
815 auto recOffRet = g_traceCollector->RecordingOff();
816 if (recOffRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
817 ConsoleLog("error: RecordingOff failed, errorCode(" + std::to_string(recOffRet.retCode) +")");
818 g_traceCollector->Close();
819 return false;
820 }
821 ConsoleLog("capture done, output files:");
822 for (std::string item : recOffRet.data) {
823 std::cout << " " << item << std::endl;
824 }
825 auto closeRet = g_traceCollector->Close();
826 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
827 ConsoleLog("error: Trace Close failed, errorCode(" + std::to_string(closeRet.retCode) +")");
828 }
829 return true;
830 }
831
HandleRecordingShortText()832 static bool HandleRecordingShortText()
833 {
834 std::string args = ReloadTraceArgs();
835 auto openRet = g_traceCollector->OpenRecording(args);
836 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
837 ConsoleLog("error: OpenRecording failed, errorCode(" + std::to_string(openRet.retCode) +")");
838 if (openRet.retCode == OHOS::HiviewDFX::UCollect::UcError::TRACE_IS_OCCUPIED ||
839 openRet.retCode == OHOS::HiviewDFX::UCollect::UcError::TRACE_WRONG_MODE) {
840 return false;
841 } else {
842 return false;
843 }
844 }
845 ConsoleLog("start capture, please wait " + std::to_string(g_traceArgs.duration) + "s ...");
846 sleep(g_traceArgs.duration);
847
848 MarkClockSync(g_traceRootPath);
849 StopTrace();
850
851 if (g_traceArgs.output.size() > 0) {
852 ConsoleLog("capture done, start to read trace.");
853 }
854 g_traceSysEventParams.opt = "DumpTextTrace";
855 DumpTrace();
856
857 auto closeRet = g_traceCollector->Close();
858 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
859 ConsoleLog("error: TraceFinish failed, errorCode(" + std::to_string(closeRet.retCode) +")");
860 } else {
861 ConsoleLog("TraceFinish done.");
862 }
863 return true;
864 }
865
HandleRecordingLongBegin()866 static bool HandleRecordingLongBegin()
867 {
868 std::string args = ReloadTraceArgs();
869 if (g_traceArgs.output.size() > 0) {
870 ConsoleLog("warning: The current state does not support specifying the output file path, " +
871 g_traceArgs.output + " is invalid.");
872 }
873 auto openRet = g_traceCollector->OpenRecording(args);
874 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
875 ConsoleLog("error: OpenRecording failed, errorCode(" + std::to_string(openRet.retCode) +")");
876 return false;
877 }
878 ConsoleLog("OpenRecording done.");
879 return true;
880 }
881
HandleRecordingLongDump()882 static bool HandleRecordingLongDump()
883 {
884 g_traceSysEventParams.opt = "DumpTextTrace";
885 if (!IsTracingOn(g_traceRootPath)) {
886 g_traceSysEventParams.errorCode = TRACING_ON_CLOSED;
887 g_traceSysEventParams.errorMessage = "Warning: tracing on is closed, no trace can be read.";
888 ConsoleLog("Warning: tracing on is closed, no trace can be read.");
889 return false;
890 }
891 MarkClockSync(g_traceRootPath);
892 ConsoleLog("start to read trace.");
893 DumpTrace();
894 return true;
895 }
896
HandleRecordingLongFinish()897 static bool HandleRecordingLongFinish()
898 {
899 g_traceSysEventParams.opt = "DumpTextTrace";
900 if (!IsTracingOn(g_traceRootPath)) {
901 g_traceSysEventParams.errorCode = TRACING_ON_CLOSED;
902 g_traceSysEventParams.errorMessage = "Warning: tracing on is closed, no trace can be read.";
903 ConsoleLog("Warning: tracing on is closed, no trace can be read.");
904 return false;
905 }
906 MarkClockSync(g_traceRootPath);
907 StopTrace();
908 ConsoleLog("start to read trace.");
909 DumpTrace();
910 auto closeRet = g_traceCollector->Close();
911 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
912 ConsoleLog("error: Trace Close failed, errorCode(" + std::to_string(closeRet.retCode) +")");
913 } else {
914 ConsoleLog("Trace Closed.");
915 }
916 return true;
917 }
918
HandleRecordingLongFinishNodump()919 static bool HandleRecordingLongFinishNodump()
920 {
921 auto closeRet = g_traceCollector->Close();
922 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
923 ConsoleLog("error: Trace Close failed, errorCode(" + std::to_string(closeRet.retCode) +")");
924 } else {
925 ConsoleLog("end capture trace.");
926 }
927
928 return true;
929 }
930
HandleRecordingLongBeginRecord()931 static bool HandleRecordingLongBeginRecord()
932 {
933 std::string args = ReloadTraceArgs();
934 if (g_traceArgs.output.size() > 0) {
935 ConsoleLog("warning: The current state does not support specifying the output file path, " +
936 g_traceArgs.output + " is invalid.");
937 }
938 auto openRet = g_traceCollector->OpenRecording(args);
939 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
940 ConsoleLog("error: OpenRecording failed, errorCode(" + std::to_string(openRet.retCode) +")");
941 return false;
942 }
943
944 auto recOnRet = g_traceCollector->RecordingOn();
945 if (recOnRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
946 ConsoleLog("error: RecordingOn failed, errorCode(" + std::to_string(recOnRet.retCode) +")");
947 g_traceCollector->Close();
948 return false;
949 }
950 ConsoleLog("trace capturing.");
951 return true;
952 }
953
HandleRecordingLongFinishRecord()954 static bool HandleRecordingLongFinishRecord()
955 {
956 auto recOffRet = g_traceCollector->RecordingOff();
957 if (recOffRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
958 ConsoleLog("error: RecordingOff failed, errorCode(" + std::to_string(recOffRet.retCode) +")");
959 return false;
960 }
961 ConsoleLog("capture done, output files:");
962 for (std::string item : recOffRet.data) {
963 std::cout << " " << item << std::endl;
964 }
965 auto closeRet = g_traceCollector->Close();
966 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
967 ConsoleLog("error: Trace Close failed, errorCode(" + std::to_string(closeRet.retCode) +")");
968 }
969 return true;
970 }
971
HandleOpenSnapshot()972 static bool HandleOpenSnapshot()
973 {
974 g_needSysEvent = false;
975 std::vector<std::string> tagGroups = { "scene_performance" };
976 auto openRet = g_traceCollector->OpenSnapshot(tagGroups);
977 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
978 ConsoleLog("error: OpenSnapshot failed, errorCode(" + std::to_string(openRet.retCode) +")");
979 return false;
980 }
981 ConsoleLog("OpenSnapshot done.");
982 return true;
983 }
984
HandleDumpSnapshot()985 static bool HandleDumpSnapshot()
986 {
987 g_needSysEvent = false;
988 bool isSuccess = true;
989 auto dumpRet = g_traceCollector->DumpSnapshot(OHOS::HiviewDFX::UCollect::TraceClient::COMMAND);
990 if (dumpRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
991 ConsoleLog("error: DumpSnapshot failed, errorCode(" + std::to_string(dumpRet.retCode) +")");
992 isSuccess = false;
993 } else {
994 ConsoleLog("DumpSnapshot done, output:");
995 for (std::string item : dumpRet.data) {
996 std::cout << " " << item << std::endl;
997 }
998 }
999 return isSuccess;
1000 }
1001
HandleCloseSnapshot()1002 static bool HandleCloseSnapshot()
1003 {
1004 g_needSysEvent = false;
1005 bool isSuccess = true;
1006 auto closeRet = g_traceCollector->Close();
1007 if (closeRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
1008 ConsoleLog("error: CloseSnapshot failed, errorCode(" + std::to_string(closeRet.retCode) +")");
1009 isSuccess = false;
1010 } else {
1011 ConsoleLog("CloseSnapshot done.");
1012 }
1013 return isSuccess;
1014 }
1015
InterruptExit(int signo)1016 static void InterruptExit(int signo)
1017 {
1018 /**
1019 * trace reset.
1020 */
1021 _exit(-1);
1022 }
1023
RecordSysEvent()1024 static void RecordSysEvent()
1025 {
1026 if (!g_needSysEvent) {
1027 return;
1028 }
1029 HiSysEventParam params[] = {
1030 {"OPT", HISYSEVENT_STRING, {.s = const_cast<char*>(g_traceSysEventParams.opt.c_str())}, 0},
1031 {"CALLER", HISYSEVENT_STRING, {.s = const_cast<char*>(g_traceSysEventParams.caller.c_str())}, 0},
1032 {"TRACE_TAG", HISYSEVENT_STRING, {.s = const_cast<char*>(g_traceSysEventParams.tags.c_str())}, 0},
1033 {"DURATION", HISYSEVENT_INT32, {.i32 = g_traceSysEventParams.duration}, 0},
1034 {"BUFFER_SIZE", HISYSEVENT_INT32, {.i32 = g_traceSysEventParams.bufferSize}, 0},
1035 {"FILE_LIMIT", HISYSEVENT_INT32, {.i32 = g_traceSysEventParams.fileLimit}, 0},
1036 {"FILE_SIZE", HISYSEVENT_INT32, {.i32 = g_traceSysEventParams.fileSize}, 0},
1037 {"CLOCK_TYPE", HISYSEVENT_STRING, {.s = const_cast<char*>(g_traceSysEventParams.clockType.c_str())}, 0},
1038 {"IS_COMPRESSED", HISYSEVENT_BOOL, {.b = g_traceSysEventParams.isCompress}, 0},
1039 {"IS_RAW", HISYSEVENT_BOOL, {.b = g_traceSysEventParams.isRaw}, 0},
1040 {"IS_OVERWRITE", HISYSEVENT_BOOL, {.b = g_traceSysEventParams.isOverwrite}, 0},
1041 {"ERROR_CODE", HISYSEVENT_INT32, {.i32 = g_traceSysEventParams.errorCode}, 0},
1042 {"ERROR_MESSAGE", HISYSEVENT_STRING, {.s = const_cast<char*>(g_traceSysEventParams.errorMessage.c_str())}, 0},
1043 };
1044 int ret = OH_HiSysEvent_Write("PROFILER", "HITRACE_USAGE",
1045 HISYSEVENT_BEHAVIOR, params, sizeof(params) / sizeof(params[0]));
1046 if (ret != 0) {
1047 HILOG_ERROR(LOG_CORE, "HiSysEventWrite failed, ret is %{public}d", ret);
1048 }
1049 }
1050
1051 #ifdef HITRACE_UNITTEST
HiTraceCMDTestMain(int argc,char ** argv)1052 int HiTraceCMDTestMain(int argc, char **argv)
1053 #else
1054 int main(int argc, char **argv)
1055 #endif
1056 {
1057 if (!IsDeveloperMode()) {
1058 ConsoleLog("error: not in developermode, exit");
1059 return -1;
1060 }
1061
1062 if (argc < 0 || argc > 256) { // 256 : max input argument counts
1063 ConsoleLog("error: the number of input arguments exceeds the upper limit.");
1064 return -1;
1065 }
1066 bool isSuccess = true;
1067 g_traceCollector = OHOS::HiviewDFX::UCollectClient::TraceCollector::Create();
1068 if (g_traceCollector == nullptr) {
1069 ConsoleLog("error: traceCollector create failed, exit.");
1070 return -1;
1071 }
1072 (void)signal(SIGKILL, InterruptExit);
1073 (void)signal(SIGINT, InterruptExit);
1074
1075 if (!IsTraceMounted(g_traceRootPath)) {
1076 ConsoleLog("error: trace isn't mounted, exit.");
1077 return -1;
1078 }
1079
1080 if (!HandleOpt(argc, argv)) {
1081 ConsoleLog("error: parsing args failed, exit.");
1082 return -1;
1083 }
1084
1085 if (g_runningState == STATE_NULL) {
1086 g_runningState = RECORDING_SHORT_TEXT;
1087 }
1088
1089 if (g_runningState != RECORDING_SHORT_TEXT && g_runningState != RECORDING_LONG_DUMP &&
1090 g_runningState != RECORDING_LONG_FINISH) {
1091 ConsoleLog(std::string(argv[0]) + " enter, running_state is " + GetStateInfo(g_runningState));
1092 }
1093
1094 SetTraceSysEventParams();
1095
1096 switch (g_runningState) {
1097 case RECORDING_SHORT_RAW:
1098 isSuccess = HandleRecordingShortRaw();
1099 break;
1100 case RECORDING_SHORT_TEXT:
1101 isSuccess = HandleRecordingShortText();
1102 break;
1103 case RECORDING_LONG_BEGIN:
1104 isSuccess = HandleRecordingLongBegin();
1105 break;
1106 case RECORDING_LONG_DUMP:
1107 isSuccess = HandleRecordingLongDump();
1108 break;
1109 case RECORDING_LONG_FINISH:
1110 isSuccess = HandleRecordingLongFinish();
1111 break;
1112 case RECORDING_LONG_FINISH_NODUMP:
1113 isSuccess = HandleRecordingLongFinishNodump();
1114 break;
1115 case RECORDING_LONG_BEGIN_RECORD:
1116 isSuccess = HandleRecordingLongBeginRecord();
1117 break;
1118 case RECORDING_LONG_FINISH_RECORD:
1119 isSuccess = HandleRecordingLongFinishRecord();
1120 break;
1121 case SNAPSHOT_START:
1122 isSuccess = HandleOpenSnapshot();
1123 break;
1124 case SNAPSHOT_DUMP:
1125 isSuccess = HandleDumpSnapshot();
1126 break;
1127 case SNAPSHOT_STOP:
1128 isSuccess = HandleCloseSnapshot();
1129 break;
1130 case SHOW_HELP:
1131 ShowHelp(argv[0]);
1132 break;
1133 case SHOW_LIST_CATEGORY:
1134 ShowListCategory();
1135 break;
1136 case SET_TRACE_LEVEL:
1137 isSuccess = SetTraceLevel();
1138 break;
1139 case GET_TRACE_LEVEL:
1140 isSuccess = GetTraceLevel();
1141 break;
1142 default:
1143 ShowHelp(argv[0]);
1144 isSuccess = false;
1145 break;
1146 }
1147 RecordSysEvent();
1148 return isSuccess ? 0 : -1;
1149 }
1150