1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <dirent.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <stdlib.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include <memory> 27 #include <string> 28 #include <type_traits> 29 30 #include <android-base/file.h> 31 #include <android-base/parseint.h> 32 #include <android-base/stringprintf.h> 33 #include <android-base/unique_fd.h> 34 35 namespace android { 36 namespace procinfo { 37 38 #if defined(__linux__) 39 40 enum ProcessState { 41 kProcessStateUnknown, 42 kProcessStateRunning, 43 kProcessStateSleeping, 44 kProcessStateUninterruptibleWait, 45 kProcessStateStopped, 46 kProcessStateZombie, 47 }; 48 49 struct ProcessInfo { 50 std::string name; 51 ProcessState state; 52 pid_t tid; 53 pid_t pid; 54 pid_t ppid; 55 pid_t tracer; 56 uid_t uid; 57 uid_t gid; 58 59 // Start time of the process since boot, measured in clock ticks. 60 uint64_t starttime; 61 }; 62 63 bool SetError(std::string* error, int errno_value, const char* fmt, ...); 64 65 // Parse the contents of /proc/<tid>/status into |process_info|. 66 bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr); 67 68 // Parse the contents of <fd>/status into |process_info|. 69 // |fd| should be an fd pointing at a /proc/<pid> directory. 70 // |pid| is used for error messages. 71 bool GetProcessInfoFromProcPidFd(int fd, int pid, ProcessInfo* process_info, std::string* error = nullptr); 72 73 // Fetch the list of threads from a given process's /proc/<pid> directory. 74 // |fd| should be an fd pointing at a /proc/<pid> directory. 75 template <typename Collection> 76 auto GetProcessTidsFromProcPidFd(int fd, Collection* out, std::string* error = nullptr) -> 77 typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type { 78 out->clear(); 79 80 int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC); 81 std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir); 82 if (!dir) { 83 return SetError(error, errno, "failed to open task directory"); 84 } 85 86 struct dirent* dent; 87 while ((dent = readdir(dir.get()))) { 88 if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) { 89 pid_t tid; 90 if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) { 91 return SetError(error, 0, "failed to parse task id %s", dent->d_name); 92 } 93 94 out->insert(out->end(), tid); 95 } 96 } 97 98 return true; 99 } 100 101 template <typename Collection> 102 auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) -> 103 typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type { 104 char task_path[32]; 105 snprintf(task_path, sizeof(task_path), "/proc/%d", pid); 106 android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC)); 107 if (fd == -1) { 108 return SetError(error, errno, "failed to open %s", task_path); 109 } 110 111 return GetProcessTidsFromProcPidFd(fd.get(), out, error); 112 } 113 114 #endif 115 116 } /* namespace procinfo */ 117 } /* namespace android */ 118