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
27using namespace std::chrono;
28namespace OHOS {
29namespace Developtools {
30namespace HiPerf {
31namespace HiperfClient {
32static const std::string HIPERF_COMMAND_NAME = "hiperf";
33static const std::string SYSTEM_BIN_PATH = "/system/bin/";
34static const std::string CURRENT_PATH = "./";
35static const std::string PERF_DATA_NAME = "perf.data";
36static const std::string COMMAND_RECORD = "record";
37static const std::string ARG_OUTPUT_PATH = "-o";
38static const std::string ARG_DEBUG = "--verbose";
39static const std::string ARG_DEBUG_MUCH = "--much";
40static const std::string ARG_HILOG = "--hilog";
41static const std::string ARG_PIPE_INPUT = "--pipe_input";
42static const std::string ARG_PIPE_OUTPUT = "--pipe_output";
43static const std::string ARG_TARGET_SYSTEM_WIDE = "-a";
44static const std::string ARG_COMPRESS_DATA = "-z";
45static const std::string ARG_SELECT_CPUS = "-c";
46static const std::string ARG_TIME_STOP_SEC = "-d";
47static const std::string ARG_FREQUENCY = "-f";
48static const std::string ARG_PERIOD = "--period";
49static const std::string ARG_SELECT_EVENTS = "-e";
50static const std::string ARG_SELECT_GROUPS = "-g";
51static const std::string ARG_NO_INHERIT = "--no-inherit";
52static const std::string ARG_SELECT_PIDS = "-p";
53static const std::string ARG_SELECT_TIDS = "-t";
54static const std::string ARG_EXCLUDE_PERF = "--exclude-hiperf";
55static const std::string ARG_CPU_PERCENT = "--cpu-limit";
56static const std::string ARG_OFF_CPU = "--offcpu";
57static const std::string ARG_CALL_GRAPH = "--call-stack";
58static const std::string ARG_DELAY_UNWIND = "--delay-unwind";
59static const std::string ARG_DISABLE_UNWIND = "--disable-unwind";
60static const std::string ARG_DISABLE_CALLSTACK_MERGE = "--disable-callstack-expand";
61static const std::string ARG_SYMBOL_DIR = "--symbol-dir";
62static const std::string ARG_DATA_LIMIT = "--data-limit";
63static const std::string ARG_APP_PACKAGE = "--app";
64static const std::string ARG_CLOCK_ID = "--clockid";
65static const std::string ARG_VEC_BRANCH_SAMPLE_TYPES = "-j";
66static const std::string ARG_MMAP_PAGES = "-m";
67static const std::string ARG_REPORT = "--report";
68
69static constexpr int DEFAULT_DURATION_TIME = 10;
70static constexpr int DEFAULT_FREQUENCY_TIME = 100;
71static constexpr uint64_t PIPE_READ = 0;
72static constexpr uint64_t PIPE_WRITE = 1;
73static constexpr ssize_t ERRINFOLEN = 512;
74static constexpr size_t SIZE_ARGV_TAIL = 1; // nullptr
75
76void 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
92void 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
106void 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
135void 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
154void 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
181void RecordOption::SetTargetSystemWide(bool enable)
182{
183    SetOption(ARG_TARGET_SYSTEM_WIDE, enable);
184}
185
186void RecordOption::SetCompressData(bool enable)
187{
188    SetOption(ARG_COMPRESS_DATA, enable);
189}
190
191void RecordOption::SetSelectCpus(const std::vector<int> &cpus)
192{
193    SetOption(ARG_SELECT_CPUS, cpus);
194}
195
196void RecordOption::SetTimeStopSec(int timeStopSec)
197{
198    this->timeSpec_ = true;
199    SetOption(ARG_TIME_STOP_SEC, timeStopSec);
200}
201
202void RecordOption::SetFrequency(int frequency)
203{
204    SetOption(ARG_FREQUENCY, frequency);
205}
206
207void RecordOption::SetPeriod(int period)
208{
209    SetOption(ARG_PERIOD, period);
210}
211
212void RecordOption::SetSelectEvents(const std::vector<std::string> &selectEvents)
213{
214    SetOption(ARG_SELECT_EVENTS, selectEvents);
215}
216
217void RecordOption::SetSelectGroups(const std::vector<std::string> &selectGroups)
218{
219    SetOption(ARG_SELECT_GROUPS, selectGroups);
220}
221
222void RecordOption::SetNoInherit(bool enable)
223{
224    SetOption(ARG_NO_INHERIT, enable);
225}
226
227void RecordOption::SetSelectPids(const std::vector<pid_t> &selectPids)
228{
229    SetOption(ARG_SELECT_PIDS, selectPids);
230}
231
232void 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
244void RecordOption::SetSelectTids(const std::vector<pid_t> &selectTids)
245{
246    SetOption(ARG_SELECT_TIDS, selectTids);
247}
248
249void RecordOption::SetExcludePerf(bool excludePerf)
250{
251    SetOption(ARG_EXCLUDE_PERF, excludePerf);
252}
253
254void RecordOption::SetCpuPercent(int cpuPercent)
255{
256    SetOption(ARG_CPU_PERCENT, cpuPercent);
257}
258
259void RecordOption::SetOffCPU(bool offCPU)
260{
261    SetOption(ARG_OFF_CPU, offCPU);
262}
263
264void RecordOption::SetCallGraph(const std::string &callGraph)
265{
266    SetOption(ARG_CALL_GRAPH, callGraph);
267}
268
269void RecordOption::SetDelayUnwind(bool delayUnwind)
270{
271    SetOption(ARG_DELAY_UNWIND, delayUnwind);
272}
273
274void RecordOption::SetDisableUnwind(bool disableUnwind)
275{
276    SetOption(ARG_DISABLE_UNWIND, disableUnwind);
277}
278
279void RecordOption::SetDisableCallstackMerge(bool disableCallstackMerge)
280{
281    SetOption(ARG_DISABLE_CALLSTACK_MERGE, disableCallstackMerge);
282}
283
284void RecordOption::SetSymbolDir(const std::string &symbolDir_)
285{
286    SetOption(ARG_SYMBOL_DIR, symbolDir_);
287}
288
289void RecordOption::SetDataLimit(const std::string &limit)
290{
291    SetOption(ARG_DATA_LIMIT, limit);
292}
293
294void RecordOption::SetAppPackage(const std::string &appPackage)
295{
296    SetOption(ARG_APP_PACKAGE, appPackage);
297}
298
299void RecordOption::SetClockId(const std::string &clockId)
300{
301    SetOption(ARG_CLOCK_ID, clockId);
302}
303
304void RecordOption::SetVecBranchSampleTypes(const std::vector<std::string> &vecBranchSampleTypes)
305{
306    SetOption(ARG_VEC_BRANCH_SAMPLE_TYPES, vecBranchSampleTypes);
307}
308
309void RecordOption::SetMmapPages(int mmapPages)
310{
311    SetOption(ARG_MMAP_PAGES, mmapPages);
312}
313
314void RecordOption::SetReport(bool report)
315{
316    SetOption(ARG_REPORT, report);
317}
318
319Client::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
326bool 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
369Client::~Client()
370{
371    KillChild();
372}
373
374bool Client::IsReady()
375{
376    return ready_;
377}
378
379void Client::SetDebugMode()
380{
381    debug_ = true;
382}
383
384void Client::SetDebugMuchMode()
385{
386    debugMuch_ = true;
387}
388
389bool 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
399void 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
419void 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
431void 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
439bool 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
501bool 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
513void 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
536bool 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
598bool 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
627bool 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
636bool 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
674void 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
697bool 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
714bool 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
727bool 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
740bool 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
753bool 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
770void 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