Bug 1177242 - Verify whether sandboxed Content process has permissions to access the camera/mic. r=jesup
authorGian-Carlo Pascutto <gcp@mozilla.com>
Wed, 17 Feb 2016 18:57:26 +0100
changeset 322842 c5d6c3e00c91dd0595a12b145c66cf4f2a890591
parent 322841 1ef77d653c4f7f5ea0452b010a9c6a85c9e87b5d
child 322843 93e0395f69fbe1242899b5e54610f4ad2d80ad27
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1177242
milestone47.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 1177242 - Verify whether sandboxed Content process has permissions to access the camera/mic. r=jesup
browser/modules/webrtcUI.jsm
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/systemservices/CamerasChild.cpp
dom/media/systemservices/CamerasChild.h
dom/media/systemservices/CamerasParent.cpp
dom/media/systemservices/CamerasParent.h
dom/media/systemservices/PCameras.ipdl
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
dom/media/webrtc/MediaEngineTabVideoSource.cpp
dom/media/webrtc/MediaEngineTabVideoSource.h
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -274,16 +274,17 @@ function getHost(uri, href) {
 }
 
 function prompt(aBrowser, aRequest) {
   let {audioDevices: audioDevices, videoDevices: videoDevices,
        sharingScreen: sharingScreen, sharingAudio: sharingAudio,
        requestTypes: requestTypes} = aRequest;
   let uri = Services.io.newURI(aRequest.documentURI, null, null);
   let host = getHost(uri);
+  let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   let chromeDoc = aBrowser.ownerDocument;
   let chromeWin = chromeDoc.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
   let stringId = "getUserMedia.share" + requestTypes.join("And") + ".message";
   let message = stringBundle.getFormattedString(stringId, [host]);
 
   let mainLabel;
   if (sharingScreen || sharingAudio) {
@@ -369,17 +370,26 @@ function prompt(aBrowser, aRequest) {
       // to avoid granting permissions automatically to background tabs.
       if (aRequest.secure) {
         let perms = Services.perms;
 
         let micPerm = perms.testExactPermission(uri, "microphone");
         if (micPerm == perms.PROMPT_ACTION)
           micPerm = perms.UNKNOWN_ACTION;
 
+        let camPermanentPerm = perms.testExactPermanentPermission(principal, "camera");
         let camPerm = perms.testExactPermission(uri, "camera");
+
+        // Session approval given but never used to allocate a camera, remove
+        // and ask again
+        if (camPerm && !camPermanentPerm) {
+          perms.remove(uri, "camera");
+          camPerm = perms.UNKNOWN_ACTION;
+        }
+
         if (camPerm == perms.PROMPT_ACTION)
           camPerm = perms.UNKNOWN_ACTION;
 
         // Screen sharing shouldn't follow the camera permissions.
         if (videoDevices.length && sharingScreen)
           camPerm = perms.UNKNOWN_ACTION;
 
         // We don't check that permissions are set to ALLOW_ACTION in this
@@ -510,21 +520,24 @@ function prompt(aBrowser, aRequest) {
 
       this.mainAction.callback = function(aRemember) {
         let allowedDevices = [];
         let perms = Services.perms;
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = chromeDoc.getElementById(listId).value;
           let allowCamera = videoDeviceIndex != "-1";
-          if (allowCamera)
+          if (allowCamera) {
             allowedDevices.push(videoDeviceIndex);
-          if (aRemember) {
-            perms.add(uri, "camera",
-                      allowCamera ? perms.ALLOW_ACTION : perms.DENY_ACTION);
+            // Session permission will be removed after use
+            // (it's really one-shot, not for the entire session)
+            perms.add(uri, "camera", perms.ALLOW_ACTION,
+                      aRemember ? perms.EXPIRE_NEVER : perms.EXPIRE_SESSION);
+          } else if (aRemember) {
+            perms.add(uri, "camera", perms.DENY_ACTION);
           }
         }
         if (audioDevices.length) {
           if (!sharingAudio) {
             let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value;
             let allowMic = audioDeviceIndex != "-1";
             if (allowMic)
               allowedDevices.push(audioDeviceIndex);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -629,23 +629,25 @@ VideoDevice::GetSource()
 
 AudioDevice::Source*
 AudioDevice::GetSource()
 {
   return static_cast<Source*>(&*mSource);
 }
 
 nsresult VideoDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
-                               const MediaEnginePrefs &aPrefs) {
-  return GetSource()->Allocate(aConstraints, aPrefs, mID);
+                               const MediaEnginePrefs &aPrefs,
+                               const nsACString& aOrigin) {
+  return GetSource()->Allocate(aConstraints, aPrefs, mID, aOrigin);
 }
 
 nsresult AudioDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
-                               const MediaEnginePrefs &aPrefs) {
-  return GetSource()->Allocate(aConstraints, aPrefs, mID);
+                               const MediaEnginePrefs &aPrefs,
+                               const nsACString& aOrigin) {
+  return GetSource()->Allocate(aConstraints, aPrefs, mID, aOrigin);
 }
 
 nsresult VideoDevice::Restart(const dom::MediaTrackConstraints &aConstraints,
                               const MediaEnginePrefs &aPrefs) {
   return GetSource()->Restart(aConstraints, aPrefs, mID);
 }
 
 nsresult AudioDevice::Restart(const dom::MediaTrackConstraints &aConstraints,
@@ -1198,26 +1200,28 @@ public:
     MOZ_ASSERT(mDeviceChosen);
 
     // Allocate a video or audio device and return a MediaStream via
     // a GetUserMediaStreamRunnable.
 
     nsresult rv;
 
     if (mAudioDevice) {
-      rv = mAudioDevice->Allocate(GetInvariant(mConstraints.mAudio), mPrefs);
+      rv = mAudioDevice->Allocate(GetInvariant(mConstraints.mAudio),
+                                  mPrefs, mOrigin);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate audiosource %d",rv));
         Fail(NS_LITERAL_STRING("SourceUnavailableError"),
              NS_LITERAL_STRING("Failed to allocate audiosource"));
         return;
       }
     }
     if (mVideoDevice) {
-      rv = mVideoDevice->Allocate(GetInvariant(mConstraints.mVideo), mPrefs);
+      rv = mVideoDevice->Allocate(GetInvariant(mConstraints.mVideo),
+                                  mPrefs, mOrigin);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate videosource %d\n",rv));
         if (mAudioDevice) {
           mAudioDevice->GetSource()->Deallocate();
         }
         Fail(NS_LITERAL_STRING("SourceUnavailableError"),
              NS_LITERAL_STRING("Failed to allocate videosource"));
         return;
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -89,31 +89,33 @@ class VideoDevice : public MediaDevice
 {
 public:
   typedef MediaEngineVideoSource Source;
 
   explicit VideoDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
   Source* GetSource();
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
-                    const MediaEnginePrefs &aPrefs);
+                    const MediaEnginePrefs &aPrefs,
+                    const nsACString& aOrigin);
   nsresult Restart(const dom::MediaTrackConstraints &aConstraints,
                    const MediaEnginePrefs &aPrefs);
 };
 
 class AudioDevice : public MediaDevice
 {
 public:
   typedef MediaEngineAudioSource Source;
 
   explicit AudioDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
   Source* GetSource();
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
-                    const MediaEnginePrefs &aPrefs);
+                    const MediaEnginePrefs &aPrefs,
+                    const nsACString& aOrigin);
   nsresult Restart(const dom::MediaTrackConstraints &aConstraints,
                    const MediaEnginePrefs &aPrefs);
 };
 
 /**
  * This class is an implementation of MediaStreamListener. This is used
  * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
  * are assigned and deassigned in content.
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -346,23 +346,25 @@ CamerasChild::RecvReplyGetCaptureDevice(
   monitor.Notify();
   return true;
 }
 
 int
 CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
                                     const char* unique_idUTF8,
                                     const unsigned int unique_idUTF8Length,
-                                    int& capture_id)
+                                    int& capture_id,
+                                    const nsACString& aOrigin)
 {
   LOG((__PRETTY_FUNCTION__));
   nsCString unique_id(unique_idUTF8);
+  nsCString origin(aOrigin);
   nsCOMPtr<nsIRunnable> runnable =
-    media::NewRunnableFrom([this, aCapEngine, unique_id]() -> nsresult {
-      if (this->SendAllocateCaptureDevice(aCapEngine, unique_id)) {
+    media::NewRunnableFrom([this, aCapEngine, unique_id, origin]() -> nsresult {
+      if (this->SendAllocateCaptureDevice(aCapEngine, unique_id, origin)) {
         return NS_OK;
       }
       return NS_ERROR_FAILURE;
     });
   LockAndDispatch<> dispatcher(this, __func__, runnable);
   if (dispatcher.Success()) {
     LOG(("Capture Device allocated: %d", mReplyInteger));
     capture_id = mReplyInteger;
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -176,17 +176,18 @@ public:
                            const int capture_id);
   int StartCapture(CaptureEngine aCapEngine,
                    const int capture_id, webrtc::CaptureCapability& capability,
                    webrtc::ExternalRenderer* func);
   int StopCapture(CaptureEngine aCapEngine, const int capture_id);
   int AllocateCaptureDevice(CaptureEngine aCapEngine,
                             const char* unique_idUTF8,
                             const unsigned int unique_idUTF8Length,
-                            int& capture_id);
+                            int& capture_id,
+                            const nsACString& aOrigin);
   int GetCaptureCapability(CaptureEngine aCapEngine,
                            const char* unique_idUTF8,
                            const unsigned int capability_number,
                            webrtc::CaptureCapability& capability);
   int GetCaptureDevice(CaptureEngine aCapEngine,
                        unsigned int list_number, char* device_nameUTF8,
                        const unsigned int device_nameUTF8Length,
                        char* unique_idUTF8,
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -6,20 +6,24 @@
 
 #include "CamerasParent.h"
 #include "CamerasUtils.h"
 #include "MediaEngine.h"
 #include "MediaUtils.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
+#include "mozilla/Services.h"
 #include "mozilla/Logging.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/Preferences.h"
+#include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
+#include "nsNetUtil.h"
 
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 
 #undef LOG
 #undef LOG_ENABLED
 mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
 #define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
@@ -636,49 +640,137 @@ CamerasParent::RecvGetCaptureDevice(cons
         });
       self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
       return NS_OK;
     });
   DispatchToVideoCaptureThread(webrtc_runnable);
   return true;
 }
 
+static nsresult
+GetPrincipalFromOrigin(const nsACString& aOrigin, nsIPrincipal** aPrincipal)
+{
+  nsAutoCString originNoSuffix;
+  mozilla::PrincipalOriginAttributes attrs;
+  if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+  principal.forget(aPrincipal);
+  return NS_OK;
+}
+
+// Find out whether the given origin has permission to use the
+// camera. If the permission is not persistent, we'll make it
+// a one-shot by removing the (session) permission.
+static bool
+HasCameraPermission(const nsCString& aOrigin)
+{
+  // Name used with nsIPermissionManager
+  static const char* cameraPermission = "camera";
+  bool allowed = false;
+  bool permanent = false;
+  nsresult rv;
+  nsCOMPtr<nsIPermissionManager> mgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsIIOService> ioServ(do_GetIOService());
+    nsCOMPtr<nsIURI> uri;
+    rv = ioServ->NewURI(aOrigin, nullptr, nullptr, getter_AddRefs(uri));
+    if (NS_SUCCEEDED(rv)) {
+      // Permanent permissions are only retrievable via principal, not uri
+      nsCOMPtr<nsIPrincipal> principal;
+      rv = GetPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
+      if (NS_SUCCEEDED(rv)) {
+        uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
+        rv = mgr->TestExactPermissionFromPrincipal(principal,
+                                                   cameraPermission,
+                                                   &video);
+        if (NS_SUCCEEDED(rv)) {
+          allowed = (video == nsIPermissionManager::ALLOW_ACTION);
+          // Was allowed, now see if this is a persistent permission
+          // or a session one.
+          if (allowed) {
+            rv = mgr->TestExactPermanentPermission(principal,
+                                                   cameraPermission,
+                                                   &video);
+            if (NS_SUCCEEDED(rv)) {
+              permanent = (video == nsIPermissionManager::ALLOW_ACTION);
+            }
+          }
+        }
+        // Session permissions are removed after one use.
+        if (allowed && !permanent) {
+          mgr->RemoveFromPrincipal(principal, cameraPermission);
+        }
+      }
+    }
+  }
+  return allowed;
+}
+
 bool
 CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
-                                         const nsCString& unique_id)
+                                         const nsCString& unique_id,
+                                         const nsCString& aOrigin)
 {
-  LOG((__PRETTY_FUNCTION__));
-
+  LOG(("%s: Verifying permissions for %s", __PRETTY_FUNCTION__, aOrigin.get()));
   RefPtr<CamerasParent> self(this);
-  RefPtr<nsRunnable> webrtc_runnable =
-    media::NewRunnableFrom([self, aCapEngine, unique_id]() -> nsresult {
-      int numdev = -1;
-      int error = -1;
-      if (self->EnsureInitialized(aCapEngine)) {
-        error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
-          unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
+  RefPtr<nsRunnable> mainthread_runnable =
+    media::NewRunnableFrom([self, aCapEngine, unique_id, aOrigin]() -> nsresult {
+      // Verify whether the claimed origin has received permission
+      // to use the camera, either persistently or this session (one shot).
+      bool allowed = HasCameraPermission(aOrigin);
+      if (!allowed) {
+        // Developer preference for turning off permission check.
+        if (Preferences::GetBool("media.navigator.permission.disabled", false)
+            || Preferences::GetBool("media.navigator.permission.fake")) {
+          allowed = true;
+          LOG(("No permission but checks are disabled or fake sources active"));
+        } else {
+          LOG(("No camera permission for this origin"));
+        }
       }
-      RefPtr<nsIRunnable> ipc_runnable =
-        media::NewRunnableFrom([self, numdev, error]() -> nsresult {
-          if (self->IsShuttingDown()) {
-            return NS_ERROR_FAILURE;
-          }
-          if (error) {
-            Unused << self->SendReplyFailure();
-            return NS_ERROR_FAILURE;
-          } else {
-            LOG(("Allocated device nr %d", numdev));
-            Unused << self->SendReplyAllocateCaptureDevice(numdev);
-            return NS_OK;
-          }
+      // After retrieving the permission (or not) on the main thread,
+      // bounce to the WebRTC thread to allocate the device (or not),
+      // then bounce back to the IPC thread for the reply to content.
+      RefPtr<nsRunnable> webrtc_runnable =
+      media::NewRunnableFrom([self, allowed, aCapEngine, unique_id]() -> nsresult {
+        int numdev = -1;
+        int error = -1;
+        if (allowed && self->EnsureInitialized(aCapEngine)) {
+          error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
+                    unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
+        }
+        RefPtr<nsIRunnable> ipc_runnable =
+          media::NewRunnableFrom([self, numdev, error]() -> nsresult {
+            if (self->IsShuttingDown()) {
+              return NS_ERROR_FAILURE;
+            }
+            if (error) {
+              Unused << self->SendReplyFailure();
+              return NS_ERROR_FAILURE;
+            } else {
+              LOG(("Allocated device nr %d", numdev));
+              Unused << self->SendReplyAllocateCaptureDevice(numdev);
+              return NS_OK;
+            }
+          });
+        self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
+        return NS_OK;
         });
-      self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
+      self->DispatchToVideoCaptureThread(webrtc_runnable);
       return NS_OK;
     });
-  DispatchToVideoCaptureThread(webrtc_runnable);
+  NS_DispatchToMainThread(mainthread_runnable);
   return true;
 }
 
 int
 CamerasParent::ReleaseCaptureDevice(const int& aCapEngine,
                                     const int& capnum)
 {
   int error = -1;
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -81,17 +81,17 @@ class CamerasParent :  public PCamerasPa
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
 public:
   static already_AddRefed<CamerasParent> Create();
 
   // Messages received form the child. These run on the IPC/PBackground thread.
-  virtual bool RecvAllocateCaptureDevice(const int&, const nsCString&) override;
+  virtual bool RecvAllocateCaptureDevice(const int&, const nsCString&, const nsCString&) override;
   virtual bool RecvReleaseCaptureDevice(const int&, const int &) override;
   virtual bool RecvNumberOfCaptureDevices(const int&) override;
   virtual bool RecvNumberOfCapabilities(const int&, const nsCString&) override;
   virtual bool RecvGetCaptureCapability(const int&, const nsCString&, const int&) override;
   virtual bool RecvGetCaptureDevice(const int&, const int&) override;
   virtual bool RecvStartCapture(const int&, const int&, const CaptureCapability&) override;
   virtual bool RecvStopCapture(const int&, const int&) override;
   virtual bool RecvReleaseFrame(mozilla::ipc::Shmem&&) override;
--- a/dom/media/systemservices/PCameras.ipdl
+++ b/dom/media/systemservices/PCameras.ipdl
@@ -40,17 +40,17 @@ child:
 
 parent:
   async NumberOfCaptureDevices(int engine);
   async NumberOfCapabilities(int engine, nsCString deviceUniqueIdUTF8);
 
   async GetCaptureCapability(int engine, nsCString unique_idUTF8, int capability_number);
   async GetCaptureDevice(int engine, int num);
 
-  async AllocateCaptureDevice(int engine, nsCString unique_idUTF8);
+  async AllocateCaptureDevice(int engine, nsCString unique_idUTF8, nsCString origin);
   async ReleaseCaptureDevice(int engine, int numdev);
   async StartCapture(int engine, int numdev, CaptureCapability capability);
   async StopCapture(int engine, int numdev);
   // transfers frame back
   async ReleaseFrame(Shmem s);
 
   // Ask parent to delete us
   async AllDone();
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -166,17 +166,18 @@ public:
 
   void SetHasFakeTracks(bool aHasFakeTracks) {
     mHasFakeTracks = aHasFakeTracks;
   }
 
   /* This call reserves but does not start the device. */
   virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                             const MediaEnginePrefs &aPrefs,
-                            const nsString& aDeviceId) = 0;
+                            const nsString& aDeviceId,
+                            const nsACString& aOrigin) = 0;
 
   virtual uint32_t GetBestFitnessDistance(
       const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets,
       const nsString& aDeviceId) = 0;
 
 protected:
   // Only class' own members can be initialized in constructor initializer list.
   explicit MediaEngineSource(MediaEngineState aState)
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -82,17 +82,18 @@ MediaEngineDefaultVideoSource::GetBestFi
   }
 #endif
   return distance;
 }
 
 nsresult
 MediaEngineDefaultVideoSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs,
