Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / memory_internals / memory_internals_proxy.cc
blobd7c6d9725e9cf81f43a5cd65860c9887bac7e06a
1 // Copyright 2013 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.
5 #include "chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/strings/string16.h"
13 #include "base/sys_info.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/memory_details.h"
18 #include "chrome/browser/prerender/prerender_manager.h"
19 #include "chrome/browser/prerender/prerender_manager_factory.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
23 #include "chrome/browser/ui/android/tab_model/tab_model.h"
24 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_iterator.h"
27 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
28 #include "chrome/browser/ui/webui/memory_internals/memory_internals_handler.h"
29 #include "chrome/common/render_messages.h"
30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/notification_observer.h"
33 #include "content/public/browser/notification_registrar.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/render_view_host.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/browser/web_ui.h"
40 #if defined(ENABLE_FULL_PRINTING)
41 #include "chrome/browser/printing/background_printing_manager.h"
42 #endif
44 using content::BrowserThread;
46 class Profile;
48 namespace {
50 class ProcessDetails : public MemoryDetails {
51 public:
52 typedef base::Callback<void(const ProcessData&)> DataCallback;
53 explicit ProcessDetails(const DataCallback& callback)
54 : callback_(callback) {}
55 // MemoryDetails:
56 virtual void OnDetailsAvailable() OVERRIDE {
57 const std::vector<ProcessData>& browser_processes = processes();
58 // [0] means Chrome.
59 callback_.Run(browser_processes[0]);
62 private:
63 virtual ~ProcessDetails() {}
65 DataCallback callback_;
67 DISALLOW_COPY_AND_ASSIGN(ProcessDetails);
70 base::DictionaryValue* FindProcessFromPid(base::ListValue* processes,
71 base::ProcessId pid) {
72 const size_t n = processes->GetSize();
73 for (size_t i = 0; i < n; ++i) {
74 base::DictionaryValue* process;
75 if (!processes->GetDictionary(i, &process))
76 return NULL;
77 int id;
78 if (process->GetInteger("pid", &id) && id == static_cast<int>(pid))
79 return process;
81 return NULL;
84 void GetAllWebContents(std::set<content::WebContents*>* web_contents) {
85 // Add all the existing WebContentses.
86 #if defined(OS_ANDROID)
87 for (TabModelList::const_iterator iter = TabModelList::begin();
88 iter != TabModelList::end(); ++iter) {
89 TabModel* model = *iter;
90 for (int i = 0; i < model->GetTabCount(); ++i)
91 web_contents->insert(model->GetWebContentsAt(i));
93 #else
94 for (TabContentsIterator iter; !iter.done(); iter.Next())
95 web_contents->insert(*iter);
96 #endif
97 // Add all the prerender pages.
98 std::vector<Profile*> profiles(
99 g_browser_process->profile_manager()->GetLoadedProfiles());
100 for (size_t i = 0; i < profiles.size(); ++i) {
101 prerender::PrerenderManager* prerender_manager =
102 prerender::PrerenderManagerFactory::GetForProfile(profiles[i]);
103 if (!prerender_manager)
104 continue;
105 const std::vector<content::WebContents*> contentses =
106 prerender_manager->GetAllPrerenderingContents();
107 web_contents->insert(contentses.begin(), contentses.end());
109 #if defined(ENABLE_FULL_PRINTING)
110 // Add all the pages being background printed.
111 printing::BackgroundPrintingManager* printing_manager =
112 g_browser_process->background_printing_manager();
113 std::set<content::WebContents*> printing_contents =
114 printing_manager->CurrentContentSet();
115 web_contents->insert(printing_contents.begin(), printing_contents.end());
116 #endif
119 } // namespace
121 class RendererDetails : public content::NotificationObserver {
122 public:
123 typedef base::Callback<void(const base::ProcessId pid,
124 const size_t v8_allocated,
125 const size_t v8_used)> V8DataCallback;
127 explicit RendererDetails(const V8DataCallback& callback)
128 : callback_(callback) {
129 registrar_.Add(this, chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
130 content::NotificationService::AllSources());
132 virtual ~RendererDetails() {}
134 void Request() {
135 for (std::set<content::WebContents*>::iterator iter = web_contents_.begin();
136 iter != web_contents_.end(); ++iter)
137 (*iter)->GetRenderViewHost()->Send(new ChromeViewMsg_GetV8HeapStats);
140 void AddWebContents(content::WebContents* content) {
141 web_contents_.insert(content);
144 void Clear() {
145 web_contents_.clear();
148 void RemoveWebContents(base::ProcessId) {
149 // We don't have to detect which content is the caller of this method.
150 if (!web_contents_.empty())
151 web_contents_.erase(web_contents_.begin());
154 int IsClean() {
155 return web_contents_.empty();
158 private:
159 // NotificationObserver:
160 virtual void Observe(int type,
161 const content::NotificationSource& source,
162 const content::NotificationDetails& details) OVERRIDE {
163 const base::ProcessId* pid =
164 content::Source<const base::ProcessId>(source).ptr();
165 const ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap =
166 content::Details<const ChromeRenderMessageFilter::V8HeapStatsDetails>(
167 details).ptr();
168 callback_.Run(*pid,
169 v8_heap->v8_memory_allocated(),
170 v8_heap->v8_memory_used());
173 V8DataCallback callback_;
174 content::NotificationRegistrar registrar_;
175 std::set<content::WebContents*> web_contents_; // This class does not own
177 DISALLOW_COPY_AND_ASSIGN(RendererDetails);
180 MemoryInternalsProxy::MemoryInternalsProxy()
181 : information_(new base::DictionaryValue()),
182 renderer_details_(new RendererDetails(
183 base::Bind(&MemoryInternalsProxy::OnRendererAvailable, this))) {}
185 void MemoryInternalsProxy::Attach(MemoryInternalsHandler* handler) {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187 handler_ = handler;
190 void MemoryInternalsProxy::Detach() {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 handler_ = NULL;
195 void MemoryInternalsProxy::StartFetch(const base::ListValue* list) {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
198 // Clear previous information before fetching new information.
199 information_->Clear();
200 scoped_refptr<ProcessDetails> process(new ProcessDetails(
201 base::Bind(&MemoryInternalsProxy::OnProcessAvailable, this)));
202 process->StartFetch(MemoryDetails::SKIP_USER_METRICS);
205 MemoryInternalsProxy::~MemoryInternalsProxy() {}
207 void MemoryInternalsProxy::RequestRendererDetails() {
208 renderer_details_->Clear();
210 #if defined(OS_ANDROID)
211 for (TabModelList::const_iterator iter = TabModelList::begin();
212 iter != TabModelList::end(); ++iter) {
213 TabModel* model = *iter;
214 for (int i = 0; i < model->GetTabCount(); ++i)
215 renderer_details_->AddWebContents(model->GetWebContentsAt(i));
217 #else
218 for (TabContentsIterator iter; !iter.done(); iter.Next())
219 renderer_details_->AddWebContents(*iter);
220 #endif
222 renderer_details_->Request();
225 void MemoryInternalsProxy::OnProcessAvailable(const ProcessData& browser) {
226 base::ListValue* process_info = new base::ListValue();
227 base::ListValue* extension_info = new base::ListValue();
228 information_->Set("processes", process_info);
229 information_->Set("extensions", extension_info);
230 for (PMIIterator iter = browser.processes.begin();
231 iter != browser.processes.end(); ++iter) {
232 base::DictionaryValue* process = new base::DictionaryValue();
233 if (iter->renderer_type == ProcessMemoryInformation::RENDERER_EXTENSION)
234 extension_info->Append(process);
235 else
236 process_info->Append(process);
238 // From MemoryDetails.
239 process->SetInteger("pid", iter->pid);
240 process->SetString("type",
241 ProcessMemoryInformation::GetFullTypeNameInEnglish(
242 iter->process_type, iter->renderer_type));
243 process->SetInteger("memory_private", iter->working_set.priv);
245 base::ListValue* titles = new base::ListValue();
246 process->Set("titles", titles);
247 for (size_t i = 0; i < iter->titles.size(); ++i)
248 titles->AppendString(iter->titles[i]);
251 std::set<content::WebContents*> web_contents;
252 GetAllWebContents(&web_contents);
253 ConvertTabsInformation(web_contents, process_info);
255 RequestRendererDetails();
258 void MemoryInternalsProxy::OnRendererAvailable(const base::ProcessId pid,
259 const size_t v8_allocated,
260 const size_t v8_used) {
261 // Do not update while no renderers are registered.
262 if (renderer_details_->IsClean())
263 return;
265 base::ListValue* processes;
266 if (!information_->GetList("processes", &processes))
267 return;
269 const size_t size = processes->GetSize();
270 for (size_t i = 0; i < size; ++i) {
271 base::DictionaryValue* process;
272 processes->GetDictionary(i, &process);
273 int id;
274 if (!process->GetInteger("pid", &id) || id != static_cast<int>(pid))
275 continue;
276 // Convert units from Bytes to KiB.
277 process->SetInteger("v8_alloc", v8_allocated / 1024);
278 process->SetInteger("v8_used", v8_used / 1024);
279 break;
282 renderer_details_->RemoveWebContents(pid);
283 if (renderer_details_->IsClean())
284 FinishCollection();
287 void MemoryInternalsProxy::ConvertTabsInformation(
288 const std::set<content::WebContents*>& web_contents,
289 base::ListValue* processes) {
290 for (std::set<content::WebContents*>::const_iterator
291 iter = web_contents.begin(); iter != web_contents.end(); ++iter) {
292 content::WebContents* web = *iter;
293 const base::ProcessId pid = base::GetProcId(
294 web->GetRenderProcessHost()->GetHandle());
296 // Find which process renders the web contents.
297 base::DictionaryValue* process = FindProcessFromPid(processes, pid);
298 if (!process)
299 continue;
301 // Prepare storage to register navigation histories.
302 base::ListValue* tabs;
303 if (!process->GetList("history", &tabs)) {
304 tabs = new base::ListValue();
305 process->Set("history", tabs);
308 base::DictionaryValue* tab = new base::DictionaryValue();
309 tabs->Append(tab);
311 base::ListValue* histories = new base::ListValue();
312 tab->Set("history", histories);
314 const content::NavigationController& controller = web->GetController();
315 const int entry_size = controller.GetEntryCount();
316 for (int i = 0; i < entry_size; ++i) {
317 content::NavigationEntry *entry = controller.GetEntryAtIndex(i);
318 base::DictionaryValue* history = new base::DictionaryValue();
319 histories->Append(history);
320 history->SetString("url", entry->GetURL().spec());
321 history->SetString("title", entry->GetTitle());
322 history->SetInteger("time", (base::Time::Now() -
323 entry->GetTimestamp()).InSeconds());
325 tab->SetInteger("index", controller.GetCurrentEntryIndex());
329 void MemoryInternalsProxy::FinishCollection() {
330 information_->SetInteger("uptime", base::SysInfo::Uptime());
331 information_->SetString("os", base::SysInfo::OperatingSystemName());
332 information_->SetString("os_version",
333 base::SysInfo::OperatingSystemVersion());
335 CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", *information_);
338 void MemoryInternalsProxy::CallJavaScriptFunctionOnUIThread(
339 const std::string& function, const base::Value& args) {
340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
342 std::vector<const base::Value*> args_vector(1, &args);
343 base::string16 update =
344 content::WebUI::GetJavascriptCall(function, args_vector);
345 // Don't forward updates to a destructed UI.
346 if (handler_)
347 handler_->OnUpdate(update);