1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "hiperf_client.h"
16 #include <sys/wait.h>
17 #include <algorithm>
18 #include <cinttypes>
19 #include <csignal>
20 #include <cstring>
21 #include <thread>
22 #include <poll.h>
23 #include <sys/prctl.h>
24 #include <unistd.h>
25 #include "hiperf_hilog.h"
26 
27 using namespace std::chrono;
28 namespace OHOS {
29 namespace Developtools {
30 namespace HiPerf {
31 namespace HiperfClient {
32 static const std::string HIPERF_COMMAND_NAME = "hiperf";
33 static const std::string SYSTEM_BIN_PATH = "/system/bin/";
34 static const std::string CURRENT_PATH = "./";
35 static const std::string PERF_DATA_NAME = "perf.data";
36 static const std::string COMMAND_RECORD = "record";
37 static const std::string ARG_OUTPUT_PATH = "-o";
38 static const std::string ARG_DEBUG = "--verbose";
39 static const std::string ARG_DEBUG_MUCH = "--much";
40 static const std::string ARG_HILOG = "--hilog";
41 static const std::string ARG_PIPE_INPUT = "--pipe_input";
42 static const std::string ARG_PIPE_OUTPUT = "--pipe_output";
43 static const std::string ARG_TARGET_SYSTEM_WIDE = "-a";
44 static const std::string ARG_COMPRESS_DATA = "-z";
45 static const std::string ARG_SELECT_CPUS = "-c";
46 static const std::string ARG_TIME_STOP_SEC = "-d";
47 static const std::string ARG_FREQUENCY = "-f";
48 static const std::string ARG_PERIOD = "--period";
49 static const std::string ARG_SELECT_EVENTS = "-e";
50 static const std::string ARG_SELECT_GROUPS = "-g";
51 static const std::string ARG_NO_INHERIT = "--no-inherit";
52 static const std::string ARG_SELECT_PIDS = "-p";
53 static const std::string ARG_SELECT_TIDS = "-t";
54 static const std::string ARG_EXCLUDE_PERF = "--exclude-hiperf";
55 static const std::string ARG_CPU_PERCENT = "--cpu-limit";
56 static const std::string ARG_OFF_CPU = "--offcpu";
57 static const std::string ARG_CALL_GRAPH = "--call-stack";
58 static const std::string ARG_DELAY_UNWIND = "--delay-unwind";
59 static const std::string ARG_DISABLE_UNWIND = "--disable-unwind";
60 static const std::string ARG_DISABLE_CALLSTACK_MERGE = "--disable-callstack-expand";
61 static const std::string ARG_SYMBOL_DIR = "--symbol-dir";
62 static const std::string ARG_DATA_LIMIT = "--data-limit";
63 static const std::string ARG_APP_PACKAGE = "--app";
64 static const std::string ARG_CLOCK_ID = "--clockid";
65 static const std::string ARG_VEC_BRANCH_SAMPLE_TYPES = "-j";
66 static const std::string ARG_MMAP_PAGES = "-m";
67 static const std::string ARG_REPORT = "--report";
68 
69 static constexpr int DEFAULT_DURATION_TIME = 10;
70 static constexpr int DEFAULT_FREQUENCY_TIME = 100;
71 static constexpr uint64_t PIPE_READ = 0;
72 static constexpr uint64_t PIPE_WRITE = 1;
73 static constexpr ssize_t ERRINFOLEN = 512;
74 static constexpr size_t SIZE_ARGV_TAIL = 1; // nullptr
75 
SetOption(const std::string &name, bool enable)76 void RecordOption::SetOption(const std::string &name, bool enable)
77 {
78     auto it = std::find(args_.begin(), args_.end(), name);
79     if (enable) {
80         if (it == args_.end()) {
81             args_.emplace_back(name);
82         }
83 
84         return;
85     }
86     if (it != args_.end()) {
87         args_.erase(it);
88         return;
89     }
90 }
91 
SetOption(const std::string &name, int value)92 void RecordOption::SetOption(const std::string &name, int value)
93 {
94     auto it = std::find(args_.begin(), args_.end(), name);
95     if (it != args_.end()) {
96         it++;
97         *it = std::to_string(value);
98         return;
99     }
100 
101     args_.emplace_back(name);
102     args_.emplace_back(std::to_string(value));
103     return;
104 }
105 
SetOption(const std::string &name, const std::vector<int> &vInt)106 void RecordOption::SetOption(const std::string &name, const std::vector<int> &vInt)
107 {
108     auto it = std::find(args_.begin(), args_.end(), name);
109     if (vInt.empty()) {
110         if (it != args_.end()) {
111             it = args_.erase(it); // remove key
112             if (it != args_.end()) {
113                 args_.erase(it); // remove value
114             }
115         }
116         return;
117     }
118 
119     std::string str;
120     for (auto n : vInt) {
121         str.append(std::to_string(n));
122         str.append(",");
123     }
124     str.pop_back(); // remove the last ','
125 
126     if (it != args_.end()) {
127         it++;
128         *it = str;
129         return;
130     }
131     args_.emplace_back(name);
132     args_.emplace_back(str);
133 }
134 
SetOption(const std::string &name, const std::string &str)135 void RecordOption::SetOption(const std::string &name, const std::string &str)
136 {
137     auto it = std::find(args_.begin(), args_.end(), name);
138     if (str.empty()) {
139         if (it != args_.end()) {
140             args_.erase(it);
141             args_.erase(it); // remove value
142         }
143         return;
144     }
145     if (it != args_.end()) {
146         it++;
147         *it = str;
148         return;
149     }
150     args_.emplace_back(name);
151     args_.emplace_back(str);
152 }
153 
SetOption(const std::string &name, const std::vector<std::string> &vStr)154 void RecordOption::SetOption(const std::string &name, const std::vector<std::string> &vStr)
155 {
156     auto it = std::find(args_.begin(), args_.end(), name);
157     if (vStr.empty()) {
158         if (it != args_.end()) {
159             args_.erase(it);
160             args_.erase(it); // remove value
161         }
162         return;
163     }
164 
165     std::string str;
166     for (auto substr : vStr) {
167         str.append(substr);
168         str.append(",");
169     }
170     str.pop_back(); // remove the last ','
171 
172     if (it != args_.end()) {
173         it++;
174         *it = str;
175         return;
176     }
177     args_.emplace_back(name);
178     args_.emplace_back(str);
179 }
180 
SetTargetSystemWide(bool enable)181 void RecordOption::SetTargetSystemWide(bool enable)
182 {
183     SetOption(ARG_TARGET_SYSTEM_WIDE, enable);
184 }
185 
SetCompressData(bool enable)186 void RecordOption::SetCompressData(bool enable)
187 {
188     SetOption(ARG_COMPRESS_DATA, enable);
189 }
190 
SetSelectCpus(const std::vector<int> &cpus)191 void RecordOption::SetSelectCpus(const std::vector<int> &cpus)
192 {
193     SetOption(ARG_SELECT_CPUS, cpus);
194 }
195 
SetTimeStopSec(int timeStopSec)196 void RecordOption::SetTimeStopSec(int timeStopSec)
197 {
198     this->timeSpec_ = true;
199     SetOption(ARG_TIME_STOP_SEC, timeStopSec);
200 }
201 
SetFrequency(int frequency)202 void RecordOption::SetFrequency(int frequency)
203 {
204     SetOption(ARG_FREQUENCY, frequency);
205 }
206 
SetPeriod(int period)207 void RecordOption::SetPeriod(int period)
208 {
209     SetOption(ARG_PERIOD, period);
210 }
211 
SetSelectEvents(const std::vector<std::string> &selectEvents)212 void RecordOption::SetSelectEvents(const std::vector<std::string> &selectEvents)
213 {
214     SetOption(ARG_SELECT_EVENTS, selectEvents);
215 }
216 
SetSelectGroups(const std::vector<std::string> &selectGroups)217 void RecordOption::SetSelectGroups(const std::vector<std::string> &selectGroups)
218 {
219     SetOption(ARG_SELECT_GROUPS, selectGroups);
220 }
221 
SetNoInherit(bool enable)222 void RecordOption::SetNoInherit(bool enable)
223 {
224     SetOption(ARG_NO_INHERIT, enable);
225 }
226 
SetSelectPids(const std::vector<pid_t> &selectPids)227 void RecordOption::SetSelectPids(const std::vector<pid_t> &selectPids)
228 {
229     SetOption(ARG_SELECT_PIDS, selectPids);
230 }
231 
SetCallStackSamplingConfigs(int duration)232 void RecordOption::SetCallStackSamplingConfigs(int duration)
233 {
234     if (duration <= 0) {
235         duration = DEFAULT_DURATION_TIME;
236     }
237     RecordOption opt;
238     SetSelectEvents(opt.GetSelectEvents());
239     SetTimeStopSec(duration);
240     SetFrequency(DEFAULT_FREQUENCY_TIME);
241     SetCallGraph("fp");
242 }
243 
SetSelectTids(const std::vector<pid_t> &selectTids)244 void RecordOption::SetSelectTids(const std::vector<pid_t> &selectTids)
245 {
246     SetOption(ARG_SELECT_TIDS, selectTids);
247 }
248 
SetExcludePerf(bool excludePerf)249 void RecordOption::SetExcludePerf(bool excludePerf)
250 {
251     SetOption(ARG_EXCLUDE_PERF, excludePerf);
252 }
253 
SetCpuPercent(int cpuPercent)254 void RecordOption::SetCpuPercent(int cpuPercent)
255 {
256     SetOption(ARG_CPU_PERCENT, cpuPercent);
257 }
258 
SetOffCPU(bool offCPU)259 void RecordOption::SetOffCPU(bool offCPU)
260 {
261     SetOption(ARG_OFF_CPU, offCPU);
262 }
263 
SetCallGraph(const std::string &callGraph)264 void RecordOption::SetCallGraph(const std::string &callGraph)
265 {
266     SetOption(ARG_CALL_GRAPH, callGraph);
267 }
268 
SetDelayUnwind(bool delayUnwind)269 void RecordOption::SetDelayUnwind(bool delayUnwind)
270 {
271     SetOption(ARG_DELAY_UNWIND, delayUnwind);
272 }
273 
SetDisableUnwind(bool disableUnwind)274 void RecordOption::SetDisableUnwind(bool disableUnwind)
275 {
276     SetOption(ARG_DISABLE_UNWIND, disableUnwind);
277 }
278 
SetDisableCallstackMerge(bool disableCallstackMerge)279 void RecordOption::SetDisableCallstackMerge(bool disableCallstackMerge)
280 {
281     SetOption(ARG_DISABLE_CALLSTACK_MERGE, disableCallstackMerge);
282 }
283 
SetSymbolDir(const std::string &symbolDir_)284 void RecordOption::SetSymbolDir(const std::string &symbolDir_)
285 {
286     SetOption(ARG_SYMBOL_DIR, symbolDir_);
287 }
288 
SetDataLimit(const std::string &limit)289 void RecordOption::SetDataLimit(const std::string &limit)
290 {
291     SetOption(ARG_DATA_LIMIT, limit);
292 }
293 
SetAppPackage(const std::string &appPackage)294 void RecordOption::SetAppPackage(const std::string &appPackage)
295 {
296     SetOption(ARG_APP_PACKAGE, appPackage);
297 }
298 
SetClockId(const std::string &clockId)299 void RecordOption::SetClockId(const std::string &clockId)
300 {
301     SetOption(ARG_CLOCK_ID, clockId);
302 }
303 
SetVecBranchSampleTypes(const std::vector<std::string> &vecBranchSampleTypes)304 void RecordOption::SetVecBranchSampleTypes(const std::vector<std::string> &vecBranchSampleTypes)
305 {
306     SetOption(ARG_VEC_BRANCH_SAMPLE_TYPES, vecBranchSampleTypes);
307 }
308 
SetMmapPages(int mmapPages)309 void RecordOption::SetMmapPages(int mmapPages)
310 {
311     SetOption(ARG_MMAP_PAGES, mmapPages);
312 }
313 
SetReport(bool report)314 void RecordOption::SetReport(bool report)
315 {
316     SetOption(ARG_REPORT, report);
317 }
318 
Client(const std::string &outputDir)319 Client::Client(const std::string &outputDir)
320 {
321     HIPERF_HILOGI(MODULE_CPP_API, "%" HILOG_PUBLIC "s default init with %" HILOG_PUBLIC "s\n",
322                   __FUNCTION__, outputDir.c_str());
323     Setup(outputDir);
324 }
325 
Setup(std::string outputDir)326 bool Client::Setup(std::string outputDir)
327 {
328     std::string CurrentCommandPath = CURRENT_PATH + HIPERF_COMMAND_NAME;
329     std::string SystemCommandPath = SYSTEM_BIN_PATH + HIPERF_COMMAND_NAME;
330     std::string TempCommandPath = TempBinPath + HIPERF_COMMAND_NAME;
331 
332     if (!outputDir.empty() && outputDir.back() != '/') {
333         outputDir.push_back('/');
334     }
335     HIPERF_HILOGI(MODULE_CPP_API, "outputDir setup to %" HILOG_PUBLIC "s\n", outputDir.c_str());
336 
337     // found command path
338     if (access(SystemCommandPath.c_str(), X_OK) == 0) {
339         executeCommandPath_ = SystemCommandPath;
340     } else if (access(TempCommandPath.c_str(), X_OK) == 0) {
341         executeCommandPath_ = TempCommandPath;
342     } else if (access(CurrentCommandPath.c_str(), X_OK) == 0) {
343         executeCommandPath_ = CurrentCommandPath;
344     } else {
345         HIPERF_HILOGI(MODULE_CPP_API, "no hiperf command found\n");
346         return ready_;
347     }
348 
349     // check output path
350     // found command path
351     if (access(outputDir.c_str(), W_OK) == 0) {
352         outputDir_ = outputDir;
353     } else if (access(CURRENT_PATH.c_str(), W_OK) == 0) {
354         outputDir_ = CURRENT_PATH;
355     } else {
356         HIPERF_HILOGI(MODULE_CPP_API, "no writeable output path found\n");
357         return ready_;
358     }
359     outputFileName_ = PERF_DATA_NAME;
360 
361     myPid_ = getpid();
362 
363     // every thing check ok
364     ready_ = true;
365 
366     return ready_;
367 }
368 
~Client()369 Client::~Client()
370 {
371     KillChild();
372 }
373 
IsReady()374 bool Client::IsReady()
375 {
376     return ready_;
377 }
378 
SetDebugMode()379 void Client::SetDebugMode()
380 {
381     debug_ = true;
382 }
383 
SetDebugMuchMode()384 void Client::SetDebugMuchMode()
385 {
386     debugMuch_ = true;
387 }
388 
Start()389 bool Client::Start()
390 {
391     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
392 
393     std::vector<std::string> args;
394     args.push_back("-p");
395     args.push_back(std::to_string(getpid()));
396     return Start(args);
397 }
398 
PrepareExecCmd(std::vector<std::string> &cmd)399 void Client::PrepareExecCmd(std::vector<std::string> &cmd)
400 {
401     cmd.clear();
402     cmd.emplace_back(executeCommandPath_);
403 
404     if (debug_) {
405         cmd.emplace_back(ARG_DEBUG);
406     } else if (debugMuch_) {
407         cmd.emplace_back(ARG_DEBUG_MUCH);
408     }
409 
410     if (hilog_) {
411         cmd.emplace_back(ARG_HILOG);
412     }
413 
414     cmd.emplace_back(COMMAND_RECORD);
415     cmd.emplace_back(ARG_OUTPUT_PATH);
416     cmd.emplace_back(GetOutputPerfDataPath());
417 }
418 
GetExecCmd(std::vector<std::string> &cmd, int pipeIn, int pipeOut, const std::vector<std::string> &args)419 void Client::GetExecCmd(std::vector<std::string> &cmd, int pipeIn, int pipeOut,
420                         const std::vector<std::string> &args)
421 {
422     PrepareExecCmd(cmd);
423     cmd.emplace_back(ARG_PIPE_INPUT);
424     cmd.emplace_back(std::to_string(pipeIn));
425     cmd.emplace_back(ARG_PIPE_OUTPUT);
426     cmd.emplace_back(std::to_string(pipeOut));
427 
428     cmd.insert(cmd.end(), args.begin(), args.end());
429 }
430 
GetExecCmd(std::vector<std::string> &cmd, const std::vector<std::string> &args)431 void Client::GetExecCmd(std::vector<std::string> &cmd,
432                         const std::vector<std::string> &args)
433 {
434     PrepareExecCmd(cmd);
435 
436     cmd.insert(cmd.end(), args.begin(), args.end());
437 }
438 
Start(const std::vector<std::string> &args, bool immediately)439 bool Client::Start(const std::vector<std::string> &args, bool immediately)
440 {
441     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
442     if (!ready_) {
443         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
444         return false;
445     }
446 
447     int clientToServerFd[2];
448     int serverToClientFd[2];
449     if (pipe(clientToServerFd) != 0) {
450         char errInfo[ERRINFOLEN] = { 0 };
451         strerror_r(errno, errInfo, ERRINFOLEN);
452         HIPERF_HILOGI(MODULE_CPP_API, "failed to create pipe: %" HILOG_PUBLIC "s", errInfo);
453         return false;
454     } else if (pipe(serverToClientFd) != 0) {
455         char errInfo[ERRINFOLEN] = { 0 };
456         strerror_r(errno, errInfo, ERRINFOLEN);
457         HIPERF_HILOGI(MODULE_CPP_API, "failed to create pipe: %" HILOG_PUBLIC "s", errInfo);
458         close(clientToServerFd[PIPE_READ]);
459         close(clientToServerFd[PIPE_WRITE]);
460         return false;
461     }
462 
463     hperfPrePid_ = fork();
464     if (hperfPrePid_ == -1) {
465         char errInfo[ERRINFOLEN] = { 0 };
466         strerror_r(errno, errInfo, ERRINFOLEN);
467         HIPERF_HILOGI(MODULE_CPP_API, "failed to fork: %" HILOG_PUBLIC "s", errInfo);
468         close(clientToServerFd[PIPE_READ]);
469         close(clientToServerFd[PIPE_WRITE]);
470         close(serverToClientFd[PIPE_READ]);
471         close(serverToClientFd[PIPE_WRITE]);
472         return false;
473     } else if (hperfPrePid_ == 0) {
474         // child process
475         close(clientToServerFd[PIPE_WRITE]);
476         close(serverToClientFd[PIPE_READ]);
477 
478         std::vector<std::string> cmd;
479         GetExecCmd(cmd, clientToServerFd[PIPE_READ], serverToClientFd[PIPE_WRITE], args);
480         ChildRunExecv(cmd);
481     } else {
482         // parent process
483         close(clientToServerFd[PIPE_READ]);
484         close(serverToClientFd[PIPE_WRITE]);
485 
486         clientToServerFd_ = clientToServerFd[PIPE_WRITE];
487         serverToClientFd_ = serverToClientFd[PIPE_READ];
488     }
489     using namespace std::chrono_literals;
490     if (!WaitCommandReply(2000ms)) {
491         HIPERF_HILOGI(MODULE_CPP_API, "start failed . lets kill it");
492         KillChild();
493         return false;
494     }
495     if (immediately) {
496         return StartRun();
497     }
498     return true;
499 }
500 
Start(const RecordOption &option)501 bool Client::Start(const RecordOption &option)
502 {
503     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
504     if (!option.GetOutputFileName().empty()) {
505         outputFileName_ = option.GetOutputFileName();
506     }
507     if (option.IsTimeSpecified()) {
508         return RunHiperfCmdSync(option);
509     }
510     return Start(option.GetOptionVecString());
511 }
512 
ChildRunExecv(std::vector<std::string> &cmd)513 void Client::ChildRunExecv(std::vector<std::string> &cmd)
514 {
515     // conver vector to array for execvp()
516     char *argv[cmd.size() + SIZE_ARGV_TAIL];
517     size_t i = 0;
518     for (i = 0; i < cmd.size(); ++i) {
519         HIPERF_HILOGI(MODULE_CPP_API, "args %" HILOG_PUBLIC "zu : %" HILOG_PUBLIC "s", i,
520                         cmd[i].c_str());
521         argv[i] = cmd[i].data();
522     }
523     argv[i] = nullptr;
524 
525     execv(argv[0], argv);
526 
527     // never reach the following line, unless calling of execv function failed.
528     char errInfo[ERRINFOLEN] = { 0 };
529     strerror_r(errno, errInfo, ERRINFOLEN);
530     HIPERF_HILOGI(MODULE_CPP_API,
531             "failed to call exec: '%" HILOG_PUBLIC "s' %" HILOG_PUBLIC "s\n",
532             executeCommandPath_.c_str(), errInfo);
533     exit(EXIT_FAILURE); // EXIT_FAILURE 1
534 }
535 
ParentWait(pid_t &wpid, pid_t pid, int &childStatus)536 bool Client::ParentWait(pid_t &wpid, pid_t pid, int &childStatus)
537 {
538     bool ret = false;
539     do {
540         // blocking...
541         int option;
542 #ifdef WCONTINUED
543         option = WUNTRACED | WCONTINUED;
544 #else
545         option = WUNTRACED;
546 #endif
547         wpid = waitpid(pid, &childStatus, option);
548         if (wpid == -1) {
549             perror("waitpid");
550             return false;
551         }
552 
553         if (WIFEXITED(childStatus)) {
554             // child normally exit
555             // WEXITSTATUS(childStatus) value :
556             // true -> Calling of execv func successed, and recording finished
557             // and child will return the value of recording process's retVal
558             // false -> Calling of execv func failed, child will output errInfo
559             ret = WEXITSTATUS(childStatus) == 0 ? true : false;
560             HIPERF_HILOGI(MODULE_CPP_API,
561                 "Hiperf Api Child normally exit Calling of execv : '%" HILOG_PUBLIC "s' \n",
562                 ret ? "success" : "failed");
563             return ret;
564         } else if (WIFSIGNALED(childStatus)) {
565             // child was killed by SIGKILL
566             HIPERF_HILOGI(MODULE_CPP_API, "Hiperf recording process was killed by signal SIGKILL\n");
567             ret = false;
568             return ret;
569         } else if (WIFSTOPPED(childStatus)) {
570             // child was stopped by SIGSTOP, and waiting for SIGCONT
571             HIPERF_HILOGI(MODULE_CPP_API, "Hiperf recording process was stopped by signal SIGSTOP\n");
572 #ifdef WIFCONTINUED
573         } else if (WIFCONTINUED(childStatus)) {
574             // child was continued by SIGCONT
575             HIPERF_HILOGI(MODULE_CPP_API, "Hiperf recording process was continued\n by SIGCONT");
576 #endif
577         } else {
578             // non-standard case, may never happen
579             HIPERF_HILOGI(MODULE_CPP_API, "Hiperf recording process Unexpected status\n");
580         }
581     } while (!WIFEXITED(childStatus) && !WIFSIGNALED(childStatus));
582 
583     // normal exit.
584     if (WIFEXITED(childStatus)) {
585         ret = WEXITSTATUS(childStatus) == HIPERF_EXIT_CODE;
586     } else {
587     // signal exit, means Hiperf recording process may occur some runtime errors.
588         HIPERF_HILOGI(MODULE_CPP_API,
589             "Hiperf recording occurs some runtime errors, end with signal : %"
590             HILOG_PUBLIC "d,  exit status : %" HILOG_PUBLIC "d\n",
591             WIFSIGNALED(childStatus), WEXITSTATUS(childStatus));
592         ret = false;
593     }
594     return ret;
595 }
596 
597 
RunHiperfCmdSync(const RecordOption &option)598 bool Client::RunHiperfCmdSync(const RecordOption &option)
599 {
600     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
601     if (!ready_) {
602         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
603         return false;
604     }
605     const std::vector<std::string> &args = option.GetOptionVecString();
606 
607     pid_t wpid;
608     int childStatus;
609     bool ret = false;
610     hperfPid_ = fork();
611     if (hperfPid_ == -1) {
612         char errInfo[ERRINFOLEN] = { 0 };
613         strerror_r(errno, errInfo, ERRINFOLEN);
614         HIPERF_HILOGI(MODULE_CPP_API, "failed to fork: %" HILOG_PUBLIC "s", errInfo);
615         return false;
616     } else if (hperfPid_ == 0) {
617         // child execute
618         std::vector<std::string> cmd;
619         GetExecCmd(cmd, args);
620         ChildRunExecv(cmd);
621     } else {
622         ret = ParentWait(wpid, hperfPid_, childStatus);
623     }
624     return ret;
625 }
626 
PrePare(const RecordOption &option)627 bool Client::PrePare(const RecordOption &option)
628 {
629     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
630     if (!option.GetOutputFileName().empty()) {
631         outputFileName_ = option.GetOutputFileName();
632     }
633     return Start(option.GetOptionVecString(), false);
634 }
635 
WaitCommandReply(std::chrono::milliseconds timeOut)636 bool Client::WaitCommandReply(std::chrono::milliseconds timeOut)
637 {
638     std::string reply;
639     struct pollfd pollFd;
640     pollFd.fd = serverToClientFd_;
641     pollFd.events = POLLIN;
642     pollFd.revents = 0;
643 
644     // wait some data
645     int polled = poll(&pollFd, 1, timeOut.count());
646     if (polled > 0) {
647         while (true) {
648             char c;
649             ssize_t result = TEMP_FAILURE_RETRY(read(serverToClientFd_, &c, 1));
650             if (result <= 0) {
651                 HIPERF_HILOGI(MODULE_CPP_API, "read failed from pipe");
652                 return false; // read fial means not ok
653             }
654 
655             reply.push_back(c);
656             if (c == '\n') {
657                 break;
658             }
659         }
660     } else if (polled == 0) {
661         HIPERF_HILOGI(MODULE_CPP_API, "Client:command no response %" HILOG_PUBLIC "" PRIu64 ".\n",
662                       (uint64_t)timeOut.count());
663     } else {
664         HIPERF_HILOGI(MODULE_CPP_API, "Client:command poll failed.\n");
665     }
666     HIPERF_HILOGI(MODULE_CPP_API, "Client:new reply:%" HILOG_PUBLIC "s\n", reply.c_str());
667     if (reply == ReplyOK) {
668         return true;
669     } else {
670         return false;
671     }
672 }
673 
KillChild()674 void Client::KillChild()
675 {
676     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
677     if (clientToServerFd_ != -1) {
678         close(clientToServerFd_);
679         clientToServerFd_ = -1;
680     }
681     if (serverToClientFd_ != -1) {
682         close(serverToClientFd_);
683         serverToClientFd_ = -1;
684     }
685     if (hperfPid_ > 0) {
686         kill(hperfPid_, SIGKILL);
687         hperfPid_ = -1;
688     }
689     if (hperfPrePid_ > 0) {
690         pid_t wpid;
691         int childStatus;
692         ParentWait(wpid, hperfPrePid_, childStatus);
693         hperfPrePid_ = -1;
694     }
695 }
696 
SendCommandAndWait(const std::string &cmd)697 bool Client::SendCommandAndWait(const std::string &cmd)
698 {
699     if (clientToServerFd_ == -1) {
700         HIPERF_HILOGI(MODULE_CPP_API, "fd not ready. maybe not called start.");
701         return false;
702     }
703     size_t size = write(clientToServerFd_, cmd.c_str(), cmd.size());
704     HIPERF_HILOGI(MODULE_CPP_API,
705                   "Client:%" HILOG_PUBLIC "s -> %" HILOG_PUBLIC "d : %" HILOG_PUBLIC "zd\n",
706                   cmd.c_str(), clientToServerFd_, size);
707     if (size == cmd.size()) {
708         return WaitCommandReply();
709     } else {
710         return false;
711     }
712 }
713 
StartRun()714 bool Client::StartRun()
715 {
716     if (!ready_) {
717         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
718         return false;
719     }
720     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
721     if (SendCommandAndWait(ReplyStart)) {
722         return true;
723     }
724     return false;
725 }
726 
Pause()727 bool Client::Pause()
728 {
729     if (!ready_) {
730         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
731         return false;
732     }
733     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
734     if (SendCommandAndWait(ReplyPause)) {
735         return true;
736     }
737     return false;
738 }
739 
Resume()740 bool Client::Resume()
741 {
742     if (!ready_) {
743         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
744         return false;
745     }
746     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
747     if (SendCommandAndWait(ReplyResume)) {
748         return true;
749     }
750     return false;
751 }
752 
Stop()753 bool Client::Stop()
754 {
755     if (!ready_) {
756         HIPERF_HILOGI(MODULE_CPP_API, "Client:hiperf not ready.\n");
757         return false;
758     }
759     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
760     if (SendCommandAndWait(ReplyStop)) {
761         // wait sampling process exit really
762         while (SendCommandAndWait(ReplyCheck)) {
763             std::this_thread::sleep_for(1s);
764         }
765         return true;
766     }
767     return false;
768 }
769 
EnableHilog()770 void Client::EnableHilog()
771 {
772     HIPERF_HILOGI(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
773     hilog_ = true;
774 }
775 } // namespace HiperfClient
776 } // namespace HiPerf
777 } // namespace Developtools
778 } // namespace OHOS
779