Bug 1265587 - Force keystatuses to be cleared when Widevine keysessions are closed. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Fri, 22 Apr 2016 08:31:18 +1200
changeset 332267 6855520a3df4df29f6163037ef0a7e1250c34a0a
parent 332266 78b83b86b1aabf320f34a2c2942499864867530b
child 332268 5816f7da8d5b801a0e15cf9c12f4cb118fc14875
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1265587
milestone48.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 1265587 - Force keystatuses to be cleared when Widevine keysessions are closed. r=gerald The Widevine CDM, and I believe the Adobe CDM too probably, do not mark a session's keys as unusable when a key session is closed. This means that the CDMCaps' copy of the keys that are usable is wrong, and so if the media with the same keys is reloaded with the same MediaKeys, Firefox will assume that the keys are usable before the license for the keys has been re-negotiated, and so decryption will fail. MozReview-Commit-ID: 1kTDzwSD8PE
dom/html/HTMLMediaElement.cpp
dom/media/eme/CDMCallbackProxy.cpp
dom/media/eme/CDMCaps.cpp
dom/media/eme/CDMCaps.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -5142,16 +5142,19 @@ HTMLMediaElement::ContainsRestrictedCont
 {
   return GetMediaKeys() != nullptr;
 }
 
 already_AddRefed<Promise>
 HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
                                ErrorResult& aRv)
 {
+  LOG(LogLevel::Debug, ("%p SetMediaKeys(%p) mMediaKeys=%p mDecoder=%p",
+    this, aMediaKeys, mMediaKeys.get(), mDecoder.get()));
+
   if (MozAudioCaptured()) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global =
     do_QueryInterface(OwnerDoc()->GetInnerWindow());
   if (!global) {
--- a/dom/media/eme/CDMCallbackProxy.cpp
+++ b/dom/media/eme/CDMCallbackProxy.cpp
@@ -210,16 +210,29 @@ CDMCallbackProxy::ExpirationChange(const
   NS_DispatchToMainThread(task);
 }
 
 void
 CDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
 {
   MOZ_ASSERT(mProxy->IsOnGMPThread());
 
+  bool keyStatusesChange = false;
+  {
+    CDMCaps::AutoLock caps(mProxy->Capabilites());
+    keyStatusesChange = caps.RemoveKeysForSession(NS_ConvertUTF8toUTF16(aSessionId));
+  }
+  if (keyStatusesChange) {
+    nsCOMPtr<nsIRunnable> task;
+    task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+      &CDMProxy::OnKeyStatusesChange,
+      NS_ConvertUTF8toUTF16(aSessionId));
+    NS_DispatchToMainThread(task);
+  }
+
   nsCOMPtr<nsIRunnable> task;
   task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
                                                &CDMProxy::OnSessionClosed,
                                                NS_ConvertUTF8toUTF16(aSessionId));
   NS_DispatchToMainThread(task);
 }
 
 class SessionErrorTask : public nsRunnable {
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -238,9 +238,21 @@ CDMCaps::AutoLock::GetSessionIdsForKeyId
 {
   for (const auto& keyStatus : mData.mKeyStatuses) {
     if (keyStatus.mId == aKeyId) {
       aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
     }
   }
 }
 
+bool
+CDMCaps::AutoLock::RemoveKeysForSession(const nsString& aSessionId)
+{
+  bool changed = false;
+  nsTArray<KeyStatus> statuses;
+  GetKeyStatusesForSession(aSessionId, statuses);
+  for (const KeyStatus& status : statuses) {
+    changed |= SetKeyStatus(status.mId, aSessionId, kGMPUnknown);
+  }
+  return changed;
+}
+
 } // namespace mozilla
--- a/dom/media/eme/CDMCaps.h
+++ b/dom/media/eme/CDMCaps.h
@@ -66,16 +66,20 @@ public:
     bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
 
     void GetKeyStatusesForSession(const nsAString& aSessionId,
                                   nsTArray<KeyStatus>& aOutKeyStatuses);
 
     void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
                                nsTArray<nsCString>& aOutSessionIds);
 
+    // Ensures all keys for a session are marked as 'unknown', i.e. removed.
+    // Returns true if a key status was changed.
+    bool RemoveKeysForSession(const nsString& aSessionId);
+
     // Sets the capabilities of the CDM. aCaps is the logical OR of the
     // GMP_EME_CAP_* flags from gmp-decryption.h.
     void SetCaps(uint64_t aCaps);
 
     bool CanRenderAudio();
     bool CanRenderVideo();
 
     bool CanDecryptAndDecodeAudio();