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

Unified Diff: chrome/browser/ui/webui/inspect_ui.cc

Issue 9724038: DevTools: convert about:workers into about:inspect (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments addressed. Created 8 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/webui/inspect_ui.h ('k') | chrome/browser/ui/webui/inspect_ui_browsertest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/webui/inspect_ui.cc
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
new file mode 100644
index 0000000000000000000000000000000000000000..68fe570dec58079e808a1d1196a32f4c78da6c05
--- /dev/null
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -0,0 +1,411 @@
+// Copyright (c) 2012 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/ui/webui/inspect_ui.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/devtools_agent_host_registry.h"
+#include "content/public/browser/devtools_client_host.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_view_host_delegate.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/worker_service.h"
+#include "content/public/browser/worker_service_observer.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "content/public/common/process_type.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "net/base/escape.h"
+#include "ui/base/resource/resource_bundle.h"
+
+using content::BrowserThread;
+using content::ChildProcessData;
+using content::DevToolsAgentHost;
+using content::DevToolsAgentHostRegistry;
+using content::DevToolsClientHost;
+using content::DevToolsManager;
+using content::RenderProcessHost;
+using content::RenderViewHost;
+using content::RenderViewHostDelegate;
+using content::RenderWidgetHost;
+using content::WebContents;
+using content::WebUIMessageHandler;
+using content::WorkerService;
+using content::WorkerServiceObserver;
+
+static const char kDataFile[] = "targets-data.json";
+
+static const char kExtensionTargetType[] = "extension";
+static const char kPageTargetType[] = "page";
+static const char kWorkerTargetType[] = "worker";
+
+static const char kInspectCommand[] = "inspect";
+static const char kTerminateCommand[] = "terminate";
+
+static const char kTargetTypeField[] = "type";
+static const char kAttachedField[] = "attached";
+static const char kProcessIdField[] = "processId";
+static const char kRouteIdField[] = "routeId";
+static const char kUrlField[] = "url";
+static const char kNameField[] = "name";
+static const char kFaviconUrlField[] = "favicon_url";
+static const char kPidField[] = "pid";
+
+namespace {
+
+DictionaryValue* BuildTargetDescriptor(
+ const std::string& target_type,
+ bool attached,
+ const GURL& url,
+ const std::string& name,
+ const GURL& favicon_url,
+ int process_id,
+ int route_id,
+ base::ProcessHandle handle = base::kNullProcessHandle) {
+ DictionaryValue* target_data = new DictionaryValue();
+ target_data->SetString(kTargetTypeField, target_type);
+ target_data->SetBoolean(kAttachedField, attached);
+ target_data->SetInteger(kProcessIdField, process_id);
+ target_data->SetInteger(kRouteIdField, route_id);
+ target_data->SetString(kUrlField, url.spec());
+ target_data->SetString(kNameField, net::EscapeForHTML(name));
+ target_data->SetInteger(kPidField, base::GetProcId(handle));
+ target_data->SetString(kFaviconUrlField, favicon_url.spec());
+
+ return target_data;
+}
+
+bool HasClientHost(RenderViewHost* rvh) {
+ if (!DevToolsAgentHostRegistry::HasDevToolsAgentHost(rvh))
+ return false;
+
+ DevToolsAgentHost* agent =
+ DevToolsAgentHostRegistry::GetDevToolsAgentHost(rvh);
+ return !!DevToolsManager::GetInstance()->GetDevToolsClientHostFor(agent);
+}
+
+DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh, bool is_tab) {
+ RenderViewHostDelegate* rvh_delegate = rvh->GetDelegate();
+ WebContents* web_contents = rvh_delegate->GetAsWebContents();
+ std::string title;
+ std::string target_type = is_tab ? kPageTargetType : "";
+ GURL favicon_url;
+ if (web_contents) {
+ title = UTF16ToUTF8(web_contents->GetTitle());
+ content::NavigationController& controller = web_contents->GetController();
+ content::NavigationEntry* entry = controller.GetActiveEntry();
+ if (entry != NULL && entry->GetURL().is_valid())
+ favicon_url = entry->GetFavicon().url;
+
+ Profile* profile = Profile::FromBrowserContext(
+ web_contents->GetBrowserContext());
+ if (profile) {
+ ExtensionService* extension_service = profile->GetExtensionService();
+ const Extension* extension = extension_service->extensions()->GetByID(
+ web_contents->GetURL().host());
+ if (extension) {
+ target_type = kExtensionTargetType;
+ title = extension->name();
+ }
+ }
+ }
+
+ return BuildTargetDescriptor(target_type,
+ HasClientHost(rvh),
+ rvh_delegate->GetURL(),
+ title,
+ favicon_url,
+ rvh->GetProcess()->GetID(),
+ rvh->GetRoutingID());
+}
+
+class InspectDataSource : public ChromeWebUIDataSource {
+ public:
+ InspectDataSource();
+
+ virtual void StartDataRequest(const std::string& path,
+ bool is_incognito,
+ int request_id);
+ private:
+ virtual ~InspectDataSource() {}
+ void SendDescriptors(int request_id, ListValue* rvh_list);
+ DISALLOW_COPY_AND_ASSIGN(InspectDataSource);
+};
+
+InspectDataSource::InspectDataSource()
+ : ChromeWebUIDataSource(chrome::kChromeUIInspectHost,
+ MessageLoop::current()) {
+ add_resource_path("inspect.css", IDR_INSPECT_CSS);
+ add_resource_path("inspect.js", IDR_INSPECT_JS);
+ set_default_resource(IDR_INSPECT_HTML);
+}
+
+void InspectDataSource::StartDataRequest(const std::string& path,
+ bool is_incognito,
+ int request_id) {
+ if (path != kDataFile) {
+ ChromeWebUIDataSource::StartDataRequest(path, is_incognito, request_id);
+ return;
+ }
+
+ std::set<RenderViewHost*> tab_rvhs;
+ for (TabContentsIterator it; !it.done(); ++it)
+ tab_rvhs.insert(it->web_contents()->GetRenderViewHost());
+
+ scoped_ptr<ListValue> rvh_list(new ListValue());
+
+ for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+ !it.IsAtEnd(); it.Advance()) {
+ RenderProcessHost* render_process_host = it.GetCurrentValue();
+ DCHECK(render_process_host);
+
+ // Ignore processes that don't have a connection, such as crashed tabs.
+ if (!render_process_host->HasConnection())
+ continue;
+
+ RenderProcessHost::RenderWidgetHostsIterator rwit(
+ render_process_host->GetRenderWidgetHostsIterator());
+ for (; !rwit.IsAtEnd(); rwit.Advance()) {
+ const RenderWidgetHost* widget = rwit.GetCurrentValue();
+ DCHECK(widget);
+ if (!widget || !widget->IsRenderView())
+ continue;
+
+ RenderViewHost* rvh =
+ RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
+
+ bool is_tab = tab_rvhs.find(rvh) != tab_rvhs.end();
+ rvh_list->Append(BuildTargetDescriptor(rvh, is_tab));
+ }
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&InspectDataSource::SendDescriptors,
+ this,
+ request_id,
+ base::Owned(rvh_list.release())));
+}
+
+void InspectDataSource::SendDescriptors(int request_id,
+ ListValue* rvh_list) {
+ std::vector<WorkerService::WorkerInfo> worker_info =
+ WorkerService::GetInstance()->GetWorkers();
+ for (size_t i = 0; i < worker_info.size(); ++i) {
+ rvh_list->Append(BuildTargetDescriptor(
+ kWorkerTargetType,
+ false,
+ worker_info[i].url,
+ UTF16ToUTF8(worker_info[i].name),
+ GURL(),
+ worker_info[i].process_id,
+ worker_info[i].route_id,
+ worker_info[i].handle));
+ }
+
+ std::string json_string;
+ base::JSONWriter::Write(rvh_list, &json_string);
+
+ SendResponse(request_id, base::RefCountedString::TakeString(&json_string));
+}
+
+class InspectMessageHandler : public WebUIMessageHandler {
+ public:
+ InspectMessageHandler() {}
+ virtual ~InspectMessageHandler() {}
+
+ private:
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages() OVERRIDE;
+
+ // Callback for "openDevTools" message.
+ void HandleInspectCommand(const ListValue* args);
+ void HandleTerminateCommand(const ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler);
+};
+
+void InspectMessageHandler::RegisterMessages() {
+ web_ui()->RegisterMessageCallback(kInspectCommand,
+ base::Bind(&InspectMessageHandler::HandleInspectCommand,
+ base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(kTerminateCommand,
+ base::Bind(&InspectMessageHandler::HandleTerminateCommand,
+ base::Unretained(this)));
+}
+
+void InspectMessageHandler::HandleInspectCommand(const ListValue* args) {
+ std::string process_id_str;
+ std::string route_id_str;
+ int process_id;
+ int route_id;
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &process_id_str));
+ CHECK(args->GetString(1, &route_id_str));
+ CHECK(base::StringToInt(process_id_str,
+ &process_id));
+ CHECK(base::StringToInt(route_id_str, &route_id));
+
+ Profile* profile = Profile::FromWebUI(web_ui());
+ if (!profile)
+ return;
+
+ RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
+ if (rvh) {
+ DevToolsWindow::OpenDevToolsWindow(rvh);
+ return;
+ }
+
+ DevToolsAgentHost* agent_host =
+ DevToolsAgentHostRegistry::GetDevToolsAgentHostForWorker(process_id,
+ route_id);
+ if (agent_host)
+ DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host);
+}
+
+static void TerminateWorker(int process_id, int route_id) {
+ WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
+}
+
+void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) {
+ std::string process_id_str;
+ std::string route_id_str;
+ int process_id;
+ int route_id;
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &process_id_str));
+ CHECK(args->GetString(1, &route_id_str));
+ CHECK(base::StringToInt(process_id_str,
+ &process_id));
+ CHECK(base::StringToInt(route_id_str, &route_id));
+
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&TerminateWorker, process_id, route_id));
+}
+
+} // namespace
+
+class InspectUI::WorkerCreationDestructionListener
+ : public WorkerServiceObserver,
+ public base::RefCountedThreadSafe<WorkerCreationDestructionListener> {
+ public:
+ explicit WorkerCreationDestructionListener(InspectUI* workers_ui)
+ : discovery_ui_(workers_ui) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&WorkerCreationDestructionListener::RegisterObserver,
+ this));
+ }
+
+ void InspectUIDestroyed() {
+ discovery_ui_ = NULL;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&WorkerCreationDestructionListener::UnregisterObserver,
+ this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<WorkerCreationDestructionListener>;
+ virtual ~WorkerCreationDestructionListener() {}
+
+ virtual void WorkerCreated(
+ const GURL& url,
+ const string16& name,
+ int process_id,
+ int route_id) OVERRIDE {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WorkerCreationDestructionListener::NotifyItemsChanged,
+ this));
+ }
+
+ virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WorkerCreationDestructionListener::NotifyItemsChanged,
+ this));
+ }
+
+ void NotifyItemsChanged() {
+ if (discovery_ui_)
+ discovery_ui_->RefreshUI();
+ }
+
+ void RegisterObserver() {
+ WorkerService::GetInstance()->AddObserver(this);
+ }
+
+ void UnregisterObserver() {
+ WorkerService::GetInstance()->RemoveObserver(this);
+ }
+
+ InspectUI* discovery_ui_;
+};
+
+InspectUI::InspectUI(content::WebUI* web_ui)
+ : WebUIController(web_ui),
+ observer_(new WorkerCreationDestructionListener(this)) {
+ web_ui->AddMessageHandler(new InspectMessageHandler());
+
+ InspectDataSource* html_source = new InspectDataSource();
+
+ Profile* profile = Profile::FromWebUI(web_ui);
+ profile->GetChromeURLDataManager()->AddDataSource(html_source);
+
+ registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
+ content::NotificationService::AllSources());
+ registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+ content::NotificationService::AllSources());
+ registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::NotificationService::AllSources());
+}
+
+InspectUI::~InspectUI() {
+ observer_->InspectUIDestroyed();
+ observer_ = NULL;
+}
+
+void InspectUI::RefreshUI() {
+ web_ui()->CallJavascriptFunction("populateLists");
+}
+
+void InspectUI::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ RefreshUI();
+}
« no previous file with comments | « chrome/browser/ui/webui/inspect_ui.h ('k') | chrome/browser/ui/webui/inspect_ui_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698