148f512ceSopenharmony_ci/* 248f512ceSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 448f512ceSopenharmony_ci * you may not use this file except in compliance with the License. 548f512ceSopenharmony_ci * You may obtain a copy of the License at 648f512ceSopenharmony_ci * 748f512ceSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 848f512ceSopenharmony_ci * 948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and 1348f512ceSopenharmony_ci * limitations under the License. 1448f512ceSopenharmony_ci */ 1548f512ceSopenharmony_ci#include "tracked_command.h" 1648f512ceSopenharmony_ci#include <cerrno> 1748f512ceSopenharmony_ci#include <csignal> 1848f512ceSopenharmony_ci#include <sys/prctl.h> 1948f512ceSopenharmony_ci#include <sys/wait.h> 2048f512ceSopenharmony_ci#include <unistd.h> 2148f512ceSopenharmony_ci#include "debug_logger.h" 2248f512ceSopenharmony_ci 2348f512ceSopenharmony_cinamespace OHOS { 2448f512ceSopenharmony_cinamespace Developtools { 2548f512ceSopenharmony_cinamespace HiPerf { 2648f512ceSopenharmony_cistd::unique_ptr<TrackedCommand> TrackedCommand::CreateInstance(const std::vector<std::string> &args) 2748f512ceSopenharmony_ci{ 2848f512ceSopenharmony_ci std::unique_ptr<TrackedCommand> command {new (std::nothrow) TrackedCommand(args)}; 2948f512ceSopenharmony_ci if (!command) { 3048f512ceSopenharmony_ci return nullptr; 3148f512ceSopenharmony_ci } 3248f512ceSopenharmony_ci if (!command->CreateChildProcess()) { 3348f512ceSopenharmony_ci return nullptr; 3448f512ceSopenharmony_ci } 3548f512ceSopenharmony_ci return command; 3648f512ceSopenharmony_ci} 3748f512ceSopenharmony_ci 3848f512ceSopenharmony_ciTrackedCommand::TrackedCommand(const std::vector<std::string> &args) : command_ {args} {} 3948f512ceSopenharmony_ci 4048f512ceSopenharmony_ciTrackedCommand::~TrackedCommand() 4148f512ceSopenharmony_ci{ 4248f512ceSopenharmony_ci MakeInvalid(); 4348f512ceSopenharmony_ci} 4448f512ceSopenharmony_ci 4548f512ceSopenharmony_civoid TrackedCommand::Stop() 4648f512ceSopenharmony_ci{ 4748f512ceSopenharmony_ci MakeInvalid(); 4848f512ceSopenharmony_ci} 4948f512ceSopenharmony_ci 5048f512ceSopenharmony_cibool TrackedCommand::InitSignalPipes(int &startFd, int &ackFd) 5148f512ceSopenharmony_ci{ 5248f512ceSopenharmony_ci int startSignalPipe[2] {-1, -1}; 5348f512ceSopenharmony_ci if (pipe2(startSignalPipe, O_CLOEXEC) != 0) { 5448f512ceSopenharmony_ci HLOGE("pipe2() failed in TrackedCommand::InitSignalPipes()"); 5548f512ceSopenharmony_ci return false; 5648f512ceSopenharmony_ci } 5748f512ceSopenharmony_ci startFd = startSignalPipe[0]; 5848f512ceSopenharmony_ci startFd_ = startSignalPipe[1]; 5948f512ceSopenharmony_ci 6048f512ceSopenharmony_ci int ackSignalPipe[2] {-1, -1}; 6148f512ceSopenharmony_ci if (pipe2(ackSignalPipe, O_CLOEXEC) != 0) { 6248f512ceSopenharmony_ci HLOGE("pipe2() failed in TrackedCommand::InitSignalPipes()"); 6348f512ceSopenharmony_ci close(startFd); 6448f512ceSopenharmony_ci close(startFd_); 6548f512ceSopenharmony_ci startFd = -1; 6648f512ceSopenharmony_ci startFd_ = -1; 6748f512ceSopenharmony_ci return false; 6848f512ceSopenharmony_ci } 6948f512ceSopenharmony_ci ackFd = ackSignalPipe[1]; 7048f512ceSopenharmony_ci ackFd_ = ackSignalPipe[0]; 7148f512ceSopenharmony_ci return true; 7248f512ceSopenharmony_ci} 7348f512ceSopenharmony_ci 7448f512ceSopenharmony_cibool TrackedCommand::CreateChildProcess() 7548f512ceSopenharmony_ci{ 7648f512ceSopenharmony_ci int startFd {-1}; 7748f512ceSopenharmony_ci int ackFd {-1}; 7848f512ceSopenharmony_ci if (!InitSignalPipes(startFd, ackFd)) { 7948f512ceSopenharmony_ci return false; 8048f512ceSopenharmony_ci } 8148f512ceSopenharmony_ci pid_t pid = fork(); 8248f512ceSopenharmony_ci if (pid == -1) { 8348f512ceSopenharmony_ci HLOGE("fork() failed in TrackedCommand::CreateChildProcess()"); 8448f512ceSopenharmony_ci MakeInvalid(); 8548f512ceSopenharmony_ci return false; 8648f512ceSopenharmony_ci } else if (pid == 0) { 8748f512ceSopenharmony_ci close(startFd_); 8848f512ceSopenharmony_ci close(ackFd_); 8948f512ceSopenharmony_ci ExecuteCommand(startFd, ackFd); 9048f512ceSopenharmony_ci _exit(0); 9148f512ceSopenharmony_ci } else { 9248f512ceSopenharmony_ci close(startFd); 9348f512ceSopenharmony_ci close(ackFd); 9448f512ceSopenharmony_ci childPid_ = pid; 9548f512ceSopenharmony_ci state_ = State::COMMAND_WAITING; 9648f512ceSopenharmony_ci return true; 9748f512ceSopenharmony_ci } 9848f512ceSopenharmony_ci} 9948f512ceSopenharmony_ci 10048f512ceSopenharmony_cibool TrackedCommand::StartCommand() 10148f512ceSopenharmony_ci{ 10248f512ceSopenharmony_ci // send start signal to start execution of command 10348f512ceSopenharmony_ci ssize_t nbyte {0}; 10448f512ceSopenharmony_ci char startSignal {1}; 10548f512ceSopenharmony_ci while (true) { 10648f512ceSopenharmony_ci nbyte = write(startFd_, &startSignal, 1); 10748f512ceSopenharmony_ci if (nbyte == -1) { 10848f512ceSopenharmony_ci continue; 10948f512ceSopenharmony_ci } 11048f512ceSopenharmony_ci break; 11148f512ceSopenharmony_ci } 11248f512ceSopenharmony_ci HLOG_ASSERT(nbyte == 1); 11348f512ceSopenharmony_ci // check execution state of command 11448f512ceSopenharmony_ci // read acknowledgement signal 11548f512ceSopenharmony_ci char ackSignal {0}; 11648f512ceSopenharmony_ci while (true) { 11748f512ceSopenharmony_ci nbyte = read(ackFd_, &ackSignal, 1); 11848f512ceSopenharmony_ci if (nbyte == -1 and (errno == EINTR or errno == EIO)) { 11948f512ceSopenharmony_ci continue; 12048f512ceSopenharmony_ci } 12148f512ceSopenharmony_ci HLOGE("*** nbyte: %zd, ackSignal: %d ***\n", nbyte, ackSignal); 12248f512ceSopenharmony_ci break; 12348f512ceSopenharmony_ci } 12448f512ceSopenharmony_ci if (nbyte == 0) { 12548f512ceSopenharmony_ci state_ = State::COMMAND_STARTED; 12648f512ceSopenharmony_ci return true; 12748f512ceSopenharmony_ci } 12848f512ceSopenharmony_ci HLOG_ASSERT(nbyte == 1); 12948f512ceSopenharmony_ci state_ = State::COMMAND_FAILURE; 13048f512ceSopenharmony_ci return false; 13148f512ceSopenharmony_ci} 13248f512ceSopenharmony_ci 13348f512ceSopenharmony_civoid TrackedCommand::ExecuteCommand(const int &startFd, const int &ackFd) 13448f512ceSopenharmony_ci{ 13548f512ceSopenharmony_ci HLOG_ASSERT(startFd != -1); 13648f512ceSopenharmony_ci HLOG_ASSERT(ackFd != -1); 13748f512ceSopenharmony_ci prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); 13848f512ceSopenharmony_ci // waiting start signal 13948f512ceSopenharmony_ci char startSignal {0}; 14048f512ceSopenharmony_ci ssize_t nbyte {0}; 14148f512ceSopenharmony_ci while (true) { 14248f512ceSopenharmony_ci nbyte = read(startFd, &startSignal, 1); 14348f512ceSopenharmony_ci if (nbyte == -1) { 14448f512ceSopenharmony_ci continue; 14548f512ceSopenharmony_ci } 14648f512ceSopenharmony_ci break; 14748f512ceSopenharmony_ci } 14848f512ceSopenharmony_ci HLOG_ASSERT(nbyte == 1); 14948f512ceSopenharmony_ci // execute command 15048f512ceSopenharmony_ci char *argv[command_.size() + 1]; 15148f512ceSopenharmony_ci for (size_t index = 0; index < command_.size(); ++index) { 15248f512ceSopenharmony_ci argv[index] = const_cast<char *>(command_[index].c_str()); 15348f512ceSopenharmony_ci } 15448f512ceSopenharmony_ci argv[command_.size()] = nullptr; 15548f512ceSopenharmony_ci // On sucees, startFd and ackFd will be closed hence parent process reads EPIPE; 15648f512ceSopenharmony_ci if (IsPath(argv[0])) { 15748f512ceSopenharmony_ci execv(argv[0], argv); 15848f512ceSopenharmony_ci } else { 15948f512ceSopenharmony_ci execvp(argv[0], argv); 16048f512ceSopenharmony_ci } 16148f512ceSopenharmony_ci // execv() or execvp() failed, send failure signal 16248f512ceSopenharmony_ci char ackSignal {1}; 16348f512ceSopenharmony_ci while (true) { 16448f512ceSopenharmony_ci nbyte = write(ackFd, &ackSignal, 1); 16548f512ceSopenharmony_ci if (nbyte == -1) { 16648f512ceSopenharmony_ci continue; 16748f512ceSopenharmony_ci } 16848f512ceSopenharmony_ci break; 16948f512ceSopenharmony_ci } 17048f512ceSopenharmony_ci HLOG_ASSERT(nbyte == 1); 17148f512ceSopenharmony_ci HLOGE("child process failed to execute command"); 17248f512ceSopenharmony_ci} 17348f512ceSopenharmony_ci 17448f512ceSopenharmony_cibool TrackedCommand::WaitCommand(int &wstatus) 17548f512ceSopenharmony_ci{ 17648f512ceSopenharmony_ci if (childPid_ != -1) { 17748f512ceSopenharmony_ci HLOG_ASSERT(state_ != State::COMMAND_STOPPED); 17848f512ceSopenharmony_ci pid_t pid = waitpid(childPid_, &wstatus, WNOHANG); 17948f512ceSopenharmony_ci if (pid == 0) { 18048f512ceSopenharmony_ci return false; 18148f512ceSopenharmony_ci } else { // pid == childPid_ or pid == -1 18248f512ceSopenharmony_ci childPid_ = -1; 18348f512ceSopenharmony_ci state_ = State::COMMAND_STOPPED; 18448f512ceSopenharmony_ci return true; 18548f512ceSopenharmony_ci } 18648f512ceSopenharmony_ci } 18748f512ceSopenharmony_ci return true; 18848f512ceSopenharmony_ci} 18948f512ceSopenharmony_ci 19048f512ceSopenharmony_civoid TrackedCommand::MakeInvalid() 19148f512ceSopenharmony_ci{ 19248f512ceSopenharmony_ci if (childPid_ != -1) { 19348f512ceSopenharmony_ci HLOG_ASSERT(state_ != State::COMMAND_STOPPED); 19448f512ceSopenharmony_ci int wstatus; 19548f512ceSopenharmony_ci pid_t pid = waitpid(childPid_, &wstatus, WNOHANG); 19648f512ceSopenharmony_ci if (pid != childPid_) { 19748f512ceSopenharmony_ci kill(childPid_, SIGKILL); 19848f512ceSopenharmony_ci } 19948f512ceSopenharmony_ci childPid_ = -1; 20048f512ceSopenharmony_ci state_ = State::COMMAND_STOPPED; 20148f512ceSopenharmony_ci } 20248f512ceSopenharmony_ci if (startFd_ != -1) { 20348f512ceSopenharmony_ci close(startFd_); 20448f512ceSopenharmony_ci startFd_ = -1; 20548f512ceSopenharmony_ci } 20648f512ceSopenharmony_ci if (ackFd_ != -1) { 20748f512ceSopenharmony_ci close(ackFd_); 20848f512ceSopenharmony_ci ackFd_ = -1; 20948f512ceSopenharmony_ci } 21048f512ceSopenharmony_ci} 21148f512ceSopenharmony_ci} // namespace HiPerf 21248f512ceSopenharmony_ci} // namespace Developtools 21348f512ceSopenharmony_ci} // namespace OHOS 214