Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / memory_internals / memory_internals_proxy.cc
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.
4
5 #include "chrome/browser/ui/webui/memory_internals/memory_internals_proxy.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
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"
39
40 #if defined(ENABLE_FULL_PRINTING)
41 #include "chrome/browser/printing/background_printing_manager.h"
42 #endif
43
44 using content::BrowserThread;
45
46 class Profile;
47
48 namespace {
49
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]);
60   }
61
62  private:
63   virtual ~ProcessDetails() {}
64
65   DataCallback callback_;
66
67   DISALLOW_COPY_AND_ASSIGN(ProcessDetails);
68 };
69
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;
80   }
81   return NULL;
82 }
83
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));
92   }
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());
108   }
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
117 }
118
119 }  // namespace
120
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;
126
127   explicit RendererDetails(const V8DataCallback& callback)
128       : callback_(callback) {
129     registrar_.Add(this, chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
130                    content::NotificationService::AllSources());
131   }
132   virtual ~RendererDetails() {}
133
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);
138   }
139
140   void AddWebContents(content::WebContents* content) {
141     web_contents_.insert(content);
142   }
143
144   void Clear() {
145     web_contents_.clear();
146   }
147
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());
152   }
153
154   int IsClean() {
155     return web_contents_.empty();
156   }
157
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());
171   }
172
173   V8DataCallback callback_;
174   content::NotificationRegistrar registrar_;
175   std::set<content::WebContents*> web_contents_;  // This class does not own
176
177   DISALLOW_COPY_AND_ASSIGN(RendererDetails);
178 };
179
180 MemoryInternalsProxy::MemoryInternalsProxy()
181     : information_(new base::DictionaryValue()),
182       renderer_details_(new RendererDetails(
183           base::Bind(&MemoryInternalsProxy::OnRendererAvailable, this))) {}
184
185 void MemoryInternalsProxy::Attach(MemoryInternalsHandler* handler) {
186   DCHECK_CURRENTLY_ON(BrowserThread::UI);
187   handler_ = handler;
188 }
189
190 void MemoryInternalsProxy::Detach() {
191   DCHECK_CURRENTLY_ON(BrowserThread::UI);
192   handler_ = NULL;
193 }
194
195 void MemoryInternalsProxy::StartFetch(const base::ListValue* list) {
196   DCHECK_CURRENTLY_ON(BrowserThread::UI);
197
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);
203 }
204
205 MemoryInternalsProxy::~MemoryInternalsProxy() {}
206
207 void MemoryInternalsProxy::RequestRendererDetails() {
208   renderer_details_->Clear();
209
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));
216   }
217 #else
218   for (TabContentsIterator iter; !iter.done(); iter.Next())
219     renderer_details_->AddWebContents(*iter);
220 #endif
221
222   renderer_details_->Request();
223 }
224
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);
237
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);
244
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]);
249   }
250
251   std::set<content::WebContents*> web_contents;
252   GetAllWebContents(&web_contents);
253   ConvertTabsInformation(web_contents, process_info);
254
255   RequestRendererDetails();
256 }
257
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;
264
265   base::ListValue* processes;
266   if (!information_->GetList("processes", &processes))
267     return;
268
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;
280   }
281
282   renderer_details_->RemoveWebContents(pid);
283   if (renderer_details_->IsClean())
284     FinishCollection();
285 }
286
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());
295
296     // Find which process renders the web contents.
297     base::DictionaryValue* process = FindProcessFromPid(processes, pid);
298     if (!process)
299       continue;
300
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);
306     }
307
308     base::DictionaryValue* tab = new base::DictionaryValue();
309     tabs->Append(tab);
310
311     base::ListValue* histories = new base::ListValue();
312     tab->Set("history", histories);
313
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());
324     }
325     tab->SetInteger("index", controller.GetCurrentEntryIndex());
326   }
327 }
328
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());
334
335   CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", *information_);
336 }
337
338 void MemoryInternalsProxy::CallJavaScriptFunctionOnUIThread(
339     const std::string& function, const base::Value& args) {
340   DCHECK_CURRENTLY_ON(BrowserThread::UI);
341
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);
348 }