3d7df23880ff13aad98defef6eed129f102d604c
[platform/framework/web/crosswalk.git] / src / chrome / browser / memory_details_linux.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/memory_details.h"
6
7 #include <sys/types.h>
8 #include <unistd.h>
9
10 #include <map>
11 #include <set>
12
13 #include "base/bind.h"
14 #include "base/files/file_util.h"
15 #include "base/process/process_iterator.h"
16 #include "base/process/process_metrics.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "chrome/grit/chromium_strings.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/common/process_type.h"
24 #include "ui/base/l10n/l10n_util.h"
25
26 using base::ProcessEntry;
27 using content::BrowserThread;
28
29 // Known browsers which we collect details for.
30 enum BrowserType {
31   CHROME = 0,
32   FIREFOX,
33   ICEWEASEL,
34   OPERA,
35   KONQUEROR,
36   EPIPHANY,
37   MIDORI,
38   MAX_BROWSERS
39 } BrowserProcess;
40
41 // The pretty printed names of those browsers. Matches up with enum
42 // BrowserType.
43 static const char kBrowserPrettyNames[][10] = {
44   "Chrome",
45   "Firefox",
46   "Iceweasel",
47   "Opera",
48   "Konqueror",
49   "Epiphany",
50   "Midori",
51 };
52
53 // A mapping from process name to the type of browser.
54 static const struct {
55   const char process_name[16];
56   BrowserType browser;
57 } kBrowserBinaryNames[] = {
58   { "firefox", FIREFOX },
59   { "firefox-3.5", FIREFOX },
60   { "firefox-3.0", FIREFOX },
61   { "firefox-bin", FIREFOX },
62   { "iceweasel", ICEWEASEL },
63   { "opera", OPERA },
64   { "konqueror", KONQUEROR },
65   { "epiphany-browse", EPIPHANY },
66   { "epiphany", EPIPHANY },
67   { "midori", MIDORI },
68   { "", MAX_BROWSERS },
69 };
70
71 MemoryDetails::MemoryDetails()
72     : user_metrics_mode_(UPDATE_USER_METRICS),
73       memory_growth_tracker_(NULL) {
74 }
75
76 ProcessData* MemoryDetails::ChromeBrowser() {
77   return &process_data_[0];
78 }
79
80 struct Process {
81   pid_t pid;
82   pid_t parent;
83   std::string name;
84 };
85
86 typedef std::map<pid_t, Process> ProcessMap;
87
88 // Get information on all the processes running on the system.
89 static ProcessMap GetProcesses() {
90   ProcessMap map;
91
92   base::ProcessIterator process_iter(NULL);
93   while (const ProcessEntry* process_entry = process_iter.NextProcessEntry()) {
94     Process process;
95     process.pid = process_entry->pid();
96     process.parent = process_entry->parent_pid();
97     process.name = process_entry->exe_file();
98     map.insert(std::make_pair(process.pid, process));
99   }
100   return map;
101 }
102
103 // Given a process name, return the type of the browser which created that
104 // process, or |MAX_BROWSERS| if we don't know about it.
105 static BrowserType GetBrowserType(const std::string& process_name) {
106   for (unsigned i = 0; kBrowserBinaryNames[i].process_name[0]; ++i) {
107     if (strcmp(process_name.c_str(), kBrowserBinaryNames[i].process_name) == 0)
108       return kBrowserBinaryNames[i].browser;
109   }
110
111   return MAX_BROWSERS;
112 }
113
114 // For each of a list of pids, collect memory information about that process.
115 static ProcessData GetProcessDataMemoryInformation(
116     const std::vector<pid_t>& pids) {
117   ProcessData process_data;
118   for (std::vector<pid_t>::const_iterator iter = pids.begin();
119        iter != pids.end();
120        ++iter) {
121     ProcessMemoryInformation pmi;
122
123     pmi.pid = *iter;
124     pmi.num_processes = 1;
125
126     if (pmi.pid == base::GetCurrentProcId())
127       pmi.process_type = content::PROCESS_TYPE_BROWSER;
128     else
129       pmi.process_type = content::PROCESS_TYPE_UNKNOWN;
130
131     base::ProcessMetrics* metrics =
132         base::ProcessMetrics::CreateProcessMetrics(*iter);
133     metrics->GetWorkingSetKBytes(&pmi.working_set);
134     delete metrics;
135
136     process_data.processes.push_back(pmi);
137   }
138   return process_data;
139 }
140
141 // Find all children of the given process with pid |root|.
142 static std::vector<pid_t> GetAllChildren(const ProcessMap& processes,
143                                          const pid_t root) {
144   std::vector<pid_t> children;
145   children.push_back(root);
146
147   std::set<pid_t> wavefront, next_wavefront;
148   wavefront.insert(root);
149
150   while (wavefront.size()) {
151     for (ProcessMap::const_iterator iter = processes.begin();
152          iter != processes.end();
153          ++iter) {
154       const Process& process = iter->second;
155       if (wavefront.count(process.parent)) {
156         children.push_back(process.pid);
157         next_wavefront.insert(process.pid);
158       }
159     }
160
161     wavefront.clear();
162     wavefront.swap(next_wavefront);
163   }
164   return children;
165 }
166
167 void MemoryDetails::CollectProcessData(
168     const std::vector<ProcessMemoryInformation>& child_info) {
169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170
171   ProcessMap process_map = GetProcesses();
172   std::set<pid_t> browsers_found;
173
174   // For each process on the system, if it appears to be a browser process and
175   // it's parent isn't a browser process, then record it in |browsers_found|.
176   for (ProcessMap::const_iterator iter = process_map.begin();
177        iter != process_map.end();
178        ++iter) {
179     const Process& current_process = iter->second;
180     const BrowserType type = GetBrowserType(current_process.name);
181     if (type == MAX_BROWSERS)
182       continue;
183
184     ProcessMap::const_iterator parent_iter =
185         process_map.find(current_process.parent);
186     if (parent_iter == process_map.end()) {
187       browsers_found.insert(current_process.pid);
188       continue;
189     }
190
191     if (GetBrowserType(parent_iter->second.name) != type) {
192       // We found a process whose type is diffent from its parent's type.
193       // That means it is the root process of the browser.
194       browsers_found.insert(current_process.pid);
195       break;
196     }
197   }
198
199   ProcessData current_browser =
200       GetProcessDataMemoryInformation(GetAllChildren(process_map, getpid()));
201   current_browser.name = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
202   current_browser.process_name = base::ASCIIToUTF16("chrome");
203
204   for (std::vector<ProcessMemoryInformation>::iterator
205        i = current_browser.processes.begin();
206        i != current_browser.processes.end(); ++i) {
207     // Check if this is one of the child processes whose data we collected
208     // on the IO thread, and if so copy over that data.
209     for (size_t child = 0; child < child_info.size(); child++) {
210       if (child_info[child].pid != i->pid)
211         continue;
212       i->titles = child_info[child].titles;
213       i->process_type = child_info[child].process_type;
214       break;
215     }
216   }
217
218   process_data_.push_back(current_browser);
219
220   // For each browser process, collect a list of its children and get the
221   // memory usage of each.
222   for (std::set<pid_t>::const_iterator iter = browsers_found.begin();
223        iter != browsers_found.end();
224        ++iter) {
225     std::vector<pid_t> browser_processes = GetAllChildren(process_map, *iter);
226     ProcessData browser = GetProcessDataMemoryInformation(browser_processes);
227
228     ProcessMap::const_iterator process_iter = process_map.find(*iter);
229     if (process_iter == process_map.end())
230       continue;
231     BrowserType type = GetBrowserType(process_iter->second.name);
232     if (type != MAX_BROWSERS)
233       browser.name = base::ASCIIToUTF16(kBrowserPrettyNames[type]);
234     process_data_.push_back(browser);
235   }
236
237 #if defined(OS_CHROMEOS)
238   base::GetSwapInfo(&swap_info_);
239 #endif
240
241   // Finally return to the browser thread.
242   BrowserThread::PostTask(
243       BrowserThread::UI, FROM_HERE,
244       base::Bind(&MemoryDetails::CollectChildInfoOnUIThread, this));
245 }