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 ALOGE_IF(task_fd_.get() < 0,
52 "Task::Task: Failed to open task directory for task_id=%d: %s",
53 task_id, strerror(errno));
54
55 ReadStatusFields();
56
57 ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
58 task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
59 cpus_allowed_mask_);
60 }
61
OpenTaskFile(const std::string & name) const62 base::unique_fd Task::OpenTaskFile(const std::string& name) const {
63 const std::string relative_path = "./" + name;
64 return base::unique_fd(
65 openat(task_fd_.get(), relative_path.c_str(), O_RDONLY));
66 }
67
OpenTaskFilePointer(const std::string & name) const68 UniqueFile Task::OpenTaskFilePointer(const std::string& name) const {
69 const std::string relative_path = "./" + name;
70 base::unique_fd fd(openat(task_fd_.get(), relative_path.c_str(), O_RDONLY));
71 if (fd.get() < 0) {
72 ALOGE("Task::OpenTaskFilePointer: Failed to open /proc/%d/%s: %s", task_id_,
73 name.c_str(), strerror(errno));
74 return nullptr;
75 }
76
77 UniqueFile fp(fdopen(fd.release(), "r"));
78 if (!fp)
79 ALOGE("Task::OpenTaskFilePointer: Failed to fdopen /proc/%d/%s: %s",
80 task_id_, name.c_str(), strerror(errno));
81
82 return fp;
83 }
84
GetStatusField(const std::string & field) const85 std::string Task::GetStatusField(const std::string& field) const {
86 if (auto file = OpenTaskFilePointer("status")) {
87 stdio_filebuf<char> filebuf(file.get());
88 std::istream file_stream(&filebuf);
89
90 for (std::string line; std::getline(file_stream, line);) {
91 auto offset = line.find(field);
92
93 ALOGD_IF(TRACE,
94 "Task::GetStatusField: field=\"%s\" line=\"%s\" offset=%zd",
95 field.c_str(), line.c_str(), offset);
96
97 if (offset == std::string::npos)
98 continue;
99
100 // The status file has lines with the format <field>:<value>. Extract the
101 // value after the colon.
102 return Trim(line.substr(offset + field.size() + 1));
103 }
104 }
105
106 return "[unknown]";
107 }
108
ReadStatusFields()109 void Task::ReadStatusFields() {
110 if (auto file = OpenTaskFilePointer("status")) {
111 stdio_filebuf<char> filebuf(file.get());
112 std::istream file_stream(&filebuf);
113
114 for (std::string line; std::getline(file_stream, line);) {
115 auto offset = line.find(":");
116 if (offset == std::string::npos) {
117 ALOGW("ReadStatusFields: Failed to find delimiter \":\" in line=\"%s\"",
118 line.c_str());
119 continue;
120 }
121
122 std::string key = line.substr(0, offset);
123 std::string value = Trim(line.substr(offset + 1));
124
125 ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
126 key.c_str(), value.c_str());
127
128 if (key == "Name")
129 name_ = value;
130 else if (key == "Tgid")
131 thread_group_id_ = std::strtol(value.c_str(), nullptr, 10);
132 else if (key == "PPid")
133 parent_process_id_ = std::strtol(value.c_str(), nullptr, 10);
134 else if (key == "Uid")
135 ParseUidStatusField(value, user_id_);
136 else if (key == "Gid")
137 ParseUidStatusField(value, group_id_);
138 else if (key == "Threads")
139 thread_count_ = std::strtoul(value.c_str(), nullptr, 10);
140 else if (key == "Cpus_allowed")
141 cpus_allowed_mask_ = std::strtoul(value.c_str(), nullptr, 16);
142 else if (key == "Cpus_allowed_list")
143 cpus_allowed_list_ = value;
144 }
145 }
146 }
147
GetCpuSetPath() const148 std::string Task::GetCpuSetPath() const {
149 if (auto file = OpenTaskFilePointer("cpuset")) {
150 stdio_filebuf<char> filebuf(file.get());
151 std::istream file_stream(&filebuf);
152
153 std::string line = "";
154 std::getline(file_stream, line);
155
156 return Trim(line);
157 } else {
158 return "";
159 }
160 }
161
162 } // namespace dvr
163 } // namespace android
164