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 process ID. |
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 return; |
| 191 |
| 192 Task* task = GetTaskForFrame(render_frame_host); |
| 193 |
| 194 if (!task) |
| 195 return; |
| 196 |
| 197 const base::ProcessId determine_pid_from_handle = base::kNullProcessId; |
| 198 provider_->UpdateTaskProcessInfoAndNotifyObserver( |
| 199 task, render_frame_host->GetProcess()->GetHandle(), |
| 200 determine_pid_from_handle); |
181 } | 201 } |
182 | 202 |
183 void WebContentsEntry::WebContentsDestroyed() { | 203 void WebContentsEntry::WebContentsDestroyed() { |
184 ClearAllTasks(true); | 204 ClearAllTasks(true); |
185 provider_->DeleteEntry(web_contents()); | 205 provider_->DeleteEntry(web_contents()); |
186 } | 206 } |
187 | 207 |
188 void WebContentsEntry::RenderProcessGone(base::TerminationStatus status) { | |
189 ClearAllTasks(true); | |
190 } | |
191 | |
192 void WebContentsEntry::OnRendererUnresponsive( | 208 void WebContentsEntry::OnRendererUnresponsive( |
193 RenderWidgetHost* render_widget_host) { | 209 RenderWidgetHost* render_widget_host) { |
194 // Find the first RenderFrameHost matching the RenderWidgetHost. | 210 // Find the first RenderFrameHost matching the RenderWidgetHost. |
195 RendererTask* task = nullptr; | 211 RendererTask* task = nullptr; |
196 for (const auto& pair : tasks_by_frames_) { | 212 for (const auto& pair : tasks_by_frames_) { |
197 if (pair.first->GetView() == render_widget_host->GetView()) { | 213 if (pair.first->GetView() == render_widget_host->GetView()) { |
198 DCHECK_EQ(pair.first->GetProcess(), render_widget_host->GetProcess()); | 214 DCHECK_EQ(pair.first->GetProcess(), render_widget_host->GetProcess()); |
199 task = pair.second; | 215 task = pair.second; |
200 break; | 216 break; |
201 } | 217 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 | 251 |
236 void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry, | 252 void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry, |
237 bool explicit_set) { | 253 bool explicit_set) { |
238 ForEachTask(base::Bind([](RendererTask* task) { | 254 ForEachTask(base::Bind([](RendererTask* task) { |
239 task->UpdateTitle(); | 255 task->UpdateTitle(); |
240 task->UpdateFavicon(); | 256 task->UpdateFavicon(); |
241 })); | 257 })); |
242 } | 258 } |
243 | 259 |
244 void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { | 260 void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { |
| 261 // Currently we do not track pending hosts, or pending delete hosts. |
| 262 DCHECK(render_frame_host->IsCurrent()); |
245 DCHECK(render_frame_host); | 263 DCHECK(render_frame_host); |
246 DCHECK(!tasks_by_frames_.count(render_frame_host)); | 264 DCHECK(!tasks_by_frames_.count(render_frame_host)); |
247 | 265 |
248 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | 266 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
249 if (!site_instance->GetProcess()->HasConnection()) | 267 |
250 return; | 268 // Exclude sad tabs and sad oopifs. |
251 if (!render_frame_host->IsRenderFrameLive()) | 269 if (!render_frame_host->IsRenderFrameLive()) |
252 return; | 270 return; |
253 | 271 |
| 272 // Exclude frames in the same SiteInstance as their parent; |tasks_by_frames_| |
| 273 // only contains local roots. |
| 274 if (render_frame_host->GetParent() && |
| 275 site_instance == render_frame_host->GetParent()->GetSiteInstance()) { |
| 276 return; |
| 277 } |
| 278 |
254 bool site_instance_exists = | 279 bool site_instance_exists = |
255 frames_by_site_instance_.count(site_instance) != 0; | 280 frames_by_site_instance_.count(site_instance) != 0; |
256 bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame()); | 281 bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame()); |
257 bool site_instance_is_main = (site_instance == main_frame_site_instance_); | 282 bool site_instance_is_main = (site_instance == main_frame_site_instance_); |
258 | 283 |
259 RendererTask* new_task = nullptr; | 284 RendererTask* new_task = nullptr; |
260 // We don't create a task if there's one for this site_instance AND | 285 |
261 // if this is not the main frame or we did record a main frame for the entry. | 286 // We need to create a task if one doesn't already exist for this |
| 287 // SiteInstance, or if the main frame navigates to a process that currently is |
| 288 // represented by a SubframeTask. |
262 if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) { | 289 if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) { |
263 if (is_main_frame) { | 290 if (is_main_frame) { |
264 const WebContentsTag* tag = | 291 const WebContentsTag* tag = |
265 WebContentsTag::FromWebContents(web_contents()); | 292 WebContentsTag::FromWebContents(web_contents()); |
266 new_task = tag->CreateTask(); | 293 new_task = tag->CreateTask(); |
267 main_frame_site_instance_ = site_instance; | 294 main_frame_site_instance_ = site_instance; |
268 } else { | 295 } else { |
269 new_task = | 296 new_task = |
270 new SubframeTask(render_frame_host, web_contents(), | 297 new SubframeTask(render_frame_host, web_contents(), |
271 GetTaskForFrame(web_contents()->GetMainFrame())); | 298 GetTaskForFrame(web_contents()->GetMainFrame())); |
272 } | 299 } |
273 } | 300 } |
274 | 301 |
275 if (site_instance_exists) { | 302 if (site_instance_exists) { |
276 // One of the existing frame hosts for this site instance. | 303 // One of the existing frame hosts for this site instance. |
277 FramesList& existing_frames_for_site_instance = | 304 FramesList& existing_frames_for_site_instance = |
278 frames_by_site_instance_[site_instance]; | 305 frames_by_site_instance_[site_instance]; |
279 RenderFrameHost* existing_rfh = existing_frames_for_site_instance[0]; | 306 RenderFrameHost* existing_rfh = existing_frames_for_site_instance[0]; |
280 RendererTask* old_task = tasks_by_frames_[existing_rfh]; | 307 RendererTask* old_task = tasks_by_frames_[existing_rfh]; |
281 | 308 |
282 if (!new_task) { | 309 if (!new_task) { |
283 // We didn't create any new task, so we keep appending the old one. | 310 // We didn't create any new task, so we keep using the old one. |
284 tasks_by_frames_[render_frame_host] = old_task; | 311 tasks_by_frames_[render_frame_host] = old_task; |
285 } else { | 312 } else { |
286 // Overwrite all the existing old tasks with the new one, and delete the | 313 // Overwrite all the existing old tasks with the new one, and delete the |
287 // old one. | 314 // old one. |
288 for (RenderFrameHost* frame : existing_frames_for_site_instance) | 315 for (RenderFrameHost* frame : existing_frames_for_site_instance) |
289 tasks_by_frames_[frame] = new_task; | 316 tasks_by_frames_[frame] = new_task; |
290 | 317 |
291 provider_->NotifyObserverTaskRemoved(old_task); | 318 provider_->NotifyObserverTaskRemoved(old_task); |
292 delete old_task; | 319 delete old_task; |
293 } | 320 } |
294 } | 321 } |
295 | 322 |
296 frames_by_site_instance_[site_instance].push_back(render_frame_host); | 323 frames_by_site_instance_[site_instance].push_back(render_frame_host); |
297 | 324 |
298 if (new_task) { | 325 if (new_task) { |
299 tasks_by_frames_[render_frame_host] = new_task; | 326 tasks_by_frames_[render_frame_host] = new_task; |
300 provider_->NotifyObserverTaskAdded(new_task); | 327 provider_->NotifyObserverTaskAdded(new_task); |
| 328 |
| 329 // If we don't know the OS process handle yet (e.g., because this task is |
| 330 // still launching), update the task when it becomes available. |
| 331 if (new_task->process_id() == base::kNullProcessId) { |
| 332 render_frame_host->GetProcess()->PostTaskWhenProcessIsReady(base::Bind( |
| 333 &WebContentsEntry::RenderFrameReady, weak_factory_.GetWeakPtr(), |
| 334 render_frame_host->GetProcess()->GetID(), |
| 335 render_frame_host->GetRoutingID())); |
| 336 } |
301 } | 337 } |
302 } | 338 } |
303 | 339 |
304 void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) { | 340 void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) { |
305 auto itr = tasks_by_frames_.find(render_frame_host); | 341 auto itr = tasks_by_frames_.find(render_frame_host); |
306 if (itr == tasks_by_frames_.end()) | 342 if (itr == tasks_by_frames_.end()) |
307 return; | 343 return; |
308 | 344 |
309 RendererTask* task = itr->second; | 345 RendererTask* task = itr->second; |
310 tasks_by_frames_.erase(itr); | 346 tasks_by_frames_.erase(itr); |
311 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | 347 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
312 FramesList& frames = frames_by_site_instance_[site_instance]; | 348 FramesList& frames = frames_by_site_instance_[site_instance]; |
313 frames.erase(std::find(frames.begin(), frames.end(), render_frame_host)); | 349 frames.erase(std::find(frames.begin(), frames.end(), render_frame_host)); |
314 | 350 |
315 if (frames.empty()) { | 351 if (frames.empty()) { |
316 frames_by_site_instance_.erase(site_instance); | 352 frames_by_site_instance_.erase(site_instance); |
317 provider_->NotifyObserverTaskRemoved(task); | 353 provider_->NotifyObserverTaskRemoved(task); |
318 delete task; | 354 delete task; |
319 | 355 |
320 if (site_instance == main_frame_site_instance_) | 356 if (site_instance == main_frame_site_instance_) |
321 main_frame_site_instance_ = nullptr; | 357 main_frame_site_instance_ = nullptr; |
322 } | 358 } |
| 359 |
| 360 // Whenever we have a task, we should have a main frame site instance. |
| 361 DCHECK(tasks_by_frames_.empty() == (main_frame_site_instance_ == nullptr)); |
323 } | 362 } |
324 | 363 |
325 void WebContentsEntry::ForEachTask( | 364 void WebContentsEntry::ForEachTask( |
326 const base::Callback<void(RendererTask*)>& on_task) { | 365 const base::Callback<void(RendererTask*)>& on_task) { |
327 for (const auto& pair : frames_by_site_instance_) { | 366 for (const auto& pair : frames_by_site_instance_) { |
328 const FramesList& frames_list = pair.second; | 367 const FramesList& frames_list = pair.second; |
329 DCHECK(!frames_list.empty()); | 368 DCHECK(!frames_list.empty()); |
330 RendererTask* task = tasks_by_frames_[frames_list[0]]; | 369 RendererTask* task = tasks_by_frames_[frames_list[0]]; |
331 | 370 |
332 on_task.Run(task); | 371 on_task.Run(task); |
333 } | 372 } |
334 } | 373 } |
335 | 374 |
336 //////////////////////////////////////////////////////////////////////////////// | 375 //////////////////////////////////////////////////////////////////////////////// |
337 | 376 |
338 WebContentsTaskProvider::WebContentsTaskProvider() | 377 WebContentsTaskProvider::WebContentsTaskProvider() : is_updating_(false) {} |
339 : is_updating_(false) { | |
340 } | |
341 | 378 |
342 WebContentsTaskProvider::~WebContentsTaskProvider() { | 379 WebContentsTaskProvider::~WebContentsTaskProvider() { |
343 if (is_updating_) { | 380 if (is_updating_) { |
344 StopUpdating(); | 381 StopUpdating(); |
345 } | 382 } |
346 } | 383 } |
347 | 384 |
348 void WebContentsTaskProvider::OnWebContentsTagCreated( | 385 void WebContentsTaskProvider::OnWebContentsTagCreated( |
349 const WebContentsTag* tag) { | 386 const WebContentsTag* tag) { |
350 DCHECK(tag); | 387 DCHECK(tag); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 } | 468 } |
432 | 469 |
433 void WebContentsTaskProvider::DeleteEntry(content::WebContents* web_contents) { | 470 void WebContentsTaskProvider::DeleteEntry(content::WebContents* web_contents) { |
434 // This erase() will delete the WebContentsEntry, which is actually our | 471 // This erase() will delete the WebContentsEntry, which is actually our |
435 // caller, but it's expecting us to delete it. | 472 // caller, but it's expecting us to delete it. |
436 bool success = entries_map_.erase(web_contents) != 0; | 473 bool success = entries_map_.erase(web_contents) != 0; |
437 DCHECK(success); | 474 DCHECK(success); |
438 } | 475 } |
439 | 476 |
440 } // namespace task_manager | 477 } // namespace task_manager |
OLD | NEW |