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 #include <procinfo/process.h> 18 19 #include <fcntl.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include <string> 26 27 #include <android-base/unique_fd.h> 28 29 using android::base::unique_fd; 30 31 namespace android { 32 namespace procinfo { 33 34 bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) { 35 char path[PATH_MAX]; 36 snprintf(path, sizeof(path), "/proc/%d", tid); 37 38 unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY)); 39 if (dirfd == -1) { 40 if (error != nullptr) { 41 *error = std::string("failed to open ") + path; 42 } 43 return false; 44 } 45 46 return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error); 47 } 48 49 static ProcessState parse_state(char state) { 50 switch (state) { 51 case 'R': 52 return kProcessStateRunning; 53 case 'S': 54 return kProcessStateSleeping; 55 case 'D': 56 return kProcessStateUninterruptibleWait; 57 case 'T': 58 return kProcessStateStopped; 59 case 'Z': 60 return kProcessStateZombie; 61 default: 62 return kProcessStateUnknown; 63 } 64 } 65 66 bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, 67 std::string* error /* can be nullptr */) { 68 int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC); 69 70 auto set_error = [&error](const char* err) { 71 if (error != nullptr) { 72 *error = err; 73 } 74 }; 75 76 if (status_fd == -1) { 77 set_error("failed to open status fd in GetProcessInfoFromProcPidFd"); 78 return false; 79 } 80 81 std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose); 82 if (!fp) { 83 set_error("failed to open status file in GetProcessInfoFromProcPidFd"); 84 close(status_fd); 85 return false; 86 } 87 88 int field_bitmap = 0; 89 static constexpr int finished_bitmap = 63; 90 char* line = nullptr; 91 size_t len = 0; 92 93 while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) { 94 char* tab = strchr(line, '\t'); 95 if (tab == nullptr) { 96 continue; 97 } 98 99 size_t header_len = tab - line; 100 std::string header = std::string(line, header_len); 101 if (header == "Name:") { 102 std::string name = line + header_len + 1; 103 104 // line includes the trailing newline. 105 name.pop_back(); 106 process_info->name = std::move(name); 107 108 field_bitmap |= 1; 109 } else if (header == "Tgid:") { 110 process_info->pid = atoi(tab + 1); 111 field_bitmap |= 2; 112 } else if (header == "Pid:") { 113 process_info->tid = atoi(tab + 1); 114 field_bitmap |= 4; 115 } else if (header == "TracerPid:") { 116 process_info->tracer = atoi(tab + 1); 117 field_bitmap |= 8; 118 } else if (header == "Uid:") { 119 process_info->uid = atoi(tab + 1); 120 field_bitmap |= 16; 121 } else if (header == "Gid:") { 122 process_info->gid = atoi(tab + 1); 123 field_bitmap |= 32; 124 } 125 } 126 127 free(line); 128 if (field_bitmap != finished_bitmap) { 129 set_error("failed to parse /proc/<pid>/status"); 130 return false; 131 } 132 133 unique_fd stat_fd(openat(fd, "stat", O_RDONLY | O_CLOEXEC)); 134 if (stat_fd == -1) { 135 set_error("failed to open /proc/<pid>/stat"); 136 } 137 138 std::string stat; 139 if (!android::base::ReadFdToString(stat_fd, &stat)) { 140 set_error("failed to read /proc/<pid>/stat"); 141 return false; 142 } 143 144 // See man 5 proc. There's no reason comm can't contain ' ' or ')', 145 // so we search backwards for the end of it. 146 const char* end_of_comm = strrchr(stat.c_str(), ')'); 147 148 static constexpr const char* pattern = 149 "%c " // state 150 "%d " // ppid 151 "%*d " // pgrp 152 "%*d " // session 153 "%*d " // tty_nr 154 "%*d " // tpgid 155 "%*u " // flags 156 "%*lu " // minflt 157 "%*lu " // cminflt 158 "%*lu " // majflt 159 "%*lu " // cmajflt 160 "%*lu " // utime 161 "%*lu " // stime 162 "%*ld " // cutime 163 "%*ld " // cstime 164 "%*ld " // priority 165 "%*ld " // nice 166 "%*ld " // num_threads 167 "%*ld " // itrealvalue 168 "%llu " // starttime 169 ; 170 171 char state = '\0'; 172 int ppid = 0; 173 unsigned long long start_time = 0; 174 int rc = sscanf(end_of_comm + 2, pattern, &state, &ppid, &start_time); 175 if (rc != 3) { 176 set_error("failed to parse /proc/<pid>/stat"); 177 return false; 178 } 179 180 process_info->state = parse_state(state); 181 process_info->ppid = ppid; 182 process_info->starttime = start_time; 183 return true; 184 } 185 186 } /* namespace procinfo */ 187 } /* namespace android */ 188