Bug 1278198 - Pipe through distinctive identifier and persistent state allowed. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Thu, 07 Jul 2016 17:26:15 +1200
changeset 346459 5325ebce568149e9fbd3892563922cb374e31922
parent 346458 6a94e3e85347a9dd76656cf6c1ddd8e7857534dc
child 346460 cb6744f212159558c5bf2e456b4b7ef48e38251f
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1278198
milestone50.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 1278198 - Pipe through distinctive identifier and persistent state allowed. r=gerald MozReview-Commit-ID: A92e0XGp5s4
dom/media/eme/CDMProxy.h
dom/media/eme/MediaKeySystemAccess.cpp
dom/media/eme/MediaKeys.cpp
dom/media/eme/MediaKeys.h
dom/media/gmp-plugin/gmp-test-decryptor.h
dom/media/gmp/GMPCDMProxy.cpp
dom/media/gmp/GMPCDMProxy.h
dom/media/gmp/GMPDecryptorChild.cpp
dom/media/gmp/GMPDecryptorChild.h
dom/media/gmp/GMPDecryptorParent.cpp
dom/media/gmp/GMPDecryptorParent.h
dom/media/gmp/GMPDecryptorProxy.h
dom/media/gmp/PGMPDecryptor.ipdl
dom/media/gmp/gmp-api/gmp-decryption.h
dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
dom/media/gmp/widevine-adapter/WidevineDecryptor.h
dom/media/gtest/TestGMPCrossOrigin.cpp
media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
media/gmp-clearkey/0.1/ClearKeySessionManager.h
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -45,18 +45,24 @@ protected:
 public:
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
   NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
 
   typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true> DecryptPromise;
 
   // Main thread only.
-  CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
-  : mKeys(aKeys), mKeySystem(aKeySystem)
+  CDMProxy(dom::MediaKeys* aKeys,
+           const nsAString& aKeySystem,
+           bool aDistinctiveIdentifierRequired,
+           bool aPersistentStateRequired)
+    : mKeys(aKeys)
+    , mKeySystem(aKeySystem)
+    , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired)
+    , mPersistentStateRequired(aPersistentStateRequired)
   {}
 
   // 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,
@@ -224,14 +230,17 @@ protected:
 
   // Onwer specified thread. e.g. Gecko Media Plugin thread.
   // All interactions with the out-of-process EME plugin must come from this thread.
   RefPtr<nsIThread> mOwnerThread;
 
   nsCString mNodeId;
 
   CDMCaps mCapabilites;
+
+  const bool mDistinctiveIdentifierRequired;
+  const bool mPersistentStateRequired;
 };
 
 
 } // namespace mozilla
 
 #endif // CDMProxy_h_
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -87,17 +87,21 @@ void
 MediaKeySystemAccess::GetConfiguration(MediaKeySystemConfiguration& aConfig)
 {
   aConfig = mConfig;
 }
 
 already_AddRefed<Promise>
 MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv)
 {
-  RefPtr<MediaKeys> keys(new MediaKeys(mParent, mKeySystem, mCDMVersion));
+  RefPtr<MediaKeys> keys(new MediaKeys(mParent,
+                                       mKeySystem,
+                                       mCDMVersion,
+                                       mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
+                                       mConfig.mPersistentState == MediaKeysRequirement::Required));
   return keys->Init(aRv);
 }
 
 static bool
 HaveGMPFor(mozIGeckoMediaPluginService* aGMPService,
            const nsCString& aKeySystem,
            const nsCString& aAPI,
            const nsCString& aTag = EmptyCString())
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -43,21 +43,25 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKey
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeys)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeys)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 MediaKeys::MediaKeys(nsPIDOMWindowInner* aParent,
                      const nsAString& aKeySystem,
-                     const nsAString& aCDMVersion)
+                     const nsAString& aCDMVersion,
+                     bool aDistinctiveIdentifierRequired,
+                     bool aPersistentStateRequired)
   : mParent(aParent)
   , mKeySystem(aKeySystem)
   , mCDMVersion(aCDMVersion)
   , mCreatePromiseId(0)
