Bug 1046245 - enumerateDevices returns label for pages w/active gUM or persistent permissions. r=jesup
☠☠ backed out by d2f789b62177 ☠ ☠
authorJan-Ivar Bruaroey <jib@mozilla.com>
Tue, 03 Mar 2015 09:51:05 -0500
changeset 265220 e966a5df87b6b7c971c20b7868ed2c5939041b70
parent 265219 609f3ca64004a62e4a8d1bea24aa779104e7e46f
child 265221 5bfb9a1c055085ccccff9384d556c09dd39bc526
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [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;