-                                        const nsString& aDeviceId)
+                                        const nsString& aDeviceId,
+                                        const nsACString& aOrigin)
 {
   if (mState != kReleased) {
     return NS_ERROR_FAILURE;
   }
 
   mOpts = aPrefs;
   mOpts.mWidth = mOpts.mWidth ? mOpts.mWidth : MediaEngine::DEFAULT_43_VIDEO_WIDTH;
   mOpts.mHeight = mOpts.mHeight ? mOpts.mHeight : MediaEngine::DEFAULT_43_VIDEO_HEIGHT;
@@ -391,17 +392,18 @@ MediaEngineDefaultAudioSource::GetBestFi
   }
 #endif
   return distance;
 }
 
 nsresult
 MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                         const MediaEnginePrefs &aPrefs,
-                                        const nsString& aDeviceId)
+                                        const nsString& aDeviceId,
+                                        const nsACString& aOrigin)
 {
   if (mState != kReleased) {
     return NS_ERROR_FAILURE;
   }
 
   mState = kAllocated;
   // generate sine wave (default 1KHz)
   mSineGenerator = new SineWaveGenerator(AUDIO_RATE,
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -40,17 +40,18 @@ public:
 
   void Shutdown() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
   void NotifyPull(MediaStreamGraph* aGraph,
@@ -109,17 +110,18 @@ public:
 
   void Shutdown() override {};
 
   void GetName(nsAString&) override;
   void GetUUID(nsACString&) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
                     const MediaEnginePrefs &aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
   void AppendToSegment(AudioSegment& aSegment, TrackTicks aSamples);
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -95,17 +95,18 @@ MediaEngineRemoteVideoSource::Shutdown()
   mState = kReleased;
   mInitDone = false;
   return;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints,
                                        const MediaEnginePrefs& aPrefs,
-                                       const nsString& aDeviceId)
+                                       const nsString& aDeviceId,
+                                       const nsACString& aOrigin)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
 
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
@@ -115,21 +116,22 @@ MediaEngineRemoteVideoSource::Allocate(c
     // (This may change depending on spec changes for Constraints/settings)
 
     if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) {
       return NS_ERROR_UNEXPECTED;
     }
 
     if (mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::AllocateCaptureDevice,
-      mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex)) {
+      mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex, aOrigin)) {
       return NS_ERROR_FAILURE;
     }
     mState = kAllocated;
