1 #include "task.h" 2 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <log/log.h> 6 #include <stdio.h> 7 8 #include <cctype> 9 #include <cstdlib> 10 #include <memory> 11 #include <sstream> 12 13 #include <android-base/strings.h> 14 #include <android-base/unique_fd.h> 15 16 #include "stdio_filebuf.h" 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_); 51 const int error = errno; 52 ALOGE_IF(task_fd_.get() < 0 && error != EACCES, 53 "Task::Task: Failed to open task directory for task_id=%d: %s", 54 task_id, strerror(error)); 55 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 } 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. 105 return android::base::Trim(line.substr(offset + field.size() + 1)); 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);) { 118 auto offset = line.find(':'); 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); 126 std::string value = android::base::Trim(line.substr(offset + 1)); 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 159 return android::base::Trim(line); 160 } else { 161 return ""; 162 } 163 } 164 165 } // namespace dvr 166 } // namespace android 167