Home | History | Annotate | Download | only in vehicle_monitor_service
      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