blob: 2fb79f1245282f40f6fa56bd6271cb1229972456 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/task_manager/web_contents_resource_provider.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/task_manager/renderer_resource.h"
#include "chrome/browser/task_manager/task_manager.h"
#include "chrome/browser/task_manager/task_manager_util.h"
#include "chrome/browser/task_manager/web_contents_information.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
using content::WebContents;
using content::RenderViewHost;
namespace task_manager {
// A WebContentsObserver that tracks changes to a WebContents on behalf of
// a WebContentsResourceProvider.
class TaskManagerWebContentsObserver : public content::WebContentsObserver {
public:
TaskManagerWebContentsObserver(WebContents* web_contents,
WebContentsResourceProvider* provider)
: content::WebContentsObserver(web_contents), provider_(provider) {}
// content::WebContentsObserver implementation.
virtual void RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) OVERRIDE {
provider_->RemoveFromTaskManager(web_contents());
provider_->AddToTaskManager(web_contents());
}
virtual void RenderViewReady() OVERRIDE {
provider_->RemoveFromTaskManager(web_contents());
provider_->AddToTaskManager(web_contents());
}
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
provider_->RemoveFromTaskManager(web_contents());
}
virtual void WebContentsDestroyed() OVERRIDE {
provider_->RemoveFromTaskManager(web_contents());
provider_->DeleteObserver(this); // Deletes |this|.
}
private:
WebContentsResourceProvider* provider_;
};
////////////////////////////////////////////////////////////////////////////////
// WebContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////
WebContentsResourceProvider::WebContentsResourceProvider(
TaskManager* task_manager,
scoped_ptr<WebContentsInformation> info)
: updating_(false), task_manager_(task_manager), info_(info.Pass()) {}
WebContentsResourceProvider::~WebContentsResourceProvider() {}
RendererResource* WebContentsResourceProvider::GetResource(int origin_pid,
int child_id,
int route_id) {
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(child_id, route_id);
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(rfh);
// If an origin PID was specified then the request originated in a plugin
// working on the WebContents's behalf, so ignore it.
if (origin_pid)
return NULL;
std::map<WebContents*, RendererResource*>::iterator res_iter =
resources_.find(web_contents);
if (res_iter == resources_.end()) {
// Can happen if the tab was closed while a network request was being
// performed.
return NULL;
}
return res_iter->second;
}
void WebContentsResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
WebContentsInformation::NewWebContentsCallback new_web_contents_callback =
base::Bind(&WebContentsResourceProvider::OnWebContentsCreated, this);
info_->GetAll(new_web_contents_callback);
info_->StartObservingCreation(new_web_contents_callback);
}
void WebContentsResourceProvider::StopUpdating() {
DCHECK(updating_);
updating_ = false;
info_->StopObservingCreation();
// Delete all observers; this dissassociates them from the WebContents too.
STLDeleteElements(&web_contents_observers_);
web_contents_observers_.clear();
// Delete all resources. We don't need to remove them from the TaskManager,
// because it's the TaskManager that's asking us to StopUpdating().
STLDeleteValues(&resources_);
resources_.clear();
}
void WebContentsResourceProvider::OnWebContentsCreated(
WebContents* web_contents) {
// Don't add dead tabs or tabs that haven't yet connected.
if (!web_contents->GetRenderProcessHost()->GetHandle() ||
!web_contents->WillNotifyDisconnection()) {
return;
}
DCHECK(info_->CheckOwnership(web_contents));
if (AddToTaskManager(web_contents)) {
web_contents_observers_.insert(
new TaskManagerWebContentsObserver(web_contents, this));
}
}
bool WebContentsResourceProvider::AddToTaskManager(WebContents* web_contents) {
if (!updating_)
return false;
if (resources_.count(web_contents)) {
// The case may happen that we have added a WebContents as part of the
// iteration performed during StartUpdating() call but the notification that
// it has connected was not fired yet. So when the notification happens, we
// are already observing this WebContents and just ignore it.
return false;
}
// TODO(nick): If the RenderView is not live, then do we still want to install
// the WebContentsObserver? Only some of the original ResourceProviders
// had that check.
scoped_ptr<RendererResource> resource = info_->MakeResource(web_contents);
if (!resource)
return false;
task_manager_->AddResource(resource.get());
resources_[web_contents] = resource.release();
return true;
}
void WebContentsResourceProvider::RemoveFromTaskManager(
WebContents* web_contents) {
if (!updating_)
return;
std::map<WebContents*, RendererResource*>::iterator resource_iter =
resources_.find(web_contents);
if (resource_iter == resources_.end()) {
return;
}
RendererResource* resource = resource_iter->second;
task_manager_->RemoveResource(resource);
// Remove the resource from the Task Manager.
// And from the provider.
resources_.erase(resource_iter);
// Finally, delete the resource.
delete resource;
}
void WebContentsResourceProvider::DeleteObserver(
TaskManagerWebContentsObserver* observer) {
if (!web_contents_observers_.erase(observer)) {
NOTREACHED();
return;
}
delete observer; // Typically, this is our caller. Deletion is okay.
}
} // namespace task_manager