Bug 1315850 - Implement CDM persistent sessions. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Thu, 09 Mar 2017 19:09:43 +1300
changeset 349370 2a6e91518a674f5e25d83403c49966631562afc9
parent 349369 fe4a4ae4ff80bb6ba53ba3e8554411499db9cf04
child 349371 98c87d2f85b3d0c5ef906bf4791bb90d5c445fb7
push id88407
push usercpearce@mozilla.com
push dateFri, 24 Mar 2017 03:07:56 +0000
treeherdermozilla-inbound@b5c478da01df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1315850
milestone55.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 1315850 - Implement CDM persistent sessions. r=gerald This is required for the browser clearing persistence tests to pass. MozReview-Commit-ID: Ai9qc6Ds1IG
dom/media/eme/CDMProxy.h
dom/media/eme/MediaKeySession.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.h
dom/media/gmp/ChromiumCDMChild.cpp
dom/media/gmp/ChromiumCDMChild.h
dom/media/gmp/ChromiumCDMParent.cpp
dom/media/gmp/ChromiumCDMParent.h
dom/media/gmp/ChromiumCDMProxy.cpp
dom/media/gmp/ChromiumCDMProxy.h
dom/media/gmp/GMPCDMProxy.cpp
dom/media/gmp/GMPCDMProxy.h
dom/media/gmp/PChromiumCDM.ipdl
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -110,16 +110,17 @@ public:
                              PromiseId aPromiseId,
                              const nsAString& aInitDataType,
                              nsTArray<uint8_t>& aInitData) = 0;
 
   // Main thread only.
   // Uses the CDM to load a presistent session stored on disk.
   // Calls MediaKeys::OnSessionActivated() when session is loaded.
   virtual void LoadSession(PromiseId aPromiseId,
+                           dom::MediaKeySessionType aSessionType,
                            const nsAString& aSessionId) = 0;
 
   // Main thread only.
   // Sends a new certificate to the CDM.
   // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
   // processed the request.
   // Assumes ownership of (Move()s) aCert's contents.
   virtual void SetServerCertificate(PromiseId aPromiseId,
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -391,17 +391,17 @@ MediaKeySession::Load(const nsAString& a
   // session from its owning MediaKey's set of sessions awaiting a sessionId.
   RefPtr<MediaKeySession> session(mKeys->GetPendingSession(Token()));
   MOZ_ASSERT(session == this, "Session should be awaiting id on its own token");
 
   // Associate with the known sessionId.
   SetSessionId(aSessionId);
 
   PromiseId pid = mKeys->StorePromise(promise);
-  mKeys->GetCDMProxy()->LoadSession(pid, aSessionId);
+  mKeys->GetCDMProxy()->LoadSession(pid, mSessionType, aSessionId);
 
   EME_LOG("MediaKeySession[%p,'%s'] Load() sent to CDM, promiseId=%d",
     this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
@@ -96,16 +96,17 @@ MediaDrmCDMProxy::CreateSession(uint32_t
     NewRunnableMethod<UniquePtr<CreateSessionData>&&>(this,
                                                       &MediaDrmCDMProxy::md_CreateSession,
                                                       Move(data)));
   mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL);
 }
 
 void
 MediaDrmCDMProxy::LoadSession(PromiseId aPromiseId,
+                              dom::MediaKeySessionType aSessionType,
                               const nsAString& aSessionId)
 {
   // TODO: Implement LoadSession.
   RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR,
                 NS_LITERAL_CSTRING("Currently Fennec did not support LoadSession"));
 }
 
 void
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
@@ -8,16 +8,17 @@
 #define MediaDrmCDMProxy_h_
 
 #include <jni.h>
 #include "mozilla/jni/Types.h"
 #include "GeneratedJNINatives.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/CDMCaps.h"
 #include "mozilla/dom/MediaKeys.h"
+#include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/MediaDrmProxySupport.h"
 #include "mozilla/UniquePtr.h"
 
 #include "MediaCodec.h"
 #include "nsString.h"
 
 using namespace mozilla::java;
 
