| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 1 | #include "task.h" | 
|  | 2 |  | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 3 | #include <errno.h> | 
|  | 4 | #include <fcntl.h> | 
| Alex Vakulenko | 4fe6058 | 2017-02-02 11:35:59 -0800 | [diff] [blame] | 5 | #include <log/log.h> | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 6 | #include <stdio.h> | 
|  | 7 |  | 
|  | 8 | #include <cctype> | 
|  | 9 | #include <cstdlib> | 
|  | 10 | #include <memory> | 
|  | 11 | #include <sstream> | 
|  | 12 |  | 
| Elliott Hughes | ccddf4c | 2018-11-08 15:32:13 -0800 | [diff] [blame] | 13 | #include <android-base/strings.h> | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 14 | #include <android-base/unique_fd.h> | 
|  | 15 |  | 
|  | 16 | #include "stdio_filebuf.h" | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 17 |  | 
|  | 18 | namespace { | 
|  | 19 |  | 
|  | 20 | const char kProcBase[] = "/proc"; | 
|  | 21 |  | 
|  | 22 | android::base::unique_fd OpenTaskDirectory(pid_t task_id) { | 
|  | 23 | std::ostringstream stream; | 
|  | 24 | stream << kProcBase << "/" << task_id; | 
|  | 25 |  | 
|  | 26 | return android::base::unique_fd( | 
|  | 27 | open(stream.str().c_str(), O_RDONLY | O_DIRECTORY)); | 
|  | 28 | } | 
|  | 29 |  | 
|  | 30 | void ParseUidStatusField(const std::string& value, std::array<int, 4>& ids) { | 
|  | 31 | const char* start = value.c_str(); | 
|  | 32 |  | 
|  | 33 | ids[0] = std::strtol(start, const_cast<char**>(&start), 10); | 
|  | 34 | ids[1] = std::strtol(start, const_cast<char**>(&start), 10); | 
|  | 35 | ids[2] = std::strtol(start, const_cast<char**>(&start), 10); | 
|  | 36 | ids[3] = std::strtol(start, const_cast<char**>(&start), 10); | 
|  | 37 | } | 
|  | 38 |  | 
|  | 39 | }  // anonymous namespace | 
|  | 40 |  | 
|  | 41 | namespace android { | 
|  | 42 | namespace dvr { | 
|  | 43 |  | 
|  | 44 | Task::Task(pid_t task_id) | 
|  | 45 | : task_id_(task_id), | 
|  | 46 | thread_group_id_(-1), | 
|  | 47 | parent_process_id_(-1), | 
|  | 48 | thread_count_(0), | 
|  | 49 | cpus_allowed_mask_(0) { | 
|  | 50 | task_fd_ = OpenTaskDirectory(task_id_); | 
| Corey Tabaka | 92f1377 | 2017-08-16 14:52:01 -0700 | [diff] [blame] | 51 | const int error = errno; | 
|  | 52 | ALOGE_IF(task_fd_.get() < 0 && error != EACCES, | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 53 | "Task::Task: Failed to open task directory for task_id=%d: %s", | 
| Corey Tabaka | 92f1377 | 2017-08-16 14:52:01 -0700 | [diff] [blame] | 54 | task_id, strerror(error)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 55 |  | 
| Corey Tabaka | 92f1377 | 2017-08-16 14:52:01 -0700 | [diff] [blame] | 56 | if (IsValid()) { | 
|  | 57 | ReadStatusFields(); | 
|  | 58 | ALOGD_IF(TRACE, | 
|  | 59 | "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x", | 
|  | 60 | task_id_, name_.c_str(), thread_group_id_, parent_process_id_, | 
|  | 61 | cpus_allowed_mask_); | 
|  | 62 | } | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 63 | } | 
|  | 64 |  | 
|  | 65 | base::unique_fd Task::OpenTaskFile(const std::string& name) const { | 
|  | 66 | const std::string relative_path = "./" + name; | 
|  | 67 | return base::unique_fd( | 
|  | 68 | openat(task_fd_.get(), relative_path.c_str(), O_RDONLY)); | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | UniqueFile Task::OpenTaskFilePointer(const std::string& name) const { | 
|  | 72 | const std::string relative_path = "./" + name; | 
|  | 73 | base::unique_fd fd(openat(task_fd_.get(), relative_path.c_str(), O_RDONLY)); | 
|  | 74 | if (fd.get() < 0) { | 
|  | 75 | ALOGE("Task::OpenTaskFilePointer: Failed to open /proc/%d/%s: %s", task_id_, | 
|  | 76 | name.c_str(), strerror(errno)); | 
|  | 77 | return nullptr; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | UniqueFile fp(fdopen(fd.release(), "r")); | 
|  | 81 | if (!fp) | 
|  | 82 | ALOGE("Task::OpenTaskFilePointer: Failed to fdopen /proc/%d/%s: %s", | 
|  | 83 | task_id_, name.c_str(), strerror(errno)); | 
|  | 84 |  | 
|  | 85 | return fp; | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | std::string Task::GetStatusField(const std::string& field) const { | 
|  | 89 | if (auto file = OpenTaskFilePointer("status")) { | 
|  | 90 | stdio_filebuf<char> filebuf(file.get()); | 
|  | 91 | std::istream file_stream(&filebuf); | 
|  | 92 |  | 
|  | 93 | for (std::string line; std::getline(file_stream, line);) { | 
|  | 94 | auto offset = line.find(field); | 
|  | 95 |  | 
|  | 96 | ALOGD_IF(TRACE, | 
|  | 97 | "Task::GetStatusField: field=\"%s\" line=\"%s\" offset=%zd", | 
|  | 98 | field.c_str(), line.c_str(), offset); | 
|  | 99 |  | 
|  | 100 | if (offset == std::string::npos) | 
|  | 101 | continue; | 
|  | 102 |  | 
|  | 103 | // The status file has lines with the format <field>:<value>. Extract the | 
|  | 104 | // value after the colon. | 
| Elliott Hughes | ccddf4c | 2018-11-08 15:32:13 -0800 | [diff] [blame] | 105 | return android::base::Trim(line.substr(offset + field.size() + 1)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 106 | } | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | return "[unknown]"; | 
|  | 110 | } | 
|  | 111 |  | 
|  | 112 | void Task::ReadStatusFields() { | 
|  | 113 | if (auto file = OpenTaskFilePointer("status")) { | 
|  | 114 | stdio_filebuf<char> filebuf(file.get()); | 
|  | 115 | std::istream file_stream(&filebuf); | 
|  | 116 |  | 
|  | 117 | for (std::string line; std::getline(file_stream, line);) { | 
| Chih-Hung Hsieh | 5548e8a | 2018-09-17 15:13:21 -0700 | [diff] [blame] | 118 | auto offset = line.find(':'); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 119 | if (offset == std::string::npos) { | 
|  | 120 | ALOGW("ReadStatusFields: Failed to find delimiter \":\" in line=\"%s\"", | 
|  | 121 | line.c_str()); | 
|  | 122 | continue; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | std::string key = line.substr(0, offset); | 
| Elliott Hughes | ccddf4c | 2018-11-08 15:32:13 -0800 | [diff] [blame] | 126 | std::string value = android::base::Trim(line.substr(offset + 1)); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 127 |  | 
|  | 128 | ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"", | 
|  | 129 | key.c_str(), value.c_str()); | 
|  | 130 |  | 
|  | 131 | if (key == "Name") | 
|  | 132 | name_ = value; | 
|  | 133 | else if (key == "Tgid") | 
|  | 134 | thread_group_id_ = std::strtol(value.c_str(), nullptr, 10); | 
|  | 135 | else if (key == "PPid") | 
|  | 136 | parent_process_id_ = std::strtol(value.c_str(), nullptr, 10); | 
|  | 137 | else if (key == "Uid") | 
|  | 138 | ParseUidStatusField(value, user_id_); | 
|  | 139 | else if (key == "Gid") | 
|  | 140 | ParseUidStatusField(value, group_id_); | 
|  | 141 | else if (key == "Threads") | 
|  | 142 | thread_count_ = std::strtoul(value.c_str(), nullptr, 10); | 
|  | 143 | else if (key == "Cpus_allowed") | 
|  | 144 | cpus_allowed_mask_ = std::strtoul(value.c_str(), nullptr, 16); | 
|  | 145 | else if (key == "Cpus_allowed_list") | 
|  | 146 | cpus_allowed_list_ = value; | 
|  | 147 | } | 
|  | 148 | } | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | std::string Task::GetCpuSetPath() const { | 
|  | 152 | if (auto file = OpenTaskFilePointer("cpuset")) { | 
|  | 153 | stdio_filebuf<char> filebuf(file.get()); | 
|  | 154 | std::istream file_stream(&filebuf); | 
|  | 155 |  | 
|  | 156 | std::string line = ""; | 
|  | 157 | std::getline(file_stream, line); | 
|  | 158 |  | 
| Elliott Hughes | ccddf4c | 2018-11-08 15:32:13 -0800 | [diff] [blame] | 159 | return android::base::Trim(line); | 
| Alex Vakulenko | e4eec20 | 2017-01-27 14:41:04 -0800 | [diff] [blame] | 160 | } else { | 
|  | 161 | return ""; | 
|  | 162 | } | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | }  // namespace dvr | 
|  | 166 | }  // namespace android |