1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "ProcessMonitor"
17
18 #include <mutex>
19 #include <sys/param.h>
20 #include <dirent.h>
21
22 #include "ProcessMonitor.h"
23
24 #define DBG_VERBOSE
25 #ifdef DBG_VERBOSE
26 #define LOG_VERBOSE(x...) ALOGD(x)
27 #else
28 #define LOG_VERBOSE(x...)
29 #endif
30
31 #define MAX_LINE 256
32 #define SELF_IO "/proc/self/io"
33 #define NUM_PROC_DUMP 10
34
35 namespace android {
36
procDeltaCpuCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)37 static bool procDeltaCpuCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
38 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
39 return a.second->delta_time > b.second->delta_time;
40 }
41
procDeltaMemCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)42 static bool procDeltaMemCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
43 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
44 return a.second->delta_rss > b.second->delta_rss;
45 }
46
procDeltaWbytesCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)47 static bool procDeltaWbytesCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
48 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
49 return a.second->delta_wbytes > b.second->delta_wbytes;
50 }
51
procCpuCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)52 static bool procCpuCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
53 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
54 return (a.second->utime + a.second->utime) > (b.second->stime + b.second->stime);
55 }
56
procMemCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)57 static bool procMemCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
58 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
59 return a.second->rss > b.second->rss;
60 }
61
procWbytesCmp(const std::pair<pid_t,const std::shared_ptr<ProcInfo>> a,const std::pair<pid_t,const std::shared_ptr<ProcInfo>> b)62 static bool procWbytesCmp(const std::pair<pid_t, const std::shared_ptr<ProcInfo>> a,
63 const std::pair<pid_t, const std::shared_ptr<ProcInfo>> b) {
64 return a.second->wbytes > b.second->wbytes;
65 }
66
ProcessMonitor()67 ProcessMonitor::ProcessMonitor() {
68 //TODO: read config from policy files.
69 if (access(SELF_IO, F_OK) == -1) {
70 mIoSupported = false;
71 ALOGE("**** DISK I/O PROFILING DISABLED!!!!****\n"
72 "Kernel doesn't support I/O profiling.");
73 } else {
74 mIoSupported = true;
75 }
76 }
77
~ProcessMonitor()78 ProcessMonitor::~ProcessMonitor() {
79 }
80
dump(String8 & msg)81 void ProcessMonitor::dump(String8& msg) {
82 std::shared_lock<std::shared_timed_mutex> lock(mMutex);
83 msg.append("ProcessMonitor\n");
84 msg.appendFormat("Processes count: %d\n", (int) mProcInfoMap.size());
85 msg.append("Top CPU usage\n");
86 dumpTopProcesses(msg, procCpuCmp);
87 msg.append("Top CPU usage increase\n");
88 dumpTopProcesses(msg, procDeltaCpuCmp);
89 msg.append("Top memory usage\n");
90 dumpTopProcesses(msg, procMemCmp);
91 msg.append("Top memory usage increase\n");
92 dumpTopProcesses(msg, procDeltaMemCmp);
93 if (mIoSupported) {
94 msg.append("Top disk IO \n");
95 dumpTopProcesses(msg, procWbytesCmp);
96 msg.append("Top disk IO increase \n");
97 dumpTopProcesses(msg, procDeltaWbytesCmp);
98 } else {
99 msg.append("Disk IO monitoring not supported.\n");
100 }
101 }
102
dumpTopProcesses(String8 & msg,bool (* procCmpFn)(const std::pair<pid_t,const std::shared_ptr<ProcInfo>>,const std::pair<pid_t,const std::shared_ptr<ProcInfo>>))103 void ProcessMonitor::dumpTopProcesses(
104 String8& msg,
105 bool (*procCmpFn) (
106 const std::pair<pid_t, const std::shared_ptr<ProcInfo>>,
107 const std::pair<pid_t, const std::shared_ptr<ProcInfo>>)) {
108
109 std::vector<std::pair<pid_t, std::shared_ptr<ProcInfo>>> topPids(NUM_PROC_DUMP);
110 std::partial_sort_copy(mProcInfoMap.begin(),
111 mProcInfoMap.end(),
112 topPids.begin(),
113 topPids.end(),
114 *procCmpFn);
115 for (auto it = topPids.begin(); it != topPids.end(); ++it) {
116 msg.appendFormat("(%s) PID: %d: delta_time: %" PRIu64 ", delta_rss: %" PRIu64 ", "
117 "delta_wbytes: %" PRIu64 ", utime: %" PRIu64" , stime: %" PRIu64 ", "
118 "rss: %" PRIu64 ", wbytes: %" PRIu64 "\n",
119 it->second->name.c_str(),
120 it->first,
121 it->second->delta_time,
122 it->second->delta_rss,
123 it->second->delta_wbytes,
124 it->second->utime,
125 it->second->stime,
126 it->second->rss,
127 it->second->wbytes);
128 }
129
130 }
131
setAppPriority(uint32_t,uint32_t,uint32_t)132 status_t ProcessMonitor::setAppPriority(uint32_t , uint32_t, uint32_t) {
133 std::unique_lock<std::shared_timed_mutex> lock(mMutex);
134 // TODO implement.
135 return NO_ERROR;
136 }
137
process()138 status_t ProcessMonitor::process() {
139 status_t status = updateProcessInfo();
140 if (status != NO_ERROR) {
141 return status;
142 }
143 return improveSystemHealth();
144 }
145
improveSystemHealth()146 status_t ProcessMonitor::improveSystemHealth() {
147 // TODO: implement policy enforcer. kill apps that abuse system.
148 return NO_ERROR;
149 }
150
updateProcessInfo()151 status_t ProcessMonitor::updateProcessInfo() {
152 std::unique_lock<std::shared_timed_mutex> lock(mMutex);
153 std::set<pid_t> oldPids;
154 populateExistingPids(oldPids);
155 DIR *procDir;
156 procDir = opendir("/proc");
157 if (!procDir) {
158 ALOGE("Failed to open /proc dir");
159 return PERMISSION_DENIED;
160 }
161 struct dirent *pidDir;
162 pid_t pid;
163 while ((pidDir = readdir(procDir))) {
164 if (!isdigit(pidDir->d_name[0])) {
165 continue;
166 }
167 pid = atoi(pidDir->d_name);
168 updateOrAddProcess(pid);
169 oldPids.erase(pid);
170 }
171 deleteOutdatedPids(oldPids);
172 return NO_ERROR;
173 }
174
deleteOutdatedPids(std::set<pid_t> & pidSet)175 void ProcessMonitor::deleteOutdatedPids(std::set<pid_t>& pidSet) {
176 for(auto it = pidSet.begin(); it != pidSet.end(); ++it) {
177 LOG_VERBOSE("Process %d ended. Removing from process map", *it);
178 mProcInfoMap.erase(*it);
179 }
180 }
181
populateExistingPids(std::set<pid_t> & pidSet)182 void ProcessMonitor::populateExistingPids(std::set<pid_t>& pidSet) {
183 for(auto it = mProcInfoMap.begin(); it != mProcInfoMap.end(); ++it) {
184 pidSet.insert(it->first);
185 }
186 }
187
updateOrAddProcess(pid_t pid)188 void ProcessMonitor::updateOrAddProcess(pid_t pid) {
189 auto pidDataIt = mProcInfoMap.find(pid);
190 std::shared_ptr<ProcInfo> pidData;
191 if (pidDataIt == mProcInfoMap.end()) {
192 pidData = std::make_shared<ProcInfo>();
193 mProcInfoMap.insert(std::pair<pid_t, std::shared_ptr<ProcInfo>>(pid, pidData));
194 } else {
195 pidData = pidDataIt->second;
196 }
197 auto originalPidData = std::make_shared<ProcInfo>(*pidData);
198 readStat(pidData, pid);
199 if (mIoSupported) {
200 readIo(pidData, pid);
201 }
202 readCmdline(pidData, pid);
203 readStatus(pidData, pid);
204 updateDiffs(pidData, originalPidData);
205 }
206
readStat(std::shared_ptr<ProcInfo> pidData,pid_t pid)207 void ProcessMonitor::readStat(std::shared_ptr<ProcInfo> pidData, pid_t pid) {
208 char filename[64];
209 sprintf(filename, "/proc/%d/stat", pid);
210 FILE *file;
211 file = fopen(filename, "r");
212 if (!file) {
213 ALOGD("Failed to open file %s for reading", filename);
214 return;
215 }
216 fscanf(file,
217 "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
218 "%" SCNu64
219 "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d "
220 "%*" SCNu64
221 "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
222 "%*d",
223 &pidData->utime,
224 &pidData->stime,
225 &pidData->rss);
226 fclose(file);
227 }
228
readIo(std::shared_ptr<ProcInfo> pidData,pid_t pid)229 void ProcessMonitor::readIo(std::shared_ptr<ProcInfo> pidData, pid_t pid) {
230 char filename[64];
231 sprintf(filename, "/proc/%d/io", pid);
232 FILE *file;
233 file = fopen(filename, "r");
234 if (!file) {
235 ALOGD("Failed to open file %s for reading", filename);
236 return;
237 }
238 char buf[MAX_LINE];
239 while (fgets(buf, MAX_LINE, file)) {
240 sscanf(buf, "write_bytes: %" PRIu64, &pidData->wbytes);
241 }
242 fclose(file);
243 }
244
readCmdline(std::shared_ptr<ProcInfo> pidData,pid_t pid)245 void ProcessMonitor::readCmdline(std::shared_ptr<ProcInfo> pidData, pid_t pid) {
246 char filename[64];
247 sprintf(filename, "/proc/%d/cmdline", pid);
248 FILE *file;
249 file = fopen(filename, "r");
250 if (!file) {
251 ALOGD("Failed to open file %s for reading", filename);
252 return;
253 }
254 char buf[MAXPATHLEN];
255 fgets(buf, MAXPATHLEN, file);
256 fclose(file);
257 if (strlen(buf) > 0) {
258 pidData->name.assign(buf);
259 }
260 }
261
readStatus(std::shared_ptr<ProcInfo> pidData,pid_t pid)262 void ProcessMonitor::readStatus(std::shared_ptr<ProcInfo> pidData, pid_t pid) {
263 char filename[64];
264 sprintf(filename, "/proc/%d/status", pid);
265 FILE *file;
266 file = fopen(filename, "r");
267 if (!file) {
268 ALOGD("Failed to open file %s for reading", filename);
269 return;
270 }
271 char line[MAX_LINE];
272 unsigned int uid;
273 while (fgets(line, MAX_LINE, file)) {
274 sscanf(line, "Uid: %u", &uid);
275 }
276 fclose(file);
277 pidData->uid = uid;
278
279 }
280
updateDiffs(std::shared_ptr<ProcInfo> pidData,std::shared_ptr<ProcInfo> oldPidData)281 void ProcessMonitor::updateDiffs(std::shared_ptr<ProcInfo> pidData,
282 std::shared_ptr<ProcInfo> oldPidData) {
283 pidData->delta_utime = pidData->utime - oldPidData->utime;
284 pidData->delta_stime = pidData->stime - oldPidData->stime;
285 pidData->delta_time = pidData->delta_utime + pidData->delta_stime;
286 pidData->delta_rss = pidData->rss - oldPidData->rss;
287 pidData->delta_wbytes = pidData->wbytes - oldPidData->wbytes;
288 }
289
290 }; // namespace android
291