Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc

Issue 1722493002: Project Eraser: Kill chrome://memory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix chrome_browser_ui.gypi. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <map>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/macros.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/strings/string16.h"
18 #include "base/sys_info.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/memory_details.h"
23 #include "chrome/browser/prerender/prerender_manager.h"
24 #include "chrome/browser/prerender/prerender_manager_factory.h"
25 #include "chrome/browser/process_resource_usage.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_manager.h"
28 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
29 #include "chrome/browser/ui/android/tab_model/tab_model.h"
30 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
31 #include "chrome/browser/ui/browser.h"
32 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
33 #include "chrome/browser/ui/webui/memory_internals/memory_internals_handler.h"
34 #include "chrome/common/features.h"
35 #include "content/public/browser/navigation_controller.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/render_process_host.h"
38 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/browser/web_ui.h"
41 #include "content/public/common/service_registry.h"
42
43 #if defined(ENABLE_PRINT_PREVIEW)
44 #include "chrome/browser/printing/background_printing_manager.h"
45 #endif
46
47 using content::BrowserThread;
48
49 class Profile;
50
51 namespace {
52
53 class ProcessDetails : public MemoryDetails {
54 public:
55 typedef base::Callback<void(const ProcessData&)> DataCallback;
56 explicit ProcessDetails(const DataCallback& callback)
57 : callback_(callback) {}
58
59 // MemoryDetails:
60 void OnDetailsAvailable() override { callback_.Run(*ChromeBrowser()); }
61
62 private:
63 ~ProcessDetails() override {}
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 BUILDFLAG(ANDROID_JAVA_UI)
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 content::WebContents* tab_web_contents = model->GetWebContentsAt(i);
92 if (tab_web_contents)
93 web_contents->insert(tab_web_contents);
94 }
95 }
96 #else
97 for (TabContentsIterator iter; !iter.done(); iter.Next())
98 web_contents->insert(*iter);
99 #endif
100 // Add all the prerender pages.
101 std::vector<Profile*> profiles(
102 g_browser_process->profile_manager()->GetLoadedProfiles());
103 for (size_t i = 0; i < profiles.size(); ++i) {
104 prerender::PrerenderManager* prerender_manager =
105 prerender::PrerenderManagerFactory::GetForProfile(profiles[i]);
106 if (!prerender_manager)
107 continue;
108 const std::vector<content::WebContents*> contentses =
109 prerender_manager->GetAllPrerenderingContents();
110 web_contents->insert(contentses.begin(), contentses.end());
111 }
112 #if defined(ENABLE_PRINT_PREVIEW)
113 // Add all the pages being background printed.
114 printing::BackgroundPrintingManager* printing_manager =
115 g_browser_process->background_printing_manager();
116 std::set<content::WebContents*> printing_contents =
117 printing_manager->CurrentContentSet();
118 web_contents->insert(printing_contents.begin(), printing_contents.end());
119 #endif
120 }
121
122 } // namespace
123
124 class RendererDetails {
125 public:
126 typedef base::Callback<void(const base::ProcessId pid,
127 const size_t v8_allocated,
128 const size_t v8_used)> V8DataCallback;
129
130 explicit RendererDetails(const V8DataCallback& callback)
131 : callback_(callback), weak_factory_(this) {}
132 ~RendererDetails() {}
133
134 void Request() {
135 for (std::set<content::WebContents*>::iterator iter = web_contents_.begin();
136 iter != web_contents_.end(); ++iter) {
137 auto rph = (*iter)->GetRenderViewHost()->GetProcess();
138 auto resource_usage = resource_usage_reporters_[(*iter)];
139 DCHECK(resource_usage.get());
140 resource_usage->Refresh(base::Bind(&RendererDetails::OnRefreshDone,
141 weak_factory_.GetWeakPtr(), *iter,
142 base::GetProcId(rph->GetHandle())));
143 }
144 }
145
146 void AddWebContents(content::WebContents* content) {
147 web_contents_.insert(content);
148
149 auto rph = content->GetRenderViewHost()->GetProcess();
150 content::ServiceRegistry* service_registry = rph->GetServiceRegistry();
151 ResourceUsageReporterPtr service;
152 if (service_registry)
153 service_registry->ConnectToRemoteService(mojo::GetProxy(&service));
154 resource_usage_reporters_.insert(std::make_pair(
155 content,
156 make_linked_ptr(new ProcessResourceUsage(std::move(service)))));
157 DCHECK_EQ(web_contents_.size(), resource_usage_reporters_.size());
158 }
159
160 void Clear() {
161 web_contents_.clear();
162 resource_usage_reporters_.clear();
163 weak_factory_.InvalidateWeakPtrs();
164 }
165
166 void RemoveWebContents(base::ProcessId) {
167 // This function should only be called once for each WebContents, so this
168 // should be non-empty every time it's called.
169 DCHECK(!web_contents_.empty());
170
171 // We don't have to detect which content is the caller of this method.
172 if (!web_contents_.empty())
173 web_contents_.erase(web_contents_.begin());
174 }
175
176 int IsClean() {
177 return web_contents_.empty();
178 }
179
180 private:
181 void OnRefreshDone(content::WebContents* content, const base::ProcessId pid) {
182 auto iter = resource_usage_reporters_.find(content);
183 DCHECK(iter != resource_usage_reporters_.end());
184 linked_ptr<ProcessResourceUsage> usage = iter->second;
185 callback_.Run(pid, usage->GetV8MemoryAllocated(), usage->GetV8MemoryUsed());
186 }
187
188 V8DataCallback callback_;
189 std::set<content::WebContents*> web_contents_; // This class does not own
190 std::map<content::WebContents*, linked_ptr<ProcessResourceUsage>>
191 resource_usage_reporters_;
192
193 base::WeakPtrFactory<RendererDetails> weak_factory_;
194
195 DISALLOW_COPY_AND_ASSIGN(RendererDetails);
196 };
197
198 MemoryInternalsProxy::MemoryInternalsProxy()
199 : information_(new base::DictionaryValue()),
200 renderer_details_(new RendererDetails(
201 base::Bind(&MemoryInternalsProxy::OnRendererAvailable, this))) {}
202
203 void MemoryInternalsProxy::Attach(MemoryInternalsHandler* handler) {
204 DCHECK_CURRENTLY_ON(BrowserThread::UI);
205 handler_ = handler;
206 }
207
208 void MemoryInternalsProxy::Detach() {
209 DCHECK_CURRENTLY_ON(BrowserThread::UI);
210 handler_ = NULL;
211 }
212
213 void MemoryInternalsProxy::StartFetch(const base::ListValue* list) {
214 DCHECK_CURRENTLY_ON(BrowserThread::UI);
215
216 // Clear previous information before fetching new information.
217 information_->Clear();
218 scoped_refptr<ProcessDetails> process(new ProcessDetails(
219 base::Bind(&MemoryInternalsProxy::OnProcessAvailable, this)));
220 process->StartFetch(MemoryDetails::FROM_CHROME_ONLY);
221 }
222
223 MemoryInternalsProxy::~MemoryInternalsProxy() {}
224
225 void MemoryInternalsProxy::RequestRendererDetails() {
226 renderer_details_->Clear();
227
228 #if BUILDFLAG(ANDROID_JAVA_UI)
229 for (TabModelList::const_iterator iter = TabModelList::begin();
230 iter != TabModelList::end(); ++iter) {
231 TabModel* model = *iter;
232 for (int i = 0; i < model->GetTabCount(); ++i) {
233 content::WebContents* tab_web_contents = model->GetWebContentsAt(i);
234 if (tab_web_contents)
235 renderer_details_->AddWebContents(tab_web_contents);
236 }
237 }
238 #else
239 for (TabContentsIterator iter; !iter.done(); iter.Next())
240 renderer_details_->AddWebContents(*iter);
241 #endif
242
243 renderer_details_->Request();
244 }
245
246 void MemoryInternalsProxy::OnProcessAvailable(const ProcessData& browser) {
247 base::ListValue* process_info = new base::ListValue();
248 base::ListValue* extension_info = new base::ListValue();
249 information_->Set("processes", process_info);
250 information_->Set("extensions", extension_info);
251 for (PMIIterator iter = browser.processes.begin();
252 iter != browser.processes.end(); ++iter) {
253 base::DictionaryValue* process = new base::DictionaryValue();
254 if (iter->renderer_type == ProcessMemoryInformation::RENDERER_EXTENSION)
255 extension_info->Append(process);
256 else
257 process_info->Append(process);
258
259 // From MemoryDetails.
260 process->SetInteger("pid", iter->pid);
261 process->SetString("type",
262 ProcessMemoryInformation::GetFullTypeNameInEnglish(
263 iter->process_type, iter->renderer_type));
264 process->SetInteger("memory_private", iter->working_set.priv);
265
266 base::ListValue* titles = new base::ListValue();
267 process->Set("titles", titles);
268 for (size_t i = 0; i < iter->titles.size(); ++i)
269 titles->AppendString(iter->titles[i]);
270 }
271
272 std::set<content::WebContents*> web_contents;
273 GetAllWebContents(&web_contents);
274 ConvertTabsInformation(web_contents, process_info);
275
276 RequestRendererDetails();
277 }
278
279 void MemoryInternalsProxy::OnRendererAvailable(const base::ProcessId pid,
280 const size_t v8_allocated,
281 const size_t v8_used) {
282 // Do not update while no renderers are registered.
283 if (renderer_details_->IsClean())
284 return;
285
286 base::ListValue* processes;
287 if (!information_->GetList("processes", &processes))
288 return;
289
290 const size_t size = processes->GetSize();
291 for (size_t i = 0; i < size; ++i) {
292 base::DictionaryValue* process;
293 processes->GetDictionary(i, &process);
294 int id;
295 if (!process->GetInteger("pid", &id) || id != static_cast<int>(pid))
296 continue;
297 // Convert units from Bytes to KiB.
298 process->SetInteger("v8_alloc", v8_allocated / 1024);
299 process->SetInteger("v8_used", v8_used / 1024);
300 break;
301 }
302
303 renderer_details_->RemoveWebContents(pid);
304 if (renderer_details_->IsClean())
305 FinishCollection();
306 }
307
308 void MemoryInternalsProxy::ConvertTabsInformation(
309 const std::set<content::WebContents*>& web_contents,
310 base::ListValue* processes) {
311 for (std::set<content::WebContents*>::const_iterator
312 iter = web_contents.begin(); iter != web_contents.end(); ++iter) {
313 content::WebContents* web = *iter;
314 content::RenderProcessHost* process_host = web->GetRenderProcessHost();
315 if (!process_host)
316 continue;
317
318 // Find which process renders the web contents.
319 const base::ProcessId pid = base::GetProcId(process_host->GetHandle());
320 base::DictionaryValue* process = FindProcessFromPid(processes, pid);
321 if (!process)
322 continue;
323
324 // Prepare storage to register navigation histories.
325 base::ListValue* tabs;
326 if (!process->GetList("history", &tabs)) {
327 tabs = new base::ListValue();
328 process->Set("history", tabs);
329 }
330
331 base::DictionaryValue* tab = new base::DictionaryValue();
332 tabs->Append(tab);
333
334 base::ListValue* histories = new base::ListValue();
335 tab->Set("history", histories);
336
337 const content::NavigationController& controller = web->GetController();
338 const int entry_size = controller.GetEntryCount();
339 for (int i = 0; i < entry_size; ++i) {
340 content::NavigationEntry *entry = controller.GetEntryAtIndex(i);
341 base::DictionaryValue* history = new base::DictionaryValue();
342 histories->Append(history);
343 history->SetString("url", entry->GetURL().spec());
344 history->SetString("title", entry->GetTitle());
345 history->SetInteger("time", (base::Time::Now() -
346 entry->GetTimestamp()).InSeconds());
347 }
348 tab->SetInteger("index", controller.GetCurrentEntryIndex());
349 }
350 }
351
352 void MemoryInternalsProxy::FinishCollection() {
353 information_->SetInteger("uptime", base::SysInfo::Uptime().InMilliseconds());
354 information_->SetString("os", base::SysInfo::OperatingSystemName());
355 information_->SetString("os_version",
356 base::SysInfo::OperatingSystemVersion());
357
358 CallJavaScriptFunctionOnUIThread("g_main_view.onSetSnapshot", *information_);
359 }
360
361 void MemoryInternalsProxy::CallJavaScriptFunctionOnUIThread(
362 const std::string& function, const base::Value& args) {
363 DCHECK_CURRENTLY_ON(BrowserThread::UI);
364
365 std::vector<const base::Value*> args_vector(1, &args);
366 base::string16 update =
367 content::WebUI::GetJavascriptCall(function, args_vector);
368 // Don't forward updates to a destructed UI.
369 if (handler_)
370 handler_->OnUpdate(update);
371 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698