| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/process_util.h" | 5 #include "base/process_util.h" |
| 6 | 6 |
| 7 #include <ctype.h> | 7 #include <ctype.h> |
| 8 #include <dirent.h> | 8 #include <dirent.h> |
| 9 #include <dlfcn.h> | 9 #include <dlfcn.h> |
| 10 #include <errno.h> | 10 #include <errno.h> |
| 11 #include <fcntl.h> | 11 #include <fcntl.h> |
| 12 #include <sys/time.h> | 12 #include <sys/time.h> |
| 13 #include <sys/types.h> | 13 #include <sys/types.h> |
| 14 #include <sys/wait.h> | 14 #include <sys/wait.h> |
| 15 #include <time.h> | 15 #include <time.h> |
| 16 #include <unistd.h> | 16 #include <unistd.h> |
| 17 | 17 |
| 18 #include "base/file_util.h" | 18 #include "base/file_util.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/stringprintf.h" | |
| 21 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 22 #include "base/string_split.h" | 21 #include "base/string_split.h" |
| 23 #include "base/string_tokenizer.h" | 22 #include "base/string_tokenizer.h" |
| 24 #include "base/string_util.h" | 23 #include "base/string_util.h" |
| 25 #include "base/sys_info.h" | 24 #include "base/sys_info.h" |
| 26 #include "base/threading/thread_restrictions.h" | 25 #include "base/threading/thread_restrictions.h" |
| 27 | 26 |
| 28 namespace { | 27 namespace { |
| 29 | 28 |
| 30 // Max score for the old oom_adj range. Used for conversion of new | |
| 31 // values to old values. | |
| 32 const int kMaxOldOomScore = 15; | |
| 33 | |
| 34 enum ParsingState { | 29 enum ParsingState { |
| 35 KEY_NAME, | 30 KEY_NAME, |
| 36 KEY_VALUE | 31 KEY_VALUE |
| 37 }; | 32 }; |
| 38 | 33 |
| 34 const char kProcDir[] = "/proc"; |
| 35 |
| 36 // Returns a FilePath to "/proc/pid". |
| 37 FilePath GetProcPidDir(pid_t pid) { |
| 38 return FilePath(kProcDir).Append(base::Int64ToString(pid)); |
| 39 } |
| 40 |
| 39 // Reads /proc/<pid>/stat and populates |proc_stats| with the values split by | 41 // Reads /proc/<pid>/stat and populates |proc_stats| with the values split by |
| 40 // spaces. Returns true if successful. | 42 // spaces. Returns true if successful. |
| 41 bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { | 43 bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { |
| 42 // Synchronously reading files in /proc is safe. | 44 // Synchronously reading files in /proc is safe. |
| 43 base::ThreadRestrictions::ScopedAllowIO allow_io; | 45 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 44 | 46 |
| 45 FilePath stat_file("/proc"); | 47 FilePath stat_file = GetProcPidDir(pid).Append("stat"); |
| 46 stat_file = stat_file.Append(base::IntToString(pid)); | |
| 47 stat_file = stat_file.Append("stat"); | |
| 48 std::string mem_stats; | 48 std::string mem_stats; |
| 49 if (!file_util::ReadFileToString(stat_file, &mem_stats)) | 49 if (!file_util::ReadFileToString(stat_file, &mem_stats)) |
| 50 return false; | 50 return false; |
| 51 base::SplitString(mem_stats, ' ', proc_stats); | 51 base::SplitString(mem_stats, ' ', proc_stats); |
| 52 return true; | 52 return true; |
| 53 } | 53 } |
| 54 | 54 |
| 55 // Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command | 55 // Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command |
| 56 // line arguments. Returns true if successful. | 56 // line arguments. Returns true if successful. |
| 57 // Note: /proc/<pid>/cmdline contains command line arguments separated by single | 57 // Note: /proc/<pid>/cmdline contains command line arguments separated by single |
| 58 // null characters. We tokenize it into a vector of strings using '\0' as a | 58 // null characters. We tokenize it into a vector of strings using '\0' as a |
| 59 // delimiter. | 59 // delimiter. |
| 60 bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) { | 60 bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) { |
| 61 // Synchronously reading files in /proc is safe. | 61 // Synchronously reading files in /proc is safe. |
| 62 base::ThreadRestrictions::ScopedAllowIO allow_io; | 62 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 63 | 63 |
| 64 FilePath cmd_line_file("/proc"); | 64 FilePath cmd_line_file = GetProcPidDir(pid).Append("cmdline"); |
| 65 cmd_line_file = cmd_line_file.Append(base::IntToString(pid)); | |
| 66 cmd_line_file = cmd_line_file.Append("cmdline"); | |
| 67 std::string cmd_line; | 65 std::string cmd_line; |
| 68 if (!file_util::ReadFileToString(cmd_line_file, &cmd_line)) | 66 if (!file_util::ReadFileToString(cmd_line_file, &cmd_line)) |
| 69 return false; | 67 return false; |
| 70 std::string delimiters; | 68 std::string delimiters; |
| 71 delimiters.push_back('\0'); | 69 delimiters.push_back('\0'); |
| 72 Tokenize(cmd_line, delimiters, proc_cmd_line_args); | 70 Tokenize(cmd_line, delimiters, proc_cmd_line_args); |
| 73 return true; | 71 return true; |
| 74 } | 72 } |
| 75 | 73 |
| 76 // Get the total CPU of a single process. Return value is number of jiffies | 74 // Get the total CPU of a single process. Return value is number of jiffies |
| 77 // on success or -1 on error. | 75 // on success or -1 on error. |
| 78 int GetProcessCPU(pid_t pid) { | 76 int GetProcessCPU(pid_t pid) { |
| 79 // Synchronously reading files in /proc is safe. | 77 // Synchronously reading files in /proc is safe. |
| 80 base::ThreadRestrictions::ScopedAllowIO allow_io; | 78 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 81 | 79 |
| 82 // Use /proc/<pid>/task to find all threads and parse their /stat file. | 80 // Use /proc/<pid>/task to find all threads and parse their /stat file. |
| 83 FilePath path = FilePath(base::StringPrintf("/proc/%d/task/", pid)); | 81 FilePath path = GetProcPidDir(pid).Append("task"); |
| 84 | 82 |
| 85 DIR* dir = opendir(path.value().c_str()); | 83 DIR* dir = opendir(path.value().c_str()); |
| 86 if (!dir) { | 84 if (!dir) { |
| 87 DPLOG(ERROR) << "opendir(" << path.value() << ")"; | 85 DPLOG(ERROR) << "opendir(" << path.value() << ")"; |
| 88 return -1; | 86 return -1; |
| 89 } | 87 } |
| 90 | 88 |
| 91 int total_cpu = 0; | 89 int total_cpu = 0; |
| 92 while (struct dirent* ent = readdir(dir)) { | 90 while (struct dirent* ent = readdir(dir)) { |
| 93 if (ent->d_name[0] == '.') | 91 if (ent->d_name[0] == '.') |
| (...skipping 13 matching lines...) Expand all Loading... |
| 107 } | 105 } |
| 108 | 106 |
| 109 } // namespace | 107 } // namespace |
| 110 | 108 |
| 111 namespace base { | 109 namespace base { |
| 112 | 110 |
| 113 ProcessId GetParentProcessId(ProcessHandle process) { | 111 ProcessId GetParentProcessId(ProcessHandle process) { |
| 114 // Synchronously reading files in /proc is safe. | 112 // Synchronously reading files in /proc is safe. |
| 115 base::ThreadRestrictions::ScopedAllowIO allow_io; | 113 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 116 | 114 |
| 117 FilePath stat_file("/proc"); | 115 FilePath stat_file = GetProcPidDir(process).Append("status"); |
| 118 stat_file = stat_file.Append(base::IntToString(process)); | |
| 119 stat_file = stat_file.Append("status"); | |
| 120 std::string status; | 116 std::string status; |
| 121 if (!file_util::ReadFileToString(stat_file, &status)) | 117 if (!file_util::ReadFileToString(stat_file, &status)) |
| 122 return -1; | 118 return -1; |
| 123 | 119 |
| 124 StringTokenizer tokenizer(status, ":\n"); | 120 StringTokenizer tokenizer(status, ":\n"); |
| 125 ParsingState state = KEY_NAME; | 121 ParsingState state = KEY_NAME; |
| 126 StringPiece last_key_name; | 122 StringPiece last_key_name; |
| 127 while (tokenizer.GetNext()) { | 123 while (tokenizer.GetNext()) { |
| 128 switch (state) { | 124 switch (state) { |
| 129 case KEY_NAME: | 125 case KEY_NAME: |
| 130 last_key_name = tokenizer.token_piece(); | 126 last_key_name = tokenizer.token_piece(); |
| 131 state = KEY_VALUE; | 127 state = KEY_VALUE; |
| 132 break; | 128 break; |
| 133 case KEY_VALUE: | 129 case KEY_VALUE: |
| 134 DCHECK(!last_key_name.empty()); | 130 DCHECK(!last_key_name.empty()); |
| 135 if (last_key_name == "PPid") { | 131 if (last_key_name == "PPid") { |
| 136 int ppid; | 132 int ppid; |
| 137 base::StringToInt(tokenizer.token_piece(), &ppid); | 133 base::StringToInt(tokenizer.token_piece(), &ppid); |
| 138 return ppid; | 134 return ppid; |
| 139 } | 135 } |
| 140 state = KEY_NAME; | 136 state = KEY_NAME; |
| 141 break; | 137 break; |
| 142 } | 138 } |
| 143 } | 139 } |
| 144 NOTREACHED(); | 140 NOTREACHED(); |
| 145 return -1; | 141 return -1; |
| 146 } | 142 } |
| 147 | 143 |
| 148 FilePath GetProcessExecutablePath(ProcessHandle process) { | 144 FilePath GetProcessExecutablePath(ProcessHandle process) { |
| 149 FilePath stat_file("/proc"); | 145 FilePath stat_file = GetProcPidDir(process).Append("exe"); |
| 150 stat_file = stat_file.Append(base::IntToString(process)); | |
| 151 stat_file = stat_file.Append("exe"); | |
| 152 FilePath exe_name; | 146 FilePath exe_name; |
| 153 if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) { | 147 if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) { |
| 154 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses | 148 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses |
| 155 return FilePath(); | 149 return FilePath(); |
| 156 } | 150 } |
| 157 return exe_name; | 151 return exe_name; |
| 158 } | 152 } |
| 159 | 153 |
| 160 ProcessIterator::ProcessIterator(const ProcessFilter* filter) | 154 ProcessIterator::ProcessIterator(const ProcessFilter* filter) |
| 161 : filter_(filter) { | 155 : filter_(filter) { |
| 162 procfs_dir_ = opendir("/proc"); | 156 procfs_dir_ = opendir(kProcDir); |
| 163 } | 157 } |
| 164 | 158 |
| 165 ProcessIterator::~ProcessIterator() { | 159 ProcessIterator::~ProcessIterator() { |
| 166 if (procfs_dir_) { | 160 if (procfs_dir_) { |
| 167 closedir(procfs_dir_); | 161 closedir(procfs_dir_); |
| 168 procfs_dir_ = NULL; | 162 procfs_dir_ = NULL; |
| 169 } | 163 } |
| 170 } | 164 } |
| 171 | 165 |
| 172 bool ProcessIterator::CheckForNextProcess() { | 166 bool ProcessIterator::CheckForNextProcess() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 203 | 197 |
| 204 // Read the process's command line. | 198 // Read the process's command line. |
| 205 std::string pid_string(slot->d_name); | 199 std::string pid_string(slot->d_name); |
| 206 int pid; | 200 int pid; |
| 207 if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args)) | 201 if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args)) |
| 208 continue; | 202 continue; |
| 209 | 203 |
| 210 // Read the process's status. | 204 // Read the process's status. |
| 211 char buf[NAME_MAX + 12]; | 205 char buf[NAME_MAX + 12]; |
| 212 sprintf(buf, "/proc/%s/stat", slot->d_name); | 206 sprintf(buf, "/proc/%s/stat", slot->d_name); |
| 213 FILE *fp = fopen(buf, "r"); | 207 FILE* fp = fopen(buf, "r"); |
| 214 if (!fp) | 208 if (!fp) |
| 215 continue; | 209 continue; |
| 216 const char* result = fgets(buf, sizeof(buf), fp); | 210 const char* result = fgets(buf, sizeof(buf), fp); |
| 217 fclose(fp); | 211 fclose(fp); |
| 218 if (!result) | 212 if (!result) |
| 219 continue; | 213 continue; |
| 220 | 214 |
| 221 // Parse the status. It is formatted like this: | 215 // Parse the status. It is formatted like this: |
| 222 // %d (%s) %c %d %d ... | 216 // %d (%s) %c %d %d ... |
| 223 // pid (name) runstate ppid gid | 217 // pid (name) runstate ppid gid |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 | 327 |
| 334 if (private_bytes) | 328 if (private_bytes) |
| 335 *private_bytes = ws_usage.priv << 10; | 329 *private_bytes = ws_usage.priv << 10; |
| 336 | 330 |
| 337 if (shared_bytes) | 331 if (shared_bytes) |
| 338 *shared_bytes = ws_usage.shared * 1024; | 332 *shared_bytes = ws_usage.shared * 1024; |
| 339 | 333 |
| 340 return true; | 334 return true; |
| 341 } | 335 } |
| 342 | 336 |
| 343 // Private and Shared working set sizes are obtained from /proc/<pid>/smaps. | 337 // Private and Shared working set sizes are obtained from /proc/<pid>/statm. |
| 344 // When that's not available, use the values from /proc<pid>/statm as a | |
| 345 // close approximation. | |
| 346 // See http://www.pixelbeat.org/scripts/ps_mem.py | |
| 347 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { | 338 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
| 348 // Synchronously reading files in /proc is safe. | 339 // Use statm instead of smaps because smaps is: |
| 349 base::ThreadRestrictions::ScopedAllowIO allow_io; | 340 // a) Large and slow to parse. |
| 341 // b) Unavailable in the SUID sandbox. |
| 350 | 342 |
| 351 FilePath proc_dir = FilePath("/proc").Append(base::IntToString(process_)); | 343 // First we need to get the page size, since everything is measured in pages. |
| 352 std::string smaps; | 344 // For details, see: man 5 proc. |
| 353 int private_kb = 0; | 345 const int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; |
| 354 int pss_kb = 0; | 346 if (page_size_kb <= 0) |
| 355 bool have_pss = false; | 347 return false; |
| 356 bool ret; | |
| 357 | 348 |
| 349 std::string statm; |
| 358 { | 350 { |
| 359 FilePath smaps_file = proc_dir.Append("smaps"); | 351 FilePath statm_file = GetProcPidDir(process_).Append("statm"); |
| 360 // Synchronously reading files in /proc is safe. | 352 // Synchronously reading files in /proc is safe. |
| 361 base::ThreadRestrictions::ScopedAllowIO allow_io; | 353 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 362 ret = file_util::ReadFileToString(smaps_file, &smaps); | 354 bool ret = file_util::ReadFileToString(statm_file, &statm); |
| 363 } | |
| 364 if (ret && smaps.length() > 0) { | |
| 365 const std::string private_prefix = "Private_"; | |
| 366 const std::string pss_prefix = "Pss"; | |
| 367 StringTokenizer tokenizer(smaps, ":\n"); | |
| 368 StringPiece last_key_name; | |
| 369 ParsingState state = KEY_NAME; | |
| 370 while (tokenizer.GetNext()) { | |
| 371 switch (state) { | |
| 372 case KEY_NAME: | |
| 373 last_key_name = tokenizer.token_piece(); | |
| 374 state = KEY_VALUE; | |
| 375 break; | |
| 376 case KEY_VALUE: | |
| 377 if (last_key_name.empty()) { | |
| 378 NOTREACHED(); | |
| 379 return false; | |
| 380 } | |
| 381 if (last_key_name.starts_with(private_prefix)) { | |
| 382 int cur; | |
| 383 base::StringToInt(tokenizer.token_piece(), &cur); | |
| 384 private_kb += cur; | |
| 385 } else if (last_key_name.starts_with(pss_prefix)) { | |
| 386 have_pss = true; | |
| 387 int cur; | |
| 388 base::StringToInt(tokenizer.token_piece(), &cur); | |
| 389 pss_kb += cur; | |
| 390 } | |
| 391 state = KEY_NAME; | |
| 392 break; | |
| 393 } | |
| 394 } | |
| 395 } else { | |
| 396 // Try statm if smaps is empty because of the SUID sandbox. | |
| 397 // First we need to get the page size though. | |
| 398 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; | |
| 399 if (page_size_kb <= 0) | |
| 400 return false; | |
| 401 | |
| 402 std::string statm; | |
| 403 { | |
| 404 FilePath statm_file = proc_dir.Append("statm"); | |
| 405 // Synchronously reading files in /proc is safe. | |
| 406 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 407 ret = file_util::ReadFileToString(statm_file, &statm); | |
| 408 } | |
| 409 if (!ret || statm.length() == 0) | 355 if (!ret || statm.length() == 0) |
| 410 return false; | 356 return false; |
| 357 } |
| 411 | 358 |
| 412 std::vector<std::string> statm_vec; | 359 std::vector<std::string> statm_vec; |
| 413 base::SplitString(statm, ' ', &statm_vec); | 360 base::SplitString(statm, ' ', &statm_vec); |
| 414 if (statm_vec.size() != 7) | 361 if (statm_vec.size() != 7) |
| 415 return false; // Not the format we expect. | 362 return false; // Not the format we expect. |
| 416 | 363 |
| 417 int statm1, statm2; | 364 int statm_rss, statm_shared; |
| 418 base::StringToInt(statm_vec[1], &statm1); | 365 base::StringToInt(statm_vec[1], &statm_rss); |
| 419 base::StringToInt(statm_vec[2], &statm2); | 366 base::StringToInt(statm_vec[2], &statm_shared); |
| 420 private_kb = (statm1 - statm2) * page_size_kb; | 367 |
| 421 } | 368 ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; |
| 422 ws_usage->priv = private_kb; | 369 ws_usage->shared = statm_shared * page_size_kb; |
| 370 |
| 423 // Sharable is not calculated, as it does not provide interesting data. | 371 // Sharable is not calculated, as it does not provide interesting data. |
| 424 ws_usage->shareable = 0; | 372 ws_usage->shareable = 0; |
| 425 | 373 |
| 426 ws_usage->shared = 0; | |
| 427 if (have_pss) | |
| 428 ws_usage->shared = pss_kb; | |
| 429 return true; | 374 return true; |
| 430 } | 375 } |
| 431 | 376 |
| 432 double ProcessMetrics::GetCPUUsage() { | 377 double ProcessMetrics::GetCPUUsage() { |
| 433 // This queries the /proc-specific scaling factor which is | 378 // This queries the /proc-specific scaling factor which is |
| 434 // conceptually the system hertz. To dump this value on another | 379 // conceptually the system hertz. To dump this value on another |
| 435 // system, try | 380 // system, try |
| 436 // od -t dL /proc/self/auxv | 381 // od -t dL /proc/self/auxv |
| 437 // and look for the number after 17 in the output; mine is | 382 // and look for the number after 17 in the output; mine is |
| 438 // 0000040 17 100 3 134512692 | 383 // 0000040 17 100 3 134512692 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 return percentage; | 417 return percentage; |
| 473 } | 418 } |
| 474 | 419 |
| 475 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING | 420 // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING |
| 476 // in your kernel configuration. | 421 // in your kernel configuration. |
| 477 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { | 422 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
| 478 // Synchronously reading files in /proc is safe. | 423 // Synchronously reading files in /proc is safe. |
| 479 base::ThreadRestrictions::ScopedAllowIO allow_io; | 424 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 480 | 425 |
| 481 std::string proc_io_contents; | 426 std::string proc_io_contents; |
| 482 FilePath io_file("/proc"); | 427 FilePath io_file = GetProcPidDir(process_).Append("io"); |
| 483 io_file = io_file.Append(base::IntToString(process_)); | |
| 484 io_file = io_file.Append("io"); | |
| 485 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) | 428 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) |
| 486 return false; | 429 return false; |
| 487 | 430 |
| 488 (*io_counters).OtherOperationCount = 0; | 431 (*io_counters).OtherOperationCount = 0; |
| 489 (*io_counters).OtherTransferCount = 0; | 432 (*io_counters).OtherTransferCount = 0; |
| 490 | 433 |
| 491 StringTokenizer tokenizer(proc_io_contents, ": \n"); | 434 StringTokenizer tokenizer(proc_io_contents, ": \n"); |
| 492 ParsingState state = KEY_NAME; | 435 ParsingState state = KEY_NAME; |
| 493 StringPiece last_key_name; | 436 StringPiece last_key_name; |
| 494 while (tokenizer.GetNext()) { | 437 while (tokenizer.GetNext()) { |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 #endif | 681 #endif |
| 739 } | 682 } |
| 740 | 683 |
| 741 // NOTE: This is not the only version of this function in the source: | 684 // NOTE: This is not the only version of this function in the source: |
| 742 // the setuid sandbox (in process_util_linux.c, in the sandbox source) | 685 // the setuid sandbox (in process_util_linux.c, in the sandbox source) |
| 743 // also has it's own C version. | 686 // also has it's own C version. |
| 744 bool AdjustOOMScore(ProcessId process, int score) { | 687 bool AdjustOOMScore(ProcessId process, int score) { |
| 745 if (score < 0 || score > kMaxOomScore) | 688 if (score < 0 || score > kMaxOomScore) |
| 746 return false; | 689 return false; |
| 747 | 690 |
| 748 FilePath oom_path("/proc"); | 691 FilePath oom_path(GetProcPidDir(process)); |
| 749 oom_path = oom_path.Append(base::Int64ToString(process)); | |
| 750 | 692 |
| 751 // Attempt to write the newer oom_score_adj file first. | 693 // Attempt to write the newer oom_score_adj file first. |
| 752 FilePath oom_file = oom_path.AppendASCII("oom_score_adj"); | 694 FilePath oom_file = oom_path.AppendASCII("oom_score_adj"); |
| 753 if (file_util::PathExists(oom_file)) { | 695 if (file_util::PathExists(oom_file)) { |
| 754 std::string score_str = base::IntToString(score); | 696 std::string score_str = base::IntToString(score); |
| 755 DVLOG(1) << "Adjusting oom_score_adj of " << process << " to " | 697 DVLOG(1) << "Adjusting oom_score_adj of " << process << " to " |
| 756 << score_str; | 698 << score_str; |
| 757 int score_len = static_cast<int>(score_str.length()); | 699 int score_len = static_cast<int>(score_str.length()); |
| 758 return (score_len == file_util::WriteFile(oom_file, | 700 return (score_len == file_util::WriteFile(oom_file, |
| 759 score_str.c_str(), | 701 score_str.c_str(), |
| 760 score_len)); | 702 score_len)); |
| 761 } | 703 } |
| 762 | 704 |
| 763 // If the oom_score_adj file doesn't exist, then we write the old | 705 // If the oom_score_adj file doesn't exist, then we write the old |
| 764 // style file and translate the oom_adj score to the range 0-15. | 706 // style file and translate the oom_adj score to the range 0-15. |
| 765 oom_file = oom_path.AppendASCII("oom_adj"); | 707 oom_file = oom_path.AppendASCII("oom_adj"); |
| 766 if (file_util::PathExists(oom_file)) { | 708 if (file_util::PathExists(oom_file)) { |
| 767 std::string score_str = base::IntToString( | 709 // Max score for the old oom_adj range. Used for conversion of new |
| 768 score * kMaxOldOomScore / kMaxOomScore); | 710 // values to old values. |
| 711 const int kMaxOldOomScore = 15; |
| 712 |
| 713 int converted_score = score * kMaxOldOomScore / kMaxOomScore; |
| 714 std::string score_str = base::IntToString(converted_score); |
| 769 DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str; | 715 DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str; |
| 770 int score_len = static_cast<int>(score_str.length()); | 716 int score_len = static_cast<int>(score_str.length()); |
| 771 return (score_len == file_util::WriteFile(oom_file, | 717 return (score_len == file_util::WriteFile(oom_file, |
| 772 score_str.c_str(), | 718 score_str.c_str(), |
| 773 score_len)); | 719 score_len)); |
| 774 } | 720 } |
| 775 | 721 |
| 776 return false; | 722 return false; |
| 777 } | 723 } |
| 778 | 724 |
| 779 } // namespace base | 725 } // namespace base |
| OLD | NEW |