| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 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 |  | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 34 | bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) { | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 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) { | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 40 |     if (error != nullptr) { | 
 | 41 |       *error = std::string("failed to open ") + path; | 
 | 42 |     } | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 43 |     return false; | 
 | 44 |   } | 
 | 45 |  | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 46 |   return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error); | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 47 | } | 
 | 48 |  | 
| Josh Gao | 9cb2e2e | 2017-06-27 14:06:19 -0700 | [diff] [blame] | 49 | static ProcessState parse_state(const 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: | 
| Josh Gao | 9cb2e2e | 2017-06-27 14:06:19 -0700 | [diff] [blame] | 62 |       return kProcessStateUnknown; | 
 | 63 |   } | 
 | 64 | } | 
 | 65 |  | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 66 | bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error) { | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 67 |   int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC); | 
 | 68 |  | 
 | 69 |   if (status_fd == -1) { | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 70 |     if (error != nullptr) { | 
 | 71 |       *error = "failed to open status fd in GetProcessInfoFromProcPidFd"; | 
 | 72 |     } | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 73 |     return false; | 
 | 74 |   } | 
 | 75 |  | 
 | 76 |   std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose); | 
 | 77 |   if (!fp) { | 
| Yabin Cui | 5f036ab | 2018-07-24 10:52:25 -0700 | [diff] [blame] | 78 |     if (error != nullptr) { | 
 | 79 |       *error = "failed to open status file in GetProcessInfoFromProcPidFd"; | 
 | 80 |     } | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 81 |     close(status_fd); | 
 | 82 |     return false; | 
 | 83 |   } | 
 | 84 |  | 
 | 85 |   int field_bitmap = 0; | 
| Josh Gao | 9cb2e2e | 2017-06-27 14:06:19 -0700 | [diff] [blame] | 86 |   static constexpr int finished_bitmap = 255; | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 87 |   char* line = nullptr; | 
 | 88 |   size_t len = 0; | 
 | 89 |  | 
 | 90 |   while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) { | 
 | 91 |     char* tab = strchr(line, '\t'); | 
 | 92 |     if (tab == nullptr) { | 
 | 93 |       continue; | 
 | 94 |     } | 
 | 95 |  | 
 | 96 |     size_t header_len = tab - line; | 
 | 97 |     std::string header = std::string(line, header_len); | 
 | 98 |     if (header == "Name:") { | 
 | 99 |       std::string name = line + header_len + 1; | 
 | 100 |  | 
 | 101 |       // line includes the trailing newline. | 
 | 102 |       name.pop_back(); | 
 | 103 |       process_info->name = std::move(name); | 
 | 104 |  | 
 | 105 |       field_bitmap |= 1; | 
 | 106 |     } else if (header == "Pid:") { | 
 | 107 |       process_info->tid = atoi(tab + 1); | 
 | 108 |       field_bitmap |= 2; | 
 | 109 |     } else if (header == "Tgid:") { | 
 | 110 |       process_info->pid = atoi(tab + 1); | 
 | 111 |       field_bitmap |= 4; | 
 | 112 |     } else if (header == "PPid:") { | 
 | 113 |       process_info->ppid = atoi(tab + 1); | 
 | 114 |       field_bitmap |= 8; | 
 | 115 |     } else if (header == "TracerPid:") { | 
 | 116 |       process_info->tracer = atoi(tab + 1); | 
 | 117 |       field_bitmap |= 16; | 
 | 118 |     } else if (header == "Uid:") { | 
 | 119 |       process_info->uid = atoi(tab + 1); | 
 | 120 |       field_bitmap |= 32; | 
 | 121 |     } else if (header == "Gid:") { | 
 | 122 |       process_info->gid = atoi(tab + 1); | 
 | 123 |       field_bitmap |= 64; | 
| Josh Gao | 9cb2e2e | 2017-06-27 14:06:19 -0700 | [diff] [blame] | 124 |     } else if (header == "State:") { | 
 | 125 |       process_info->state = parse_state(tab + 1); | 
 | 126 |       field_bitmap |= 128; | 
| Josh Gao | 911d729 | 2016-10-28 15:23:25 -0700 | [diff] [blame] | 127 |     } | 
 | 128 |   } | 
 | 129 |  | 
 | 130 |   free(line); | 
 | 131 |   return field_bitmap == finished_bitmap; | 
 | 132 | } | 
 | 133 |  | 
 | 134 | } /* namespace procinfo */ | 
 | 135 | } /* namespace android */ |