Bug 1208417 - Part 3 - Leverage socket-based session transport to establish presentation connection, r=schien, r=smaug
authorKuoE0 <kuoe0.tw@gmail.com>
Thu, 28 Apr 2016 15:05:53 +0800
changeset 295178 c2da65057928abc7fb07c061c0581b743a7baec1
parent 295177 4f95de9b438f19200f3399814348ea6dda563bc1
child 295179 e3245a8dfacdefc22a21261c32e5129afc725dfb
push id75837
push usergachen@mozilla.com
push dateThu, 28 Apr 2016 07:07:10 +0000
treeherdermozilla-inbound@c2da65057928 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersschien, smaug
bugs1208417
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1208417 - Part 3 - Leverage socket-based session transport to establish presentation connection, r=schien, r=smaug
dom/presentation/provider/DisplayDeviceProvider.cpp
dom/presentation/provider/DisplayDeviceProvider.h
dom/presentation/provider/MulticastDNSDeviceProvider.cpp
dom/presentation/provider/nsTCPDeviceInfo.h
--- a/dom/presentation/provider/DisplayDeviceProvider.cpp
+++ b/dom/presentation/provider/DisplayDeviceProvider.cpp
@@ -6,34 +6,63 @@
 
 #include "DisplayDeviceProvider.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
+#include "nsITCPPresentationServer.h"
 #include "nsIWindowWatcher.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsSimpleURI.h"
