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

Side by Side Diff: chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.cc

Issue 2961423002: [TaskManager] Allow a Task to mutate its PID after creation (Closed)
Patch Set: Rework comment. Created 3 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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/task_manager/providers/task_provider.cc ('k') | chrome/browser/task_manager/sampling/task_group.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698