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

Side by Side Diff: chrome/browser/task_manager/web_contents_resource_provider.cc

Issue 2197483003: Move the Mac Task Manager to the new backend code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: mark Created 4 years, 4 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 2014 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/task_manager/web_contents_resource_provider.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/macros.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/prerender/prerender_manager.h"
15 #include "chrome/browser/prerender/prerender_manager_factory.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/task_manager/renderer_resource.h"
19 #include "chrome/browser/task_manager/task_manager.h"
20 #include "chrome/browser/task_manager/task_manager_util.h"
21 #include "chrome/browser/task_manager/web_contents_information.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_process_host_observer.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/render_widget_host_iterator.h"
28 #include "content/public/browser/site_instance.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_observer.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/gfx/image/image_skia.h"
33
34 using content::RenderFrameHost;
35 using content::RenderProcessHost;
36 using content::RenderViewHost;
37 using content::SiteInstance;
38 using content::WebContents;
39
40 namespace task_manager {
41
42 // A resource for a process hosting out-of-process iframes.
43 class SubframeResource : public RendererResource {
44 public:
45 explicit SubframeResource(WebContents* web_contents,
46 SiteInstance* site_instance,
47 RenderFrameHost* example_rfh);
48 ~SubframeResource() override {}
49
50 // Resource methods:
51 Type GetType() const override;
52 base::string16 GetTitle() const override;
53 gfx::ImageSkia GetIcon() const override;
54 WebContents* GetWebContents() const override;
55
56 private:
57 WebContents* web_contents_;
58 base::string16 title_;
59 DISALLOW_COPY_AND_ASSIGN(SubframeResource);
60 };
61
62 SubframeResource::SubframeResource(WebContents* web_contents,
63 SiteInstance* subframe_site_instance,
64 RenderFrameHost* example_rfh)
65 : RendererResource(subframe_site_instance->GetProcess()->GetHandle(),
66 example_rfh->GetRenderViewHost()),
67 web_contents_(web_contents) {
68 int message_id = subframe_site_instance->GetBrowserContext()->IsOffTheRecord()
69 ? IDS_TASK_MANAGER_SUBFRAME_INCOGNITO_PREFIX
70 : IDS_TASK_MANAGER_SUBFRAME_PREFIX;
71 title_ = l10n_util::GetStringFUTF16(
72 message_id,
73 base::UTF8ToUTF16(subframe_site_instance->GetSiteURL().spec()));
74 }
75
76 Resource::Type SubframeResource::GetType() const {
77 return RENDERER;
78 }
79
80 base::string16 SubframeResource::GetTitle() const {
81 return title_;
82 }
83
84 gfx::ImageSkia SubframeResource::GetIcon() const {
85 return gfx::ImageSkia();
86 }
87
88 WebContents* SubframeResource::GetWebContents() const {
89 return web_contents_;
90 }
91
92 // Tracks changes to one WebContents, and manages task manager resources for
93 // that WebContents, on behalf of a WebContentsResourceProvider.
94 class TaskManagerWebContentsEntry : public content::WebContentsObserver,
95 public content::RenderProcessHostObserver {
96 public:
97 typedef std::multimap<SiteInstance*, RendererResource*> ResourceMap;
98 typedef std::pair<ResourceMap::iterator, ResourceMap::iterator> ResourceRange;
99
100 TaskManagerWebContentsEntry(WebContents* web_contents,
101 WebContentsResourceProvider* provider)
102 : content::WebContentsObserver(web_contents),
103 provider_(provider),
104 main_frame_site_instance_(NULL) {}
105
106 ~TaskManagerWebContentsEntry() override { ClearAllResources(false); }
107
108 // content::WebContentsObserver implementation.
109 void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
110 ClearResourceForFrame(render_frame_host);
111 }
112
113 void RenderFrameHostChanged(RenderFrameHost* old_host,
114 RenderFrameHost* new_host) override {
115 if (old_host)
116 ClearResourceForFrame(old_host);
117 CreateResourceForFrame(new_host);
118 }
119
120 void RenderViewReady() override {
121 ClearAllResources(true);
122 CreateAllResources();
123 }
124
125 void WebContentsDestroyed() override {
126 ClearAllResources(true);
127 provider_->DeleteEntry(web_contents(), this); // Deletes |this|.
128 }
129
130 // content::RenderProcessHostObserver implementation.
131 void RenderProcessExited(RenderProcessHost* process_host,
132 base::TerminationStatus status,
133 int exit_code) override {
134 ClearResourcesForProcess(process_host);
135 }
136
137 void RenderProcessHostDestroyed(RenderProcessHost* process_host) override {
138 tracked_process_hosts_.erase(process_host);
139 }
140
141 // Called by WebContentsResourceProvider.
142 RendererResource* GetResourceForSiteInstance(SiteInstance* site_instance) {
143 ResourceMap::iterator i = resources_by_site_instance_.find(site_instance);
144 if (i == resources_by_site_instance_.end())
145 return NULL;
146 return i->second;
147 }
148
149 void CreateAllResources() {
150 // We'll show one row per SiteInstance in the task manager.
151 DCHECK(web_contents()->GetMainFrame() != NULL);
152 web_contents()->ForEachFrame(
153 base::Bind(&TaskManagerWebContentsEntry::CreateResourceForFrame,
154 base::Unretained(this)));
155 }
156
157 void ClearAllResources(bool update_task_manager) {
158 RendererResource* last_resource = NULL;
159 for (auto& x : resources_by_site_instance_) {
160 RendererResource* resource = x.second;
161 if (resource == last_resource)
162 continue; // Skip multiset duplicates.
163 if (update_task_manager)
164 task_manager()->RemoveResource(resource);
165 delete resource;
166 last_resource = resource;
167 }
168 resources_by_site_instance_.clear();
169
170 RenderProcessHost* last_process_host = NULL;
171 for (RenderProcessHost* process_host : tracked_process_hosts_) {
172 if (last_process_host == process_host)
173 continue; // Skip multiset duplicates.
174 process_host->RemoveObserver(this);
175 last_process_host = process_host;
176 }
177 tracked_process_hosts_.clear();
178 tracked_frame_hosts_.clear();
179 }
180
181 void ClearResourceForFrame(RenderFrameHost* render_frame_host) {
182 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
183 std::set<RenderFrameHost*>::iterator frame_set_iterator =
184 tracked_frame_hosts_.find(render_frame_host);
185 if (frame_set_iterator == tracked_frame_hosts_.end()) {
186 // We weren't tracking this RenderFrameHost.
187 return;
188 }
189 tracked_frame_hosts_.erase(frame_set_iterator);
190 ResourceRange resource_range =
191 resources_by_site_instance_.equal_range(site_instance);
192 if (resource_range.first == resource_range.second) {
193 NOTREACHED();
194 return;
195 }
196 RendererResource* resource = resource_range.first->second;
197 resources_by_site_instance_.erase(resource_range.first++);
198 if (resource_range.first == resource_range.second) {
199 // The removed entry was the sole remaining reference to that resource, so
200 // actually destroy it.
201 task_manager()->RemoveResource(resource);
202 delete resource;
203 DecrementProcessWatch(site_instance->GetProcess());
204 if (site_instance == main_frame_site_instance_) {
205 main_frame_site_instance_ = NULL;
206 }
207 }
208 }
209
210 void ClearResourcesForProcess(RenderProcessHost* crashed_process) {
211 std::vector<RenderFrameHost*> frame_hosts_to_delete;
212 for (RenderFrameHost* frame_host : tracked_frame_hosts_) {
213 if (frame_host->GetProcess() == crashed_process) {
214 frame_hosts_to_delete.push_back(frame_host);
215 }
216 }
217 for (RenderFrameHost* frame_host : frame_hosts_to_delete) {
218 ClearResourceForFrame(frame_host);
219 }
220 }
221
222 void CreateResourceForFrame(RenderFrameHost* render_frame_host) {
223 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
224
225 DCHECK_EQ(0u, tracked_frame_hosts_.count(render_frame_host));
226
227 if (!site_instance->GetProcess()->HasConnection())
228 return;
229
230 tracked_frame_hosts_.insert(render_frame_host);
231
232 ResourceRange existing_resource_range =
233 resources_by_site_instance_.equal_range(site_instance);
234 bool existing_resource =
235 (existing_resource_range.first != existing_resource_range.second);
236 bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame());
237 bool site_instance_is_main = (site_instance == main_frame_site_instance_);
238 std::unique_ptr<RendererResource> new_resource;
239 if (!existing_resource || (is_main_frame && !site_instance_is_main)) {
240 if (is_main_frame) {
241 new_resource = info()->MakeResource(web_contents());
242 main_frame_site_instance_ = site_instance;
243 } else {
244 new_resource.reset(new SubframeResource(
245 web_contents(), site_instance, render_frame_host));
246 }
247 }
248
249 if (existing_resource) {
250 RendererResource* old_resource = existing_resource_range.first->second;
251 if (!new_resource) {
252 resources_by_site_instance_.insert(
253 std::make_pair(site_instance, old_resource));
254 } else {
255 for (ResourceMap::iterator it = existing_resource_range.first;
256 it != existing_resource_range.second;
257 ++it) {
258 it->second = new_resource.get();
259 }
260 task_manager()->RemoveResource(old_resource);
261 delete old_resource;
262 DecrementProcessWatch(site_instance->GetProcess());
263 }
264 }
265
266 if (new_resource) {
267 task_manager()->AddResource(new_resource.get());
268 resources_by_site_instance_.insert(
269 std::make_pair(site_instance, new_resource.release()));
270 IncrementProcessWatch(site_instance->GetProcess());
271 }
272 }
273
274 // Add ourself as an observer of |process|, if we aren't already. Must be
275 // balanced by a call to DecrementProcessWatch().
276 // TODO(nick): Move away from RenderProcessHostObserver once
277 // WebContentsObserver supports per-frame process death notices.
278 void IncrementProcessWatch(RenderProcessHost* process) {
279 auto range = tracked_process_hosts_.equal_range(process);
280 if (range.first == range.second) {
281 process->AddObserver(this);
282 }
283 tracked_process_hosts_.insert(range.first, process);
284 }
285
286 void DecrementProcessWatch(RenderProcessHost* process) {
287 auto range = tracked_process_hosts_.equal_range(process);
288 if (range.first == range.second) {
289 NOTREACHED();
290 return;
291 }
292
293 auto element = range.first++;
294 if (range.first == range.second) {
295 process->RemoveObserver(this);
296 }
297 tracked_process_hosts_.erase(element, range.first);
298 }
299
300 private:
301 TaskManager* task_manager() { return provider_->task_manager(); }
302
303 WebContentsInformation* info() { return provider_->info(); }
304
305 WebContentsResourceProvider* const provider_;
306
307 // Every RenderFrameHost that we're watching.
308 std::set<RenderFrameHost*> tracked_frame_hosts_;
309
310 // The set of processes we're currently observing. There is one entry here per
311 // RendererResource we create. A multimap because we may request observation
312 // more than once, say if two resources happen to share a process.
313 std::multiset<RenderProcessHost*> tracked_process_hosts_;
314
315 // Maps SiteInstances to the RendererResources. A multimap, this contains one
316 // entry per tracked RenderFrameHost, so we can tell when we're done reusing.
317 ResourceMap resources_by_site_instance_;
318
319 // The site instance of the main frame.
320 SiteInstance* main_frame_site_instance_;
321 };
322
323 ////////////////////////////////////////////////////////////////////////////////
324 // WebContentsResourceProvider class
325 ////////////////////////////////////////////////////////////////////////////////
326
327 WebContentsResourceProvider::WebContentsResourceProvider(
328 TaskManager* task_manager,
329 std::unique_ptr<WebContentsInformation> info)
330 : task_manager_(task_manager), info_(std::move(info)) {}
331
332 WebContentsResourceProvider::~WebContentsResourceProvider() {}
333
334 RendererResource* WebContentsResourceProvider::GetResource(int origin_pid,
335 int child_id,
336 int route_id) {
337 RenderFrameHost* rfh = RenderFrameHost::FromID(child_id, route_id);
338 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
339
340 // If an origin PID was specified then the request originated in a plugin
341 // working on the WebContents's behalf, so ignore it.
342 if (origin_pid)
343 return NULL;
344
345 EntryMap::const_iterator web_contents_it = entries_.find(web_contents);
346
347 if (web_contents_it == entries_.end()) {
348 // Can happen if the tab was closed while a network request was being
349 // performed.
350 return NULL;
351 }
352
353 return web_contents_it->second->GetResourceForSiteInstance(
354 rfh->GetSiteInstance());
355 }
356
357 void WebContentsResourceProvider::StartUpdating() {
358 WebContentsInformation::NewWebContentsCallback new_web_contents_callback =
359 base::Bind(&WebContentsResourceProvider::OnWebContentsCreated, this);
360 info_->GetAll(new_web_contents_callback);
361 info_->StartObservingCreation(new_web_contents_callback);
362 }
363
364 void WebContentsResourceProvider::StopUpdating() {
365 info_->StopObservingCreation();
366
367 // Delete all entries; this dissassociates them from the WebContents too.
368 STLDeleteValues(&entries_);
369 }
370
371 void WebContentsResourceProvider::OnWebContentsCreated(
372 WebContents* web_contents) {
373 // Don't add dead tabs or tabs that haven't yet connected.
374 if (!web_contents->GetRenderProcessHost()->GetHandle() ||
375 !web_contents->WillNotifyDisconnection()) {
376 return;
377 }
378
379 DCHECK(info_->CheckOwnership(web_contents));
380 if (entries_.count(web_contents)) {
381 // The case may happen that we have added a WebContents as part of the
382 // iteration performed during StartUpdating() call but the notification that
383 // it has connected was not fired yet. So when the notification happens, we
384 // are already observing this WebContents and just ignore it.
385 return;
386 }
387 std::unique_ptr<TaskManagerWebContentsEntry> entry(
388 new TaskManagerWebContentsEntry(web_contents, this));
389 entry->CreateAllResources();
390 entries_[web_contents] = entry.release();
391 }
392
393 void WebContentsResourceProvider::DeleteEntry(
394 WebContents* web_contents,
395 TaskManagerWebContentsEntry* entry) {
396 if (!entries_.erase(web_contents)) {
397 NOTREACHED();
398 return;
399 }
400 delete entry; // Typically, this is our caller. Deletion is okay.
401 }
402
403 } // namespace task_manager
OLDNEW
« no previous file with comments | « chrome/browser/task_manager/web_contents_resource_provider.h ('k') | chrome/browser/ui/browser_dialogs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698