diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc index 2544b1ac6014..57981e391ab6 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.cc +++ b/chrome/browser/devtools/device/devtools_android_bridge.cc @@ -9,6 +9,7 @@ #include "base/base64.h" #include "base/bind.h" +#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/json/json_reader.h" #include "base/lazy_instance.h" @@ -27,12 +28,18 @@ #include "chrome/browser/devtools/device/port_forwarding_controller.h" #include "chrome/browser/devtools/device/self_device_provider.h" #include "chrome/browser/devtools/device/usb/usb_device_provider.h" +#include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" #include "chrome/browser/devtools/devtools_protocol.h" #include "chrome/browser/devtools/devtools_target_impl.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/signin/core/browser/profile_oauth2_token_service.h" +#include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_external_agent_proxy.h" #include "content/public/browser/devtools_external_agent_proxy_delegate.h" @@ -60,6 +67,11 @@ const char kPageNavigateCommand[] = "Page.navigate"; const int kMinVersionNewWithURL = 32; const int kNewPageNavigateDelayMs = 500; +bool IsWebRTCDeviceProviderEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableDevToolsExperiments); +} + } // namespace // DiscoveryRequest ----------------------------------------------------- @@ -252,13 +264,29 @@ DevToolsAndroidBridge* DevToolsAndroidBridge::Factory::GetForProfile( DevToolsAndroidBridge::Factory::Factory() : BrowserContextKeyedServiceFactory( "DevToolsAndroidBridge", - BrowserContextDependencyManager::GetInstance()) {} + BrowserContextDependencyManager::GetInstance()) { + if (IsWebRTCDeviceProviderEnabled()) { + DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); + DependsOn(SigninManagerFactory::GetInstance()); + } +} DevToolsAndroidBridge::Factory::~Factory() {} KeyedService* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new DevToolsAndroidBridge(Profile::FromBrowserContext(context)); + Profile* profile = Profile::FromBrowserContext(context); + + ProfileOAuth2TokenService* token_service = nullptr; + SigninManagerBase* signin_manager = nullptr; + + if (IsWebRTCDeviceProviderEnabled()) { + token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(profile); + signin_manager = SigninManagerFactory::GetForProfile(profile); + } + + return new DevToolsAndroidBridge( + profile, signin_manager, token_service); } // AgentHostDelegate ---------------------------------------------------------- @@ -762,8 +790,13 @@ DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() { // DevToolsAndroidBridge ------------------------------------------------------ -DevToolsAndroidBridge::DevToolsAndroidBridge(Profile* profile) +DevToolsAndroidBridge::DevToolsAndroidBridge( + Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* const token_service) : profile_(profile), + signin_manager_(signin_manager), + token_service_(token_service), device_manager_(AndroidDeviceManager::Create()), task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)), port_forwarding_controller_(new PortForwardingController(profile, this)), @@ -968,6 +1001,12 @@ void DevToolsAndroidBridge::CreateDeviceProviders() { if (pref_value->GetAsBoolean(&enabled) && enabled) { device_providers.push_back(new UsbDeviceProvider(profile_)); } + + if (IsWebRTCDeviceProviderEnabled()) { + device_providers.push_back( + new WebRTCDeviceProvider(profile_, signin_manager_, token_service_)); + } + device_manager_->SetDeviceProviders(device_providers); if (NeedsDeviceListPolling()) { StopDeviceListPolling(); diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h index e0819059c13e..674f838bca84 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.h +++ b/chrome/browser/devtools/device/devtools_android_bridge.h @@ -36,6 +36,9 @@ class BrowserContext; class DevToolsTargetImpl; class PortForwardingController; class Profile; +class WebRTCDeviceProvider; +class SigninManagerBase; +class ProfileOAuth2TokenService; class DevToolsAndroidBridge : public KeyedService { public: @@ -158,7 +161,9 @@ class DevToolsAndroidBridge : public KeyedService { virtual ~DeviceListListener() {} }; - explicit DevToolsAndroidBridge(Profile* profile); + DevToolsAndroidBridge(Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service); void AddDeviceListListener(DeviceListListener* listener); void RemoveDeviceListListener(DeviceListListener* listener); @@ -214,6 +219,7 @@ class DevToolsAndroidBridge : public KeyedService { scoped_refptr GetBrowserAgentHost( scoped_refptr browser); + private: friend struct content::BrowserThread::DeleteOnThread< content::BrowserThread::UI>; @@ -282,7 +288,9 @@ class DevToolsAndroidBridge : public KeyedService { return weak_factory_.GetWeakPtr(); } - Profile* profile_; + Profile* const profile_; + SigninManagerBase* const signin_manager_; + ProfileOAuth2TokenService* const token_service_; const scoped_ptr device_manager_; typedef std::map> diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc index fa69ad8abf92..c6f6935cf52c 100644 --- a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc +++ b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc @@ -4,59 +4,93 @@ #include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/signin/profile_identity_provider.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/url_constants.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_source.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_message_handler.h" #include "grit/webrtc_device_provider_resources_map.h" +#include "net/base/net_errors.h" +#include "net/socket/stream_socket.h" #include "ui/base/page_transition_types.h" +using content::BrowserThread; +using content::NotificationDetails; +using content::NotificationObserver; +using content::NotificationRegistrar; +using content::NotificationSource; +using content::WebContents; +using content::WebUIDataSource; +using content::WebUIMessageHandler; + +namespace { + const char kBackgroundWorkerURL[] = "chrome://webrtc-device-provider/background_worker.html"; -namespace { +} // namespace -class MessageHandler : public content::WebUIMessageHandler { +// Lives on the UI thread. +class WebRTCDeviceProvider::DevToolsBridgeClient : + private NotificationObserver, + private IdentityProvider::Observer { public: - explicit MessageHandler(WebRTCDeviceProvider* owner); + static base::WeakPtr Create( + Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service); - void RegisterMessages() override; + void DeleteSelf(); private: - void HandleLoaded(const base::ListValue* args); + DevToolsBridgeClient(Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service); - WebRTCDeviceProvider* const owner_; -}; + ~DevToolsBridgeClient(); -// MessageHandler ------------------------------------------------------------- + void CreateBackgroundWorker(); -MessageHandler::MessageHandler( - WebRTCDeviceProvider* owner) : owner_(owner) { -} + // Implementation of IdentityProvider::Observer. + void OnActiveAccountLogin() override; + void OnActiveAccountLogout() override; -void MessageHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback( - "loaded", - base::Bind(&MessageHandler::HandleLoaded, base::Unretained(this))); -} + // Implementation of NotificationObserver. + void Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) override; -void MessageHandler::HandleLoaded( - const base::ListValue* args) { - if (!owner_) - return; - // TODO(serya): implement -} + Profile* const profile_; + ProfileIdentityProvider identity_provider_; + NotificationRegistrar registrar_; + scoped_ptr background_worker_; + base::WeakPtrFactory weak_factory_; +}; -} // namespace +class WebRTCDeviceProvider::MessageHandler : public WebUIMessageHandler { + public: + explicit MessageHandler(DevToolsBridgeClient* owner); -// WebRTCDeviceProvider::WebUI ------------------------------------------------ + void RegisterMessages() override; + + private: + void HandleLoaded(const base::ListValue* args); + + DevToolsBridgeClient* const owner_; +}; + +// WebRTCDeviceProvider::WebUI ------------------------------------------------- WebRTCDeviceProvider::WebUI::WebUI(content::WebUI* web_ui) : content::WebUIController(web_ui) { Profile* profile = Profile::FromWebUI(web_ui); - content::WebUIDataSource* source = content::WebUIDataSource::Create( + WebUIDataSource* source = WebUIDataSource::Create( chrome::kChromeUIWebRTCDeviceProviderHost); for (size_t i = 0; i < kWebrtcDeviceProviderResourcesSize; i++) { @@ -69,21 +103,61 @@ WebRTCDeviceProvider::WebUI::WebUI(content::WebUI* web_ui) // a real implementation. web_ui->AddMessageHandler(new MessageHandler(nullptr)); - content::WebUIDataSource::Add(profile, source); + WebUIDataSource::Add(profile, source); } WebRTCDeviceProvider::WebUI::~WebUI() { } -// WebRTCDeviceProvider ------------------------------------------------------- +// WebRTCDeviceProvider::DevToolsBridgeClient ---------------------------------- + +// static +base::WeakPtr +WebRTCDeviceProvider::DevToolsBridgeClient::Create( + Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + auto instance = new DevToolsBridgeClient( + profile, signin_manager, token_service); + return instance->weak_factory_.GetWeakPtr(); +} -WebRTCDeviceProvider::WebRTCDeviceProvider(content::BrowserContext* context) { - background_worker_.reset(content::WebContents::Create( - content::WebContents::CreateParams(context))); +WebRTCDeviceProvider::DevToolsBridgeClient::DevToolsBridgeClient( + Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service) + : profile_(profile), + identity_provider_(signin_manager, token_service, nullptr), + weak_factory_(this) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + identity_provider_.AddObserver(this); + registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, + content::Source(profile_)); + + if (!identity_provider_.GetActiveAccountId().empty()) + CreateBackgroundWorker(); +} - // TODO(serya): Make sure background_worker_ destructed before profile. - GURL url(kBackgroundWorkerURL); +WebRTCDeviceProvider::DevToolsBridgeClient::~DevToolsBridgeClient() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + identity_provider_.RemoveObserver(this); +} + +void WebRTCDeviceProvider::DevToolsBridgeClient::DeleteSelf() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + delete this; +} + +void WebRTCDeviceProvider::DevToolsBridgeClient::CreateBackgroundWorker() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + background_worker_.reset( + WebContents::Create(WebContents::CreateParams(profile_))); + + GURL url(kBackgroundWorkerURL); DCHECK_EQ(chrome::kChromeUIWebRTCDeviceProviderHost, url.host()); background_worker_->GetController().LoadURL( @@ -96,20 +170,80 @@ WebRTCDeviceProvider::WebRTCDeviceProvider(content::BrowserContext* context) { new MessageHandler(this)); } +void WebRTCDeviceProvider::DevToolsBridgeClient::Observe( + int type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); + + delete this; +} + +void WebRTCDeviceProvider::DevToolsBridgeClient::OnActiveAccountLogin() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CreateBackgroundWorker(); +} + +void WebRTCDeviceProvider::DevToolsBridgeClient::OnActiveAccountLogout() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + background_worker_.reset(); +} + +// WebRTCDeviceProvider::MessageHandler ---------------------------------------- + +WebRTCDeviceProvider::MessageHandler::MessageHandler( + DevToolsBridgeClient* owner) : owner_(owner) { +} + +void WebRTCDeviceProvider::MessageHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "loaded", + base::Bind(&MessageHandler::HandleLoaded, base::Unretained(this))); +} + +void WebRTCDeviceProvider::MessageHandler::HandleLoaded( + const base::ListValue* args) { + if (!owner_) + return; + // TODO(serya): implement +} + +// WebRTCDeviceProvider -------------------------------------------------------- + +WebRTCDeviceProvider::WebRTCDeviceProvider( + Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service) + : client_(DevToolsBridgeClient::Create( + profile, signin_manager, token_service)) { +} + WebRTCDeviceProvider::~WebRTCDeviceProvider() { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&DevToolsBridgeClient::DeleteSelf, client_)); } void WebRTCDeviceProvider::QueryDevices(const SerialsCallback& callback) { // TODO(serya): Implement + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(callback, std::vector())); } void WebRTCDeviceProvider::QueryDeviceInfo(const std::string& serial, const DeviceInfoCallback& callback) { // TODO(serya): Implement + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(callback, AndroidDeviceManager::DeviceInfo())); } void WebRTCDeviceProvider::OpenSocket(const std::string& serial, const std::string& socket_name, const SocketCallback& callback) { // TODO(serya): Implement + scoped_ptr socket; + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(callback, net::ERR_FAILED, base::Passed(&socket))); } diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h index ee70eebd6e73..0c39ce515381 100644 --- a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h +++ b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h @@ -9,10 +9,14 @@ #include "content/public/browser/web_ui_controller.h" namespace content { -class BrowserContext; class WebUI; } +class OAuth2TokenService; +class Profile; +class ProfileOAuth2TokenService; +class SigninManagerBase; + // Provides access to remote DevTools targets over WebRTC data channel and GCD. class WebRTCDeviceProvider final : public AndroidDeviceManager::DeviceProvider { public: @@ -28,7 +32,9 @@ class WebRTCDeviceProvider final : public AndroidDeviceManager::DeviceProvider { ~WebUI() override; }; - explicit WebRTCDeviceProvider(content::BrowserContext* context); + WebRTCDeviceProvider(Profile* profile, + SigninManagerBase* signin_manager, + ProfileOAuth2TokenService* token_service); // AndroidDeviceManager::DeviceProvider implementation. void QueryDevices(const SerialsCallback& callback) override; @@ -41,9 +47,12 @@ class WebRTCDeviceProvider final : public AndroidDeviceManager::DeviceProvider { const SocketCallback& callback) override; private: + class DevToolsBridgeClient; + class MessageHandler; + ~WebRTCDeviceProvider() override; - scoped_ptr background_worker_; + const base::WeakPtr client_; DISALLOW_COPY_AND_ASSIGN(WebRTCDeviceProvider); }; diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc b/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc new file mode 100644 index 000000000000..4959a4b14a14 --- /dev/null +++ b/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc @@ -0,0 +1,52 @@ +// 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 "base/bind.h" +#include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" +#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/signin/core/browser/signin_manager.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/test/test_utils.h" + +using content::BrowserThread; +using content::MessageLoopRunner; + +class WebRTCDeviceProviderTest : public InProcessBrowserTest { + protected: + scoped_refptr CreateProvider(); + static void Unreference( + scoped_refptr provider); + + scoped_refptr provider_; +}; + +scoped_refptr +WebRTCDeviceProviderTest::CreateProvider() { + return new WebRTCDeviceProvider( + browser()->profile(), + SigninManagerFactory::GetForProfile(browser()->profile()), + ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile())); +} + +// static +void WebRTCDeviceProviderTest::Unreference( + scoped_refptr provider) { +} + +IN_PROC_BROWSER_TEST_F(WebRTCDeviceProviderTest, TestDeleteSelf) { + scoped_refptr runner = new MessageLoopRunner; + BrowserThread::PostTaskAndReply( + BrowserThread::IO, + FROM_HERE, + base::Bind(&Unreference, CreateProvider()), + runner->QuitClosure()); + runner->Run(); +} + +IN_PROC_BROWSER_TEST_F(WebRTCDeviceProviderTest, OutliveProfile) { + provider_ = CreateProvider(); +} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 4c04a90366ba..6c96fbfd8c87 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -227,6 +227,7 @@ 'browser/devtools/device/adb/adb_client_socket_browsertest.cc', 'browser/devtools/device/adb/mock_adb_server.cc', 'browser/devtools/device/adb/mock_adb_server.h', + 'browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc', 'browser/devtools/device/webrtc/webrtc_device_provider_browsertest.js', 'browser/devtools/device/port_forwarding_browsertest.cc', 'browser/devtools/device/usb/android_usb_browsertest.cc',