Bug 1317927 - Media caching needs to use origin attributes, r=cpearce, r=jesup
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 07 Dec 2016 07:07:09 -1000
changeset 325387 4ed75a24f8b5bd3b400ec44a5c3a3a48575347ff
parent 325386 d3bd1851509f1619ad5be143d1aff50d6a39a004
child 325388 653e7327b3f835cdc42de5632f8831f1616fcddc
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerscpearce, jesup
bugs1317927
milestone53.0a1
Bug 1317927 - Media caching needs to use origin attributes, r=cpearce, r=jesup
caps/BasePrincipal.cpp
caps/BasePrincipal.h
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/eme/CDMProxy.h
dom/media/eme/MediaKeys.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.h
dom/media/gmp/GMPCDMProxy.cpp
dom/media/gmp/GMPCDMProxy.h
dom/media/gmp/GMPServiceChild.cpp
dom/media/gmp/GMPServiceChild.h
dom/media/gmp/GMPServiceParent.cpp
dom/media/gmp/GMPServiceParent.h
dom/media/gmp/PGMPService.ipdl
dom/media/gmp/mozIGeckoMediaPluginService.idl
dom/media/gtest/TestGMPCrossOrigin.cpp
dom/media/systemservices/MediaChild.cpp
dom/media/systemservices/MediaChild.h
dom/media/systemservices/MediaParent.cpp
dom/media/systemservices/MediaParent.h
dom/media/systemservices/PMedia.ipdl
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -346,16 +346,29 @@ OriginAttributes::IsFirstPartyEnabled()
   if (!sCachedFirstPartyPref) {
     sCachedFirstPartyPref = true;
     Preferences::AddBoolVarCache(&sFirstPartyIsolation, "privacy.firstparty.isolate");
   }
 
   return sFirstPartyIsolation;
 }
 
+/* static */
+bool
+OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin)
+{
+  nsAutoCString dummy;
+  PrincipalOriginAttributes attrs;
+  if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) {
+    return false;
+  }
+
+  return !!attrs.mPrivateBrowsingId;
+}
+
 BasePrincipal::BasePrincipal()
 {}
 
 BasePrincipal::~BasePrincipal()
 {}
 
 NS_IMETHODIMP
 BasePrincipal::GetOrigin(nsACString& aOrigin)
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -63,16 +63,20 @@ public:
   // flags. Once all other flags are removed, this can be removed too.
   void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
 
   void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
 
   // check if "privacy.firstparty.isolate" is enabled.
   static bool IsFirstPartyEnabled();
 
+  // returns true if the originAttributes suffix has mPrivateBrowsingId value
+  // different than 0.
+  static bool IsPrivateBrowsing(const nsACString& aOrigin);
+
 protected:
   OriginAttributes() {}
   explicit OriginAttributes(const OriginAttributesDictionary& aOther)
     : OriginAttributesDictionary(aOther) {}
 };
 
 class PrincipalOriginAttributes;
 class DocShellOriginAttributes;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1225,20 +1225,20 @@ public:
         new MediaOperationTask(MEDIA_START, mListener, domStream,
                                tracksAvailableCallback,
                                mAudioDevice, mVideoDevice,
                                false, mWindowID, mOnFailure.forget());
     MediaManager::PostTask(mediaOperation.forget());
     // We won't need mOnFailure now.
     mOnFailure = nullptr;
 
-    if (!MediaManager::IsPrivateBrowsing(window)) {
+    if (!OriginAttributes::IsPrivateBrowsing(mOrigin)) {
       // Call GetOriginKey again, this time w/persist = true, to promote
       // deviceIds to persistent, in case they're not already. Fire'n'forget.
-      RefPtr<Pledge<nsCString>> p = media::GetOriginKey(mOrigin, false, true);
+      RefPtr<Pledge<nsCString>> p = media::GetOriginKey(mOrigin, true);
     }
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   MediaStreamConstraints mConstraints;
@@ -1929,23 +1929,16 @@ MediaManager::NotifyRecordingStatusChang
                                                                    requestURL,
                                                                    aIsAudio,
                                                                    aIsVideo);
   }
 
   return NS_OK;
 }
 