+  , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired)
+  , mPersistentStateRequired(aPersistentStateRequired)
 {
   EME_LOG("MediaKeys[%p] constructed keySystem=%s",
           this, NS_ConvertUTF16toUTF8(mKeySystem).get());
 }
 
 MediaKeys::~MediaKeys()
 {
   Shutdown();
@@ -308,17 +312,21 @@ already_AddRefed<DetailedPromise>
 MediaKeys::Init(ErrorResult& aRv)
 {
   RefPtr<DetailedPromise> promise(MakePromise(aRv,
     NS_LITERAL_CSTRING("MediaKeys::Init()")));
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  mProxy = new GMPCDMProxy(this, mKeySystem, new MediaKeysGMPCrashHelper(this));
+  mProxy = new GMPCDMProxy(this,
+                           mKeySystem,
+                           new MediaKeysGMPCrashHelper(this),
+                           mDistinctiveIdentifierRequired,
+                           mPersistentStateRequired);
 
   // Determine principal (at creation time) of the MediaKeys object.
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());
   if (!sop) {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
                          NS_LITERAL_CSTRING("Couldn't get script principal in MediaKeys::Init"));
     return promise.forget();
   }
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -45,17 +45,20 @@ class MediaKeys final : public nsISuppor
   ~MediaKeys();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys)
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MediaKeys)
 
   MediaKeys(nsPIDOMWindowInner* aParentWindow,
-            const nsAString& aKeySystem, const nsAString& aCDMVersion);
+            const nsAString& aKeySystem,
+            const nsAString& aCDMVersion,
+            bool aDistinctiveIdentifierRequired,
+            bool aPersistentStateRequired);
 
   already_AddRefed<DetailedPromise> Init(ErrorResult& aRv);
 
   nsPIDOMWindowInner* GetParentObject() const;
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   nsresult Bind(HTMLMediaElement* aElement);
@@ -142,14 +145,16 @@ private:
   KeySessionHashMap mKeySessions;
   PromiseHashMap mPromises;
   PendingKeySessionsHashMap mPendingSessions;
   PromiseId mCreatePromiseId;
 
   RefPtr<nsIPrincipal> mPrincipal;
   RefPtr<nsIPrincipal> mTopLevelPrincipal;
 
+  const bool mDistinctiveIdentifierRequired;
+  const bool mPersistentStateRequired;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mediakeys_h__
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -11,17 +11,17 @@
 #include <string>
 #include "mozilla/Attributes.h"
 
 class FakeDecryptor : public GMPDecryptor {
 public:
 
   explicit FakeDecryptor(GMPDecryptorHost* aHost);
 
-  void Init(GMPDecryptorCallback* aCallback) override {
+  void Init(GMPDecryptorCallback* aCallback, bool, bool) override {
     mCallback = aCallback;
   }
 
   void CreateSession(uint32_t aCreateSessionToken,
                      uint32_t aPromiseId,
                      const char* aInitDataType,
                      uint32_t aInitDataTypeSize,
                      const uint8_t* aInitData,
--- a/dom/media/gmp/GMPCDMProxy.cpp
+++ b/dom/media/gmp/GMPCDMProxy.cpp
@@ -22,18 +22,23 @@
 #include "GMPService.h"
 #include "MainThreadUtils.h"
 #include "MediaData.h"
 
 namespace mozilla {
 
 GMPCDMProxy::GMPCDMProxy(dom::MediaKeys* aKeys,
                          const nsAString& aKeySystem,
-                         GMPCrashHelper* aCrashHelper)
-  : CDMProxy(aKeys, aKeySystem)
+                         GMPCrashHelper* aCrashHelper,
+                         bool aDistinctiveIdentifierRequired,
+                         bool aPersistentStateRequired)
+  : CDMProxy(aKeys,
+             aKeySystem,
+             aDistinctiveIdentifierRequired,
+             aPersistentStateRequired)
   , mCrashHelper(aCrashHelper)
   , mCDM(nullptr)
   , mDecryptionJobCount(0)
   , mShutdownCalled(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(GMPCDMProxy);
 }
@@ -118,17 +123,19 @@ GMPCDMProxy::gmp_InitDone(GMPDecryptorPr
   if (!aCDM) {
     RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
                   NS_LITERAL_CSTRING("GetGMPDecryptor failed to return a CDM"));
     return;
   }
 
   mCDM = aCDM;
   mCallback = new GMPCDMCallbackProxy(this);
-  mCDM->Init(mCallback);
+  mCDM->Init(mCallback,
+             mDistinctiveIdentifierRequired,
+             mPersistentStateRequired);
   nsCOMPtr<nsIRunnable> task(
     NewRunnableMethod<uint32_t>(this,
                                 &GMPCDMProxy::OnCDMCreated,
                                 aData->mPromiseId));
   NS_DispatchToMainThread(task);
 }
 
 class gmp_InitDoneCallback : public GetGMPDecryptorCallback
@@ -232,17 +239,20 @@ GMPCDMProxy::gmp_InitGetGMPDecryptor(nsr
   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);
   UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this,
                                                                        Move(aData)));
