blob: ff8fef34747d3dd006c0daed0e7d5f1fc8865d06 [file] [log] [blame]
[email protected]4306df72012-04-20 18:58:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]54fd1d32009-09-01 00:12:582// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/memory_details.h"
6
avi6846aef2015-12-26 01:09:387#include <stddef.h>
[email protected]500c8722012-06-18 17:34:238#include <sys/types.h>
9#include <unistd.h>
10
[email protected]e9720e822012-06-07 00:07:4811#include <map>
[email protected]8e2b6472010-12-15 22:19:4812#include <set>
13
[email protected]24d69692011-10-21 18:26:5114#include "base/bind.h"
thestig18dfb7a52014-08-26 10:44:0415#include "base/files/file_util.h"
[email protected]d09a4ce1c2013-07-24 17:37:0216#include "base/process/process_iterator.h"
17#include "base/process/process_metrics.h"
[email protected]48e303442013-07-18 19:13:1518#include "base/strings/string_number_conversions.h"
[email protected]f9b294362013-06-10 20:22:3119#include "base/strings/string_util.h"
[email protected]112158af2013-06-07 23:46:1820#include "base/strings/utf_string_conversions.h"
avi6846aef2015-12-26 01:09:3821#include "build/build_config.h"
[email protected]54fd1d32009-09-01 00:12:5822#include "chrome/common/chrome_constants.h"
[email protected]af39f002014-08-22 10:18:1823#include "chrome/grit/chromium_strings.h"
[email protected]c38831a12011-10-28 12:44:4924#include "content/public/browser/browser_thread.h"
[email protected]bd5d6cf2011-12-01 00:39:1225#include "content/public/common/process_type.h"
[email protected]b4320742013-02-06 02:57:3126#include "ui/base/l10n/l10n_util.h"
[email protected]54fd1d32009-09-01 00:12:5827
[email protected]e9720e822012-06-07 00:07:4828using base::ProcessEntry;
[email protected]631bb742011-11-02 11:29:3929using content::BrowserThread;
30
asvitkine6f5f3592015-01-21 20:50:3731namespace {
32
[email protected]54fd1d32009-09-01 00:12:5833// Known browsers which we collect details for.
34enum BrowserType {
35 CHROME = 0,
36 FIREFOX,
[email protected]f3f032f82010-07-07 17:32:5337 ICEWEASEL,
[email protected]54fd1d32009-09-01 00:12:5838 OPERA,
39 KONQUEROR,
40 EPIPHANY,
41 MIDORI,
42 MAX_BROWSERS
asvitkine6f5f3592015-01-21 20:50:3743};
[email protected]54fd1d32009-09-01 00:12:5844
45// The pretty printed names of those browsers. Matches up with enum
46// BrowserType.
asvitkine6f5f3592015-01-21 20:50:3747const char kBrowserPrettyNames[][10] = {
[email protected]54fd1d32009-09-01 00:12:5848 "Chrome",
49 "Firefox",
[email protected]f3f032f82010-07-07 17:32:5350 "Iceweasel",
[email protected]54fd1d32009-09-01 00:12:5851 "Opera",
52 "Konqueror",
53 "Epiphany",
54 "Midori",
55};
56
57// A mapping from process name to the type of browser.
asvitkine6f5f3592015-01-21 20:50:3758const struct {
p.forysiuk52f6146b2015-01-21 14:01:0959 const char process_name[17];
[email protected]54fd1d32009-09-01 00:12:5860 BrowserType browser;
[email protected]b4320742013-02-06 02:57:3161} kBrowserBinaryNames[] = {
[email protected]54fd1d32009-09-01 00:12:5862 { "firefox", FIREFOX },
63 { "firefox-3.5", FIREFOX },
64 { "firefox-3.0", FIREFOX },
[email protected]576786482010-04-05 18:54:3265 { "firefox-bin", FIREFOX },
[email protected]f3f032f82010-07-07 17:32:5366 { "iceweasel", ICEWEASEL },
[email protected]54fd1d32009-09-01 00:12:5867 { "opera", OPERA },
68 { "konqueror", KONQUEROR },
p.forysiuk52f6146b2015-01-21 14:01:0969 { "epiphany-browser", EPIPHANY },
[email protected]54fd1d32009-09-01 00:12:5870 { "epiphany", EPIPHANY },
71 { "midori", MIDORI },
72 { "", MAX_BROWSERS },
73};
74
[email protected]54fd1d32009-09-01 00:12:5875struct Process {
76 pid_t pid;
77 pid_t parent;
78 std::string name;
79};
80
[email protected]e9720e822012-06-07 00:07:4881typedef std::map<pid_t, Process> ProcessMap;
[email protected]54fd1d32009-09-01 00:12:5882
[email protected]e9720e822012-06-07 00:07:4883// Get information on all the processes running on the system.
asvitkine6f5f3592015-01-21 20:50:3784ProcessMap GetProcesses() {
[email protected]e9720e822012-06-07 00:07:4885 ProcessMap map;
[email protected]54fd1d32009-09-01 00:12:5886
[email protected]e9720e822012-06-07 00:07:4887 base::ProcessIterator process_iter(NULL);
88 while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
[email protected]54fd1d32009-09-01 00:12:5889 Process process;
[email protected]e9720e822012-06-07 00:07:4890 process.pid = process_entry->pid();
91 process.parent = process_entry->parent_pid();
92 process.name = process_entry->exe_file();
93 map.insert(std::make_pair(process.pid, process));
[email protected]54fd1d32009-09-01 00:12:5894 }
[email protected]e9720e822012-06-07 00:07:4895 return map;
[email protected]54fd1d32009-09-01 00:12:5896}
97
98// Given a process name, return the type of the browser which created that
99// process, or |MAX_BROWSERS| if we don't know about it.
asvitkine6f5f3592015-01-21 20:50:37100BrowserType GetBrowserType(const std::string& process_name) {
[email protected]54fd1d32009-09-01 00:12:58101 for (unsigned i = 0; kBrowserBinaryNames[i].process_name[0]; ++i) {
102 if (strcmp(process_name.c_str(), kBrowserBinaryNames[i].process_name) == 0)
103 return kBrowserBinaryNames[i].browser;
104 }
105
106 return MAX_BROWSERS;
107}
108
[email protected]e9720e822012-06-07 00:07:48109// For each of a list of pids, collect memory information about that process.
asvitkine6f5f3592015-01-21 20:50:37110ProcessData GetProcessDataMemoryInformation(
[email protected]e9720e822012-06-07 00:07:48111 const std::vector<pid_t>& pids) {
112 ProcessData process_data;
asvitkine6f5f3592015-01-21 20:50:37113 for (pid_t pid : pids) {
[email protected]54fd1d32009-09-01 00:12:58114 ProcessMemoryInformation pmi;
115
asvitkine6f5f3592015-01-21 20:50:37116 pmi.pid = pid;
[email protected]54fd1d32009-09-01 00:12:58117 pmi.num_processes = 1;
118
119 if (pmi.pid == base::GetCurrentProcId())
[email protected]f3b357692013-03-22 05:16:13120 pmi.process_type = content::PROCESS_TYPE_BROWSER;
[email protected]54fd1d32009-09-01 00:12:58121 else
[email protected]f3b357692013-03-22 05:16:13122 pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
[email protected]54fd1d32009-09-01 00:12:58123
asvitkine6f5f3592015-01-21 20:50:37124 scoped_ptr<base::ProcessMetrics> metrics(
125 base::ProcessMetrics::CreateProcessMetrics(pid));
[email protected]54fd1d32009-09-01 00:12:58126 metrics->GetWorkingSetKBytes(&pmi.working_set);
[email protected]54fd1d32009-09-01 00:12:58127
[email protected]e9720e822012-06-07 00:07:48128 process_data.processes.push_back(pmi);
[email protected]54fd1d32009-09-01 00:12:58129 }
[email protected]e9720e822012-06-07 00:07:48130 return process_data;
[email protected]54fd1d32009-09-01 00:12:58131}
132
[email protected]e9720e822012-06-07 00:07:48133// Find all children of the given process with pid |root|.
asvitkine6f5f3592015-01-21 20:50:37134std::vector<pid_t> GetAllChildren(const ProcessMap& processes, pid_t root) {
[email protected]e9720e822012-06-07 00:07:48135 std::vector<pid_t> children;
136 children.push_back(root);
[email protected]54fd1d32009-09-01 00:12:58137
138 std::set<pid_t> wavefront, next_wavefront;
139 wavefront.insert(root);
140
141 while (wavefront.size()) {
asvitkine6f5f3592015-01-21 20:50:37142 for (const auto& entry : processes) {
143 const Process& process = entry.second;
[email protected]e9720e822012-06-07 00:07:48144 if (wavefront.count(process.parent)) {
145 children.push_back(process.pid);
146 next_wavefront.insert(process.pid);
[email protected]54fd1d32009-09-01 00:12:58147 }
148 }
149
150 wavefront.clear();
151 wavefront.swap(next_wavefront);
152 }
[email protected]e9720e822012-06-07 00:07:48153 return children;
[email protected]54fd1d32009-09-01 00:12:58154}
155
asvitkine6f5f3592015-01-21 20:50:37156} // namespace
157
158MemoryDetails::MemoryDetails() {
159}
160
161ProcessData* MemoryDetails::ChromeBrowser() {
162 return &process_data_[0];
163}
164
[email protected]54fd1d32009-09-01 00:12:58165void MemoryDetails::CollectProcessData(
asvitkine6f5f3592015-01-21 20:50:37166 CollectionMode mode,
[email protected]4df3ac62011-03-11 04:38:52167 const std::vector<ProcessMemoryInformation>& child_info) {
hashimotoa8ea28d2015-04-11 02:50:48168 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
[email protected]54fd1d32009-09-01 00:12:58169
[email protected]e9720e822012-06-07 00:07:48170 ProcessMap process_map = GetProcesses();
[email protected]54fd1d32009-09-01 00:12:58171 std::set<pid_t> browsers_found;
172
173 // For each process on the system, if it appears to be a browser process and
174 // it's parent isn't a browser process, then record it in |browsers_found|.
asvitkine6f5f3592015-01-21 20:50:37175 for (const auto& entry : process_map) {
176 const Process& current_process = entry.second;
[email protected]e9720e822012-06-07 00:07:48177 const BrowserType type = GetBrowserType(current_process.name);
178 if (type == MAX_BROWSERS)
179 continue;
asvitkine6f5f3592015-01-21 20:50:37180 if (type != CHROME && mode == FROM_CHROME_ONLY)
181 continue;
[email protected]54fd1d32009-09-01 00:12:58182
[email protected]e9720e822012-06-07 00:07:48183 ProcessMap::const_iterator parent_iter =
184 process_map.find(current_process.parent);
185 if (parent_iter == process_map.end()) {
186 browsers_found.insert(current_process.pid);
187 continue;
188 }
[email protected]54fd1d32009-09-01 00:12:58189
[email protected]e9720e822012-06-07 00:07:48190 if (GetBrowserType(parent_iter->second.name) != type) {
asvitkine6f5f3592015-01-21 20:50:37191 // We found a process whose type is different from its parent's type.
[email protected]e9720e822012-06-07 00:07:48192 // That means it is the root process of the browser.
193 browsers_found.insert(current_process.pid);
p.forysiukdd7ed9cd2015-01-22 21:28:52194 continue;
[email protected]54fd1d32009-09-01 00:12:58195 }
196 }
197
[email protected]e9720e822012-06-07 00:07:48198 ProcessData current_browser =
199 GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
[email protected]b4320742013-02-06 02:57:31200 current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
[email protected]6778fed2013-12-24 20:09:37201 current_browser.process_name = base::ASCIIToUTF16("chrome");
[email protected]e1873b92011-05-13 19:22:22202
203 for (std::vector<ProcessMemoryInformation>::iterator
204 i = current_browser.processes.begin();
205 i != current_browser.processes.end(); ++i) {
206 // Check if this is one of the child processes whose data we collected
207 // on the IO thread, and if so copy over that data.
208 for (size_t child = 0; child < child_info.size(); child++) {
209 if (child_info[child].pid != i->pid)
210 continue;
211 i->titles = child_info[child].titles;
[email protected]f3b357692013-03-22 05:16:13212 i->process_type = child_info[child].process_type;
[email protected]e1873b92011-05-13 19:22:22213 break;
214 }
215 }
216
[email protected]54fd1d32009-09-01 00:12:58217 process_data_.push_back(current_browser);
218
219 // For each browser process, collect a list of its children and get the
220 // memory usage of each.
asvitkine6f5f3592015-01-21 20:50:37221 for (pid_t pid : browsers_found) {
222 std::vector<pid_t> browser_processes = GetAllChildren(process_map, pid);
[email protected]e9720e822012-06-07 00:07:48223 ProcessData browser = GetProcessDataMemoryInformation(browser_processes);
[email protected]54fd1d32009-09-01 00:12:58224
asvitkine6f5f3592015-01-21 20:50:37225 ProcessMap::const_iterator process_iter = process_map.find(pid);
[email protected]e9720e822012-06-07 00:07:48226 if (process_iter == process_map.end())
227 continue;
228 BrowserType type = GetBrowserType(process_iter->second.name);
229 if (type != MAX_BROWSERS)
[email protected]6778fed2013-12-24 20:09:37230 browser.name = base::ASCIIToUTF16(kBrowserPrettyNames[type]);
[email protected]54fd1d32009-09-01 00:12:58231 process_data_.push_back(browser);
232 }
233
[email protected]48e303442013-07-18 19:13:15234#if defined(OS_CHROMEOS)
[email protected]f4134782013-08-29 21:25:20235 base::GetSwapInfo(&swap_info_);
[email protected]48e303442013-07-18 19:13:15236#endif
237
[email protected]54fd1d32009-09-01 00:12:58238 // Finally return to the browser thread.
[email protected]f8b3ef82010-10-11 02:45:52239 BrowserThread::PostTask(
240 BrowserThread::UI, FROM_HERE,
[email protected]24d69692011-10-21 18:26:51241 base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
[email protected]54fd1d32009-09-01 00:12:58242}