• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentTime);
215     struct tm timeInfo = {};
216     const int bufferSize = 20;
217     char timeStr[bufferSize] = {0};
218     localtime_r(&currentTime, &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