1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci 16800b99b8Sopenharmony_ci#include "pid_utils.h" 17800b99b8Sopenharmony_ci#include <cerrno> 18800b99b8Sopenharmony_ci#include <cstdint> 19800b99b8Sopenharmony_ci#include <cstdio> 20800b99b8Sopenharmony_ci#include <ctime> 21800b99b8Sopenharmony_ci#include <sys/ptrace.h> 22800b99b8Sopenharmony_ci#include <sys/types.h> 23800b99b8Sopenharmony_ci#include <sys/wait.h> 24800b99b8Sopenharmony_ci#include <unistd.h> 25800b99b8Sopenharmony_ci#include "dfx_log.h" 26800b99b8Sopenharmony_ci 27800b99b8Sopenharmony_cinamespace OHOS { 28800b99b8Sopenharmony_cinamespace HiviewDFX { 29800b99b8Sopenharmony_cinamespace { 30800b99b8Sopenharmony_ci#undef LOG_DOMAIN 31800b99b8Sopenharmony_ci#undef LOG_TAG 32800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11 33800b99b8Sopenharmony_ci#define LOG_TAG "DfxPidUtils" 34800b99b8Sopenharmony_ci 35800b99b8Sopenharmony_cistatic constexpr time_t MAX_WAIT_TIME_SECONDS = 30; 36800b99b8Sopenharmony_cistatic constexpr time_t USLEEP_TIME = 5000; 37800b99b8Sopenharmony_ci} 38800b99b8Sopenharmony_ci 39800b99b8Sopenharmony_cistatic bool Exited(pid_t pid) 40800b99b8Sopenharmony_ci{ 41800b99b8Sopenharmony_ci int status; 42800b99b8Sopenharmony_ci pid_t waitPid = waitpid(pid, &status, WNOHANG); 43800b99b8Sopenharmony_ci if (waitPid != pid) { 44800b99b8Sopenharmony_ci return false; 45800b99b8Sopenharmony_ci } 46800b99b8Sopenharmony_ci 47800b99b8Sopenharmony_ci if (WIFEXITED(status)) { 48800b99b8Sopenharmony_ci DFXLOGE("%{public}d died: Process exited with code %{public}d", pid, WEXITSTATUS(status)); 49800b99b8Sopenharmony_ci } else if (WIFSIGNALED(status)) { 50800b99b8Sopenharmony_ci DFXLOGE("%{public}d died: Process exited due to signal %{public}d", pid, WTERMSIG(status)); 51800b99b8Sopenharmony_ci } else { 52800b99b8Sopenharmony_ci DFXLOGE("%{public}d died: Process finished for unknown reason", pid); 53800b99b8Sopenharmony_ci } 54800b99b8Sopenharmony_ci return true; 55800b99b8Sopenharmony_ci} 56800b99b8Sopenharmony_ci 57800b99b8Sopenharmony_cibool PidUtils::Quiesce(pid_t pid) 58800b99b8Sopenharmony_ci{ 59800b99b8Sopenharmony_ci siginfo_t si; 60800b99b8Sopenharmony_ci // Wait for up to 10 seconds. 61800b99b8Sopenharmony_ci for (time_t startTime = time(nullptr); time(nullptr) - startTime < 10;) { 62800b99b8Sopenharmony_ci if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) { 63800b99b8Sopenharmony_ci return true; 64800b99b8Sopenharmony_ci } 65800b99b8Sopenharmony_ci if (errno != ESRCH) { 66800b99b8Sopenharmony_ci if (errno != EINVAL) { 67800b99b8Sopenharmony_ci DFXLOGE("ptrace getsiginfo failed"); 68800b99b8Sopenharmony_ci return false; 69800b99b8Sopenharmony_ci } 70800b99b8Sopenharmony_ci // The process is in group-stop state, so try and kick the process out of that state. 71800b99b8Sopenharmony_ci if (ptrace(PTRACE_LISTEN, pid, 0, 0) == -1) { 72800b99b8Sopenharmony_ci // Cannot recover from this, so just pretend it worked and see if we can unwind. 73800b99b8Sopenharmony_ci return true; 74800b99b8Sopenharmony_ci } 75800b99b8Sopenharmony_ci } 76800b99b8Sopenharmony_ci usleep(USLEEP_TIME); 77800b99b8Sopenharmony_ci } 78800b99b8Sopenharmony_ci DFXLOGE("%{public}d: Did not quiesce in 10 seconds", pid); 79800b99b8Sopenharmony_ci return false; 80800b99b8Sopenharmony_ci} 81800b99b8Sopenharmony_ci 82800b99b8Sopenharmony_cibool PidUtils::Attach(pid_t pid) 83800b99b8Sopenharmony_ci{ 84800b99b8Sopenharmony_ci // Wait up to 45 seconds to attach. 85800b99b8Sopenharmony_ci for (time_t startTime = time(nullptr); time(nullptr) - startTime < 45;) { 86800b99b8Sopenharmony_ci if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) { 87800b99b8Sopenharmony_ci break; 88800b99b8Sopenharmony_ci } 89800b99b8Sopenharmony_ci if (errno != ESRCH) { 90800b99b8Sopenharmony_ci DFXLOGE("Failed to attach"); 91800b99b8Sopenharmony_ci return false; 92800b99b8Sopenharmony_ci } 93800b99b8Sopenharmony_ci usleep(USLEEP_TIME); 94800b99b8Sopenharmony_ci } 95800b99b8Sopenharmony_ci 96800b99b8Sopenharmony_ci if (Quiesce(pid)) { 97800b99b8Sopenharmony_ci return true; 98800b99b8Sopenharmony_ci } 99800b99b8Sopenharmony_ci 100800b99b8Sopenharmony_ci if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) { 101800b99b8Sopenharmony_ci DFXLOGE("Failed to detach"); 102800b99b8Sopenharmony_ci } 103800b99b8Sopenharmony_ci return false; 104800b99b8Sopenharmony_ci} 105800b99b8Sopenharmony_ci 106800b99b8Sopenharmony_cibool PidUtils::Detach(pid_t pid) 107800b99b8Sopenharmony_ci{ 108800b99b8Sopenharmony_ci if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) { 109800b99b8Sopenharmony_ci DFXLOGE("ptrace detach failed"); 110800b99b8Sopenharmony_ci return false; 111800b99b8Sopenharmony_ci } 112800b99b8Sopenharmony_ci return true; 113800b99b8Sopenharmony_ci} 114800b99b8Sopenharmony_ci 115800b99b8Sopenharmony_cibool PidUtils::WaitForPidState(pid_t pid, const std::function<PidRunEnum()>& stateCheckFunc) 116800b99b8Sopenharmony_ci{ 117800b99b8Sopenharmony_ci PidRunEnum status = PID_RUN_KEEP_GOING; 118800b99b8Sopenharmony_ci for (time_t startTime = time(nullptr); 119800b99b8Sopenharmony_ci time(nullptr) - startTime < MAX_WAIT_TIME_SECONDS && status == PID_RUN_KEEP_GOING;) { 120800b99b8Sopenharmony_ci if (Attach(pid)) { 121800b99b8Sopenharmony_ci status = stateCheckFunc(); 122800b99b8Sopenharmony_ci if (status == PID_RUN_PASS) { 123800b99b8Sopenharmony_ci return true; 124800b99b8Sopenharmony_ci } 125800b99b8Sopenharmony_ci 126800b99b8Sopenharmony_ci if (!Detach(pid)) { 127800b99b8Sopenharmony_ci return false; 128800b99b8Sopenharmony_ci } 129800b99b8Sopenharmony_ci } else if (Exited(pid)) { 130800b99b8Sopenharmony_ci return false; 131800b99b8Sopenharmony_ci } 132800b99b8Sopenharmony_ci usleep(USLEEP_TIME); 133800b99b8Sopenharmony_ci } 134800b99b8Sopenharmony_ci if (status == PID_RUN_KEEP_GOING) { 135800b99b8Sopenharmony_ci DFXLOGE("Timed out waiting for pid %{public}d to be ready", pid); 136800b99b8Sopenharmony_ci } 137800b99b8Sopenharmony_ci return status == PID_RUN_PASS; 138800b99b8Sopenharmony_ci} 139800b99b8Sopenharmony_ci 140800b99b8Sopenharmony_cibool PidUtils::WaitForPidStateAfterAttach(pid_t pid, const std::function<PidRunEnum()>& stateCheckFunc) 141800b99b8Sopenharmony_ci{ 142800b99b8Sopenharmony_ci PidRunEnum status; 143800b99b8Sopenharmony_ci time_t startTime = time(nullptr); 144800b99b8Sopenharmony_ci do { 145800b99b8Sopenharmony_ci status = stateCheckFunc(); 146800b99b8Sopenharmony_ci if (status == PID_RUN_PASS) { 147800b99b8Sopenharmony_ci return true; 148800b99b8Sopenharmony_ci } 149800b99b8Sopenharmony_ci if (!Detach(pid)) { 150800b99b8Sopenharmony_ci return false; 151800b99b8Sopenharmony_ci } 152800b99b8Sopenharmony_ci usleep(USLEEP_TIME); 153800b99b8Sopenharmony_ci } while (time(nullptr) - startTime < MAX_WAIT_TIME_SECONDS && status == PID_RUN_KEEP_GOING && Attach(pid)); 154800b99b8Sopenharmony_ci if (status == PID_RUN_KEEP_GOING) { 155800b99b8Sopenharmony_ci DFXLOGE("Timed out waiting for pid %{public}d to be ready", pid); 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci return status == PID_RUN_PASS; 158800b99b8Sopenharmony_ci} 159800b99b8Sopenharmony_ci 160800b99b8Sopenharmony_ci} 161800b99b8Sopenharmony_ci}