1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 <arpa/inet.h>
17 #include <cinttypes>
18 #include <condition_variable>
19 #include <csignal>
20 #include <cstdio>
21 #include <cstring>
22 #include <fstream>
23 #include <getopt.h>
24 #include <grpcpp/grpcpp.h>
25 #include <ifaddrs.h>
26 #include <netinet/in.h>
27 #include <ostream>
28 #include <sys/types.h>
29 #include <thread>
30 #include <unistd.h>
31 #include <vector>
32 #include <future>
33 
34 #include "common.h"
35 #include "command_line.h"
36 #include "google/protobuf/text_format.h"
37 #include "parameters.h"
38 #include "parse_plugin_config.h"
39 #include "profiler_service.grpc.pb.h"
40 #include "trace_plugin_config.pb.h"
41 
42 using google::protobuf::TextFormat;
43 
44 namespace {
45 constexpr int ADDR_BUFFER_SIZE = 128;
46 constexpr int MS_PER_S = 1000;
47 constexpr int KEEP_SESSION_TIMEOUT_MS = 5 * 1000;
48 constexpr int KEEP_SESSION_SLEEP_SECOND = 3;
49 constexpr int DEFAULT_SESSION_TIME_S = 10;
50 constexpr uint32_t INT_MAX_LEN = 10;
51 const std::string DEFAULT_OUTPUT_FILE = "/data/local/tmp/hiprofiler_data.htrace";
52 const std::string HIPROFILERD_NAME("hiprofilerd");
53 const std::string HIPROFILER_PLUGINS_NAME("hiprofiler_plugins");
54 const std::string NATIVE_DAEMON_NAME("native_daemon");
55 
56 uint32_t g_sampleDuration = 0;
57 int g_hiprofilerdPid = -1;
58 int g_hiprofilerPluginsPid = -1;
59 int g_nativeDaemonPid = -1;
60 std::condition_variable g_sessionCv;
61 std::condition_variable g_keepSessionCv;
62 bool g_exitProcessFlag = false;
63 
64 std::mutex g_keepSessionMutex;
65 std::mutex g_sessionMutex;
66 
GetLoopbackAddress()67 std::string GetLoopbackAddress()
68 {
69     char addressBuffer[ADDR_BUFFER_SIZE] = "";
70     struct ifaddrs* ifAddrStruct = nullptr;
71     void* tmpAddrPtr = nullptr;
72 
73     getifaddrs(&ifAddrStruct);
74     while (ifAddrStruct != nullptr) {
75         if (ifAddrStruct->ifa_addr == nullptr) {
76             ifAddrStruct = ifAddrStruct->ifa_next;
77             continue;
78         }
79         if (ifAddrStruct->ifa_addr->sa_family == AF_INET) {
80             // is a valid IP4 Address
81             tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
82             inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
83             if (strcmp(addressBuffer, "127.0.0.1") == 0) {
84                 break;
85             }
86         } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { // check it is IP6
87             // is a valid IP6 Address
88             tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
89             inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
90         }
91         ifAddrStruct = ifAddrStruct->ifa_next;
92     }
93 
94     freeifaddrs(ifAddrStruct);
95     return addressBuffer;
96 }
97 
GetServicePort()98 uint16_t GetServicePort()
99 {
100     return COMMON::GetServicePort();
101 }
102 
MakeCreateRequest(const std::string& config, const std::string& keepSecond, const std::string& outputFile)103 std::unique_ptr<CreateSessionRequest> MakeCreateRequest(const std::string& config,
104                                                         const std::string& keepSecond,
105                                                         const std::string& outputFile)
106 {
107     auto request = std::make_unique<CreateSessionRequest>();
108     std::string content = config;
109     if (content.empty()) {
110         printf("config file empty!");
111         return nullptr;
112     }
113 
114     if (!ParsePluginConfig::GetInstance().GetParser().ParseFromString(content, request.get())) {
115         printf("config [%s] parse FAILED!\n", content.c_str());
116         return nullptr;
117     }
118 
119     auto sessionConfig = request->mutable_session_config();
120     if (!sessionConfig) {
121         return nullptr;
122     }
123 
124     request->set_request_id(1);
125     if (!keepSecond.empty() && keepSecond.size() < INT_MAX_LEN) {
126         int ks = COMMON::IsNumeric(keepSecond) ? std::stoi(keepSecond) : 0;
127         if (ks > 0) {
128             sessionConfig->set_sample_duration(ks * MS_PER_S);
129         }
130     } else if (sessionConfig->sample_duration() <= 0) {
131         sessionConfig->set_sample_duration(DEFAULT_SESSION_TIME_S * MS_PER_S);
132     }
133     if (!outputFile.empty()) {
134         sessionConfig->set_result_file(outputFile);
135     } else if (sessionConfig->result_file() == "") {
136         sessionConfig->set_result_file(DEFAULT_OUTPUT_FILE);
137     }
138     printf("keepSecond: %us, outputFileName: %s\n", sessionConfig->sample_duration() / MS_PER_S,
139         sessionConfig->result_file().c_str());
140 
141     g_sampleDuration = sessionConfig->sample_duration();
142     for (int i = 0; i < request->plugin_configs().size(); i++) {
143         auto pluginConfig = request->mutable_plugin_configs(i);
144         if (!ParsePluginConfig::GetInstance().SetSerializePluginsConfig(pluginConfig->name(), *pluginConfig)) {
145             printf("set %s plugin config failed\n", pluginConfig->name().c_str());
146             return nullptr;
147         }
148     }
149 
150     content.clear();
151     if (!TextFormat::PrintToString(*request.get(), &content)) {
152         printf("config message format FAILED!\n");
153         return nullptr;
154     }
155 
156     return request;
157 }
158 
GetProfilerServiceStub()159 std::unique_ptr<IProfilerService::Stub> GetProfilerServiceStub()
160 {
161     std::string serviceUri = GetLoopbackAddress() + ":" + std::to_string(GetServicePort());
162     auto grpcChannel = grpc::CreateChannel(serviceUri, grpc::InsecureChannelCredentials());
163     if (grpcChannel == nullptr) {
164         printf("Create gRPC channel failed!\n");
165         return nullptr;
166     }
167     return IProfilerService::NewStub(grpcChannel);
168 }
169 
GetCapabilities(std::string& content, bool isCheck)170 bool GetCapabilities(std::string& content, bool isCheck)
171 {
172     auto profilerStub = GetProfilerServiceStub();
173     if (profilerStub == nullptr) {
174         printf("Get profiler service stub failed!\n");
175         return false;
176     }
177 
178     GetCapabilitiesRequest capRequest;
179     GetCapabilitiesResponse capResponse;
180     capRequest.set_request_id(0);
181     grpc::ClientContext capContext;
182     grpc::Status status = profilerStub->GetCapabilities(&capContext, capRequest, &capResponse);
183     if (!status.ok()) {
184         printf("Service not started\n");
185         return false;
186     }
187 
188     if (!TextFormat::PrintToString(capResponse, &content)) {
189         printf("capabilities message format FAILED!\n");
190         return false;
191     }
192 
193     if (!isCheck) {
194         printf("support plugin list:\n%s\n", content.c_str());
195     }
196     return true;
197 }
198 
CreateSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, const std::string& config, const std::string& keepSecond, const std::string& outputFile)199 uint32_t CreateSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, const std::string& config,
200     const std::string& keepSecond, const std::string& outputFile)
201 {
202     auto request = MakeCreateRequest(config, keepSecond, outputFile);
203     if (!request) {
204         printf("MakeCreateRequest failed!\n");
205         return 0;
206     }
207 
208     CreateSessionResponse createResponse;
209     grpc::ClientContext createSessionContext;
210     grpc::Status status = profilerStub->CreateSession(&createSessionContext, *request, &createResponse);
211     if (!status.ok()) {
212         printf("CreateSession FAIL\n");
213         return 0;
214     }
215 
216     return createResponse.session_id();
217 }
218 
CheckStartSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)219 bool CheckStartSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
220 {
221     StartSessionRequest startRequest;
222     StartSessionResponse startResponse;
223     startRequest.set_request_id(0);
224     startRequest.set_session_id(sessionId);
225     grpc::ClientContext startContext;
226     grpc::Status status = profilerStub->StartSession(&startContext, startRequest, &startResponse);
227     if (!status.ok()) {
228         printf("StartSession FAIL\n");
229         return false;
230     }
231 
232     return true;
233 }
234 
CheckStopSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)235 bool CheckStopSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
236 {
237     StopSessionRequest stopRequest;
238     StopSessionResponse stopResponse;
239     grpc::ClientContext stopContext;
240     stopRequest.set_session_id(sessionId);
241     grpc::Status status = profilerStub->StopSession(&stopContext, stopRequest, &stopResponse);
242     if (!status.ok()) {
243         return false;
244     }
245 
246     printf("StopSession done!\n");
247     return true;
248 }
249 
CheckDestroySession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)250 bool CheckDestroySession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
251 {
252     DestroySessionRequest destroyRequest;
253     DestroySessionResponse destroyResponse;
254     grpc::ClientContext destroyContext;
255     destroyRequest.set_session_id(sessionId);
256     grpc::Status status = profilerStub->DestroySession(&destroyContext, destroyRequest, &destroyResponse);
257     if (!status.ok()) {
258         return false;
259     }
260 
261     printf("DestroySession done!\n");
262     return true;
263 }
264 
StartThread(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& id, std::atomic<bool>& sendHeart)265 void StartThread(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& id, std::atomic<bool>& sendHeart)
266 {
267     while (sendHeart.load()) {
268         KeepSessionRequest keepRequest;
269         keepRequest.set_request_id(0);
270         keepRequest.set_session_id(id);
271         keepRequest.set_keep_alive_time(KEEP_SESSION_TIMEOUT_MS);
272         grpc::ClientContext keepContext;
273         KeepSessionResponse keepResponse;
274         profilerStub->KeepSession(&keepContext, keepRequest, &keepResponse);
275 
276         std::unique_lock<std::mutex> lck(g_keepSessionMutex);
277         g_keepSessionCv.wait_for(lck, std::chrono::seconds(KEEP_SESSION_SLEEP_SECOND));
278     }
279 }
280 
StopThread(std::thread& keepSessionThread, std::atomic<bool>& sendHeart)281 void StopThread(std::thread& keepSessionThread, std::atomic<bool>& sendHeart)
282 {
283     sendHeart = false;
284     g_keepSessionCv.notify_one();
285     if (keepSessionThread.joinable()) {
286         keepSessionThread.join();
287     }
288 }
289 
DoCapture(const std::string& config, const std::string& keepSecond, const std::string& outputFile)290 bool DoCapture(const std::string& config, const std::string& keepSecond, const std::string& outputFile)
291 {
292     auto profilerStub = GetProfilerServiceStub();
293     if (profilerStub == nullptr) {
294         printf("Get profiler service stub failed!\n");
295         return false;
296     }
297     if (g_exitProcessFlag) {
298         return false;
299     }
300 
301     if (!COMMON::IsNumeric(keepSecond)) {
302         printf("please input a valid time value");
303         return false;
304     }
305     uint32_t sessionId = CreateSession(profilerStub, config, keepSecond, outputFile);
306     if (sessionId == 0) {
307         printf("Create session returns Id 0\n");
308         return false;
309     }
310     if (g_exitProcessFlag) {
311         // session has been created, need to destroy the session.
312         return CheckDestroySession(profilerStub, sessionId);
313     }
314 
315     // start keepSessionThread, in order to ensure the sessionId is valid.
316     std::atomic<bool> sendHeart = true;
317     std::thread keepSessionThread(StartThread, std::ref(profilerStub), std::ref(sessionId), std::ref(sendHeart));
318     if (g_exitProcessFlag) {
319         // session has been created and keepSessionThread has been started.
320         // need to stop keepSessionThread and destroy the session.
321         StopThread(keepSessionThread, sendHeart);
322         return CheckDestroySession(profilerStub, sessionId);
323     }
324 
325     if (!CheckStartSession(profilerStub, sessionId)) {
326         return false;
327     }
328 
329     if (!g_exitProcessFlag) {
330         // waiting for the collection time to end or signal wakeup.
331         printf("tracing %u ms....\n", g_sampleDuration);
332         std::cout.flush();
333         std::unique_lock<std::mutex> lck(g_sessionMutex);
334         g_sessionCv.wait_for(lck, std::chrono::milliseconds(g_sampleDuration));
335     }
336 
337     bool ret = false;
338     if (CheckStopSession(profilerStub, sessionId) && CheckDestroySession(profilerStub, sessionId)) {
339         ret = true;
340     }
341 
342     StopThread(keepSessionThread, sendHeart);
343     return ret;
344 }
345 
346 struct DataContext {
347     bool isGetGrpcAddr = false;
348     std::string traceKeepSecond;
349     std::string configFile;
350     std::string outputFile;
351     bool isHelp = false;
352     bool isShowPluginList = false;
353     bool isStartProcess = false;
354     bool isKillProcess = false;
355 };
356 
ParseCmdline(CommandLine& cmdLine, DataContext& data)357 void ParseCmdline(CommandLine& cmdLine, DataContext& data)
358 {
359     cmdLine.AddParamSwitch("--getport", "-q", data.isGetGrpcAddr, "get grpc address");
360     cmdLine.AddParamText("--time", "-t", data.traceKeepSecond, "trace time");
361     cmdLine.AddParamText("--out", "-o", data.outputFile, "output file name");
362     cmdLine.AddParamSwitch("--help", "-h", data.isHelp, "make some help");
363     cmdLine.AddParamSwitch("--list", "-l", data.isShowPluginList, "plugin list");
364     cmdLine.AddParamSwitch("--start", "-s", data.isStartProcess, "start dependent process");
365     cmdLine.AddParamSwitch("--kill", "-k", data.isKillProcess, "kill dependent process");
366     cmdLine.AddParamText("--config", "-c", data.configFile, "start trace by config file");
367 }
368 
CheckGrpcMsgSend()369 int CheckGrpcMsgSend()
370 {
371     auto profilerStub = GetProfilerServiceStub();
372     if (profilerStub == nullptr) {
373         printf("Get profiler service stub failed!\n");
374         return -1;
375     }
376 
377     GetCapabilitiesRequest request;
378     GetCapabilitiesResponse response;
379     request.set_request_id(0);
380 
381     grpc::ClientContext context;
382     grpc::Status status = profilerStub->GetCapabilities(&context, request, &response);
383     if (!status.ok()) {
384         printf("Service not started\n");
385         return -1;
386     }
387 
388     printf("OK\n");
389     printf("ip:%s\n", GetLoopbackAddress().c_str());
390     printf("port:%u\n", GetServicePort());
391     return 0;
392 }
393 
StartDependentProcess()394 bool StartDependentProcess()
395 {
396     constexpr int waitProcMills = 300;
397     OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "0");
398     std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
399     if (getuid() == 0) {
400         if (!COMMON::IsProcessExist(HIPROFILERD_NAME, g_hiprofilerdPid)) {
401             // need start hiprofilerd
402             std::vector<char*> argvVec;
403             argvVec.push_back(const_cast<char*>(HIPROFILERD_NAME.c_str()));
404             g_hiprofilerdPid = COMMON::StartProcess("/system/bin/hiprofilerd", argvVec);
405             // Wait for the hiprofilerd to start
406             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
407         }
408 
409         if (!COMMON::IsProcessExist(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid)) {
410             // need start hiprofiler_plugins
411             std::vector<char*> argvVec;
412             argvVec.push_back(const_cast<char*>(HIPROFILER_PLUGINS_NAME.c_str()));
413             g_hiprofilerPluginsPid = COMMON::StartProcess("/system/bin/hiprofiler_plugins", argvVec);
414             // Wait for the hiprofiler_plugins add preset plugin
415             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
416         }
417 
418         if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
419             // need start native_daemon
420             std::vector<char*> argvVec;
421             argvVec.push_back(const_cast<char*>(NATIVE_DAEMON_NAME.c_str()));
422             g_nativeDaemonPid = COMMON::StartProcess("/system/bin/native_daemon", argvVec);
423             // Wait for the native_daemon to start
424             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
425         }
426     } else {
427         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "0");
428         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "0");
429         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "0");
430 
431         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "1");
432         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
433         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "1");
434         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
435         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "1");
436         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
437     }
438 
439     std::string content = "";
440     GetCapabilities(content, true);
441     if (content == "") {
442         printf("Please confirm whether the plugin exists\n");
443         return false;
444     }
445 
446     return true;
447 }
448 
CheckProcessExit(const std::string& processName, int& pid)449 bool CheckProcessExit(const std::string& processName, int& pid)
450 {
451     int nCount = 5; // 5: try 5 times
452     constexpr int waitExitMills = 1000;
453     while (nCount > 0) {
454         if (COMMON::IsProcessExist(processName, pid)) {
455             nCount--;
456             std::this_thread::sleep_for(std::chrono::milliseconds(waitExitMills));
457         } else {
458             break;
459         }
460     }
461     return nCount > 0;
462 }
463 
KillDependentProcess()464 void KillDependentProcess()
465 {
466     constexpr int waitProcMills = 300;
467     OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "0");
468     std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
469     if (getuid() == 0) {
470         // if pid is equal to -1, need to get pid first.
471         if (g_nativeDaemonPid == -1) {
472             COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid);
473         }
474         if (g_hiprofilerPluginsPid == -1) {
475             COMMON::IsProcessExist(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid);
476         }
477         if (g_hiprofilerdPid == -1) {
478             COMMON::IsProcessExist(HIPROFILERD_NAME, g_hiprofilerdPid);
479         }
480         COMMON::KillProcess(g_nativeDaemonPid);
481         if (CheckProcessExit(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
482             printf("process native_daemon exits successfully\n");
483         } else {
484             printf("process native_daemon exits failed\n");
485         }
486         COMMON::KillProcess(g_hiprofilerPluginsPid);
487         if (CheckProcessExit(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid)) {
488             printf("process hiprofiler_plugins exits successfully\n");
489         } else {
490             printf("process hiprofiler_plugins exits failed\n");
491         }
492         COMMON::KillProcess(g_hiprofilerdPid);
493         if (CheckProcessExit(HIPROFILERD_NAME, g_hiprofilerdPid)) {
494             printf("process hiprofilerd exits successfully\n");
495         } else {
496             printf("process hiprofilerd exits failed\n");
497         }
498     } else {
499         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "0");
500         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "0");
501         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "0");
502     }
503 }
504 
ParseConfig(const std::string& configFile, std::string& config)505 bool ParseConfig(const std::string& configFile, std::string& config)
506 {
507     std::string configFileWithPath = configFile;
508     if (configFile.find('/') == std::string::npos) {
509         std::string path("/data/local/tmp/");
510         configFileWithPath = path + configFile; // add default path
511     }
512 
513     printf("Read config from %s\n", configFileWithPath.c_str());
514     std::vector<std::string> validPaths = { "/data/local/tmp/" };
515     if (!COMMON::ReadFile(configFileWithPath, validPaths, config)) {
516         printf("Read %s fail, please place it under \'/data/local/tmp/\'.\n", configFile.c_str());
517         return false;
518     }
519     config = ParsePluginConfig::GetInstance().GetPluginsConfig(config);
520     if (config.empty()) {
521         printf("Error config file: %s\n", configFileWithPath.c_str()); // no config in command or config file
522         return false;
523     }
524     return true;
525 }
526 
SignalHandler(int signal)527 void SignalHandler(int signal)
528 {
529     if (signal == SIGINT) {
530         g_exitProcessFlag = true;
531         std::async(&std::condition_variable::notify_one, &g_sessionCv);
532     }
533 }
534 } // namespace
535 
main(int argc, char* argv[])536 int main(int argc, char* argv[])
537 {
538     if (!COMMON::GetDeveloperMode()) {
539         return -1;
540     }
541     signal(SIGINT, SignalHandler);
542 
543     std::string config = "";
544     while (true) {
545         struct option long_options[] = {
546             {"getport", no_argument, nullptr, 'q'},
547             {"time", required_argument, nullptr, 't'},
548             {"out", required_argument, nullptr, 'o'},
549             {"help", no_argument, nullptr, 'h'},
550             {"list", no_argument, nullptr, 'l'},
551             {"start", no_argument,  nullptr, 's'},
552             {"kill", no_argument,  nullptr, 'k'},
553             {"config", required_argument, nullptr, 'c'},
554             {nullptr, 0, nullptr, 0}
555         };
556         int option = getopt_long(argc, argv, "c:t:o:qhlsk", long_options, nullptr);
557         if (option == -1) {
558             break;  // CONFIG.
559         }
560 
561         if (option == 'c' && strcmp(optarg, "-") == 0) {
562             std::string content;
563             std::istreambuf_iterator<char> begin(std::cin);
564             std::istreambuf_iterator<char> end = {};
565             content.assign(begin, end);
566             config = ParsePluginConfig::GetInstance().GetPluginsConfig(content);
567             if (config.empty()) {
568                 printf("Please check the configuration!\n");
569                 return -1;
570             }
571         }
572     }
573 
574     DataContext data;
575     CommandLine& cmdLine = CommandLine::GetInstance();
576     ParseCmdline(cmdLine, data);
577 
578     std::vector<std::string> argvVector;
579     for (int i = 0; i < argc; i++) {
580         if (((i + 1) < argc) && (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0) &&
581             (strcmp(argv[i + 1], "-") == 0)) {
582             i++;
583         } else {
584             argvVector.push_back(argv[i]);
585         }
586     }
587     if (argc < 1 || cmdLine.AnalyzeParam(argvVector) < 0 || data.isHelp) {
588         cmdLine.PrintHelp();
589         exit(0);
590     }
591 
592     // need to delete old file.
593     remove(data.outputFile.c_str());
594 
595     if (config.empty() && !data.configFile.empty()) {
596         if (!ParseConfig(data.configFile, config)) {
597             return -1;
598         }
599     }
600 
601     if (data.isStartProcess) {
602         if (!StartDependentProcess()) {
603             if (data.isKillProcess) {
604                 KillDependentProcess();
605             }
606             return 0;
607         }
608     }
609 
610     if (data.isGetGrpcAddr) { // handle get port
611         int ret = CheckGrpcMsgSend();
612         if (data.isKillProcess) {
613             KillDependentProcess();
614         }
615         return ret;
616     }
617 
618     if (data.isShowPluginList) { // handle show plugin list
619         std::string content = "";
620         GetCapabilities(content, false);
621         if (data.isKillProcess) {
622             KillDependentProcess();
623         }
624         return 0;
625     }
626 
627     if (config.empty()) { // normal case
628         if (data.isKillProcess) {
629             KillDependentProcess();
630             return 1;
631         }
632         if (!data.isStartProcess) {
633             printf("config file argument must sepcified!\n");
634         }
635         return 1;
636     }
637     // do capture work
638     if (DoCapture(config, data.traceKeepSecond, data.outputFile)) {
639         printf("DONE\n");
640     }
641 
642     if (data.isKillProcess) {
643         KillDependentProcess();
644     }
645     return 0;
646 }
647