-bool MediaManager::IsPrivateBrowsing(nsPIDOMWindowInner* window)
-{
-  nsCOMPtr<nsIDocument> doc = window->GetDoc();
-  nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
-  return loadContext && loadContext->UsePrivateBrowsing();
-}
-
 int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
 {
   bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
   MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
     RefPtr<MediaManager> manager = MediaManager_GetInstance();
     manager->GetBackend(0)->AddDeviceChangeCallback(manager);
     if (fakeDeviceChangeEventOn)
       manager->GetBackend(0)->SetFakeDeviceChangeEvents();
@@ -2492,33 +2485,31 @@ MediaManager::EnumerateDevicesImpl(uint6
   RefPtr<PledgeSourceSet> pledge = new PledgeSourceSet();
   uint32_t id = mOutstandingPledges.Append(*pledge);
 
   // To get a device list anonymized for a particular origin, we must:
   // 1. Get an origin-key (for either regular or private browsing)
   // 2. Get the raw devices list
   // 3. Anonymize the raw list with the origin-key.
 
-  bool privateBrowsing = IsPrivateBrowsing(window);
   nsCOMPtr<nsIPrincipal> principal =
     nsGlobalWindow::Cast(window)->GetPrincipal();
   MOZ_ASSERT(principal);
 
   nsAutoCString origin;
   principal->GetOrigin(origin);
 
   bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);
 
   // GetOriginKey is an async API that returns a pledge (a promise-like
   // pattern). We use .Then() to pass in a lambda to run back on this same
   // thread later once GetOriginKey resolves. Needed variables are "captured"
   // (passed by value) safely into the lambda.
 
-  RefPtr<Pledge<nsCString>> p = media::GetOriginKey(origin, privateBrowsing,
-                                                      persist);
+  RefPtr<Pledge<nsCString>> p = media::GetOriginKey(origin, persist);
   p->Then([id, aWindowId, aVideoType, aAudioType,
            aFake](const nsCString& aOriginKey) mutable {
     MOZ_ASSERT(NS_IsMainThread());
     RefPtr<MediaManager> mgr = MediaManager_GetInstance();
 
     RefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId, aVideoType,
                                                          aAudioType, aFake);
     p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable {
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -252,17 +252,16 @@ public:
 
   nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow, dom::Promise& aPromise);
   void OnNavigation(uint64_t aWindowID);
   bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
 
   MediaEnginePrefs mPrefs;
 
   typedef nsTArray<RefPtr<MediaDevice>> SourceSet;
-  static bool IsPrivateBrowsing(nsPIDOMWindowInner* window);
 
   virtual int AddDeviceChangeCallback(DeviceChangeCallback* aCallback) override;
   virtual void OnDeviceChange() override;
 private:
   typedef media::Pledge<SourceSet*, dom::MediaStreamError*> PledgeSourceSet;
   typedef media::Pledge<const char*, dom::MediaStreamError*> PledgeChar;
   typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
 
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -90,18 +90,17 @@ public:
   {}
 
   // Main thread only.
   // Loads the CDM corresponding to mKeySystem.
   // Calls MediaKeys::OnCDMCreated() when the CDM is created.
   virtual void Init(PromiseId aPromiseId,
                     const nsAString& aOrigin,
                     const nsAString& aTopLevelOrigin,
-                    const nsAString& aName,
-                    bool aInPrivateBrowsing) = 0;
+                    const nsAString& aName) = 0;
 
   virtual void OnSetDecryptorId(uint32_t aId) {}
 
   // Main thread only.
   // Uses the CDM to create a key session.
   // Calls MediaKeys::OnSessionActivated() when session is created.
   // Assumes ownership of (Move()s) aInitData's contents.
   virtual void CreateSession(uint32_t aCreateSessionToken,
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -404,41 +404,36 @@ MediaKeys::Init(ErrorResult& aRv)
   nsAutoCString topLevelOrigin;
   rv = mTopLevelPrincipal->GetOrigin(topLevelOrigin);
   if (NS_FAILED(rv)) {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
                          NS_LITERAL_CSTRING("Couldn't get top-level principal origin string in MediaKeys::Init"));
     return promise.forget();
   }
 
-  nsIDocument* doc = window->GetExtantDoc();
-  const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
-
-  EME_LOG("MediaKeys[%p]::Create() (%s, %s), %s",
+  EME_LOG("MediaKeys[%p]::Create() (%s, %s)",
           this,
           origin.get(),
-          topLevelOrigin.get(),
-          (inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
+          topLevelOrigin.get());
 
   // The CDMProxy's initialization is asynchronous. The MediaKeys is
   // refcounted, and its instance is returned to JS by promise once
   // it's been initialized. No external refs exist to the MediaKeys while
   // we're waiting for the promise to be resolved, so we must hold a
   // reference to the new MediaKeys object until it's been created,
   // or its creation has failed. Store the id of the promise returned
   // here, and hold a self-reference until that promise is resolved or
   // rejected.
   MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!");
   mCreatePromiseId = StorePromise(promise);
   AddRef();
   mProxy->Init(mCreatePromiseId,
                NS_ConvertUTF8toUTF16(origin),
                NS_ConvertUTF8toUTF16(topLevelOrigin),
-               KeySystemToGMPName(mKeySystem),
-               inPrivateBrowsing);
+               KeySystemToGMPName(mKeySystem));
 
   return promise.forget();
 }
 
 void
 MediaKeys::OnCDMCreated(PromiseId aId, const uint32_t aPluginId)
 {
   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
@@ -41,26 +41,24 @@ MediaDrmCDMProxy::~MediaDrmCDMProxy()
 {
   MOZ_COUNT_DTOR(MediaDrmCDMProxy);
 }
 
 void
 MediaDrmCDMProxy::Init(PromiseId aPromiseId,
                        const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
-                       const nsAString& aName,
-                       bool aInPrivateBrowsing)
+                       const nsAString& aName)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
 
   EME_LOG("MediaDrmCDMProxy::Init (%s, %s) %s",
           NS_ConvertUTF16toUTF8(aOrigin).get(),
-          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
-          (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
+          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
 
   // Create a thread to work with cdm.
   if (!mOwnerThread) {
     nsresult rv = NS_NewNamedThread("MDCDMThread", getter_AddRefs(mOwnerThread));
     if (NS_FAILED(rv)) {
       RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
                     NS_LITERAL_CSTRING("Couldn't create CDM thread MediaDrmCDMProxy::Init"));
       return;
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
@@ -32,18 +32,17 @@ public:
   MediaDrmCDMProxy(dom::MediaKeys* aKeys,
                    const nsAString& aKeySystem,
                    bool aDistinctiveIdentifierRequired,
                    bool aPersistentStateRequired);
 
   void Init(PromiseId aPromiseId,
             const nsAString& aOrigin,
             const nsAString& aTopLevelOrigin,
-            const nsAString& aGMPName,
-            bool aInPrivateBrowsing) override;
+            const nsAString& aGMPName) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
                      MediaKeySessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
                      nsTArray<uint8_t>& aInitData) override;
 
   void LoadSession(PromiseId aPromiseId,
--- a/dom/media/gmp/GMPCDMProxy.cpp
+++ b/dom/media/gmp/GMPCDMProxy.cpp
@@ -49,26 +49,24 @@ GMPCDMProxy::~GMPCDMProxy()
 {
   MOZ_COUNT_DTOR(GMPCDMProxy);
 }
 
 void
 GMPCDMProxy::Init(PromiseId aPromiseId,
                   const nsAString& aOrigin,
                   const nsAString& aTopLevelOrigin,
-                  const nsAString& aGMPName,
-                  bool aInPrivateBrowsing)
+                  const nsAString& aGMPName)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
 
-  EME_LOG("GMPCDMProxy::Init (%s, %s) %s",
+  EME_LOG("GMPCDMProxy::Init (%s, %s)",
           NS_ConvertUTF16toUTF8(aOrigin).get(),
-          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
-          (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
+          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
 
   nsCString pluginVersion;
   if (!mOwnerThread) {
     nsCOMPtr<mozIGeckoMediaPluginService> mps =
       do_GetService("@mozilla.org/gecko-media-plugin-service;1");
     if (!mps) {
       RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
                     NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::Init"));
@@ -88,17 +86,16 @@ GMPCDMProxy::Init(PromiseId aPromiseId,
     return;
   }
 
   UniquePtr<InitData> data(new InitData());
   data->mPromiseId = aPromiseId;
   data->mOrigin = aOrigin;
   data->mTopLevelOrigin = aTopLevelOrigin;
   data->mGMPName = aGMPName;
-  data->mInPrivateBrowsing = aInPrivateBrowsing;
   data->mCrashHelper = mCrashHelper;
   nsCOMPtr<nsIRunnable> task(
     NewRunnableMethod<UniquePtr<InitData>&&>(this,
                                              &GMPCDMProxy::gmp_Init,
                                              Move(data)));
   mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
 }
 
@@ -205,17 +202,16 @@ GMPCDMProxy::gmp_Init(UniquePtr<InitData
   // Make a copy before we transfer ownership of aData to the
   // gmp_InitGetGMPDecryptorCallback.
   InitData data(*aData);
   UniquePtr<GetNodeIdCallback> callback(
     new gmp_InitGetGMPDecryptorCallback(this, Move(aData)));
   nsresult rv = mps->GetNodeId(data.mOrigin,
                                data.mTopLevelOrigin,
                                data.mGMPName,
-                               data.mInPrivateBrowsing,
                                Move(callback));
   if (NS_FAILED(rv)) {
     RejectPromise(data.mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
                   NS_LITERAL_CSTRING("Call to GetNodeId() failed early"));
   }
 }
 
 void
@@ -236,20 +232,19 @@ GMPCDMProxy::gmp_InitGetGMPDecryptor(nsr
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (!mps) {
     RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
                   NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::gmp_InitGetGMPDecryptor"));
     return;
   }
 
-  EME_LOG("GMPCDMProxy::gmp_Init (%s, %s) %s NodeId=%s",
+  EME_LOG("GMPCDMProxy::gmp_Init (%s, %s) NodeId=%s",
           NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
           NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
-          (aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
           GetNodeId().get());
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
 
   // Note: must capture helper refptr here, before the Move()
   // when we create the GetGMPDecryptorCallback below.
   RefPtr<GMPCrashHelper> crashHelper = Move(aData->mCrashHelper);
--- a/dom/media/gmp/GMPCDMProxy.h
+++ b/dom/media/gmp/GMPCDMProxy.h
@@ -26,18 +26,17 @@ public:
               const nsAString& aKeySystem,
               GMPCrashHelper* aCrashHelper,
               bool aDistinctiveIdentifierRequired,
               bool aPersistentStateRequired);
 
   void Init(PromiseId aPromiseId,
             const nsAString& aOrigin,
             const nsAString& aTopLevelOrigin,
-            const nsAString& aGMPName,
-            bool aInPrivateBrowsing) override;
+            const nsAString& aGMPName) override;
 
   void OnSetDecryptorId(uint32_t aId) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
                      dom::MediaKeySessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
                      nsTArray<uint8_t>& aInitData) override;
@@ -118,17 +117,16 @@ private:
   friend class gmp_InitGetGMPDecryptorCallback;
 
   struct InitData {
     uint32_t mPromiseId;
     nsString mOrigin;
     nsString mTopLevelOrigin;
     nsString mGMPName;
     RefPtr<GMPCrashHelper> mCrashHelper;
-    bool mInPrivateBrowsing;
   };
 
   // GMP thread only.
   void gmp_Init(UniquePtr<InitData>&& aData);
   void gmp_InitDone(GMPDecryptorProxy* aCDM, UniquePtr<InitData>&& aData);
   void gmp_InitGetGMPDecryptor(nsresult aResult,
                                const nsACString& aNodeId,
                                UniquePtr<InitData>&& aData);
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -230,34 +230,31 @@ GeckoMediaPluginServiceChild::HasPluginF
   *aHasPlugin = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginServiceChild::GetNodeId(const nsAString& aOrigin,
                                         const nsAString& aTopLevelOrigin,
                                         const nsAString& aGMPName,
-                                        bool aInPrivateBrowsing,
                                         UniquePtr<GetNodeIdCallback>&& aCallback)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   GetNodeIdCallback* rawCallback = aCallback.release();
   RefPtr<AbstractThread> thread(GetAbstractGMPThread());
   nsString origin(aOrigin);
   nsString topLevelOrigin(aTopLevelOrigin);
   nsString gmpName(aGMPName);
-  bool pb = aInPrivateBrowsing;
   GetServiceChild()->Then(thread, __func__,
-    [rawCallback, origin, topLevelOrigin, gmpName, pb](GMPServiceChild* child) {
+    [rawCallback, origin, topLevelOrigin, gmpName](GMPServiceChild* child) {
       UniquePtr<GetNodeIdCallback> callback(rawCallback);
       nsCString outId;
       if (!child->SendGetGMPNodeId(origin, topLevelOrigin,
-                                   gmpName,
-                                   pb, &outId)) {
+                                   gmpName, &outId)) {
         callback->Done(NS_ERROR_FAILURE, EmptyCString());
         return;
       }
 
       callback->Done(NS_OK, outId);
     },
     [rawCallback](nsresult rv) {
       UniquePtr<GetNodeIdCallback> callback(rawCallback);
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -27,17 +27,16 @@ public:
   static already_AddRefed<GeckoMediaPluginServiceChild> GetSingleton();
 
   NS_IMETHOD HasPluginForAPI(const nsACString& aAPI,
                              nsTArray<nsCString>* aTags,
                              bool *aRetVal) override;
   NS_IMETHOD GetNodeId(const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
                        const nsAString& aGMPName,
-                       bool aInPrivateBrowsingMode,
                        UniquePtr<GetNodeIdCallback>&& aCallback) override;
 
   NS_DECL_NSIOBSERVER
 
   void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
 
   void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
 
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1383,24 +1383,22 @@ GeckoMediaPluginServiceParent::IsPersist
                  mPersistentStorageAllowed.Get(aNodeId);
   return NS_OK;
 }
 
 nsresult
 GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
                                          const nsAString& aTopLevelOrigin,
                                          const nsAString& aGMPName,
-                                         bool aInPrivateBrowsing,
                                          nsACString& aOutId)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
-  LOGD(("%s::%s: (%s, %s), %s", __CLASS__, __FUNCTION__,
+  LOGD(("%s::%s: (%s, %s)", __CLASS__, __FUNCTION__,
        NS_ConvertUTF16toUTF8(aOrigin).get(),
-       NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
-       (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")));
+       NS_ConvertUTF16toUTF8(aTopLevelOrigin).get()));
 
   nsresult rv;
 
   if (aOrigin.EqualsLiteral("null") ||
       aOrigin.IsEmpty() ||
       aTopLevelOrigin.EqualsLiteral("null") ||
       aTopLevelOrigin.IsEmpty()) {
     // (origin, topLevelOrigin) is null or empty; this is for an anonymous
@@ -1416,17 +1414,17 @@ GeckoMediaPluginServiceParent::GetNodeId
     aOutId = salt;
     mPersistentStorageAllowed.Put(salt, false);
     return NS_OK;
   }
 
   const uint32_t hash = AddToHash(HashString(aOrigin),
                                   HashString(aTopLevelOrigin));
 
-  if (aInPrivateBrowsing) {
+  if (OriginAttributes::IsPrivateBrowsing(NS_ConvertUTF16toUTF8(aOrigin))) {
     // For PB mode, we store the node id, indexed by the origin pair and GMP name,
     // so that if the same origin pair is opened for the same GMP in this session,
     // it gets the same node id.
     const uint32_t pbHash = AddToHash(HashString(aGMPName), hash);
     nsCString* salt = nullptr;
     if (!(salt = mTempNodeIds.Get(pbHash))) {
       // No salt stored, generate and temporarily store some for this id.
       nsAutoCString newSalt;
@@ -1546,21 +1544,20 @@ GeckoMediaPluginServiceParent::GetNodeId
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginServiceParent::GetNodeId(const nsAString& aOrigin,
                                          const nsAString& aTopLevelOrigin,
                                          const nsAString& aGMPName,
-                                         bool aInPrivateBrowsing,
                                          UniquePtr<GetNodeIdCallback>&& aCallback)
 {
   nsCString nodeId;
-  nsresult rv = GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, aInPrivateBrowsing, nodeId);
+  nsresult rv = GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, nodeId);
   aCallback->Done(rv, nodeId);
   return rv;
 }
 
 static bool
 ExtractHostName(const nsACString& aOrigin, nsACString& aOutData)
 {
   nsCString str;
@@ -2005,21 +2002,19 @@ GMPServiceParent::RecvLaunchGMP(const ns
   *aOutRv = NS_OK;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 GMPServiceParent::RecvGetGMPNodeId(const nsString& aOrigin,
                                    const nsString& aTopLevelOrigin,
                                    const nsString& aGMPName,
-                                   const bool& aInPrivateBrowsing,
                                    nsCString* aID)
 {
-  nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName,
-                                    aInPrivateBrowsing, *aID);
+  nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, *aID);
   if (!NS_SUCCEEDED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 class DeleteGMPServiceParent : public mozilla::Runnable
 {
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -39,17 +39,16 @@ public:
 
   // mozIGeckoMediaPluginService
   NS_IMETHOD HasPluginForAPI(const nsACString& aAPI,
                              nsTArray<nsCString>* aTags,
                              bool *aRetVal) override;
   NS_IMETHOD GetNodeId(const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
                        const nsAString& aGMPName,
-                       bool aInPrivateBrowsingMode,
                        UniquePtr<GetNodeIdCallback>&& aCallback) override;
 
   NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE
   NS_DECL_NSIOBSERVER
 
   void AsyncShutdownNeeded(GMPParent* aParent);
   void AsyncShutdownComplete(GMPParent* aParent);
 
@@ -85,18 +84,17 @@ private:
                                                  const nsTArray<nsCString>& aTags);
 
   already_AddRefed<GMPParent> FindPluginForAPIFrom(size_t aSearchStartIndex,
                                                    const nsCString& aAPI,
                                                    const nsTArray<nsCString>& aTags,
                                                    size_t* aOutPluginIndex);
 
   nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
-                     const nsAString& aGMPName,
-                     bool aInPrivateBrowsing, nsACString& aOutId);
+                     const nsAString& aGMPName, nsACString& aOutId);
 
   void UnloadPlugins();
   void CrashPlugins();
   void NotifySyncShutdownComplete();
   void NotifyAsyncShutdownComplete();
 
   void ProcessPossiblePlugin(nsIFile* aDir);
 
@@ -245,17 +243,16 @@ public:
   {
     mService->ServiceUserCreated();
   }
   virtual ~GMPServiceParent();
 
   mozilla::ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin,
                                            const nsString& aTopLevelOrigin,
                                            const nsString& aGMPName,
-                                           const bool& aInPrivateBrowsing,
                                            nsCString* aID) override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   static PGMPServiceParent* Create(Transport* aTransport, ProcessId aOtherPid);
 
   mozilla::ipc::IPCResult RecvLaunchGMP(const nsCString& aNodeId,
                                         const nsCString& aAPI,
                                         nsTArray<nsCString>&& aTags,
--- a/dom/media/gmp/PGMPService.ipdl
+++ b/dom/media/gmp/PGMPService.ipdl
@@ -17,16 +17,14 @@ sync protocol PGMPService
 parent:
 
   sync LaunchGMP(nsCString nodeId,
                  nsCString api,
                  nsCString[] tags,
                  ProcessId[] alreadyBridgedTo)
     returns (uint32_t pluginId, ProcessId id, nsCString displayName, nsresult aResult);
 
-  sync GetGMPNodeId(nsString origin, nsString topLevelOrigin,
-                    nsString gmpName,
-                    bool inPrivateBrowsing)
+  sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, nsString gmpName)
     returns (nsCString id);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl
@@ -156,17 +156,16 @@ interface mozIGeckoMediaPluginService : 
    */
   [noscript]
   void getGMPDecryptor(in GMPCrashHelperPtr helper,
                        in TagArray tags,
                        in ACString nodeId,
                        in GetGMPDecryptorCallback callback);
 
   /**
-   * Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
+   * Gets the NodeId for a (origin, urlbarOrigin) pair.
    */
   [noscript]
   void getNodeId(in AString origin,
                  in AString topLevelOrigin,
                  in AString gmpName,
-                 in bool inPrivateBrowsingMode,
                  in GetNodeIdCallback callback);
 };
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -468,22 +468,36 @@ GetNodeId(const nsAString& aOrigin,
 {
   RefPtr<GeckoMediaPluginServiceParent> service =
     GeckoMediaPluginServiceParent::GetSingleton();
   EXPECT_TRUE(service);
   nsCString nodeId;
   nsresult result;
   UniquePtr<GetNodeIdCallback> callback(new TestGetNodeIdCallback(nodeId,
                                                                   result));
+
+  PrincipalOriginAttributes attrs;
+  attrs.mPrivateBrowsingId = aInPBMode ? 1 : 0;
+
+  nsAutoCString suffix;
+  attrs.CreateSuffix(suffix);
+
+  nsAutoString origin;
+  origin.Assign(aOrigin);
+  origin.Append(NS_ConvertUTF8toUTF16(suffix));
+
+  nsAutoString topLevelOrigin;
+  topLevelOrigin.Assign(aTopLevelOrigin);
+  topLevelOrigin.Append(NS_ConvertUTF8toUTF16(suffix));
+
   // We rely on the fact that the GetNodeId implementation for
   // GeckoMediaPluginServiceParent is synchronous.
-  nsresult rv = service->GetNodeId(aOrigin,
-                                   aTopLevelOrigin,
+  nsresult rv = service->GetNodeId(origin,
+                                   topLevelOrigin,
                                    NS_LITERAL_STRING("gmp-fake"),
-                                   aInPBMode,
                                    Move(callback));
   EXPECT_TRUE(NS_SUCCEEDED(rv) && NS_SUCCEEDED(result));
   return nodeId;
 }
 
 static bool
 IsGMPStorageIsEmpty()
 {
--- a/dom/media/systemservices/MediaChild.cpp
+++ b/dom/media/systemservices/MediaChild.cpp
@@ -15,29 +15,28 @@
 #undef LOG
 mozilla::LazyLogModule gMediaChildLog("MediaChild");
 #define LOG(args) MOZ_LOG(gMediaChildLog, mozilla::LogLevel::Debug, args)
 
 namespace mozilla {
 namespace media {
 
 already_AddRefed<Pledge<nsCString>>
-GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing, bool aPersist)
+GetOriginKey(const nsCString& aOrigin, bool aPersist)
 {
   RefPtr<MediaManager> mgr = MediaManager::GetInstance();
   MOZ_ASSERT(mgr);
 
   RefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
   uint32_t id = mgr->mGetOriginKeyPledges.Append(*p);
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
-    mgr->GetNonE10sParent()->RecvGetOriginKey(id, aOrigin, aPrivateBrowsing,
-                                              aPersist);
+    mgr->GetNonE10sParent()->RecvGetOriginKey(id, aOrigin, aPersist);
   } else {
-    Child::Get()->SendGetOriginKey(id, aOrigin, aPrivateBrowsing, aPersist);
+    Child::Get()->SendGetOriginKey(id, aOrigin, aPersist);
   }
   return p.forget();
 }
 
 void
 SanitizeOriginKeys(const uint64_t& aSinceWhen, bool aOnlyPrivateBrowsing)
 {
   LOG(("SanitizeOriginKeys since %llu %s", aSinceWhen,
--- a/dom/media/systemservices/MediaChild.h
+++ b/dom/media/systemservices/MediaChild.h
@@ -20,17 +20,17 @@ namespace media {
 //
 // GetOriginKey() - get a cookie-like persisted unique key for a given origin.
 // SanitizeOriginKeys() - reset persisted unique keys.
 
 // GetOriginKey and SanitizeOriginKeys are asynchronous APIs that return pledges
 // (promise-like objects) with the future value. Use pledge.Then(func) to access.
 
 already_AddRefed<Pledge<nsCString>>
-GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing, bool aPersist);
+GetOriginKey(const nsCString& aOrigin, bool aPersist);
 
 void
 SanitizeOriginKeys(const uint64_t& aSinceWhen, bool aOnlyPrivateBrowsing);
 
 class Child : public PMediaChild
 {
 public:
   static Child* Get();
--- a/dom/media/systemservices/MediaParent.cpp
+++ b/dom/media/systemservices/MediaParent.cpp
@@ -364,17 +364,16 @@ bool NonE10s::SendGetOriginKeyResponse(c
     pledge->Resolve(aKey);
   }
   return true;
 }
 
 template<class Super> mozilla::ipc::IPCResult
 Parent<Super>::RecvGetOriginKey(const uint32_t& aRequestId,
                                 const nsCString& aOrigin,
-                                const bool& aPrivateBrowsing,
                                 const bool& aPersist)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // First, get profile dir.
 
   MOZ_ASSERT(NS_IsMainThread());
   nsCOMPtr<nsIFile> profileDir;
@@ -390,21 +389,22 @@ Parent<Super>::RecvGetOriginKey(const ui
   RefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
   uint32_t id = mOutstandingPledges.Append(*p);
 
   nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   MOZ_ASSERT(sts);
   RefPtr<Parent<Super>> that(this);
 
   rv = sts->Dispatch(NewRunnableFrom([this, that, id, profileDir, aOrigin,
-                                      aPrivateBrowsing, aPersist]() -> nsresult {
+                                      aPersist]() -> nsresult {
     MOZ_ASSERT(!NS_IsMainThread());
     mOriginKeyStore->mOriginKeys.SetProfileDir(profileDir);
-    nsCString result;
-    if (aPrivateBrowsing) {
+
+    nsAutoCString result;
+    if (OriginAttributes::IsPrivateBrowsing(aOrigin)) {
       mOriginKeyStore->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result);
     } else {
       mOriginKeyStore->mOriginKeys.GetOriginKey(aOrigin, result, aPersist);
     }
 
     // Pass result back to main thread.
     nsresult rv;
     rv = NS_DispatchToMainThread(NewRunnableFrom([this, that, id,
--- a/dom/media/systemservices/MediaParent.h
+++ b/dom/media/systemservices/MediaParent.h
@@ -24,17 +24,16 @@ class NonE10s
 {
   typedef mozilla::ipc::IProtocol::ActorDestroyReason
       ActorDestroyReason;
 public:
   virtual ~NonE10s() {}
 protected:
   virtual mozilla::ipc::IPCResult RecvGetOriginKey(const uint32_t& aRequestId,
                                                    const nsCString& aOrigin,
-                                                   const bool& aPrivateBrowsing,
                                                    const bool& aPersist) = 0;
   virtual mozilla::ipc::IPCResult RecvSanitizeOriginKeys(const uint64_t& aSinceWhen,
                                                          const bool& aOnlyPrivateBrowsing) = 0;
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) = 0;
 
   bool SendGetOriginKeyResponse(const uint32_t& aRequestId,
                                 nsCString aKey);
@@ -47,17 +46,16 @@ class Parent : public Super
 {
   typedef mozilla::ipc::IProtocol::ActorDestroyReason
       ActorDestroyReason;
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Parent<Super>)
 
   virtual mozilla::ipc::IPCResult RecvGetOriginKey(const uint32_t& aRequestId,
                                                    const nsCString& aOrigin,
-                                                   const bool& aPrivateBrowsing,
                                                    const bool& aPersist) override;
   virtual mozilla::ipc::IPCResult RecvSanitizeOriginKeys(const uint64_t& aSinceWhen,
                                                          const bool& aOnlyPrivateBrowsing) override;
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   Parent();
 private:
   virtual ~Parent();
--- a/dom/media/systemservices/PMedia.ipdl
+++ b/dom/media/systemservices/PMedia.ipdl
@@ -13,28 +13,29 @@ protocol PMedia
 
 parent:
   /**
    * Requests a potentially persistent unique secret key for each origin.
    * Has no expiry, but is cleared by age along with cookies.
    * This is needed by mediaDevices.enumerateDevices() to produce persistent
    * deviceIds that wont work cross-origin.
    *
-   * If aPrivateBrowsing is false, a key for this origin is returned from a
-   * primary pool of temporal in-memory keys and persistent keys read from disk.
-   * If no key exists, a temporal one is created.
+   * The origin string must contain the OriginAttributes suffix.
+   * If this OriginAttributes dictionary has the privateBrowsing flag set to
+   * false, a key for this origin is returned from a primary pool of temporal
+   * in-memory keys and persistent keys read from disk. If no key exists, a
+   * temporal one is created.
    * If aPersist is true and key is temporal, the key is promoted to persistent.
    * Once persistent, a key cannot become temporal again.
    *
-   * If aPrivateBrowsing is true, a different key for this origin is returned
-   * from a secondary pool that is never persisted to disk, and aPersist is
-   * ignored.
+   * If the OriginAttributes dictionary has the privateBrowsing flag set to
+   * true, a different key for this origin is returned from a secondary pool
+   * that is never persisted to disk, and aPersist is ignored.
    */
-  async GetOriginKey(uint32_t aRequestId, nsCString aOrigin, bool aPrivateBrowsing,
-                     bool aPersist);
+  async GetOriginKey(uint32_t aRequestId, nsCString aOrigin, bool aPersist);
 
   /**
    * Clear per-orgin list of persistent deviceIds stored for enumerateDevices
    * Fire and forget.
    *
    * aSinceTime - milliseconds since 1 January 1970 00:00:00 UTC. 0 = clear all
    *
    * aOnlyPrivateBrowsing - if true then only purge the separate in-memory