+#include "nsTCPDeviceInfo.h"
 #include "nsThreadUtils.h"
 
 static mozilla::LazyLogModule gDisplayDeviceProviderLog("DisplayDeviceProvider");
 
 #define LOG(format) MOZ_LOG(gDisplayDeviceProviderLog, mozilla::LogLevel::Debug, format)
 
 #define DISPLAY_CHANGED_NOTIFICATION "display-changed"
 #define DEFAULT_CHROME_FEATURES_PREF "toolkit.defaultChromeFeatures"
 #define CHROME_REMOTE_URL_PREF       "b2g.multiscreen.chrome_remote_url"
 
 namespace mozilla {
 namespace dom {
 namespace presentation {
 
+/**
+ * This wrapper is used to break circular-reference problem.
+ */
+class DisplayDeviceProviderWrappedListener final
+  : public nsITCPPresentationServerListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_FORWARD_SAFE_NSITCPPRESENTATIONSERVERLISTENER(mListener)
+
+  explicit DisplayDeviceProviderWrappedListener() = default;
+
+  nsresult SetListener(DisplayDeviceProvider* aListener)
+  {
+    mListener = aListener;
+    return NS_OK;
+  }
+
+private:
+  virtual ~DisplayDeviceProviderWrappedListener() = default;
+
+  DisplayDeviceProvider* mListener = nullptr;
+};
+
+NS_IMPL_ISUPPORTS(DisplayDeviceProviderWrappedListener,
+                  nsITCPPresentationServerListener)
+
 NS_IMPL_ISUPPORTS(DisplayDeviceProvider::HDMIDisplayDevice,
                   nsIPresentationDevice,
                   nsIPresentationLocalDevice)
 
 // nsIPresentationDevice
 NS_IMETHODIMP
 DisplayDeviceProvider::HDMIDisplayDevice::GetId(nsACString& aId)
 {
@@ -146,38 +175,58 @@ DisplayDeviceProvider::HDMIDisplayDevice
     return rv;
   }
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(DisplayDeviceProvider,
                   nsIObserver,
-                  nsIPresentationDeviceProvider)
+                  nsIPresentationDeviceProvider,
+                  nsITCPPresentationServerListener)
 
 DisplayDeviceProvider::~DisplayDeviceProvider()
 {
   Uninit();
 }
 
 nsresult
 DisplayDeviceProvider::Init()
 {
   // Provider must be initialized only once.
   if (mInitialized) {
     return NS_OK;
   }
 
+  nsresult rv;
+
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   MOZ_ASSERT(obs);
 
   obs->AddObserver(this, DISPLAY_CHANGED_NOTIFICATION, false);
 
   mDevice = new HDMIDisplayDevice(this);
 
+  mWrappedListener = new DisplayDeviceProviderWrappedListener();
+  rv = mWrappedListener->SetListener(this);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mPresentationServer = do_CreateInstance(TCP_PRESENTATION_SERVER_CONTACT_ID,
+                                          &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = StartTCPService();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   mInitialized = true;
   return NS_OK;
 }
 
 nsresult
 DisplayDeviceProvider::Uninit()
 {
   // Provider must be deleted only once.
@@ -189,16 +238,60 @@ DisplayDeviceProvider::Uninit()
   if (obs) {
     obs->RemoveObserver(this, DISPLAY_CHANGED_NOTIFICATION);
   }
 
   // Remove device from device manager when the provider is uninit
   RemoveExternalScreen();
 
   mInitialized = false;
+  mWrappedListener->SetListener(nullptr);
+  return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::StartTCPService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv;
+  rv =  mPresentationServer->SetId(NS_LITERAL_CSTRING("DisplayDeviceProvider"));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  uint16_t servicePort;
+  rv = mPresentationServer->GetPort(&servicePort);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  /*
+   * If |servicePort| is non-zero, it means PresentationServer is running.
+   * Otherwise, we should make it start serving.
+   */
+  if (!servicePort) {
+    rv = mPresentationServer->SetListener(mWrappedListener);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = mPresentationServer->StartService(0);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = mPresentationServer->GetPort(&servicePort);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  mPort = servicePort;
+
   return NS_OK;
 }
 
 nsresult
 DisplayDeviceProvider::AddExternalScreen()
 {
   MOZ_ASSERT(mDeviceListener);
 
@@ -270,16 +363,56 @@ DisplayDeviceProvider::SetListener(nsIPr
 }
 
 NS_IMETHODIMP
 DisplayDeviceProvider::ForceDiscovery()
 {
   return NS_OK;
 }
 
+// nsITCPPresentationServerListener
+NS_IMETHODIMP
+DisplayDeviceProvider::OnPortChange(uint16_t aPort)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mPort = aPort;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
+                                      const nsAString& aUrl,
+                                      const nsAString& aPresentationId,
+                                      nsIPresentationControlChannel* aControlChannel)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aDeviceInfo);
+  MOZ_ASSERT(aControlChannel);
+
+  nsresult rv;
+
+  nsCOMPtr<nsIPresentationDeviceListener> listener;
+  rv = GetListener(getter_AddRefs(listener));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  MOZ_ASSERT(!listener);
+
+  rv = listener->OnSessionRequest(mDevice,
+                                  aUrl,
+                                  aPresentationId,
+                                  aControlChannel);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 // nsIObserver
 NS_IMETHODIMP
 DisplayDeviceProvider::Observe(nsISupports* aSubject,
                                const char* aTopic,
                                const char16_t* aData)
 {
   if (!strcmp(aTopic, DISPLAY_CHANGED_NOTIFICATION)) {
     nsCOMPtr<nsIDisplayInfo> displayInfo = do_QueryInterface(aSubject);
@@ -300,19 +433,30 @@ DisplayDeviceProvider::Observe(nsISuppor
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 DisplayDeviceProvider::RequestSession(HDMIDisplayDevice* aDevice,
-                                    const nsAString& aUrl,
-                                    const nsAString& aPresentationId,
-                                    nsIPresentationControlChannel** aControlChannel)
+                                      const nsAString& aUrl,
+                                      const nsAString& aPresentationId,
+                                      nsIPresentationControlChannel** aControlChannel)
 {
-  // Implement in part 3
-  return NS_OK;
+  MOZ_ASSERT(aDevice);
+  MOZ_ASSERT(mPresentationServer);
+  NS_ENSURE_ARG_POINTER(aControlChannel);
+  *aControlChannel = nullptr;
+
+  nsCOMPtr<nsITCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
+                                                            aDevice->Address(),
+                                                            mPort);
+
+  return mPresentationServer->RequestSession(deviceInfo,
+                                             aUrl,
+                                             aPresentationId,
+                                             aControlChannel);
 }
 
 } // namespace presentation
 } // namespace dom
 } // namespace mozilla