@@ -42,16 +43,17 @@ public:
 
   void CreateSession(uint32_t aCreateSessionToken,
                      MediaKeySessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
                      nsTArray<uint8_t>& aInitData) override;
 
   void LoadSession(PromiseId aPromiseId,
+                   dom::MediaKeySessionType aSessionType,
                    const nsAString& aSessionId) override;
 
   void SetServerCertificate(PromiseId aPromiseId,
                             nsTArray<uint8_t>& aCert) override;
 
   void UpdateSession(const nsAString& aSessionId,
                      PromiseId aPromiseId,
                      nsTArray<uint8_t>& aResponse) override;
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -74,16 +74,33 @@ ChromiumCDMChild::OnResolveNewSessionPro
                                              const char* aSessionId,
                                              uint32_t aSessionIdSize)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::OnResolveNewSessionPromise(pid=%" PRIu32
           ", sid=%s)",
           aPromiseId,
           aSessionId);
+
+  if (mLoadSessionPromiseIds.Contains(aPromiseId)) {
+    // As laid out in the Chromium CDM API, if the CDM fails to load
+    // a session it calls OnResolveNewSessionPromise with nullptr as the sessionId.
+    // We can safely assume this means that we have failed to load a session
+    // as the other methods specify calling 'OnRejectPromise' when they fail.
+    bool loadSuccessful = aSessionId != nullptr;
+    GMP_LOG("ChromiumCDMChild::OnResolveNewSessionPromise(pid=%u, sid=%s) "
+            "resolving %s load session ",
+            aPromiseId,
+            aSessionId,
+            (loadSuccessful ? "successful" : "failed"));
+    Unused << SendResolveLoadSessionPromise(aPromiseId, loadSuccessful);
+    mLoadSessionPromiseIds.RemoveElement(aPromiseId);
+    return;
+  }
+
   Unused << SendOnResolveNewSessionPromise(aPromiseId,
                                            nsCString(aSessionId, aSessionIdSize));
 }
 
 void ChromiumCDMChild::OnResolvePromise(uint32_t aPromiseId)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::OnResolvePromise(pid=%" PRIu32 ")", aPromiseId);