-  nsresult rv = mps->GetGMPDecryptor(crashHelper, &tags, GetNodeId(), Move(callback));
+  nsresult rv = mps->GetGMPDecryptor(crashHelper,
+                                     &tags,
+                                     GetNodeId(),
+                                     Move(callback));
   if (NS_FAILED(rv)) {
     RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
                   NS_LITERAL_CSTRING("Call to GetGMPDecryptor() failed early"));
   }
 }
 
 void
 GMPCDMProxy::OnCDMCreated(uint32_t aPromiseId)
--- a/dom/media/gmp/GMPCDMProxy.h
+++ b/dom/media/gmp/GMPCDMProxy.h
@@ -19,17 +19,19 @@ class GMPCDMProxy : public CDMProxy {
 public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPCDMProxy, override)
 
   typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true> DecryptPromise;
 
   GMPCDMProxy(dom::MediaKeys* aKeys,
               const nsAString& aKeySystem,
-              GMPCrashHelper* aCrashHelper);
+              GMPCrashHelper* aCrashHelper,
+              bool aDistinctiveIdentifierRequired,
+              bool aPersistentStateRequired);
 
   void Init(PromiseId aPromiseId,
             const nsAString& aOrigin,
             const nsAString& aTopLevelOrigin,
             const nsAString& aGMPName,
             bool aInPrivateBrowsing) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
--- a/dom/media/gmp/GMPDecryptorChild.cpp
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -215,22 +215,23 @@ GMPDecryptorChild::GetPluginVoucher(cons
   if (!aVoucher || !aVoucherLength) {
     return;
   }
   *aVoucher = mPluginVoucher.Elements();
   *aVoucherLength = mPluginVoucher.Length();
 }
 
 bool