--- a/dom/presentation/provider/DisplayDeviceProvider.h
+++ b/dom/presentation/provider/DisplayDeviceProvider.h
@@ -10,16 +10,17 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/WeakPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMWindow.h"
 #include "nsIDisplayInfo.h"
 #include "nsIObserver.h"
 #include "nsIPresentationDeviceProvider.h"
 #include "nsIPresentationLocalDevice.h"
+#include "nsITCPPresentationServer.h"
 #include "nsIWindowWatcher.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 namespace dom {
 namespace presentation {
@@ -28,88 +29,103 @@ namespace presentation {
 // widget/gonk/libdisplay/GonkDisplay.h.
 enum DisplayType {
     DISPLAY_PRIMARY,
     DISPLAY_EXTERNAL,
     DISPLAY_VIRTUAL,
     NUM_DISPLAY_TYPES
 };
 
+class DisplayDeviceProviderWrappedListener;
+
 class DisplayDeviceProvider final : public nsIObserver
                                   , public nsIPresentationDeviceProvider
+                                  , public nsITCPPresentationServerListener
                                   , public SupportsWeakPtr<DisplayDeviceProvider>
 {
 private:
   class HDMIDisplayDevice final : public nsIPresentationLocalDevice
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIPRESENTATIONDEVICE
     NS_DECL_NSIPRESENTATIONLOCALDEVICE
 
     // mScreenId is as same as the definition of display type.
     explicit HDMIDisplayDevice(DisplayDeviceProvider* aProvider)
       : mScreenId(DisplayType::DISPLAY_EXTERNAL)
       , mName("HDMI")
       , mType("external")
       , mWindowId("hdmi")
+      , mAddress("127.0.0.1")
       , mProvider(aProvider)
     {}
 
     nsresult OpenTopLevelWindow();
     nsresult CloseTopLevelWindow();
 
     const nsCString& Id() const { return mWindowId; }
+    const nsCString& Address() const { return mAddress; }
 
   private:
     virtual ~HDMIDisplayDevice() = default;
 
     // Due to the limitation of nsWinodw, mScreenId must be an integer.
     // And mScreenId is also align to the display type defined in
     // widget/gonk/libdisplay/GonkDisplay.h.
     // HDMI display is DisplayType::DISPLAY_EXTERNAL.
     uint32_t mScreenId;
     nsCString mName;
     nsCString mType;
     nsCString mWindowId;
+    nsCString mAddress;
 
     nsCOMPtr<mozIDOMWindowProxy> mWindow;
     // weak pointer
     // Provider hold a strong pointer to the device. Use weak pointer to prevent
     // the reference cycle.
     WeakPtr<DisplayDeviceProvider> mProvider;
   };
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
+  NS_DECL_NSITCPPRESENTATIONSERVERLISTENER
   // For using WeakPtr when MOZ_REFCOUNTED_LEAK_CHECKING defined
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(DisplayDeviceProvider)
 
   nsresult RequestSession(HDMIDisplayDevice* aDevice,
                           const nsAString& aUrl,
                           const nsAString& aPresentationId,
                           nsIPresentationControlChannel** aControlChannel);
 private:
   virtual ~DisplayDeviceProvider();
 
   nsresult Init();
   nsresult Uninit();
 
   nsresult AddExternalScreen();
   nsresult RemoveExternalScreen();
 
+  nsresult StartTCPService();
+
   // Now support HDMI display only and there should be only one HDMI display.
   nsCOMPtr<nsIPresentationLocalDevice> mDevice = nullptr;
   // weak pointer
   // PresentationDeviceManager (mDeviceListener) hold strong pointer to
   // DisplayDeviceProvider. Use nsWeakPtr to avoid reference cycle.
   nsWeakPtr mDeviceListener = nullptr;
+  nsCOMPtr<nsITCPPresentationServer> mPresentationServer;
+  // Used to prevent reference cycle between DisplayDeviceProvider and
+  // TCPPresentationServer.
+  RefPtr<DisplayDeviceProviderWrappedListener> mWrappedListener;
+
   bool mInitialized = false;
+  uint16_t mPort;
 };
 
 } // mozilla
 } // dom
 } // presentation
 
 #endif // mozilla_dom_presentation_provider_DisplayDeviceProvider_h
 
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsAutoPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
+#include "nsTCPDeviceInfo.h"
 #include "nsThreadUtils.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "nsIPropertyBag2.h"
 #endif // MOZ_WIDGET_ANDROID
 
 #define PREF_PRESENTATION_DISCOVERY "dom.presentation.discovery.enabled"
 #define PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS "dom.presentation.discovery.timeout_ms"