@@ -290,16 +307,35 @@ ChromiumCDMChild::RecvCreateSessionAndGe
                                           static_cast<cdm::InitDataType>(aInitDataType),
                                           aInitData.Elements(),
                                           aInitData.Length());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvLoadSession(const uint32_t& aPromiseId,
+                                  const uint32_t& aSessionType,
+                                  const nsCString& aSessionId)
+{
+  GMP_LOG("ChromiumCDMChild::RecvLoadSession(pid=%u, type=%u, sessionId=%s)",
+          aPromiseId,
+          aSessionType,
+          aSessionId.get());
+  if (mCDM) {
+    mLoadSessionPromiseIds.AppendElement(aPromiseId);
+    mCDM->LoadSession(aPromiseId,
+                      static_cast<cdm::SessionType>(aSessionType),
+                      aSessionId.get(),
+                      aSessionId.Length());
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 ChromiumCDMChild::RecvUpdateSession(const uint32_t& aPromiseId,
                                     const nsCString& aSessionId,
                                     nsTArray<uint8_t>&& aResponse)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::RecvUpdateSession(pid=%" PRIu32
           ", sid=%s) responseLen=%zu",
           aPromiseId,
--- a/dom/media/gmp/ChromiumCDMChild.h
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -83,16 +83,19 @@ protected:
   ipc::IPCResult RecvSetServerCertificate(
     const uint32_t& aPromiseId,
     nsTArray<uint8_t>&& aServerCert) override;
   ipc::IPCResult RecvCreateSessionAndGenerateRequest(
     const uint32_t& aPromiseId,
     const uint32_t& aSessionType,
     const uint32_t& aInitDataType,
     nsTArray<uint8_t>&& aInitData) override;
+  ipc::IPCResult RecvLoadSession(const uint32_t& aPromiseId,
+                                 const uint32_t& aSessionType,
+                                 const nsCString& aSessionId) override;
   ipc::IPCResult RecvUpdateSession(const uint32_t& aPromiseId,
                                    const nsCString& aSessionId,
                                    nsTArray<uint8_t>&& aResponse) override;
   ipc::IPCResult RecvCloseSession(const uint32_t& aPromiseId,
                                   const nsCString& aSessionId) override;
   ipc::IPCResult RecvRemoveSession(const uint32_t& aPromiseId,
                                    const nsCString& aSessionId) override;
   ipc::IPCResult RecvDecrypt(const uint32_t& aId,
@@ -109,16 +112,17 @@ protected:
   void DecryptFailed(uint32_t aId, cdm::Status aStatus);
   void ReturnOutput(WidevineVideoFrame& aFrame);
 
   GMPContentChild* mPlugin = nullptr;
   cdm::ContentDecryptionModule_8* mCDM = nullptr;
 
   typedef SimpleMap<uint64_t> DurationMap;
   DurationMap mFrameDurations;
+  nsTArray<uint32_t> mLoadSessionPromiseIds;
 
   bool mDecoderInitialized = false;
   bool mPersistentStateAllowed = false;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -62,16 +62,42 @@ ChromiumCDMParent::CreateSession(uint32_
       NS_ERROR_DOM_INVALID_STATE_ERR,
       NS_LITERAL_CSTRING("Failed to send generateRequest to CDM process."));
     return;
   }
   mPromiseToCreateSessionToken.Put(aPromiseId, aCreateSessionToken);
 }
 
 void
+ChromiumCDMParent::LoadSession(uint32_t aPromiseId,
+                               uint32_t aSessionType,
+                               nsString aSessionId)
+{
+  GMP_LOG("ChromiumCDMParent::LoadSession(this=%p, pid=%u, type=%u, sid=%s)",
+          this,
+          aPromiseId,
+          aSessionType,
+          NS_ConvertUTF16toUTF8(aSessionId).get());
+  if (mIsShutdown) {
+    RejectPromise(aPromiseId,
+                  NS_ERROR_DOM_INVALID_STATE_ERR,
+                  NS_LITERAL_CSTRING("CDM is shutdown."));
+    return;
+  }
+  if (!SendLoadSession(
+        aPromiseId, aSessionType, NS_ConvertUTF16toUTF8(aSessionId))) {
+    RejectPromise(
+      aPromiseId,
+      NS_ERROR_DOM_INVALID_STATE_ERR,
+      NS_LITERAL_CSTRING("Failed to send loadSession to CDM process."));
+    return;
+  }
+}
+
+void
 ChromiumCDMParent::SetServerCertificate(uint32_t aPromiseId,
                                         const nsTArray<uint8_t>& aCert)
 {
   GMP_LOG("ChromiumCDMParent::SetServerCertificate(this=%p)", this);
   if (mIsShutdown) {
     RejectPromise(aPromiseId,
                   NS_ERROR_DOM_INVALID_STATE_ERR,
                   NS_LITERAL_CSTRING("CDM is shutdown."));
@@ -231,16 +257,36 @@ ChromiumCDMParent::RecvOnResolveNewSessi
                                           NS_ConvertUTF8toUTF16(aSessionId));
   NS_DispatchToMainThread(task);
 
   ResolvePromise(aPromiseId);
 
   return IPC_OK();
 }
 
+ipc::IPCResult
+ChromiumCDMParent::RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
+                                                 const bool& aSuccessful)
+{
+  GMP_LOG("ChromiumCDMParent::RecvResolveLoadSessionPromise(this=%p, pid=%u, "
+          "successful=%d)",
+          this,
+          aPromiseId,
+          aSuccessful);
+  if (!mProxy || mIsShutdown) {
+    return IPC_OK();
+  }
+
+  NS_DispatchToMainThread(NewRunnableMethod<uint32_t, bool>(
+    mProxy,
+    &ChromiumCDMProxy::OnResolveLoadSessionPromise,
+    aPromiseId,
+    aSuccessful));
+  return IPC_OK();
+}
 void
 ChromiumCDMParent::ResolvePromise(uint32_t aPromiseId)
 {
   GMP_LOG(
     "ChromiumCDMParent::ResolvePromise(this=%p, pid=%u)", this, aPromiseId);
 
   // Note: The MediaKeys rejects all pending DOM promises when it
   // initiates shutdown.
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -41,16 +41,20 @@ public:
             bool aAllowPersistentState);
 
   void CreateSession(uint32_t aCreateSessionToken,
                      uint32_t aSessionType,
                      uint32_t aInitDataType,
                      uint32_t aPromiseId,
                      const nsTArray<uint8_t>& aInitData);
 
+  void LoadSession(uint32_t aPromiseId,
+                   uint32_t aSessionType,
+                   nsString aSessionId);
+
   void SetServerCertificate(uint32_t aPromiseId,
                             const nsTArray<uint8_t>& aCert);
 
   void UpdateSession(const nsCString& aSessionId,
                      uint32_t aPromiseId,
                      const nsTArray<uint8_t>& aResponse);
 
   void CloseSession(const nsCString& aSessionId, uint32_t aPromiseId);
@@ -79,16 +83,19 @@ public:
 
 protected:
   ~ChromiumCDMParent() {}
 
   ipc::IPCResult Recv__delete__() override;
   ipc::IPCResult RecvOnResolveNewSessionPromise(
     const uint32_t& aPromiseId,
     const nsCString& aSessionId) override;
+  ipc::IPCResult RecvResolveLoadSessionPromise(
+    const uint32_t& aPromiseId,
+    const bool& aSuccessful) override;
   ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId) override;
   ipc::IPCResult RecvOnRejectPromise(const uint32_t& aPromiseId,
                                      const uint32_t& aError,
                                      const uint32_t& aSystemCode,
                                      const nsCString& aErrorMessage) override;
   ipc::IPCResult RecvOnSessionMessage(const nsCString& aSessionId,
                                       const uint32_t& aMessageType,
                                       nsTArray<uint8_t>&& aMessage) override;
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -219,23 +219,36 @@ ChromiumCDMProxy::CreateSession(uint32_t
                                          aCreateSessionToken,
                                          sessionType,
                                          initDataType,
                                          aPromiseId,
                                          Move(aInitData)));
 }
 
 void
