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 |