@@ -54,64 +55,16 @@ GetAndroidDeviceName(nsACString& aRetVal
   nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
   MOZ_ASSERT(infoService, "Could not find a system info service");
 
   Unused << NS_WARN_IF(NS_FAILED(infoService->GetPropertyAsACString(
                                    NS_LITERAL_STRING("device"), aRetVal)));
 }
 #endif // MOZ_WIDGET_ANDROID
 
-class TCPDeviceInfo final : public nsITCPDeviceInfo
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSITCPDEVICEINFO
-
-  explicit TCPDeviceInfo(const nsACString& aId,
-                         const nsACString& aAddress,
-                         const uint16_t aPort)
-    : mId(aId)
-    , mAddress(aAddress)
-    , mPort(aPort)
-  {
-  }
-
-private:
-  virtual ~TCPDeviceInfo() {}
-
-  nsCString mId;
-  nsCString mAddress;
-  uint16_t mPort;
-};
-
-NS_IMPL_ISUPPORTS(TCPDeviceInfo,
-                  nsITCPDeviceInfo)
-
-// nsITCPDeviceInfo
-NS_IMETHODIMP
-TCPDeviceInfo::GetId(nsACString& aId)
-{
-  aId = mId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetAddress(nsACString& aAddress)
-{
-  aAddress = mAddress;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetPort(uint16_t* aPort)
-{
-  *aPort = mPort;
-  return NS_OK;
-}
-
 } //anonymous namespace
 
 /**
  * This wrapper is used to break circular-reference problem.
  */
 class DNSServiceWrappedListener final
   : public nsIDNSServiceDiscoveryListener
   , public nsIDNSRegistrationListener
new file mode 100644
--- /dev/null
+++ b/dom/presentation/provider/nsTCPDeviceInfo.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __TCPDeviceInfo_h__
+#define __TCPDeviceInfo_h__
+
+namespace mozilla {
+namespace dom {
+namespace presentation {
+
+class TCPDeviceInfo final : public nsITCPDeviceInfo
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITCPDEVICEINFO
+
+  explicit TCPDeviceInfo(const nsACString& aId,
+                         const nsACString& aAddress,
+                         const uint16_t aPort)
+    : mId(aId)
+    , mAddress(aAddress)
+    , mPort(aPort)
+  {
+  }
+
+private:
+  virtual ~TCPDeviceInfo() {}
+
+  nsCString mId;
+  nsCString mAddress;
+  uint16_t mPort;
+};
+
+NS_IMPL_ISUPPORTS(TCPDeviceInfo,
+                  nsITCPDeviceInfo)
+
+// nsITCPDeviceInfo
+NS_IMETHODIMP
+TCPDeviceInfo::GetId(nsACString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetAddress(nsACString& aAddress)
+{
+  aAddress = mAddress;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetPort(uint16_t* aPort)
+{
+  *aPort = mPort;
+  return NS_OK;
+}
+
+}
+}
+}
+
+#endif /* !__TCPDeviceInfo_h__ */
+