191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris/*
291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * Copyright 2013 The Android Open Source Project
391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris *
491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * Licensed under the Apache License, Version 2.0 (the "License");
591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * you may not use this file except in compliance with the License.
691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * You may obtain a copy of the License at
791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris *
891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris *     http://www.apache.org/licenses/LICENSE-2.0
991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris *
1091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * Unless required by applicable law or agreed to in writing, software
1191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * distributed under the License is distributed on an "AS IS" BASIS,
1291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * See the License for the specific language governing permissions and
1491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris * limitations under the License.
1591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris */
1691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
1791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <stdio.h>
1891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <limits.h>
1991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <ctype.h>
2091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <unistd.h>
2191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
2291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <signal.h>
2391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <sys/types.h>
2491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <sys/stat.h>
2591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <fcntl.h>
2691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <dirent.h>
2791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
2891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <cutils/log.h>
2991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
3091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <algorithm>
3191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include <vector>
3291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
3391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#include "memtrack.h"
3491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
3591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#ifdef LOG_TAG
3691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#undef LOG_TAG
3791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#endif
3891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris#define LOG_TAG "MemTracker"
3991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
4091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher FerrisFileData::FileData(char *filename, char *buffer, size_t buffer_len)
4191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    : data_(buffer), max_(buffer_len), cur_idx_(0), len_(0),
4291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      read_complete_(false) {
4391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  fd_ = open(filename, O_RDONLY);
4491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (fd_ < 0) {
4591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    read_complete_ = true;
4691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
4791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
4891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
4991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher FerrisFileData::~FileData() {
5091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (fd_ >= 0) {
5191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    close(fd_);
5291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
5391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
5491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
5591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisbool FileData::isAvail(size_t bytes_needed) {
5691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (cur_idx_ + bytes_needed < len_) {
5791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    return true;
5891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
5991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
6091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (read_complete_) {
6191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    return false;
6291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
6391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
6491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (cur_idx_ != len_) {
6591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    // Copy the leftover to the front of the buffer.
6691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    len_ = len_ - cur_idx_;
6791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    memcpy(data_, data_ + cur_idx_, len_);
6891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
6991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
7091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  ssize_t bytes;
7191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  cur_idx_ = 0;
7291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  while (cur_idx_ + bytes_needed >= len_) {
7391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    bytes = read(fd_, data_ + len_, max_ - len_);
7491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (bytes == 0 || bytes == -1) {
7591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      read_complete_;
7691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      break;
7791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
7891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    len_ += bytes;
7991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
8091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
8191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  return cur_idx_ + bytes_needed < len_;
8291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
8391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
8491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisbool FileData::getPss(size_t *pss) {
8591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  size_t value;
8691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  while (true) {
8791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (!isAvail(4)) {
8891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      return false;
8991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
9091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
9191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (data_[cur_idx_] != 'P' || data_[cur_idx_+1] != 's' ||
9291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        data_[cur_idx_+2] != 's' || data_[cur_idx_+3] != ':') {
9391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      // Consume the rest of the line.
9491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      while (isAvail(1) && data_[cur_idx_++] != '\n');
9591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    } else {
9691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      cur_idx_ += 4;
9791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      while (isAvail(1) && isspace(data_[cur_idx_])) {
9891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        cur_idx_++;
9991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
10091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
10191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      value = 0;
10291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      while (isAvail(1) && isdigit(data_[cur_idx_])) {
10391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        value = value * 10 + data_[cur_idx_] - '0';
10491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        cur_idx_++;
10591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
10691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      *pss = value;
10791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
10891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      // Consume the rest of the line.
10991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      while (isAvail(1) && data_[cur_idx_++] != '\n');
11091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
11191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      return true;
11291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
11391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
11491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
11591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
11691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisconst char *ProcessInfo::kProc = "/proc/";
11791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisconst char *ProcessInfo::kCmdline = "/cmdline";
11891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisconst char *ProcessInfo::kSmaps = "/smaps";
11991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
12091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher FerrisProcessInfo::ProcessInfo() {
12191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  memcpy(proc_file_, kProc, kProcLen);
12291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
12391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
12491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher FerrisProcessInfo::~ProcessInfo() {
12591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
12691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
12791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisbool ProcessInfo::getInformation(int pid, char *pid_str, size_t pid_str_len) {
12891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  memcpy(proc_file_ + kProcLen, pid_str, pid_str_len);
12991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  memcpy(proc_file_ + kProcLen + pid_str_len, kCmdline, kCmdlineLen);
13091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
13191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  // Read the cmdline for the process.
13291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  int fd = open(proc_file_, O_RDONLY);
13391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (fd < 0) {
13491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    return false;
13591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
13691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
13791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  ssize_t bytes = read(fd, cmd_name_, sizeof(cmd_name_));
13891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  close(fd);
13991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (bytes == -1 || bytes == 0) {
14091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    return false;
14191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
14291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
14391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  memcpy(proc_file_ + kProcLen + pid_str_len, kSmaps, kSmapsLen);
14491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  FileData smaps(proc_file_, buffer_, sizeof(buffer_));
14591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
14691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  cur_process_info_t process_info;
14791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  size_t pss_kb;
14891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  process_info.pss_kb = 0;
14991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  while (smaps.getPss(&pss_kb)) {
15091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    process_info.pss_kb += pss_kb;
15191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
15291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
15391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (cur_.count(cmd_name_) == 0) {
15491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    cur_[cmd_name_] = process_info;
15591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  } else {
15691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    cur_[cmd_name_].pss_kb += process_info.pss_kb;
15791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
15891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  cur_[cmd_name_].pids.push_back(pid);
15991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
16091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  return true;
16191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
16291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
16391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisvoid ProcessInfo::scan() {
16491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  DIR *proc_dir = opendir(kProc);
16591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (proc_dir == NULL) {
16691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    perror("Cannot open directory.\n");
16791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    exit(1);
16891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
16991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
17091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  // Clear any current pids.
17191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (processes_t::iterator it = all_.begin(); it != all_.end(); ++it) {
17291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    it->second.pids.clear();
17391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
17491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
17591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  struct dirent *dir_data;
17691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  int len;
17791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  bool is_pid;
17891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  size_t pid;
17991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  cur_.clear();
18091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  while ((dir_data = readdir(proc_dir))) {
18191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    // Check if the directory entry represents a pid.
18291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    len = strlen(dir_data->d_name);
18391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    is_pid = true;
18491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    pid = 0;
18591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    for (int i = 0; i < len; i++) {
18691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      if (!isdigit(dir_data->d_name[i])) {
18791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        is_pid = false;
18891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        break;
18991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
19091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      pid = pid * 10 + dir_data->d_name[i] - '0';
19191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
19291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (is_pid) {
19391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      getInformation(pid, dir_data->d_name, len);
19491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
19591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
19691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  closedir(proc_dir);
19791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
19891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  // Loop through the current processes and add them into our real list.
19991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (cur_processes_t::const_iterator it = cur_.begin();
20091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris       it != cur_.end(); ++it) {
20191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
20291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (all_.count(it->first) == 0) {
20391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      // Initialize all of the variables.
20491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].num_samples = 0;
20591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].name = it->first;
20691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].avg_pss_kb = 0;
20791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].min_pss_kb = 0;
20891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].max_pss_kb = 0;
20991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
21091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
21191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (it->second.pids.size() > all_[it->first].max_num_pids) {
21291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].max_num_pids = it->second.pids.size();
21391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
21491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
21591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    all_[it->first].pids = it->second.pids;
21691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
21791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (it->second.pss_kb > all_[it->first].max_pss_kb) {
21891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].max_pss_kb = it->second.pss_kb;
21991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
22091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
22191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (all_[it->first].min_pss_kb == 0 ||
22291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        it->second.pss_kb < all_[it->first].min_pss_kb) {
22391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      all_[it->first].min_pss_kb = it->second.pss_kb;
22491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
22591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
22691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    all_[it->first].last_pss_kb = it->second.pss_kb;
22791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
22891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    computeAvg(&all_[it->first].avg_pss_kb, it->second.pss_kb,
22991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris               all_[it->first].num_samples);
23091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    all_[it->first].num_samples++;
23191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
23291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
23391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
23491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisbool comparePss(const process_info_t *first, const process_info_t *second) {
23591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  return first->max_pss_kb > second->max_pss_kb;
23691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
23791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
23891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisvoid ProcessInfo::dumpToLog() {
23991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  list_.clear();
24091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (processes_t::const_iterator it = all_.begin(); it != all_.end(); ++it) {
24191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    list_.push_back(&it->second);
24291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
24391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
24491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  // Now sort the list.
24591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  std::sort(list_.begin(), list_.end(), comparePss);
24691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
24791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  ALOGI("Dumping process list");
24891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (std::vector<const process_info_t *>::const_iterator it = list_.begin();
24991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris       it != list_.end(); ++it) {
25091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("  Name: %s", (*it)->name.c_str());
25191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("    Max running processes: %d", (*it)->max_num_pids);
25291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if ((*it)->pids.size() > 0) {
25391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      ALOGI("    Currently running pids:");
25491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      for (std::vector<int>::const_iterator pid_it = (*it)->pids.begin();
25591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris           pid_it != (*it)->pids.end(); ++pid_it) {
25691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        ALOGI("      %d", *pid_it);
25791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
25891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
25991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
26091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("    Min  PSS %0.4fM", (*it)->min_pss_kb/1024.0);
26191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("    Avg  PSS %0.4fM", (*it)->avg_pss_kb/1024.0);
26291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("    Max  PSS %0.4fM", (*it)->max_pss_kb/1024.0);
26391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    ALOGI("    Last PSS %0.4fM", (*it)->last_pss_kb/1024.0);
26491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
26591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
26691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
26791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisvoid usage() {
26891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("Usage: memtrack [--verbose | --quiet] [--scan_delay TIME_SECS]\n");
26991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("  --scan_delay TIME_SECS\n");
27091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("    The amount of delay in seconds between scans.\n");
27191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("  --verbose\n");
27291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("    Print information about the scans to stdout only.\n");
27391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("  --quiet\n");
27491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("    Nothing will be printed to stdout.\n");
27591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  printf("  All scan data is dumped to the android log using the tag %s\n",
27691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris         LOG_TAG);
27791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
27891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
27991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisint SignalReceived = 0;
28091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
28191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisint SignalsToHandle[] = {
28291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  SIGTSTP,
28391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  SIGINT,
28491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  SIGHUP,
28591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  SIGPIPE,
28691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  SIGUSR1,
28791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris};
28891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
28991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisvoid handleSignal(int signo) {
29091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (SignalReceived == 0) {
29191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    SignalReceived = signo;
29291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
29391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
29491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
29591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferrisint main(int argc, char **argv) {
29691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (geteuid() != 0) {
29791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    printf("Must be run as root.\n");
29891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    exit(1);
29991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
30091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
30191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  bool verbose = false;
30291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  bool quiet = false;
30391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  unsigned int scan_delay_sec = DEFAULT_SLEEP_DELAY_SECONDS;
30491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (int i = 1; i < argc; i++) {
30591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (strcmp(argv[i], "--verbose") == 0) {
30691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      verbose = true;
30791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    } else if (strcmp(argv[i], "--quiet") == 0) {
30891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      quiet = true;
30991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    } else if (strcmp(argv[i], "--scan_delay") == 0) {
31091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      if (i+1 == argc) {
31191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        printf("The %s options requires a single argument.\n", argv[i]);
31291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        usage();
31391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        exit(1);
31491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
31591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      scan_delay_sec = atoi(argv[++i]);
31691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    } else {
31791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      printf("Unknown option %s\n", argv[i]);
31891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      usage();
31991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      exit(1);
32091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
32191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
32291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (quiet && verbose) {
32391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    printf("Both --quiet and --verbose cannot be specified.\n");
32491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    usage();
32591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    exit(1);
32691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
32791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
32891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  // Set up the signal handlers.
32991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  for (size_t i = 0; i < sizeof(SignalsToHandle)/sizeof(int); i++) {
33091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (signal(SignalsToHandle[i], handleSignal) == SIG_ERR) {
33191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      printf("Unable to handle signal %d\n", SignalsToHandle[i]);
33291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      exit(1);
33391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
33491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
33591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
33691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  ProcessInfo proc_info;
33791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
33891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  if (!quiet) {
33991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    printf("Hit Ctrl-Z or send SIGUSR1 to pid %d to print the current list of\n",
34091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris           getpid());
34191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    printf("processes.\n");
34291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    printf("Hit Ctrl-C to print the list of processes and terminate.\n");
34391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
34491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
34591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  struct timespec t;
34691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  unsigned long long nsecs;
34791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  while (true) {
34891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (verbose) {
34991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      memset(&t, 0, sizeof(t));
35091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      clock_gettime(CLOCK_MONOTONIC, &t);
35191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      nsecs = (unsigned long long)t.tv_sec*NS_PER_SEC + t.tv_nsec;
35291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
35391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    proc_info.scan();
35491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (verbose) {
35591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      memset(&t, 0, sizeof(t));
35691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      clock_gettime(CLOCK_MONOTONIC, &t);
35791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      nsecs = ((unsigned long long)t.tv_sec*NS_PER_SEC + t.tv_nsec) - nsecs;
35891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      printf("Scan Time %0.4f\n", ((double)nsecs)/NS_PER_SEC);
35991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
36091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris
36191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    if (SignalReceived != 0) {
36291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      proc_info.dumpToLog();
36391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      if (SignalReceived != SIGUSR1 && SignalReceived != SIGTSTP) {
36491f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        if (!quiet) {
36591f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris          printf("Terminating...\n");
36691f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        }
36791f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris        exit(1);
36891f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      }
36991f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris      SignalReceived = 0;
37091f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    }
37191f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris    sleep(scan_delay_sec);
37291f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris  }
37391f4410f49f8f701f9001c447b5bc6162c348f6bChristopher Ferris}
374