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

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: Totally change approach; just let Tasks modify their PIDs. Created 3 years, 5 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 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698