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/unique_fd.h>
14
15 #include "stdio_filebuf.h"
16 #include "string_trim.h"
17
18 namespace {
19
20 const char kProcBase[] = "/proc";
21
OpenTaskDirectory(pid_t task_id)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
ParseUidStatusField(const std::string & value,std::array<int,4> & ids)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
Task(pid_t task_id)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
OpenTaskFile(const std::string & name) const65 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
OpenTaskFilePointer(const std::string & name) const71 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
GetStatusField(const std::string & field) const88 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 Trim(line.substr(offset + field.size() + 1));
106 }
107 }
108
109 return "[unknown]";
110 }
111
ReadStatusFields()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 = 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
GetCpuSetPath() const151 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 Trim(line);
160 } else {
161 return "";
162 }
163 }
164
165 } // namespace dvr
166 } // namespace android
167