-ChromiumCDMProxy::LoadSession(PromiseId aPromiseId, const nsAString& aSessionId)
+ChromiumCDMProxy::LoadSession(PromiseId aPromiseId,
+                              dom::MediaKeySessionType aSessionType,
+                              const nsAString& aSessionId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  RejectPromise(aPromiseId,
-                NS_ERROR_DOM_NOT_SUPPORTED_ERR,
-                NS_LITERAL_CSTRING("loadSession is not supported"));
+  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+  if (!cdm) {
+    RejectPromise(aPromiseId,
+                  NS_ERROR_DOM_INVALID_STATE_ERR,
+                  NS_LITERAL_CSTRING("Null CDM in LoadSession"));
+    return;
+  }
+
+  mGMPThread->Dispatch(NewRunnableMethod<uint32_t, uint32_t, nsString>(
+    cdm,
+    &gmp::ChromiumCDMParent::LoadSession,
+    aPromiseId,
+    ToCDMSessionType(aSessionType),
+    aSessionId));
 }
 
 void
 ChromiumCDMProxy::SetServerCertificate(PromiseId aPromiseId,
                                        nsTArray<uint8_t>& aCert)
 {
   MOZ_ASSERT(NS_IsMainThread());
   EME_LOG("ChromiumCDMProxy::SetServerCertificate(pid=%u) certLen=%zu",
@@ -412,16 +425,21 @@ ChromiumCDMProxy::OnSetSessionId(uint32_
     session->SetSessionId(aSessionId);
   }
 }
 
 void
 ChromiumCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId,
                                               bool aSuccess)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mKeys.IsNull()) {
+    return;
+  }
+  mKeys->OnSessionLoaded(aPromiseId, aSuccess);
 }
 
 void
 ChromiumCDMProxy::OnSessionMessage(const nsAString& aSessionId,
                                    dom::MediaKeyMessageType aMessageType,
                                    nsTArray<uint8_t>& aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -34,17 +34,19 @@ public:
             const nsAString& aGMPName) override;
 
   void CreateSession(uint32_t aCreateSessionToken,
                      dom::MediaKeySessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
                      nsTArray<uint8_t>& aInitData) override;
 
