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 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 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 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 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 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 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 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 78 ProcessMonitor::~ProcessMonitor() { 79 } 80 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 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 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 138 status_t ProcessMonitor::process() { 139 status_t status = updateProcessInfo(); 140 if (status != NO_ERROR) { 141 return status; 142 } 143 return improveSystemHealth(); 144 } 145 146 status_t ProcessMonitor::improveSystemHealth() { 147 // TODO: implement policy enforcer. kill apps that abuse system. 148 return NO_ERROR; 149 } 150 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 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 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 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 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 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 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 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 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