Bug 1046245 - enumerateDevices returns label for pages w/active gUM or persistent permissions. r=jesup
☠☠ backed out by 99c3baae746d ☠ ☠
authorJan-Ivar Bruaroey <jib@mozilla.com>
Tue, 03 Mar 2015 09:51:05 -0500
changeset 266722 2b99b193828ac8f8f66adb2803bc1b3448ede6ce
parent 266721 d1ac67faccbbaa92c68f8d9f2a5b702f32fa4c23
child 266723 2ed2b15fe94055f08517d4c8fff63ce97fe30988
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1046245
milestone39.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 1046245 - enumerateDevices returns label for pages w/active gUM or persistent permissions. r=jesup
dom/media/MediaDevices.cpp
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaDevices.cpp
+++ b/dom/media/MediaDevices.cpp
@@ -4,16 +4,17 @@
 
 #include "mozilla/dom/MediaDevices.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaDevicesBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/MediaManager.h"
 #include "nsIEventTarget.h"
 #include "nsIScriptGlobalObject.h"
+#include "nsIPermissionManager.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 class MediaDevices::GumResolver : public nsIDOMGetUserMediaSuccessCallback
 {
 public:
@@ -34,20 +35,53 @@ public:
 
 private:
   virtual ~GumResolver() {}
   nsRefPtr<Promise> mPromise;
 };
 
 class MediaDevices::EnumDevResolver : public nsIGetUserMediaDevicesSuccessCallback
 {
+  static bool HasAPersistentPermission(uint64_t aWindowId)
+  {
+    nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
+        (nsGlobalWindow::GetInnerWindowWithId(aWindowId));
+    if (NS_WARN_IF(!window)) {
+      return false;
+    }
+    // Check if this site has persistent permissions.
+    nsresult rv;
+    nsCOMPtr<nsIPermissionManager> mgr =
+      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false; // no permission manager no permissions!
+    }
+
+    uint32_t audio = nsIPermissionManager::UNKNOWN_ACTION;
+    uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
+    {
+      auto* principal = window->GetExtantDoc()->NodePrincipal();
+      rv = mgr->TestExactPermissionFromPrincipal(principal, "microphone", &audio);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+      rv = mgr->TestExactPermissionFromPrincipal(principal, "camera", &video);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return false;
+      }
+    }
+    return audio == nsIPermissionManager::ALLOW_ACTION ||
+           video == nsIPermissionManager::ALLOW_ACTION;
+  }
+
 public:
   NS_DECL_ISUPPORTS
 
-  explicit EnumDevResolver(Promise* aPromise) : mPromise(aPromise) {}
+  EnumDevResolver(Promise* aPromise, uint64_t aWindowId)
+  : mPromise(aPromise), mWindowId(aWindowId) {}
 
   NS_IMETHOD
   OnSuccess(nsIVariant* aDevices) override
   {
     // Cribbed from MediaPermissionGonk.cpp
     nsIID elementIID;
     uint16_t elementType;
 
@@ -78,29 +112,40 @@ public:
     for (auto& device : devices) {
       nsString type;
       device->GetType(type);
       bool isVideo = type.EqualsLiteral("video");
       bool isAudio = type.EqualsLiteral("audio");
       if (isVideo || isAudio) {
         MediaDeviceKind kind = isVideo ?
             MediaDeviceKind::Videoinput : MediaDeviceKind::Audioinput;
-        // TODO: return anonymized id, +label (origins w/gUM permission) (1046245)
+        nsString id;
+        nsString name;
+        device->GetId(id);
+        // Include name only if page currently has a gUM stream active or
+        // persistent permissions (audio or video) have been granted
+        if (MediaManager::Get()->IsWindowActivelyCapturing(mWindowId) ||
+            HasAPersistentPermission(mWindowId) ||
+            Preferences::GetBool("media.navigator.permission.disabled", false)) {
+          device->GetName(name);
+        }
+        // TODO: return anonymized origin-persistent id (1046245)
         nsRefPtr<MediaDeviceInfo> info = new MediaDeviceInfo(nsString(), kind,
-                                                             nsString());
+                                                             name);
         infos.AppendElement(info);
       }
     }
     mPromise->MaybeResolve(infos);
     return NS_OK;
   }
 
 private:
   virtual ~EnumDevResolver() {}
   nsRefPtr<Promise> mPromise;
+  uint64_t mWindowId;
 };
 
 class MediaDevices::GumRejecter : public nsIDOMGetUserMediaErrorCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit GumRejecter(Promise* aPromise) : mPromise(aPromise) {}
@@ -145,17 +190,17 @@ MediaDevices::GetUserMedia(const MediaSt
 already_AddRefed<Promise>
 MediaDevices::EnumerateDevices(ErrorResult &aRv)
 {
   nsPIDOMWindow* window = GetOwner();
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
   nsRefPtr<Promise> p = Promise::Create(go, aRv);
   NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
-  nsRefPtr<EnumDevResolver> resolver = new EnumDevResolver(p);
+  nsRefPtr<EnumDevResolver> resolver = new EnumDevResolver(p, window->WindowID());
   nsRefPtr<GumRejecter> rejecter = new GumRejecter(p);
 
   aRv = MediaManager::Get()->EnumerateDevices(window, resolver, rejecter);
   return p.forget();
 }
 
 NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MediaDevices, DOMEventTargetHelper)
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2363,16 +2363,34 @@ MediaManager::StopMediaStreams()
     array->GetElementAt(i, getter_AddRefs(window));
     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(window));
     if (win) {
       OnNavigation(win->WindowID());
     }
   }
 }
 
+bool
+MediaManager::IsWindowActivelyCapturing(uint64_t aWindowId)
+{
+  nsCOMPtr<nsISupportsArray> array;
+  GetActiveMediaCaptureWindows(getter_AddRefs(array));
+  uint32_t len;
+  array->Count(&len);
+  for (uint32_t i = 0; i < len; i++) {
+    nsCOMPtr<nsISupports> window;
+    array->GetElementAt(i, getter_AddRefs(window));
+    nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(window));
+    if (win && win->WindowID() == aWindowId) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void
 GetUserMediaCallbackMediaStreamListener::AudioConfig(bool aEchoOn,
               uint32_t aEcho,
               bool aAgcOn, uint32_t aAGC,
               bool aNoiseOn, uint32_t aNoise,
               int32_t aPlayoutDelay)
 {
   if (mAudioSource) {
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -598,16 +598,17 @@ public:
     uint64_t aInnerWindowID = 0);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow,
                             nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                             nsIDOMGetUserMediaErrorCallback* aOnFailure);
 
   nsresult EnumerateDevices(nsPIDOMWindow* aWindow, dom::Promise& aPromise);
   void OnNavigation(uint64_t aWindowID);
+  bool IsWindowActivelyCapturing(uint64_t aWindowId);
 
   MediaEnginePrefs mPrefs;
 
 private:
   StreamListeners* AddWindowID(uint64_t aWindowId);
   WindowTable *GetActiveWindows() {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
     return &mActiveWindows;