-  void LoadSession(PromiseId aPromiseId, const nsAString& aSessionId) override;
+  void LoadSession(PromiseId aPromiseId,
+                   dom::MediaKeySessionType aSessionType,
+                   const nsAString& aSessionId) override;
 
   void SetServerCertificate(PromiseId aPromiseId,
                             nsTArray<uint8_t>& aCert) override;
 
   void UpdateSession(const nsAString& aSessionId,
                      PromiseId aPromiseId,
                      nsTArray<uint8_t>& aResponse) override;
 
--- a/dom/media/gmp/GMPCDMProxy.cpp
+++ b/dom/media/gmp/GMPCDMProxy.cpp
@@ -323,16 +323,17 @@ GMPCDMProxy::gmp_CreateSession(UniquePtr
                       aData->mPromiseId,
                       aData->mInitDataType,
                       aData->mInitData,
                       ToGMPSessionType(aData->mSessionType));
 }
 
 void
 GMPCDMProxy::LoadSession(PromiseId aPromiseId,
+                         dom::MediaKeySessionType aSessionType,
                          const nsAString& aSessionId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mOwnerThread);
 
   UniquePtr<SessionOpData> data(new SessionOpData());
   data->mPromiseId = aPromiseId;
   data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
--- a/dom/media/gmp/GMPCDMProxy.h
+++ b/dom/media/gmp/GMPCDMProxy.h
@@ -38,16 +38,17 @@ public:
 
   void CreateSession(uint32_t aCreateSessionToken,
                      dom::MediaKeySessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
                      nsTArray<uint8_t>& aInitData) override;
 
   void LoadSession(PromiseId aPromiseId,
+                   dom::MediaKeySessionType aSessionType,
                    const nsAString& aSessionId) override;
 
   void SetServerCertificate(PromiseId aPromiseId,
                             nsTArray<uint8_t>& aCert) override;
 
   void UpdateSession(const nsAString& aSessionId,
                      PromiseId aPromiseId,
                      nsTArray<uint8_t>& aResponse) override;
--- a/dom/media/gmp/PChromiumCDM.ipdl
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -21,16 +21,20 @@ child:
   async SetServerCertificate(uint32_t aPromiseId,
                              uint8_t[] aServerCert);
 
   async CreateSessionAndGenerateRequest(uint32_t aPromiseId,
                                         uint32_t aSessionType,
                                         uint32_t aInitDataType,
                                         uint8_t[] aInitData);
 
+  async LoadSession(uint32_t aPromiseId,
+                    uint32_t aSessionType,
+                    nsCString aSessionId);
+
   async UpdateSession(uint32_t aPromiseId,
                       nsCString aSessionId,
                       uint8_t[] aResponse);
 
   async CloseSession(uint32_t aPromiseId,
                      nsCString aSessionId);
 
   async RemoveSession(uint32_t aPromiseId,
@@ -75,16 +79,18 @@ parent:
 
   async OnSessionClosed(nsCString aSessionId);
 
   async OnLegacySessionError(nsCString aSessionId,
                              uint32_t aError,
                              uint32_t aSystemCode,
                              nsCString aMessage);
 
+  async ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccessful);
+
   // Return values of cdm::ContentDecryptionModule8::Decrypt
   async Decrypted(uint32_t aId, uint32_t aStatus, uint8_t[] aData);
 
   async OnDecoderInitDone(uint32_t aStatus);
 
   // Return values of cdm::ContentDecryptionModule8::DecryptAndDecodeFrame
   async Decoded(CDMVideoFrame aFrame);
   async DecodeFailed(uint32_t aStatus);