-GMPDecryptorChild::RecvInit()
+GMPDecryptorChild::RecvInit(const bool& aDistinctiveIdentifierRequired,
+                            const bool& aPersistentStateRequired)
 {
   if (!mSession) {
     return false;
   }
-  mSession->Init(this);
+  mSession->Init(this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
   return true;
 }
 
 bool
 GMPDecryptorChild::RecvCreateSession(const uint32_t& aCreateSessionToken,
                                      const uint32_t& aPromiseId,
                                      const nsCString& aInitDataType,
                                      InfallibleTArray<uint8_t>&& aInitData,
--- a/dom/media/gmp/GMPDecryptorChild.h
+++ b/dom/media/gmp/GMPDecryptorChild.h
@@ -78,17 +78,18 @@ public:
                          uint32_t* aVoucherLength) override;
 
   void GetPluginVoucher(const uint8_t** aVoucher,
                         uint32_t* aVoucherLength) override;
 private:
   ~GMPDecryptorChild();
 
   // GMPDecryptorChild
-  bool RecvInit() override;
+  bool RecvInit(const bool& aDistinctiveIdentifierRequired,
+                const bool& aPersistentStateRequired) override;
 
   bool RecvCreateSession(const uint32_t& aCreateSessionToken,
                          const uint32_t& aPromiseId,
                          const nsCString& aInitDataType,
                          InfallibleTArray<uint8_t>&& aInitData,
                          const GMPSessionType& aSessionType) override;
 
   bool RecvLoadSession(const uint32_t& aPromiseId,
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -36,26 +36,28 @@ GMPDecryptorParent::GMPDecryptorParent(G
   MOZ_ASSERT(mPlugin && mGMPThread);
 }
 
 GMPDecryptorParent::~GMPDecryptorParent()
 {
 }
 
 nsresult
-GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback)
+GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback,
+                         bool aDistinctiveIdentifierRequired,
+                         bool aPersistentStateRequired)
 {
   LOGD(("GMPDecryptorParent[%p]::Init()", this));
 
   if (mIsOpen) {
     NS_WARNING("Trying to re-use an in-use GMP decrypter!");
     return NS_ERROR_FAILURE;
   }
   mCallback = aCallback;
-  if (!SendInit()) {
+  if (!SendInit(aDistinctiveIdentifierRequired, aPersistentStateRequired)) {
     return NS_ERROR_FAILURE;
   }
   mIsOpen = true;
   return NS_OK;
 }
 
 void
 GMPDecryptorParent::CreateSession(uint32_t aCreateSessionToken,
--- a/dom/media/gmp/GMPDecryptorParent.h
+++ b/dom/media/gmp/GMPDecryptorParent.h
@@ -28,17 +28,19 @@ public:
   NS_INLINE_DECL_REFCOUNTING(GMPDecryptorParent)
 
   explicit GMPDecryptorParent(GMPContentParent *aPlugin);
 
   // GMPDecryptorProxy
 
   uint32_t GetPluginId() const override { return mPluginId; }
 
-  nsresult Init(GMPDecryptorProxyCallback* aCallback) override;
+  nsresult Init(GMPDecryptorProxyCallback* aCallback,
+                bool aDistinctiveIdentifierRequired,
+                bool aPersistentStateRequired) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
                      uint32_t aPromiseId,
                      const nsCString& aInitDataType,
                      const nsTArray<uint8_t>& aInitData,
                      GMPSessionType aSessionType) override;
 
   void LoadSession(uint32_t aPromiseId,
--- a/dom/media/gmp/GMPDecryptorProxy.h
+++ b/dom/media/gmp/GMPDecryptorProxy.h
@@ -54,17 +54,19 @@ public:
 };
 
 class GMPDecryptorProxy {
 public:
   ~GMPDecryptorProxy() {}
 
   virtual uint32_t GetPluginId() const = 0;
 
-  virtual nsresult Init(GMPDecryptorProxyCallback* aCallback) = 0;
+  virtual nsresult Init(GMPDecryptorProxyCallback* aCallback,
+                        bool aDistinctiveIdentifierRequired,
+                        bool aPersistentStateRequired) = 0;
 
   virtual void CreateSession(uint32_t aCreateSessionToken,
                              uint32_t aPromiseId,
                              const nsCString& aInitDataType,
                              const nsTArray<uint8_t>& aInitData,
                              GMPSessionType aSessionType) = 0;
 
   virtual void LoadSession(uint32_t aPromiseId,
--- a/dom/media/gmp/PGMPDecryptor.ipdl
+++ b/dom/media/gmp/PGMPDecryptor.ipdl
@@ -15,17 +15,18 @@ using GMPErr from "gmp-errors.h";
 namespace mozilla {
 namespace gmp {
 
 async protocol PGMPDecryptor
 {
   manager PGMPContent;
 child:
 
-  async Init();
+  async Init(bool aDistinctiveIdentifierRequired,
+             bool aPersistentStateRequired);
 
   async CreateSession(uint32_t aCreateSessionToken,
                       uint32_t aPromiseId,
                       nsCString aInitDataType,
                       uint8_t[] aInitData,
                       GMPSessionType aSessionType);
 
   async LoadSession(uint32_t aPromiseId,
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -222,17 +222,19 @@ enum GMPSessionType {
 //
 // API name macro: GMP_API_DECRYPTOR
 // Host API: GMPDecryptorHost
 class GMPDecryptor {
 public:
 
   // Sets the callback to use with the decryptor to return results
   // to Gecko.
-  virtual void Init(GMPDecryptorCallback* aCallback) = 0;
+  virtual void Init(GMPDecryptorCallback* aCallback,
+                    bool aDistinctiveIdentifierRequired,
+                    bool aPersistentStateRequired) = 0;
 
   // Initiates the creation of a session given |aType| and |aInitData|, and
   // the generation of a license request message.
   //
   // This corresponds to a MediaKeySession.generateRequest() call in JS.
   //
   // The GMPDecryptor must do the following, in order, upon this method
   // being called:
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -117,20 +117,16 @@ WidevineAdapter::GMPGetAPI(const char* a
     if (!cdm) {
       Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p FAILED to create cdm",
           aAPIName, aHostAPI, aPluginAPI, this);
       return GMPGenericErr;
     }
     Log("cdm: 0x%x", cdm);
     sCDMWrapper = new CDMWrapper(cdm);
     decryptor->SetCDM(RefPtr<CDMWrapper>(sCDMWrapper));
-
-    cdm->Initialize(false, /* allow_distinctive_identifier */
-                    false /* allow_persistent_state */);
-
     *aPluginAPI = decryptor;
 
   } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) {
     if (!sCDMWrapper) {
       Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p No cdm for video decoder",
           aAPIName, aHostAPI, aPluginAPI, this);
       return GMPGenericErr;
     }
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #include "WidevineDecryptor.h"
 
 #include "WidevineAdapter.h"
 #include "WidevineUtils.h"
+#include "WidevineFileIO.h"
 #include <mozilla/SizePrintfMacros.h>
 #include <stdarg.h>
 
 using namespace cdm;
 using namespace std;
 
 namespace mozilla {
 
@@ -30,20 +31,31 @@ WidevineDecryptor::~WidevineDecryptor()
 
 void
 WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM)
 {
   mCDM = aCDM;
 }
 
 void
-WidevineDecryptor::Init(GMPDecryptorCallback* aCallback)
+WidevineDecryptor::Init(GMPDecryptorCallback* aCallback,
+                        bool aDistinctiveIdentifierRequired,
+                        bool aPersistentStateRequired)
 {
+  Log("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d",
+      this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
   MOZ_ASSERT(aCallback);
   mCallback = aCallback;
+  MOZ_ASSERT(mCDM);
+  mDistinctiveIdentifierRequired = aDistinctiveIdentifierRequired;
+  mPersistentStateRequired = aPersistentStateRequired;
+  if (CDM()) {
+    CDM()->Initialize(aDistinctiveIdentifierRequired,
+                      aPersistentStateRequired);
+  }
 }
 
 static SessionType
 ToCDMSessionType(GMPSessionType aSessionType)
 {
   switch (aSessionType) {
     case kGMPTemporySession: return kTemporary;
     case kGMPPersistentSession: return kPersistentLicense;
@@ -479,14 +491,15 @@ WidevineDecryptor::OnDeferredInitializat
 {
   Log("Decryptor::OnDeferredInitializationDone()");
 }
 
 FileIO*
 WidevineDecryptor::CreateFileIO(FileIOClient* aClient)
 {
   Log("Decryptor::CreateFileIO()");
-  // Persistent storage not required or supported!
-  MOZ_ASSERT(false);
-  return nullptr;
+  if (!mPersistentStateRequired) {
+    return nullptr;
+  }
+  return new WidevineFileIO(aClient);
 }
 
 } // namespace mozilla
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
@@ -22,17 +22,19 @@ public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WidevineDecryptor)
 
   WidevineDecryptor();
 
   void SetCDM(RefPtr<CDMWrapper> aCDM);
 
   // GMPDecryptor
-  void Init(GMPDecryptorCallback* aCallback) override;
+  void Init(GMPDecryptorCallback* aCallback,
+            bool aDistinctiveIdentifierRequired,
+            bool aPersistentStateRequired) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
                      uint32_t aPromiseId,
                      const char* aInitDataType,
                      uint32_t aInitDataTypeSize,
                      const uint8_t* aInitData,
                      uint32_t aInitDataSize,
                      GMPSessionType aSessionType) override;
@@ -115,13 +117,15 @@ public:
   RefPtr<CDMWrapper> GetCDMWrapper() const { return mCDM; }
 private:
   ~WidevineDecryptor();
   RefPtr<CDMWrapper> mCDM;
   cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); }
 
   GMPDecryptorCallback* mCallback;
   std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens;
+  bool mDistinctiveIdentifierRequired = false;
+  bool mPersistentStateRequired = false;
 };
 
 } // namespace mozilla
 
 #endif // WidevineDecryptor_h_
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -601,17 +601,17 @@ class GMPStorageTest : public GMPDecrypt
     }
 
     void Done(GMPDecryptorProxy* aDecryptor) override
     {
       mRunner->mDecryptor = aDecryptor;
       EXPECT_TRUE(!!mRunner->mDecryptor);
 
       if (mRunner->mDecryptor) {
-        mRunner->mDecryptor->Init(mRunner);
+        mRunner->mDecryptor->Init(mRunner, false, true);
       }
       nsCOMPtr<nsIThread> thread(GetGMPThread());
       thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
     }
 
   private:
     RefPtr<GMPStorageTest> mRunner;
     nsCOMPtr<nsIRunnable> mContinuation;
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
@@ -41,17 +41,19 @@ ClearKeySessionManager::ClearKeySessionM
 }
 
 ClearKeySessionManager::~ClearKeySessionManager()
 {
   CK_LOGD("ClearKeySessionManager dtor %p", this);
 }
 
 void
-ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback)
+ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback,
+                             bool aDistinctiveIdentifierAllowed,
+                             bool aPersistentStateAllowed)
 {
   CK_LOGD("ClearKeySessionManager::Init");
   mCallback = aCallback;
   ClearKeyPersistence::EnsureInitialized();
 }
 
 void
 ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken,
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h
@@ -29,17 +29,19 @@
 #include "RefCounted.h"
 
 class ClearKeySessionManager final : public GMPDecryptor
                                    , public RefCounted
 {
 public:
   ClearKeySessionManager();
 
-  virtual void Init(GMPDecryptorCallback* aCallback) override;
+  virtual void Init(GMPDecryptorCallback* aCallback,
+                    bool aDistinctiveIdentifierAllowed,
+                    bool aPersistentStateAllowed) override;
 
   virtual void CreateSession(uint32_t aCreateSessionToken,
                              uint32_t aPromiseId,
                              const char* aInitDataType,
                              uint32_t aInitDataTypeSize,
                              const uint8_t* aInitData,
                              uint32_t aInitDataSize,
                              GMPSessionType aSessionType) override;