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

Unified Diff: chrome/browser/devtools/devtools_targets_ui.cc

Issue 65143004: DevTools: Refactor InspectUI class for extensibility (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments, rebased Created 7 years, 1 month 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/devtools/devtools_targets_ui.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/devtools/devtools_targets_ui.cc
diff --git a/chrome/browser/devtools/devtools_targets_ui.cc b/chrome/browser/devtools/devtools_targets_ui.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2fcfeea0f5fdb5ac7171c25fd087af5b01abefee
--- /dev/null
+++ b/chrome/browser/devtools/devtools_targets_ui.cc
@@ -0,0 +1,525 @@
+// Copyright (c) 2013 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/devtools/devtools_targets_ui.h"
+
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/devtools/devtools_adb_bridge.h"
+#include "chrome/browser/devtools/devtools_target_impl.h"
+#include "chrome/browser/devtools/port_forwarding_controller.h"
+#include "content/public/browser/browser_child_process_observer.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.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/web_contents.h"
+#include "content/public/browser/worker_service.h"
+#include "content/public/browser/worker_service_observer.h"
+#include "content/public/common/process_type.h"
+#include "net/base/escape.h"
+
+using content::BrowserThread;
+using content::WebContents;
+
+namespace {
+
+const char kTargetSourceField[] = "source";
+const char kTargetSourceRenderer[] = "renderers";
+const char kTargetSourceWorker[] = "workers";
+const char kTargetSourceAdb[] = "adb";
+
+const char kTargetIdField[] = "id";
+const char kTargetTypeField[] = "type";
+const char kAttachedField[] = "attached";
+const char kUrlField[] = "url";
+const char kNameField[] = "name";
+const char kFaviconUrlField[] = "faviconUrl";
+const char kDescriptionField[] = "description";
+
+const char kGuestList[] = "guests";
+
+const char kAdbModelField[] = "adbModel";
+const char kAdbConnectedField[] = "adbConnected";
+const char kAdbSerialField[] = "adbSerial";
+const char kAdbPortStatus[] = "adbPortStatus";
+const char kAdbBrowsersList[] = "browsers";
+
+const char kAdbBrowserNameField[] = "adbBrowserName";
+const char kAdbBrowserVersionField[] = "adbBrowserVersion";
+const char kAdbBrowserChromeVersionField[] = "adbBrowserChromeVersion";
+const char kAdbPagesList[] = "pages";
+
+const char kAdbScreenWidthField[] = "adbScreenWidth";
+const char kAdbScreenHeightField[] = "adbScreenHeight";
+const char kAdbAttachedForeignField[] = "adbAttachedForeign";
+
+// RenderViewHostTargetsUIHandler ---------------------------------------------
+
+class RenderViewHostTargetsUIHandler
+ : public DevToolsTargetsUIHandler,
+ public content::NotificationObserver {
+ public:
+ explicit RenderViewHostTargetsUIHandler(Callback callback);
+ virtual ~RenderViewHostTargetsUIHandler();
+ private:
+ // content::NotificationObserver overrides.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ void UpdateTargets();
+
+ content::NotificationRegistrar notification_registrar_;
+};
+
+RenderViewHostTargetsUIHandler::RenderViewHostTargetsUIHandler(
+ Callback callback)
+ : DevToolsTargetsUIHandler(kTargetSourceRenderer, callback) {
+ notification_registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
+ content::NotificationService::AllSources());
+ notification_registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
+ content::NotificationService::AllSources());
+ notification_registrar_.Add(this,
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::NotificationService::AllSources());
+ UpdateTargets();
+}
+
+RenderViewHostTargetsUIHandler::~RenderViewHostTargetsUIHandler() {
+ notification_registrar_.RemoveAll();
+}
+
+void RenderViewHostTargetsUIHandler::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ UpdateTargets();
+}
+
+void RenderViewHostTargetsUIHandler::UpdateTargets() {
+ scoped_ptr<ListValue> list_value(new ListValue());
+
+ std::map<WebContents*, DictionaryValue*> web_contents_to_descriptor_;
+ std::vector<DevToolsTargetImpl*> guest_targets;
+
+ DevToolsTargetImpl::List targets =
+ DevToolsTargetImpl::EnumerateRenderViewHostTargets();
+
+ STLDeleteValues(&targets_);
+ for (DevToolsTargetImpl::List::iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ scoped_ptr<DevToolsTargetImpl> target(*it);
+ content::RenderViewHost* rvh = target->GetRenderViewHost();
+ if (!rvh)
+ continue;
+ WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+ if (!web_contents)
+ continue;
+
+ DevToolsTargetImpl* target_ptr = target.get();
+ targets_[target_ptr->GetId()] = target.release();
+ if (rvh->GetProcess()->IsGuest()) {
+ guest_targets.push_back(target_ptr);
+ } else {
+ DictionaryValue* descriptor = Serialize(*target_ptr);
+ list_value->Append(descriptor);
+ web_contents_to_descriptor_[web_contents] = descriptor;
+ }
+ }
+
+ // Add the list of guest-views to each of its embedders.
+ for (std::vector<DevToolsTargetImpl*>::iterator it(guest_targets.begin());
+ it != guest_targets.end(); ++it) {
+ DevToolsTargetImpl* guest = (*it);
+ WebContents* guest_web_contents =
+ WebContents::FromRenderViewHost(guest->GetRenderViewHost());
+ WebContents* embedder = guest_web_contents->GetEmbedderWebContents();
+ if (embedder && web_contents_to_descriptor_.count(embedder) > 0) {
+ DictionaryValue* parent = web_contents_to_descriptor_[embedder];
+ ListValue* guests = NULL;
+ if (!parent->GetList(kGuestList, &guests)) {
+ guests = new ListValue();
+ parent->Set(kGuestList, guests);
+ }
+ guests->Append(Serialize(*guest));
+ }
+ }
+
+ SendSerializedTargets(list_value.Pass());
+}
+
+// WorkerObserver -------------------------------------------------------------
+
+class WorkerObserver
+ : public content::WorkerServiceObserver,
+ public base::RefCountedThreadSafe<WorkerObserver> {
+ public:
+ WorkerObserver() {}
+
+ void Start(DevToolsTargetImpl::Callback callback) {
+ DCHECK(callback_.is_null());
+ DCHECK(!callback.is_null());
+ callback_ = callback;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&WorkerObserver::StartOnIOThread, this));
+ }
+
+ void Stop() {
+ DCHECK(!callback_.is_null());
+ callback_ = DevToolsTargetImpl::Callback();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&WorkerObserver::StopOnIOThread, this));
+ }
+
+ void Enumerate() {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&WorkerObserver::EnumerateOnIOThread,
+ this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<WorkerObserver>;
+ virtual ~WorkerObserver() {}
+
+ // content::WorkerServiceObserver overrides:
+ virtual void WorkerCreated(
+ const GURL& url,
+ const string16& name,
+ int process_id,
+ int route_id) OVERRIDE {
+ EnumerateOnIOThread();
+ }
+
+ virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
+ EnumerateOnIOThread();
+ }
+
+ void StartOnIOThread() {
+ content::WorkerService::GetInstance()->AddObserver(this);
+ EnumerateOnIOThread();
+ }
+
+ void StopOnIOThread() {
+ content::WorkerService::GetInstance()->RemoveObserver(this);
+ }
+
+ void EnumerateOnIOThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DevToolsTargetImpl::EnumerateWorkerTargets(
+ base::Bind(&WorkerObserver::RespondOnUIThread, this));
+ }
+
+ void RespondOnUIThread(const DevToolsTargetImpl::List& targets) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (callback_.is_null())
+ return;
+ callback_.Run(targets);
+ }
+
+ DevToolsTargetImpl::Callback callback_;
+};
+
+// WorkerTargetsUIHandler -----------------------------------------------------
+
+class WorkerTargetsUIHandler
+ : public DevToolsTargetsUIHandler,
+ public content::BrowserChildProcessObserver {
+ public:
+ explicit WorkerTargetsUIHandler(Callback callback);
+ virtual ~WorkerTargetsUIHandler();
+
+ private:
+ // content::BrowserChildProcessObserver overrides.
+ virtual void BrowserChildProcessHostConnected(
+ const content::ChildProcessData& data) OVERRIDE;
+ virtual void BrowserChildProcessHostDisconnected(
+ const content::ChildProcessData& data) OVERRIDE;
+
+ void UpdateTargets(const DevToolsTargetImpl::List& targets);
+
+ scoped_refptr<WorkerObserver> observer_;
+};
+
+WorkerTargetsUIHandler::WorkerTargetsUIHandler(Callback callback)
+ : DevToolsTargetsUIHandler(kTargetSourceWorker, callback),
+ observer_(new WorkerObserver()) {
+ observer_->Start(base::Bind(&WorkerTargetsUIHandler::UpdateTargets,
+ base::Unretained(this)));
+ BrowserChildProcessObserver::Add(this);
+}
+
+WorkerTargetsUIHandler::~WorkerTargetsUIHandler() {
+ BrowserChildProcessObserver::Remove(this);
+ observer_->Stop();
+}
+
+void WorkerTargetsUIHandler::BrowserChildProcessHostConnected(
+ const content::ChildProcessData& data) {
+ if (data.process_type == content::PROCESS_TYPE_WORKER)
+ observer_->Enumerate();
+}
+
+void WorkerTargetsUIHandler::BrowserChildProcessHostDisconnected(
+ const content::ChildProcessData& data) {
+ if (data.process_type == content::PROCESS_TYPE_WORKER)
+ observer_->Enumerate();
+}
+
+void WorkerTargetsUIHandler::UpdateTargets(
+ const DevToolsTargetImpl::List& targets) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_ptr<ListValue> list_value(new ListValue());
+ STLDeleteValues(&targets_);
+ for (DevToolsTargetImpl::List::const_iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ DevToolsTargetImpl* target = *it;
+ list_value->Append(Serialize(*target));
+ targets_[target->GetId()] = target;
+ }
+ SendSerializedTargets(list_value.Pass());
+}
+
+// AdbTargetsUIHandler --------------------------------------------------------
+
+class AdbTargetsUIHandler
+ : public DevToolsRemoteTargetsUIHandler,
+ public DevToolsAdbBridge::Listener {
+ public:
+ AdbTargetsUIHandler(Callback callback, Profile* profile);
+ virtual ~AdbTargetsUIHandler();
+
+ virtual void Open(const std::string& browser_id,
+ const std::string& url) OVERRIDE;
+
+ private:
+ // DevToolsAdbBridge::Listener overrides.
+ virtual void RemoteDevicesChanged(
+ DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE;
+
+ Profile* profile_;
+
+ typedef std::map<std::string,
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
+ RemoteBrowsers remote_browsers_;
+};
+
+AdbTargetsUIHandler::AdbTargetsUIHandler(Callback callback, Profile* profile)
+ : DevToolsRemoteTargetsUIHandler(kTargetSourceAdb, callback),
+ profile_(profile) {
+ DevToolsAdbBridge* adb_bridge =
+ DevToolsAdbBridge::Factory::GetForProfile(profile_);
+ if (adb_bridge)
+ adb_bridge->AddListener(this);
+}
+
+AdbTargetsUIHandler::~AdbTargetsUIHandler() {
+ DevToolsAdbBridge* adb_bridge =
+ DevToolsAdbBridge::Factory::GetForProfile(profile_);
+ if (adb_bridge)
+ adb_bridge->RemoveListener(this);
+}
+
+void AdbTargetsUIHandler::Open(const std::string& browser_id,
+ const std::string& url) {
+ RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
+ if (it != remote_browsers_.end())
+ it->second->Open(url);
+}
+
+void AdbTargetsUIHandler::RemoteDevicesChanged(
+ DevToolsAdbBridge::RemoteDevices* devices) {
+ PortForwardingController* port_forwarding_controller =
+ PortForwardingController::Factory::GetForProfile(profile_);
+ PortForwardingController::DevicesStatus port_forwarding_status;
+ if (port_forwarding_controller)
+ port_forwarding_status =
+ port_forwarding_controller->UpdateDeviceList(*devices);
+
+ remote_browsers_.clear();
+ STLDeleteValues(&targets_);
+
+ scoped_ptr<ListValue> device_list(new ListValue());
+ for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
+ dit != devices->end(); ++dit) {
+ DevToolsAdbBridge::RemoteDevice* device = dit->get();
+ DictionaryValue* device_data = new DictionaryValue();
+ device_data->SetString(kAdbModelField, device->GetModel());
+ device_data->SetString(kAdbSerialField, device->GetSerial());
+ device_data->SetBoolean(kAdbConnectedField, device->IsConnected());
+ std::string device_id = base::StringPrintf(
+ "device:%s",
+ device->GetSerial().c_str());
+ device_data->SetString(kTargetIdField, device_id);
+ ListValue* browser_list = new ListValue();
+ device_data->Set(kAdbBrowsersList, browser_list);
+
+ DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers();
+ for (DevToolsAdbBridge::RemoteBrowsers::iterator bit =
+ browsers.begin(); bit != browsers.end(); ++bit) {
+ DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
+ DictionaryValue* browser_data = new DictionaryValue();
+ browser_data->SetString(kAdbBrowserNameField, browser->display_name());
+ browser_data->SetString(kAdbBrowserVersionField, browser->version());
+ DevToolsAdbBridge::RemoteBrowser::ParsedVersion parsed =
+ browser->GetParsedVersion();
+ browser_data->SetInteger(
+ kAdbBrowserChromeVersionField,
+ browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
+ std::string browser_id = base::StringPrintf(
+ "browser:%s:%s:%s:%s",
+ device->GetSerial().c_str(), // Ensure uniqueness across devices.
+ browser->display_name().c_str(), // Sort by display name.
+ browser->version().c_str(), // Then by version.
+ browser->socket().c_str()); // Ensure uniqueness on the device.
+ browser_data->SetString(kTargetIdField, browser_id);
+ browser_data->SetString(kTargetSourceField, source_id());
+ remote_browsers_[browser_id] = browser;
+ ListValue* page_list = new ListValue();
+ browser_data->Set(kAdbPagesList, page_list);
+
+ DevToolsTargetImpl::List pages = browser->CreatePageTargets();
+ for (DevToolsTargetImpl::List::iterator it =
+ pages.begin(); it != pages.end(); ++it) {
+ DevToolsTargetImpl* target = *it;
+ DictionaryValue* target_data = Serialize(*target);
+ target_data->SetBoolean(
+ kAdbAttachedForeignField,
+ target->IsAttached() &&
+ !DevToolsAdbBridge::HasDevToolsWindow(target->GetId()));
+ // Pass the screen size in the target object to make sure that
+ // the caching logic does not prevent the target item from updating
+ // when the screen size changes.
+ gfx::Size screen_size = device->screen_size();
+ target_data->SetInteger(kAdbScreenWidthField, screen_size.width());
+ target_data->SetInteger(kAdbScreenHeightField, screen_size.height());
+ targets_[target->GetId()] = target;
+ page_list->Append(target_data);
+ }
+ browser_list->Append(browser_data);
+ }
+
+ if (port_forwarding_controller) {
+ PortForwardingController::DevicesStatus::iterator sit =
+ port_forwarding_status.find(device->GetSerial());
+ if (sit != port_forwarding_status.end()) {
+ DictionaryValue* port_status_dict = new DictionaryValue();
+ typedef PortForwardingController::PortStatusMap StatusMap;
+ const StatusMap& port_status = sit->second;
+ for (StatusMap::const_iterator it = port_status.begin();
+ it != port_status.end(); ++it) {
+ port_status_dict->SetInteger(
+ base::StringPrintf("%d", it->first), it->second);
+ }
+ device_data->Set(kAdbPortStatus, port_status_dict);
+ }
+ }
+
+ device_list->Append(device_data);
+ }
+ SendSerializedTargets(device_list.Pass());
+}
+
+} // namespace
+
+// DevToolsTargetsUIHandler ---------------------------------------------------
+
+DevToolsTargetsUIHandler::DevToolsTargetsUIHandler(
+ const std::string& source_id,
+ Callback callback)
+ : source_id_(source_id),
+ callback_(callback) {
+}
+
+DevToolsTargetsUIHandler::~DevToolsTargetsUIHandler() {
+ STLDeleteValues(&targets_);
+}
+
+// static
+scoped_ptr<DevToolsTargetsUIHandler>
+DevToolsTargetsUIHandler::CreateForRenderers(
+ DevToolsTargetsUIHandler::Callback callback) {
+ return scoped_ptr<DevToolsTargetsUIHandler>(
+ new RenderViewHostTargetsUIHandler(callback));
+}
+
+// static
+scoped_ptr<DevToolsTargetsUIHandler>
+DevToolsTargetsUIHandler::CreateForWorkers(
+ DevToolsTargetsUIHandler::Callback callback) {
+ return scoped_ptr<DevToolsTargetsUIHandler>(
+ new WorkerTargetsUIHandler(callback));
+}
+
+void DevToolsTargetsUIHandler::Inspect(const std::string& target_id,
+ Profile* profile) {
+ TargetMap::iterator it = targets_.find(target_id);
+ if (it != targets_.end())
+ it->second->Inspect(profile);
+}
+
+void DevToolsTargetsUIHandler::Activate(const std::string& target_id) {
+ TargetMap::iterator it = targets_.find(target_id);
+ if (it != targets_.end())
+ it->second->Activate();
+}
+
+void DevToolsTargetsUIHandler::Close(const std::string& target_id) {
+ TargetMap::iterator it = targets_.find(target_id);
+ if (it != targets_.end())
+ it->second->Close();
+}
+
+void DevToolsTargetsUIHandler::Reload(const std::string& target_id) {
+ TargetMap::iterator it = targets_.find(target_id);
+ if (it != targets_.end())
+ it->second->Reload();
+}
+
+base::DictionaryValue*
+DevToolsTargetsUIHandler::Serialize(
+ const DevToolsTargetImpl& target) {
+ DictionaryValue* target_data = new DictionaryValue();
+ target_data->SetString(kTargetSourceField, source_id_);
+ target_data->SetString(kTargetIdField, target.GetId());
+ target_data->SetString(kTargetTypeField, target.GetType());
+ target_data->SetBoolean(kAttachedField, target.IsAttached());
+ target_data->SetString(kUrlField, target.GetUrl().spec());
+ target_data->SetString(kNameField, net::EscapeForHTML(target.GetTitle()));
+ target_data->SetString(kFaviconUrlField, target.GetFaviconUrl().spec());
+ target_data->SetString(kDescriptionField, target.GetDescription());
+ return target_data;
+}
+
+void DevToolsTargetsUIHandler::SendSerializedTargets(
+ scoped_ptr<ListValue> list) {
+ callback_.Run(source_id_, list.Pass());
+}
+
+// DevToolsRemoteTargetsUIHandler ---------------------------------------------
+
+DevToolsRemoteTargetsUIHandler::DevToolsRemoteTargetsUIHandler(
+ const std::string& source_id,
+ Callback callback)
+ : DevToolsTargetsUIHandler(source_id, callback) {
+}
+
+// static
+scoped_ptr<DevToolsRemoteTargetsUIHandler>
+DevToolsRemoteTargetsUIHandler::CreateForAdb(
+ DevToolsTargetsUIHandler::Callback callback, Profile* profile) {
+ return scoped_ptr<DevToolsRemoteTargetsUIHandler>(
+ new AdbTargetsUIHandler(callback, profile));
+}
« no previous file with comments | « chrome/browser/devtools/devtools_targets_ui.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698