blob: bda168233108197dc9b3dfdf49ada36dca2c897d [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "task.h"
2
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08003#include <errno.h>
4#include <fcntl.h>
Alex Vakulenko4fe60582017-02-02 11:35:59 -08005#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08006#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
18namespace {
19
20const char kProcBase[] = "/proc";
21
22android::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
30void 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
41namespace android {
42namespace dvr {
43
44Task::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 Tabaka92f13772017-08-16 14:52:01 -070051 const int error = errno;
52 ALOGE_IF(task_fd_.get() < 0 && error != EACCES,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080053 "Task::Task: Failed to open task directory for task_id=%d: %s",
Corey Tabaka92f13772017-08-16 14:52:01 -070054 task_id, strerror(error));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080055
Corey Tabaka92f13772017-08-16 14:52:01 -070056 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 Vakulenkoe4eec202017-01-27 14:41:04 -080063}
64
65base::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
71UniqueFile 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
88std::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
112void 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 Hsieh5548e8a2018-09-17 15:13:21 -0700118 auto offset = line.find(':');
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800119 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
151std::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