1// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/process_util.h" 6 7#include <ctype.h> 8#include <dirent.h> 9#include <dlfcn.h> 10#include <errno.h> 11#include <fcntl.h> 12#include <sys/time.h> 13#include <sys/types.h> 14#include <sys/wait.h> 15#include <time.h> 16#include <unistd.h> 17 18#include "base/file_util.h" 19#include "base/logging.h" 20#include "base/string_tokenizer.h" 21#include "base/string_util.h" 22 23namespace { 24 25enum ParsingState { 26 KEY_NAME, 27 KEY_VALUE 28}; 29 30// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by 31// spaces. 32void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { 33 FilePath stat_file("/proc"); 34 stat_file = stat_file.Append(IntToString(pid)); 35 stat_file = stat_file.Append("stat"); 36 std::string mem_stats; 37 if (!file_util::ReadFileToString(stat_file, &mem_stats)) 38 return; 39 SplitString(mem_stats, ' ', proc_stats); 40} 41 42} // namespace 43 44namespace base { 45 46ProcessId GetParentProcessId(ProcessHandle process) { 47 FilePath stat_file("/proc"); 48 stat_file = stat_file.Append(IntToString(process)); 49 stat_file = stat_file.Append("status"); 50 std::string status; 51 if (!file_util::ReadFileToString(stat_file, &status)) 52 return -1; 53 54 StringTokenizer tokenizer(status, ":\n"); 55 ParsingState state = KEY_NAME; 56 std::string last_key_name; 57 while (tokenizer.GetNext()) { 58 switch (state) { 59 case KEY_NAME: 60 last_key_name = tokenizer.token(); 61 state = KEY_VALUE; 62 break; 63 case KEY_VALUE: 64 DCHECK(!last_key_name.empty()); 65 if (last_key_name == "PPid") { 66 pid_t ppid = StringToInt(tokenizer.token()); 67 return ppid; 68 } 69 state = KEY_NAME; 70 break; 71 } 72 } 73 NOTREACHED(); 74 return -1; 75} 76 77FilePath GetProcessExecutablePath(ProcessHandle process) { 78 FilePath stat_file("/proc"); 79 stat_file = stat_file.Append(IntToString(process)); 80 stat_file = stat_file.Append("exe"); 81 char exename[2048]; 82 ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); 83 if (len < 1) { 84 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses 85 return FilePath(); 86 } 87 return FilePath(std::string(exename, len)); 88} 89 90NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name, 91 const ProcessFilter* filter) 92 : executable_name_(executable_name), filter_(filter) { 93 procfs_dir_ = opendir("/proc"); 94} 95 96NamedProcessIterator::~NamedProcessIterator() { 97 if (procfs_dir_) { 98 closedir(procfs_dir_); 99 procfs_dir_ = NULL; 100 } 101} 102 103const ProcessEntry* NamedProcessIterator::NextProcessEntry() { 104 bool result = false; 105 do { 106 result = CheckForNextProcess(); 107 } while (result && !IncludeEntry()); 108 109 if (result) 110 return &entry_; 111 112 return NULL; 113} 114 115bool NamedProcessIterator::CheckForNextProcess() { 116 // TODO(port): skip processes owned by different UID 117 118 dirent* slot = 0; 119 const char* openparen; 120 const char* closeparen; 121 122 // Arbitrarily guess that there will never be more than 200 non-process 123 // files in /proc. Hardy has 53. 124 int skipped = 0; 125 const int kSkipLimit = 200; 126 while (skipped < kSkipLimit) { 127 slot = readdir(procfs_dir_); 128 // all done looking through /proc? 129 if (!slot) 130 return false; 131 132 // If not a process, keep looking for one. 133 bool notprocess = false; 134 int i; 135 for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) { 136 if (!isdigit(slot->d_name[i])) { 137 notprocess = true; 138 break; 139 } 140 } 141 if (i == NAME_MAX || notprocess) { 142 skipped++; 143 continue; 144 } 145 146 // Read the process's status. 147 char buf[NAME_MAX + 12]; 148 sprintf(buf, "/proc/%s/stat", slot->d_name); 149 FILE *fp = fopen(buf, "r"); 150 if (!fp) 151 return false; 152 const char* result = fgets(buf, sizeof(buf), fp); 153 fclose(fp); 154 if (!result) 155 return false; 156 157 // Parse the status. It is formatted like this: 158 // %d (%s) %c %d ... 159 // pid (name) runstate ppid 160 // To avoid being fooled by names containing a closing paren, scan 161 // backwards. 162 openparen = strchr(buf, '('); 163 closeparen = strrchr(buf, ')'); 164 if (!openparen || !closeparen) 165 return false; 166 char runstate = closeparen[2]; 167 168 // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped? 169 // Allowed values: D R S T Z 170 if (runstate != 'Z') 171 break; 172 173 // Nope, it's a zombie; somebody isn't cleaning up after their children. 174 // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.) 175 // There could be a lot of zombies, can't really decrement i here. 176 } 177 if (skipped >= kSkipLimit) { 178 NOTREACHED(); 179 return false; 180 } 181 182 entry_.pid = atoi(slot->d_name); 183 entry_.ppid = atoi(closeparen + 3); 184 185 // TODO(port): read pid's commandline's $0, like killall does. Using the 186 // short name between openparen and closeparen won't work for long names! 187 int len = closeparen - openparen - 1; 188 if (len > NAME_MAX) 189 len = NAME_MAX; 190 memcpy(entry_.szExeFile, openparen + 1, len); 191 entry_.szExeFile[len] = 0; 192 193 return true; 194} 195 196bool NamedProcessIterator::IncludeEntry() { 197 // TODO(port): make this also work for non-ASCII filenames 198 if (WideToASCII(executable_name_) != entry_.szExeFile) 199 return false; 200 if (!filter_) 201 return true; 202 return filter_->Includes(entry_.pid, entry_.ppid); 203} 204 205// On linux, we return vsize. 206size_t ProcessMetrics::GetPagefileUsage() const { 207 std::vector<std::string> proc_stats; 208 GetProcStats(process_, &proc_stats); 209 const size_t kVmSize = 22; 210 if (proc_stats.size() > kVmSize) 211 return static_cast<size_t>(StringToInt(proc_stats[kVmSize])); 212 return 0; 213} 214 215// On linux, we return the high water mark of vsize. 216size_t ProcessMetrics::GetPeakPagefileUsage() const { 217 std::vector<std::string> proc_stats; 218 GetProcStats(process_, &proc_stats); 219 const size_t kVmPeak = 21; 220 if (proc_stats.size() > kVmPeak) 221 return static_cast<size_t>(StringToInt(proc_stats[kVmPeak])); 222 return 0; 223} 224 225// On linux, we return RSS. 226size_t ProcessMetrics::GetWorkingSetSize() const { 227 std::vector<std::string> proc_stats; 228 GetProcStats(process_, &proc_stats); 229 const size_t kVmRss = 23; 230 if (proc_stats.size() > kVmRss) { 231 size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss])); 232 return num_pages * getpagesize(); 233 } 234 return 0; 235} 236 237// On linux, we return the high water mark of RSS. 238size_t ProcessMetrics::GetPeakWorkingSetSize() const { 239 std::vector<std::string> proc_stats; 240 GetProcStats(process_, &proc_stats); 241 const size_t kVmHwm = 23; 242 if (proc_stats.size() > kVmHwm) { 243 size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm])); 244 return num_pages * getpagesize(); 245 } 246 return 0; 247} 248 249size_t ProcessMetrics::GetPrivateBytes() const { 250 WorkingSetKBytes ws_usage; 251 GetWorkingSetKBytes(&ws_usage); 252 return ws_usage.priv << 10; 253} 254 255// Private and Shared working set sizes are obtained from /proc/<pid>/smaps. 256// When that's not available, use the values from /proc<pid>/statm as a 257// close approximation. 258// See http://www.pixelbeat.org/scripts/ps_mem.py 259bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 260 FilePath stat_file = 261 FilePath("/proc").Append(IntToString(process_)).Append("smaps"); 262 std::string smaps; 263 int private_kb = 0; 264 int pss_kb = 0; 265 bool have_pss = false; 266 if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) { 267 StringTokenizer tokenizer(smaps, ":\n"); 268 ParsingState state = KEY_NAME; 269 std::string last_key_name; 270 while (tokenizer.GetNext()) { 271 switch (state) { 272 case KEY_NAME: 273 last_key_name = tokenizer.token(); 274 state = KEY_VALUE; 275 break; 276 case KEY_VALUE: 277 if (last_key_name.empty()) { 278 NOTREACHED(); 279 return false; 280 } 281 if (StartsWithASCII(last_key_name, "Private_", 1)) { 282 private_kb += StringToInt(tokenizer.token()); 283 } else if (StartsWithASCII(last_key_name, "Pss", 1)) { 284 have_pss = true; 285 pss_kb += StringToInt(tokenizer.token()); 286 } 287 state = KEY_NAME; 288 break; 289 } 290 } 291 } else { 292 // Try statm if smaps is empty because of the SUID sandbox. 293 // First we need to get the page size though. 294 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; 295 if (page_size_kb <= 0) 296 return false; 297 298 stat_file = 299 FilePath("/proc").Append(IntToString(process_)).Append("statm"); 300 std::string statm; 301 if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0) 302 return false; 303 304 std::vector<std::string> statm_vec; 305 SplitString(statm, ' ', &statm_vec); 306 if (statm_vec.size() != 7) 307 return false; // Not the format we expect. 308 private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]); 309 private_kb *= page_size_kb; 310 } 311 ws_usage->priv = private_kb; 312 // Sharable is not calculated, as it does not provide interesting data. 313 ws_usage->shareable = 0; 314 315 ws_usage->shared = 0; 316 if (have_pss) 317 ws_usage->shared = pss_kb; 318 return true; 319} 320 321// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING 322// in your kernel configuration. 323bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { 324 std::string proc_io_contents; 325 FilePath io_file("/proc"); 326 io_file = io_file.Append(IntToString(process_)); 327 io_file = io_file.Append("io"); 328 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) 329 return false; 330 331 (*io_counters).OtherOperationCount = 0; 332 (*io_counters).OtherTransferCount = 0; 333 334 StringTokenizer tokenizer(proc_io_contents, ": \n"); 335 ParsingState state = KEY_NAME; 336 std::string last_key_name; 337 while (tokenizer.GetNext()) { 338 switch (state) { 339 case KEY_NAME: 340 last_key_name = tokenizer.token(); 341 state = KEY_VALUE; 342 break; 343 case KEY_VALUE: 344 DCHECK(!last_key_name.empty()); 345 if (last_key_name == "syscr") { 346 (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token()); 347 } else if (last_key_name == "syscw") { 348 (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token()); 349 } else if (last_key_name == "rchar") { 350 (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token()); 351 } else if (last_key_name == "wchar") { 352 (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token()); 353 } 354 state = KEY_NAME; 355 break; 356 } 357 } 358 return true; 359} 360 361 362// Exposed for testing. 363int ParseProcStatCPU(const std::string& input) { 364 // /proc/<pid>/stat contains the process name in parens. In case the 365 // process name itself contains parens, skip past them. 366 std::string::size_type rparen = input.rfind(')'); 367 if (rparen == std::string::npos) 368 return -1; 369 370 // From here, we expect a bunch of space-separated fields, where the 371 // 0-indexed 11th and 12th are utime and stime. On two different machines 372 // I found 42 and 39 fields, so let's just expect the ones we need. 373 std::vector<std::string> fields; 374 SplitString(input.substr(rparen + 2), ' ', &fields); 375 if (fields.size() < 13) 376 return -1; // Output not in the format we expect. 377 378 return StringToInt(fields[11]) + StringToInt(fields[12]); 379} 380 381// Get the total CPU of a single process. Return value is number of jiffies 382// on success or -1 on error. 383static int GetProcessCPU(pid_t pid) { 384 // Use /proc/<pid>/task to find all threads and parse their /stat file. 385 FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid)); 386 387 DIR* dir = opendir(path.value().c_str()); 388 if (!dir) { 389 PLOG(ERROR) << "opendir(" << path.value() << ")"; 390 return -1; 391 } 392 393 int total_cpu = 0; 394 while (struct dirent* ent = readdir(dir)) { 395 if (ent->d_name[0] == '.') 396 continue; 397 398 FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat"); 399 std::string stat; 400 if (file_util::ReadFileToString(stat_path, &stat)) { 401 int cpu = ParseProcStatCPU(stat); 402 if (cpu > 0) 403 total_cpu += cpu; 404 } 405 } 406 closedir(dir); 407 408 return total_cpu; 409} 410 411double ProcessMetrics::GetCPUUsage() { 412 // This queries the /proc-specific scaling factor which is 413 // conceptually the system hertz. To dump this value on another 414 // system, try 415 // od -t dL /proc/self/auxv 416 // and look for the number after 17 in the output; mine is 417 // 0000040 17 100 3 134512692 418 // which means the answer is 100. 419 // It may be the case that this value is always 100. 420 static const int kHertz = sysconf(_SC_CLK_TCK); 421 422 struct timeval now; 423 int retval = gettimeofday(&now, NULL); 424 if (retval) 425 return 0; 426 int64 time = TimeValToMicroseconds(now); 427 428 if (last_time_ == 0) { 429 // First call, just set the last values. 430 last_time_ = time; 431 last_cpu_ = GetProcessCPU(process_); 432 return 0; 433 } 434 435 int64 time_delta = time - last_time_; 436 DCHECK_NE(time_delta, 0); 437 if (time_delta == 0) 438 return 0; 439 440 int cpu = GetProcessCPU(process_); 441 442 // We have the number of jiffies in the time period. Convert to percentage. 443 // Note this means we will go *over* 100 in the case where multiple threads 444 // are together adding to more than one CPU's worth. 445 int percentage = 100 * (cpu - last_cpu_) / 446 (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF()); 447 448 last_time_ = time; 449 last_cpu_ = cpu; 450 451 return percentage; 452} 453 454namespace { 455 456// The format of /proc/meminfo is: 457// 458// MemTotal: 8235324 kB 459// MemFree: 1628304 kB 460// Buffers: 429596 kB 461// Cached: 4728232 kB 462// ... 463const size_t kMemTotalIndex = 1; 464const size_t kMemFreeIndex = 4; 465const size_t kMemBuffersIndex = 7; 466const size_t kMemCacheIndex = 10; 467 468} // namespace 469 470size_t GetSystemCommitCharge() { 471 // Used memory is: total - free - buffers - caches 472 FilePath meminfo_file("/proc/meminfo"); 473 std::string meminfo_data; 474 if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) { 475 LOG(WARNING) << "Failed to open /proc/meminfo."; 476 return 0; 477 } 478 std::vector<std::string> meminfo_fields; 479 SplitStringAlongWhitespace(meminfo_data, &meminfo_fields); 480 481 if (meminfo_fields.size() < kMemCacheIndex) { 482 LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " << 483 meminfo_fields.size() << " fields."; 484 return 0; 485 } 486 487 DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); 488 DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); 489 DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); 490 DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); 491 492 size_t result_in_kb; 493 result_in_kb = StringToInt(meminfo_fields[kMemTotalIndex]); 494 result_in_kb -= StringToInt(meminfo_fields[kMemFreeIndex]); 495 result_in_kb -= StringToInt(meminfo_fields[kMemBuffersIndex]); 496 result_in_kb -= StringToInt(meminfo_fields[kMemCacheIndex]); 497 498 return result_in_kb; 499} 500 501namespace { 502 503void OnNoMemorySize(size_t size) { 504 if (size != 0) 505 CHECK(false) << "Out of memory, size = " << size; 506 CHECK(false) << "Out of memory."; 507} 508 509void OnNoMemory() { 510 OnNoMemorySize(0); 511} 512 513} // namespace 514 515extern "C" { 516 517#if !defined(LINUX_USE_TCMALLOC) 518 519extern "C" { 520void* __libc_malloc(size_t size); 521void* __libc_realloc(void* ptr, size_t size); 522void* __libc_calloc(size_t nmemb, size_t size); 523void* __libc_valloc(size_t size); 524void* __libc_pvalloc(size_t size); 525void* __libc_memalign(size_t alignment, size_t size); 526} // extern "C" 527 528// Overriding the system memory allocation functions: 529// 530// For security reasons, we want malloc failures to be fatal. Too much code 531// doesn't check for a NULL return value from malloc and unconditionally uses 532// the resulting pointer. If the first offset that they try to access is 533// attacker controlled, then the attacker can direct the code to access any 534// part of memory. 535// 536// Thus, we define all the standard malloc functions here and mark them as 537// visibility 'default'. This means that they replace the malloc functions for 538// all Chromium code and also for all code in shared libraries. There are tests 539// for this in process_util_unittest.cc. 540// 541// If we are using tcmalloc, then the problem is moot since tcmalloc handles 542// this for us. Thus this code is in a !defined(LINUX_USE_TCMALLOC) block. 543// 544// We call the real libc functions in this code by using __libc_malloc etc. 545// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on 546// the link order. Since ld.so needs calloc during symbol resolution, it 547// defines its own versions of several of these functions in dl-minimal.c. 548// Depending on the runtime library order, dlsym ended up giving us those 549// functions and bad things happened. See crbug.com/31809 550// 551// This means that any code which calls __libc_* gets the raw libc versions of 552// these functions. 553 554#define DIE_ON_OOM_1(function_name) \ 555 void* function_name(size_t) __attribute__ ((visibility("default"))); \ 556 \ 557 void* function_name(size_t size) { \ 558 void* ret = __libc_##function_name(size); \ 559 if (ret == NULL && size != 0) \ 560 OnNoMemorySize(size); \ 561 return ret; \ 562 } 563 564#define DIE_ON_OOM_2(function_name, arg1_type) \ 565 void* function_name(arg1_type, size_t) \ 566 __attribute__ ((visibility("default"))); \ 567 \ 568 void* function_name(arg1_type arg1, size_t size) { \ 569 void* ret = __libc_##function_name(arg1, size); \ 570 if (ret == NULL && size != 0) \ 571 OnNoMemorySize(size); \ 572 return ret; \ 573 } 574 575DIE_ON_OOM_1(malloc) 576DIE_ON_OOM_1(valloc) 577DIE_ON_OOM_1(pvalloc) 578 579DIE_ON_OOM_2(calloc, size_t) 580DIE_ON_OOM_2(realloc, void*) 581DIE_ON_OOM_2(memalign, size_t) 582 583// posix_memalign has a unique signature and doesn't have a __libc_ variant. 584int posix_memalign(void** ptr, size_t alignment, size_t size) 585 __attribute__ ((visibility("default"))); 586 587int posix_memalign(void** ptr, size_t alignment, size_t size) { 588 // This will use the safe version of memalign, above. 589 *ptr = memalign(alignment, size); 590 return 0; 591} 592 593#endif // !defined(LINUX_USE_TCMALLOC) 594} // extern C 595 596void EnableTerminationOnOutOfMemory() { 597 // Set the new-out of memory handler. 598 std::set_new_handler(&OnNoMemory); 599 // If we're using glibc's allocator, the above functions will override 600 // malloc and friends and make them die on out of memory. 601} 602 603bool AdjustOOMScore(ProcessId process, int score) { 604 if (score < 0 || score > 15) 605 return false; 606 607 FilePath oom_adj("/proc"); 608 oom_adj = oom_adj.Append(Int64ToString(process)); 609 oom_adj = oom_adj.AppendASCII("oom_adj"); 610 611 if (!file_util::PathExists(oom_adj)) 612 return false; 613 614 std::string score_str = IntToString(score); 615 return (static_cast<int>(score_str.length()) == 616 file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length())); 617} 618 619} // namespace base 620