OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/task_manager/providers/web_contents/web_contents_task_p rovider.h" | 5 #include "chrome/browser/task_manager/providers/web_contents/web_contents_task_p rovider.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/macros.h" | 8 #include "base/macros.h" |
9 #include "base/memory/weak_ptr.h" | 9 #include "base/memory/weak_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
48 // |render_frame_host| or |nullptr| if the given frame is not tracked by this | 48 // |render_frame_host| or |nullptr| if the given frame is not tracked by this |
49 // entry. | 49 // entry. |
50 RendererTask* GetTaskForFrame(RenderFrameHost* render_frame_host) const; | 50 RendererTask* GetTaskForFrame(RenderFrameHost* render_frame_host) const; |
51 | 51 |
52 // content::WebContentsObserver: | 52 // content::WebContentsObserver: |
53 void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; | 53 void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; |
54 void RenderFrameHostChanged(RenderFrameHost* old_host, | 54 void RenderFrameHostChanged(RenderFrameHost* old_host, |
55 RenderFrameHost* new_host) override; | 55 RenderFrameHost* new_host) override; |
56 void RenderFrameCreated(RenderFrameHost*) override; | 56 void RenderFrameCreated(RenderFrameHost*) override; |
57 void WebContentsDestroyed() override; | 57 void WebContentsDestroyed() override; |
58 void RenderProcessGone(base::TerminationStatus status) override; | |
59 void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) override; | 58 void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) override; |
60 void DidFinishNavigation( | 59 void DidFinishNavigation( |
61 content::NavigationHandle* navigation_handle) override; | 60 content::NavigationHandle* navigation_handle) override; |
62 void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; | 61 void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; |
63 | 62 |
64 void RenderFrameReady(int process_routing_id, int frame_routing_id); | 63 void RenderFrameReady(int process_routing_id, int frame_routing_id); |
65 | 64 |
66 private: | 65 private: |
67 // Defines a callback for WebContents::ForEachFrame() to create a | 66 // Defines a callback for WebContents::ForEachFrame() to create a |
68 // corresponding task for the given |render_frame_host| and notifying the | 67 // corresponding task for the given |render_frame_host| and notifying the |
69 // provider's observer of the new task. | 68 // provider's observer of the new task. |
70 void CreateTaskForFrame(RenderFrameHost* render_frame_host); | 69 void CreateTaskForFrame(RenderFrameHost* render_frame_host); |
71 | 70 |
72 // Clears the task that corresponds to the given |render_frame_host| and | 71 // Clears the task that corresponds to the given |render_frame_host| and |
73 // notifies the provider's observer of the tasks removal. | 72 // notifies the provider's observer of the tasks removal. |
74 void ClearTaskForFrame(RenderFrameHost* render_frame_host); | 73 void ClearTaskForFrame(RenderFrameHost* render_frame_host); |
75 | 74 |
76 // Calls |on_task| for each task managed by this WebContentsEntry. | 75 // Calls |on_task| for each task managed by this WebContentsEntry. |
77 void ForEachTask(const base::Callback<void(RendererTask*)>& on_task); | 76 void ForEachTask(const base::Callback<void(RendererTask*)>& on_task); |
78 | 77 |
78 // Walks parents until hitting a process boundary. Returns the highest frame | |
79 // in the same SiteInstance as |render_frame_host|. | |
80 RenderFrameHost* FindLocalRoot(RenderFrameHost* render_frame_host) const; | |
81 | |
79 // The provider that owns this entry. | 82 // The provider that owns this entry. |
80 WebContentsTaskProvider* provider_; | 83 WebContentsTaskProvider* provider_; |
81 | 84 |
82 // The RenderFrameHosts associated with this entry's WebContents that we're | 85 // The RenderFrameHosts associated with this entry's WebContents that we're |
83 // tracking mapped by their SiteInstances. | 86 // tracking mapped by their SiteInstances. |
84 using FramesList = std::vector<RenderFrameHost*>; | 87 using FramesList = std::vector<RenderFrameHost*>; |
85 std::map<SiteInstance*, FramesList> frames_by_site_instance_; | 88 std::map<SiteInstance*, FramesList> frames_by_site_instance_; |
86 | 89 |
87 // The RendererTasks that we create for the task manager, mapped by their | 90 // The RendererTasks that we create for the task manager, mapped by their |
88 // RenderFrameHosts. This owns the RenderTasks. | 91 // RenderFrameHosts. This owns the RenderTasks. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
128 }, | 131 }, |
129 provider_, notify_observer, web_contents())); | 132 provider_, notify_observer, web_contents())); |
130 | 133 |
131 frames_by_site_instance_.clear(); | 134 frames_by_site_instance_.clear(); |
132 tasks_by_frames_.clear(); | 135 tasks_by_frames_.clear(); |
133 main_frame_site_instance_ = nullptr; | 136 main_frame_site_instance_ = nullptr; |
134 } | 137 } |
135 | 138 |
136 RendererTask* WebContentsEntry::GetTaskForFrame( | 139 RendererTask* WebContentsEntry::GetTaskForFrame( |
137 RenderFrameHost* render_frame_host) const { | 140 RenderFrameHost* render_frame_host) const { |
138 auto itr = tasks_by_frames_.find(render_frame_host); | 141 // Only local roots are in |tasks_by_frames_|. |
142 auto itr = tasks_by_frames_.find(FindLocalRoot(render_frame_host)); | |
139 if (itr == tasks_by_frames_.end()) | 143 if (itr == tasks_by_frames_.end()) |
140 return nullptr; | 144 return nullptr; |
141 | 145 |
142 return itr->second; | 146 return itr->second; |
143 } | 147 } |
144 | 148 |
149 RenderFrameHost* WebContentsEntry::FindLocalRoot( | |
150 RenderFrameHost* render_frame_host) const { | |
151 SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | |
152 RenderFrameHost* candidate = render_frame_host; | |
153 while (RenderFrameHost* parent = candidate->GetParent()) { | |
154 if (parent->GetSiteInstance() != site_instance) | |
155 break; | |
156 candidate = parent; | |
157 } | |
158 return candidate; | |
159 } | |
160 | |
145 void WebContentsEntry::RenderFrameDeleted(RenderFrameHost* render_frame_host) { | 161 void WebContentsEntry::RenderFrameDeleted(RenderFrameHost* render_frame_host) { |
146 ClearTaskForFrame(render_frame_host); | 162 ClearTaskForFrame(render_frame_host); |
147 } | 163 } |
148 | 164 |
149 void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host, | 165 void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host, |
150 RenderFrameHost* new_host) { | 166 RenderFrameHost* new_host) { |
167 DCHECK(new_host->IsCurrent()); | |
151 ClearTaskForFrame(old_host); | 168 ClearTaskForFrame(old_host); |
152 CreateTaskForFrame(new_host); | 169 CreateTaskForFrame(new_host); |
153 } | 170 } |
154 | 171 |
155 void WebContentsEntry::RenderFrameCreated(RenderFrameHost* render_frame_host) { | 172 void WebContentsEntry::RenderFrameCreated(RenderFrameHost* render_frame_host) { |
173 DCHECK(render_frame_host->IsRenderFrameLive()); | |
174 | |
156 // Skip pending/speculative hosts. We'll create tasks for these if the | 175 // Skip pending/speculative hosts. We'll create tasks for these if the |
157 // navigation commits, at which point RenderFrameHostChanged() will fire. | 176 // navigation commits, at which point RenderFrameHostChanged() will fire. |
158 if (!render_frame_host->IsCurrent()) | 177 if (!render_frame_host->IsCurrent()) |
159 return; | 178 return; |
160 | 179 |
161 // Task manager will have no separate entry for |render_frame_host| if it has | 180 CreateTaskForFrame(render_frame_host); |
162 // the same site instance as its parent - quit early in this case. | |
163 if (render_frame_host->GetParent() && | |
164 render_frame_host->GetParent()->GetSiteInstance() == | |
165 render_frame_host->GetSiteInstance()) | |
166 return; | |
167 | |
168 // Postpone processing |render_frame_host| until its process has a PID. | |
169 render_frame_host->GetProcess()->PostTaskWhenProcessIsReady(base::Bind( | |
170 &WebContentsEntry::RenderFrameReady, weak_factory_.GetWeakPtr(), | |
171 render_frame_host->GetProcess()->GetID(), | |
172 render_frame_host->GetRoutingID())); | |
173 } | 181 } |
174 | 182 |
175 void WebContentsEntry::RenderFrameReady(int render_process_id, | 183 void WebContentsEntry::RenderFrameReady(int render_process_id, |
176 int render_frame_id) { | 184 int render_frame_id) { |
185 // We get here when a RenderProcessHost we are tracking transitions to the | |
186 // IsReady state. This might mean we know its the process ID. | |
afakhry
2017/07/10 17:27:53
Nit: This might mean we know its (-the) process ID
ncarter (slow)
2017/07/31 22:30:29
Done.
| |
177 content::RenderFrameHost* render_frame_host = | 187 content::RenderFrameHost* render_frame_host = |
178 content::RenderFrameHost::FromID(render_process_id, render_frame_id); | 188 content::RenderFrameHost::FromID(render_process_id, render_frame_id); |
179 if (render_frame_host) | 189 if (render_frame_host) { |
180 CreateTaskForFrame(render_frame_host); | 190 Task* task = GetTaskForFrame(render_frame_host); |
191 | |
192 if (task) { | |
afakhry
2017/07/10 17:27:53
Nit: Much indented nested blocks?
if (!render_fram
ncarter (slow)
2017/07/31 22:30:29
Done.
| |
193 base::ProcessId determine_pid_from_handle = base::kNullProcessId; | |
afakhry
2017/07/10 17:27:53
Nit: Can you make this a const?
ncarter (slow)
2017/07/31 22:30:29
Done.
| |
194 provider_->UpdateTaskProcessInfoAndNotifyObserver( | |
195 task, render_frame_host->GetProcess()->GetHandle(), | |
196 determine_pid_from_handle); | |
197 } | |
198 } | |
181 } | 199 } |
182 | 200 |
183 void WebContentsEntry::WebContentsDestroyed() { | 201 void WebContentsEntry::WebContentsDestroyed() { |
184 ClearAllTasks(true); | 202 ClearAllTasks(true); |
185 provider_->DeleteEntry(web_contents()); | 203 provider_->DeleteEntry(web_contents()); |
186 } | 204 } |
187 | 205 |
188 void WebContentsEntry::RenderProcessGone(base::TerminationStatus status) { | |
189 ClearAllTasks(true); | |
190 } | |
191 | |
192 void WebContentsEntry::OnRendererUnresponsive( | 206 void WebContentsEntry::OnRendererUnresponsive( |
193 RenderWidgetHost* render_widget_host) { | 207 RenderWidgetHost* render_widget_host) { |
194 // Find the first RenderFrameHost matching the RenderWidgetHost. | 208 // Find the first RenderFrameHost matching the RenderWidgetHost. |
195 RendererTask* task = nullptr; | 209 RendererTask* task = nullptr; |
196 for (const auto& pair : tasks_by_frames_) { | 210 for (const auto& pair : tasks_by_frames_) { |
197 if (pair.first->GetView() == render_widget_host->GetView()) { | 211 if (pair.first->GetView() == render_widget_host->GetView()) { |
198 DCHECK_EQ(pair.first->GetProcess(), render_widget_host->GetProcess()); | 212 DCHECK_EQ(pair.first->GetProcess(), render_widget_host->GetProcess()); |
199 task = pair.second; | 213 task = pair.second; |
200 break; | 214 break; |
201 } | 215 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 | 249 |
236 void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry, | 250 void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry, |
237 bool explicit_set) { | 251 bool explicit_set) { |
238 ForEachTask(base::Bind([](RendererTask* task) { | 252 ForEachTask(base::Bind([](RendererTask* task) { |
239 task->UpdateTitle(); | 253 task->UpdateTitle(); |
240 task->UpdateFavicon(); | 254 task->UpdateFavicon(); |
241 })); | 255 })); |
242 } | 256 } |
243 | 257 |
244 void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { | 258 void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { |
259 // Currently we do not track pending hosts, or pending delete hosts. | |
260 DCHECK(render_frame_host->IsCurrent()); | |
245 DCHECK(render_frame_host); | 261 DCHECK(render_frame_host); |
246 DCHECK(!tasks_by_frames_.count(render_frame_host)); | 262 DCHECK(!tasks_by_frames_.count(render_frame_host)); |
247 | 263 |
248 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | 264 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
249 if (!site_instance->GetProcess()->HasConnection()) | 265 |
266 // Exclude sad tabs and sad oopifs. | |
267 if (!render_frame_host->IsRenderFrameLive()) | |
250 return; | 268 return; |
251 if (!render_frame_host->IsRenderFrameLive()) | 269 |
270 // Exclude frames in the same SiteInstance as their parent; |tasks_by_frames_| | |
271 // only contains local roots. | |
272 if (render_frame_host->GetParent() && | |
273 site_instance == render_frame_host->GetParent()->GetSiteInstance()) | |
afakhry
2017/07/10 17:27:53
Nit: braces here.
ncarter (slow)
2017/07/31 22:30:29
Done.
| |
252 return; | 274 return; |
253 | 275 |
254 bool site_instance_exists = | 276 bool site_instance_exists = |
255 frames_by_site_instance_.count(site_instance) != 0; | 277 frames_by_site_instance_.count(site_instance) != 0; |
256 bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame()); | 278 bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame()); |
257 bool site_instance_is_main = (site_instance == main_frame_site_instance_); | 279 bool site_instance_is_main = (site_instance == main_frame_site_instance_); |
258 | 280 |
259 RendererTask* new_task = nullptr; | 281 RendererTask* new_task = nullptr; |
260 // We don't create a task if there's one for this site_instance AND | 282 |
261 // if this is not the main frame or we did record a main frame for the entry. | 283 // We need to create a task if one doesn't already exist for this |
284 // SiteInstance, or if the main frame navigates to a process that currently is | |
285 // represented by a SubframeTask. | |
262 if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) { | 286 if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) { |
263 if (is_main_frame) { | 287 if (is_main_frame) { |
264 const WebContentsTag* tag = | 288 const WebContentsTag* tag = |
265 WebContentsTag::FromWebContents(web_contents()); | 289 WebContentsTag::FromWebContents(web_contents()); |
266 new_task = tag->CreateTask(); | 290 new_task = tag->CreateTask(); |
267 main_frame_site_instance_ = site_instance; | 291 main_frame_site_instance_ = site_instance; |
268 } else { | 292 } else { |
269 new_task = | 293 new_task = |
270 new SubframeTask(render_frame_host, web_contents(), | 294 new SubframeTask(render_frame_host, web_contents(), |
271 GetTaskForFrame(web_contents()->GetMainFrame())); | 295 GetTaskForFrame(web_contents()->GetMainFrame())); |
272 } | 296 } |
273 } | 297 } |
274 | 298 |
275 if (site_instance_exists) { | 299 if (site_instance_exists) { |
276 // One of the existing frame hosts for this site instance. | 300 // One of the existing frame hosts for this site instance. |
277 FramesList& existing_frames_for_site_instance = | 301 FramesList& existing_frames_for_site_instance = |
278 frames_by_site_instance_[site_instance]; | 302 frames_by_site_instance_[site_instance]; |
279 RenderFrameHost* existing_rfh = existing_frames_for_site_instance[0]; | 303 RenderFrameHost* existing_rfh = existing_frames_for_site_instance[0]; |
280 RendererTask* old_task = tasks_by_frames_[existing_rfh]; | 304 RendererTask* old_task = tasks_by_frames_[existing_rfh]; |
281 | 305 |
282 if (!new_task) { | 306 if (!new_task) { |
283 // We didn't create any new task, so we keep appending the old one. | 307 // We didn't create any new task, so we keep using the old one. |
284 tasks_by_frames_[render_frame_host] = old_task; | 308 tasks_by_frames_[render_frame_host] = old_task; |
285 } else { | 309 } else { |
286 // Overwrite all the existing old tasks with the new one, and delete the | 310 // Overwrite all the existing old tasks with the new one, and delete the |
287 // old one. | 311 // old one. |
288 for (RenderFrameHost* frame : existing_frames_for_site_instance) | 312 for (RenderFrameHost* frame : existing_frames_for_site_instance) |
289 tasks_by_frames_[frame] = new_task; | 313 tasks_by_frames_[frame] = new_task; |
290 | 314 |
291 provider_->NotifyObserverTaskRemoved(old_task); | 315 provider_->NotifyObserverTaskRemoved(old_task); |
292 delete old_task; | 316 delete old_task; |
293 } | 317 } |
294 } | 318 } |
295 | 319 |
296 frames_by_site_instance_[site_instance].push_back(render_frame_host); | 320 frames_by_site_instance_[site_instance].push_back(render_frame_host); |
297 | 321 |
298 if (new_task) { | 322 if (new_task) { |
299 tasks_by_frames_[render_frame_host] = new_task; | 323 tasks_by_frames_[render_frame_host] = new_task; |
300 provider_->NotifyObserverTaskAdded(new_task); | 324 provider_->NotifyObserverTaskAdded(new_task); |
325 | |
326 // If we don't know the OS process handle yet (e.g., because this | |
327 // task is still launching), update the task when it becomes | |
328 // available. | |
329 if (new_task->process_id() == base::kNullProcessId) { | |
afakhry
2017/07/10 17:27:53
Nit: Indented nested blocks here too?
if (new_tas
ncarter (slow)
2017/07/31 22:30:29
I opted not to do this one; in my mind early-retur
afakhry
2017/08/01 17:25:35
Acknowledged.
| |
330 render_frame_host->GetProcess()->PostTaskWhenProcessIsReady(base::Bind( | |
331 &WebContentsEntry::RenderFrameReady, weak_factory_.GetWeakPtr(), | |
332 render_frame_host->GetProcess()->GetID(), | |
333 render_frame_host->GetRoutingID())); | |
334 } | |
301 } | 335 } |
302 } | 336 } |
303 | 337 |
304 void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) { | 338 void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) { |
305 auto itr = tasks_by_frames_.find(render_frame_host); | 339 auto itr = tasks_by_frames_.find(render_frame_host); |
306 if (itr == tasks_by_frames_.end()) | 340 if (itr == tasks_by_frames_.end()) |
307 return; | 341 return; |
308 | 342 |
309 RendererTask* task = itr->second; | 343 RendererTask* task = itr->second; |
310 tasks_by_frames_.erase(itr); | 344 tasks_by_frames_.erase(itr); |
311 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | 345 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
312 FramesList& frames = frames_by_site_instance_[site_instance]; | 346 FramesList& frames = frames_by_site_instance_[site_instance]; |
313 frames.erase(std::find(frames.begin(), frames.end(), render_frame_host)); | 347 frames.erase(std::find(frames.begin(), frames.end(), render_frame_host)); |
314 | 348 |
315 if (frames.empty()) { | 349 if (frames.empty()) { |
316 frames_by_site_instance_.erase(site_instance); | 350 frames_by_site_instance_.erase(site_instance); |
317 provider_->NotifyObserverTaskRemoved(task); | 351 provider_->NotifyObserverTaskRemoved(task); |
318 delete task; | 352 delete task; |
319 | 353 |
320 if (site_instance == main_frame_site_instance_) | 354 if (site_instance == main_frame_site_instance_) |
321 main_frame_site_instance_ = nullptr; | 355 main_frame_site_instance_ = nullptr; |
322 } | 356 } |
357 | |
358 // Whenever we have a task, we should have a main frame site instance. | |
359 DCHECK(tasks_by_frames_.empty() == (main_frame_site_instance_ == nullptr)); | |
323 } | 360 } |
324 | 361 |
325 void WebContentsEntry::ForEachTask( | 362 void WebContentsEntry::ForEachTask( |
326 const base::Callback<void(RendererTask*)>& on_task) { | 363 const base::Callback<void(RendererTask*)>& on_task) { |
327 for (const auto& pair : frames_by_site_instance_) { | 364 for (const auto& pair : frames_by_site_instance_) { |
328 const FramesList& frames_list = pair.second; | 365 const FramesList& frames_list = pair.second; |
329 DCHECK(!frames_list.empty()); | 366 DCHECK(!frames_list.empty()); |
330 RendererTask* task = tasks_by_frames_[frames_list[0]]; | 367 RendererTask* task = tasks_by_frames_[frames_list[0]]; |
331 | 368 |
332 on_task.Run(task); | 369 on_task.Run(task); |
333 } | 370 } |
334 } | 371 } |
335 | 372 |
336 //////////////////////////////////////////////////////////////////////////////// | 373 //////////////////////////////////////////////////////////////////////////////// |
337 | 374 |
338 WebContentsTaskProvider::WebContentsTaskProvider() | 375 WebContentsTaskProvider::WebContentsTaskProvider() : is_updating_(false) {} |
339 : is_updating_(false) { | |
340 } | |
341 | 376 |
342 WebContentsTaskProvider::~WebContentsTaskProvider() { | 377 WebContentsTaskProvider::~WebContentsTaskProvider() { |
343 if (is_updating_) { | 378 if (is_updating_) { |
344 StopUpdating(); | 379 StopUpdating(); |
345 } | 380 } |
346 } | 381 } |
347 | 382 |
348 void WebContentsTaskProvider::OnWebContentsTagCreated( | 383 void WebContentsTaskProvider::OnWebContentsTagCreated( |
349 const WebContentsTag* tag) { | 384 const WebContentsTag* tag) { |
350 DCHECK(tag); | 385 DCHECK(tag); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
431 } | 466 } |
432 | 467 |
433 void WebContentsTaskProvider::DeleteEntry(content::WebContents* web_contents) { | 468 void WebContentsTaskProvider::DeleteEntry(content::WebContents* web_contents) { |
434 // This erase() will delete the WebContentsEntry, which is actually our | 469 // This erase() will delete the WebContentsEntry, which is actually our |
435 // caller, but it's expecting us to delete it. | 470 // caller, but it's expecting us to delete it. |
436 bool success = entries_map_.erase(web_contents) != 0; | 471 bool success = entries_map_.erase(web_contents) != 0; |
437 DCHECK(success); | 472 DCHECK(success); |
438 } | 473 } |
439 | 474 |
440 } // namespace task_manager | 475 } // namespace task_manager |
OLD | NEW |