* Copyright (C) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _WIN32
#include "process_handle.h"
#include "define_plus.h"
#include "../host_common.h"
#include "log.h"
#include "base.h"
#include "define.h"
#include <unistd.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <fcntl.h>
#include <csignal>
#include <sstream>
#include <fstream>
#include <vector>
#include <memory>
#ifdef __APPLE__
#include <libproc.h>
#endif
namespace Hdc {
struct ProcessHandle::ProcessHandleImpl {
pid_t pid = -1;
bool IsAlive() const
{
if (pid <= 0) {
return false;
}
return kill(pid, 0) == 0;
}
int GetExitCode() const
{
if (pid <= 0) {
return -1;
}
int status = 0;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}
bool IsValid() const
{
return pid > 0;
}
};
std::string ProcessHandle::GetExecutablePathImpl()
{
std::unique_ptr<char[]> path(new (std::nothrow) char[BUF_SIZE_SMALL]);
if (path == nullptr) {
WRITE_LOG(LOG_WARN, "Failed to allocate memory for path");
return "";
}
size_t nPathSize = BUF_SIZE_SMALL;
int ret = uv_exepath(path.get(), &nPathSize);
if (ret < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
uv_err_name_r(ret, buf, bufSize);
WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
return "";
}
return path.get();
}
std::string ProcessHandle::GetParentProcessNameImpl()
{
std::string parentName;
#ifdef __APPLE__
pid_t parentPid = getppid();
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
if (proc_pidpath(parentPid, pathbuf, sizeof(pathbuf)) > 0) {
std::string fullPath = pathbuf;
size_t pos = fullPath.find_last_of('/');
if (pos != std::string::npos) {
parentName = fullPath.substr(pos + 1);
} else {
parentName = fullPath;
}
}
#else
pid_t parentPid = getppid();
std::string path = "/proc/" + std::to_string(parentPid) + "/comm";
std::ifstream file(path);
if (file.is_open()) {
std::getline(file, parentName);
}
#endif
return parentName;
}
bool ProcessHandle::BuildSubserverArgsImpl(char* buf, size_t bufSize, const char* listenString,
const char* serial, const char* port)
{
std::string logFileName = Base::GenerateSubserverLogFileName();
if (logFileName.empty()) {
return sprintf_s(buf, bufSize, "-l 0 -s %s -m -N -i %s -o %s",
listenString, serial, port) >= 0;
}
return sprintf_s(buf, bufSize, "-l %d -s %s -m -N -i %s -o %s -L %s",
Base::GetLogLevelByEnv(), listenString, serial, port, logFileName.c_str()) >= 0;
}
uint32_t ProcessHandle::GetCurrentPidImpl()
{
return getpid();
}
ProcessHandle::ProcessHandle() : processImpl_(nullptr) {}
ProcessHandle::~ProcessHandle() = default;
ProcessHandle::ProcessHandle(ProcessHandle&& other) noexcept : processImpl_(std::move(other.processImpl_)) {}
ProcessHandle& ProcessHandle::operator=(ProcessHandle&& other) noexcept
{
if (this != &other) {
processImpl_ = std::move(other.processImpl_);
}
return *this;
}
std::unique_ptr<ProcessHandle> ProcessHandle::SpawnSubprocess(const std::string& path, const char* args)
{
auto handle = std::make_unique<ProcessHandle>();
handle->processImpl_ = std::make_unique<ProcessHandleImpl>();
std::vector<std::string> argList;
std::vector<char*> argv;
argList.push_back(path);
if (args && strlen(args) > 0) {
std::istringstream iss(args);
std::string arg;
while (iss >> arg) {
argList.push_back(arg);
}
}
for (auto& a : argList) {
argv.push_back(a.data());
}
argv.push_back(nullptr);
pid_t pid = fork();
if (pid < 0) {
WRITE_LOG(LOG_WARN, "fork failed, error: %d", errno);
return nullptr;
}
if (pid == 0) {
Base::CloseOpenFd();
execv(path.c_str(), argv.data());
_exit(1);
}
handle->processImpl_->pid = pid;
return handle;
}
bool ProcessHandle::IsAlive() const
{
return processImpl_ ? processImpl_->IsAlive() : false;
}
int ProcessHandle::GetExitCode() const
{
return processImpl_ ? processImpl_->GetExitCode() : -1;
}
bool ProcessHandle::IsValid() const
{
return processImpl_ && processImpl_->IsValid();
}
}
#endif