-    LOG(("Video device %d allocated", mCaptureIndex));
+    LOG(("Video device %d allocated for %s", mCaptureIndex,
+         PromiseFlatCString(aOrigin).get()));
   } else if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
     MonitorAutoLock lock(mMonitor);
     if (mSources.IsEmpty()) {
       LOG(("Video device %d reallocated", mCaptureIndex));
     } else {
       LOG(("Video device %d allocated shared", mCaptureIndex));
     }
   }
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -68,17 +68,18 @@ public:
 
   // MediaEngineCameraVideoSource
   MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine,
                                dom::MediaSourceEnum aMediaSource,
                                const char* aMonitorName = "RemoteVideo.Monitor");
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;;
   nsresult Start(SourceMediaStream*, TrackID) override;
   nsresult Stop(SourceMediaStream*, TrackID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void NotifyPull(MediaStreamGraph* aGraph,
                   SourceMediaStream* aSource,
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -123,17 +123,18 @@ MediaEngineTabVideoSource::GetUUID(nsACS
 
 #define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096
 #define DEFAULT_TABSHARE_VIDEO_MAX_HEIGHT 4096
 #define DEFAULT_TABSHARE_VIDEO_FRAMERATE 30
 
 nsresult
 MediaEngineTabVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints,
                                     const MediaEnginePrefs& aPrefs,
-                                    const nsString& aDeviceId)
+                                    const nsString& aDeviceId,
+                                    const nsACString& aOrigin)
 {
   // windowId is not a proper constraint, so just read it.
   // It has no well-defined behavior in advanced, so ignore it there.
 
   mWindowId = aConstraints.mBrowserWindow.WasPassed() ?
               aConstraints.mBrowserWindow.Value() : -1;
 
   return Restart(aConstraints, aPrefs, aDeviceId);
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -18,17 +18,18 @@ class MediaEngineTabVideoSource : public
     NS_DECL_NSITIMERCALLBACK
     MediaEngineTabVideoSource();
 
     void Shutdown() override {};
     void GetName(nsAString_internal&) override;
     void GetUUID(nsACString_internal&) override;
     nsresult Allocate(const dom::MediaTrackConstraints &,
                       const mozilla::MediaEnginePrefs&,
-                      const nsString& aDeviceId) override;
+                      const nsString& aDeviceId,
+                      const nsACString& aOrigin) override;
     nsresult Deallocate() override;
     nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     void SetDirectListeners(bool aHasDirectListeners) override {};
     void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime) override;
     nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID) override;
     nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                      const mozilla::MediaEnginePrefs& aPrefs,
                      const nsString& aDeviceId) override;
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -67,17 +67,18 @@ public:
   explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid)
     : MediaEngineAudioSource(kReleased)
   {
   }
   void GetName(nsAString& aName) override;
   void GetUUID(nsACString& aUUID) override;
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     return NS_OK;
   }
   nsresult Deallocate() override
   {
     // Nothing to do here, everything is managed in MediaManager.cpp
     return NS_OK;
@@ -430,17 +431,18 @@ public:
     Init();
   }
 
   void GetName(nsAString& aName) override;
   void GetUUID(nsACString& aUUID) override;
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
-                    const nsString& aDeviceId) override;
+                    const nsString& aDeviceId,
+                    const nsACString& aOrigin) override;
   nsresult Deallocate() override;
   nsresult Start(SourceMediaStream* aStream, TrackID aID) override;
   nsresult Stop(SourceMediaStream* aSource, TrackID aID) override;
   nsresult Restart(const dom::MediaTrackConstraints& aConstraints,
                    const MediaEnginePrefs &aPrefs,
                    const nsString& aDeviceId) override;
   void SetDirectListeners(bool aHasDirectListeners) override {};
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -215,17 +215,18 @@ uint32_t MediaEngineWebRTCMicrophoneSour
     break; // distance is read from first entry only
   }
   return distance;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints,
                                             const MediaEnginePrefs &aPrefs,
-                                            const nsString& aDeviceId)
+                                            const nsString& aDeviceId,
+                                            const nsACString& aOrigin)
 {
   AssertIsOnOwningThread();
   if (mState == kReleased) {
     if (mInitDone) {
       if (mAudioInput->SetRecordingDevice(mCapIndex)) {
         return NS_ERROR_FAILURE;
       }
       mState = kAllocated;