LCOV - code coverage report
Current view: top level - dom/media/gmp/widevine-adapter - WidevineDecryptor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 226 0.9 %
Date: 2017-07-14 16:53:18 Functions: 2 42 4.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "WidevineDecryptor.h"
       7             : 
       8             : #include "WidevineAdapter.h"
       9             : #include "WidevineUtils.h"
      10             : #include "WidevineFileIO.h"
      11             : #include <stdarg.h>
      12             : #include "base/time.h"
      13             : 
      14             : using namespace cdm;
      15             : using namespace std;
      16             : 
      17             : namespace mozilla {
      18             : 
      19           3 : static map<uint32_t, RefPtr<CDMWrapper>> sDecryptors;
      20             : 
      21             : /* static */
      22             : RefPtr<CDMWrapper>
      23           0 : WidevineDecryptor::GetInstance(uint32_t aInstanceId)
      24             : {
      25           0 :   auto itr = sDecryptors.find(aInstanceId);
      26           0 :   if (itr != sDecryptors.end()) {
      27           0 :     return itr->second;
      28             :   }
      29           0 :   return nullptr;
      30             : }
      31             : 
      32             : 
      33           0 : WidevineDecryptor::WidevineDecryptor()
      34           0 :   : mCallback(nullptr)
      35             : {
      36           0 :   CDM_LOG("WidevineDecryptor created this=%p, instanceId=%u", this, mInstanceId);
      37           0 :   AddRef(); // Released in DecryptingComplete().
      38           0 : }
      39             : 
      40           0 : WidevineDecryptor::~WidevineDecryptor()
      41             : {
      42           0 :   CDM_LOG("WidevineDecryptor destroyed this=%p, instanceId=%u", this, mInstanceId);
      43           0 : }
      44             : 
      45             : void
      46           0 : WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aInstanceId)
      47             : {
      48           0 :   mCDM = aCDM;
      49           0 :   mInstanceId = aInstanceId;
      50           0 :   sDecryptors[mInstanceId] = aCDM.forget();
      51           0 : }
      52             : 
      53             : void
      54           0 : WidevineDecryptor::Init(GMPDecryptorCallback* aCallback,
      55             :                         bool aDistinctiveIdentifierRequired,
      56             :                         bool aPersistentStateRequired)
      57             : {
      58           0 :   CDM_LOG("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d",
      59             :           this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
      60           0 :   MOZ_ASSERT(aCallback);
      61           0 :   mCallback = aCallback;
      62           0 :   MOZ_ASSERT(mCDM);
      63           0 :   mDistinctiveIdentifierRequired = aDistinctiveIdentifierRequired;
      64           0 :   mPersistentStateRequired = aPersistentStateRequired;
      65           0 :   if (CDM()) {
      66           0 :     CDM()->Initialize(aDistinctiveIdentifierRequired,
      67           0 :                       aPersistentStateRequired);
      68             :   }
      69           0 : }
      70             : 
      71             : static SessionType
      72           0 : ToCDMSessionType(GMPSessionType aSessionType)
      73             : {
      74           0 :   switch (aSessionType) {
      75           0 :     case kGMPTemporySession: return kTemporary;
      76           0 :     case kGMPPersistentSession: return kPersistentLicense;
      77           0 :     case kGMPSessionInvalid: return kTemporary;
      78             :     // TODO: kPersistentKeyRelease
      79             :   }
      80           0 :   MOZ_ASSERT(false); // Not supposed to get here.
      81             :   return kTemporary;
      82             : }
      83             : 
      84             : void
      85           0 : WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken,
      86             :                                  uint32_t aPromiseId,
      87             :                                  const char* aInitDataType,
      88             :                                  uint32_t aInitDataTypeSize,
      89             :                                  const uint8_t* aInitData,
      90             :                                  uint32_t aInitDataSize,
      91             :                                  GMPSessionType aSessionType)
      92             : {
      93           0 :   CDM_LOG("Decryptor::CreateSession(token=%d, pid=%d)", aCreateSessionToken, aPromiseId);
      94             :   InitDataType initDataType;
      95           0 :   if (!strcmp(aInitDataType, "cenc")) {
      96           0 :     initDataType = kCenc;
      97           0 :   } else if (!strcmp(aInitDataType, "webm")) {
      98           0 :     initDataType = kWebM;
      99           0 :   } else if (!strcmp(aInitDataType, "keyids")) {
     100           0 :     initDataType = kKeyIds;
     101             :   } else {
     102             :     // Invalid init data type
     103           0 :     const char* errorMsg = "Invalid init data type when creating session.";
     104           0 :     OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg));
     105           0 :     return;
     106             :   }
     107           0 :   mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken;
     108           0 :   CDM()->CreateSessionAndGenerateRequest(aPromiseId,
     109             :                                          ToCDMSessionType(aSessionType),
     110             :                                          initDataType,
     111           0 :                                          aInitData, aInitDataSize);
     112             : }
     113             : 
     114             : void
     115           0 : WidevineDecryptor::LoadSession(uint32_t aPromiseId,
     116             :                                const char* aSessionId,
     117             :                                uint32_t aSessionIdLength)
     118             : {
     119           0 :   CDM_LOG("Decryptor::LoadSession(pid=%d, %s)", aPromiseId, aSessionId);
     120             :   // TODO: session type??
     121           0 :   CDM()->LoadSession(aPromiseId, kPersistentLicense, aSessionId, aSessionIdLength);
     122           0 : }
     123             : 
     124             : void
     125           0 : WidevineDecryptor::UpdateSession(uint32_t aPromiseId,
     126             :                                  const char* aSessionId,
     127             :                                  uint32_t aSessionIdLength,
     128             :                                  const uint8_t* aResponse,
     129             :                                  uint32_t aResponseSize)
     130             : {
     131           0 :   CDM_LOG("Decryptor::UpdateSession(pid=%d, session=%s)", aPromiseId, aSessionId);
     132           0 :   CDM()->UpdateSession(aPromiseId, aSessionId, aSessionIdLength, aResponse, aResponseSize);
     133           0 : }
     134             : 
     135             : void
     136           0 : WidevineDecryptor::CloseSession(uint32_t aPromiseId,
     137             :                                 const char* aSessionId,
     138             :                                 uint32_t aSessionIdLength)
     139             : {
     140           0 :   CDM_LOG("Decryptor::CloseSession(pid=%d, session=%s)", aPromiseId, aSessionId);
     141           0 :   CDM()->CloseSession(aPromiseId, aSessionId, aSessionIdLength);
     142           0 : }
     143             : 
     144             : void
     145           0 : WidevineDecryptor::RemoveSession(uint32_t aPromiseId,
     146             :                                  const char* aSessionId,
     147             :                                  uint32_t aSessionIdLength)
     148             : {
     149           0 :   CDM_LOG("Decryptor::RemoveSession(%s)", aSessionId);
     150           0 :   CDM()->RemoveSession(aPromiseId, aSessionId, aSessionIdLength);
     151           0 : }
     152             : 
     153             : void
     154           0 : WidevineDecryptor::SetServerCertificate(uint32_t aPromiseId,
     155             :                                         const uint8_t* aServerCert,
     156             :                                         uint32_t aServerCertSize)
     157             : {
     158           0 :   CDM_LOG("Decryptor::SetServerCertificate()");
     159           0 :   CDM()->SetServerCertificate(aPromiseId, aServerCert, aServerCertSize);
     160           0 : }
     161             : 
     162             : void
     163           0 : WidevineDecryptor::Decrypt(GMPBuffer* aBuffer,
     164             :                            GMPEncryptedBufferMetadata* aMetadata)
     165             : {
     166           0 :   if (!mCallback) {
     167           0 :     CDM_LOG("WidevineDecryptor::Decrypt() this=%p FAIL; !mCallback", this);
     168           0 :     return;
     169             :   }
     170           0 :   const GMPEncryptedBufferMetadata* crypto = aMetadata;
     171           0 :   InputBuffer sample;
     172           0 :   nsTArray<SubsampleEntry> subsamples;
     173           0 :   InitInputBuffer(crypto, aBuffer->Id(), aBuffer->Data(), aBuffer->Size(), sample, subsamples);
     174           0 :   WidevineDecryptedBlock decrypted;
     175           0 :   Status rv = CDM()->Decrypt(sample, &decrypted);
     176           0 :   CDM_LOG("Decryptor::Decrypt(timestamp=%" PRId64 ") rv=%d sz=%d",
     177             :           sample.timestamp, rv, decrypted.DecryptedBuffer()->Size());
     178           0 :   if (rv == kSuccess) {
     179           0 :     aBuffer->Resize(decrypted.DecryptedBuffer()->Size());
     180           0 :     memcpy(aBuffer->Data(),
     181           0 :            decrypted.DecryptedBuffer()->Data(),
     182           0 :            decrypted.DecryptedBuffer()->Size());
     183             :   }
     184           0 :   mCallback->Decrypted(aBuffer, ToGMPErr(rv));
     185             : }
     186             : 
     187             : void
     188           0 : WidevineDecryptor::DecryptingComplete()
     189             : {
     190           0 :   CDM_LOG("WidevineDecryptor::DecryptingComplete() this=%p, instanceId=%u",
     191             :           this, mInstanceId);
     192             :   // Drop our references to the CDMWrapper. When any other references
     193             :   // held elsewhere are dropped (for example references held by a
     194             :   // WidevineVideoDecoder, or a runnable), the CDMWrapper destroys
     195             :   // the CDM.
     196           0 :   mCDM = nullptr;
     197           0 :   sDecryptors.erase(mInstanceId);
     198           0 :   mCallback = nullptr;
     199           0 :   Release();
     200           0 : }
     201             : 
     202             : Buffer*
     203           0 : WidevineDecryptor::Allocate(uint32_t aCapacity)
     204             : {
     205           0 :   CDM_LOG("Decryptor::Allocate(capacity=%u)", aCapacity);
     206           0 :   return new WidevineBuffer(aCapacity);
     207             : }
     208             : 
     209             : class TimerTask : public GMPTask {
     210             : public:
     211           0 :   TimerTask(WidevineDecryptor* aDecryptor,
     212             :             RefPtr<CDMWrapper> aCDM,
     213             :             void* aContext)
     214           0 :     : mDecryptor(aDecryptor)
     215             :     , mCDM(aCDM)
     216           0 :     , mContext(aContext)
     217             :   {
     218           0 :   }
     219           0 :   ~TimerTask() override = default;
     220           0 :   void Run() override {
     221           0 :     mCDM->GetCDM()->TimerExpired(mContext);
     222           0 :   }
     223           0 :   void Destroy() override { delete this; }
     224             : private:
     225             :   RefPtr<WidevineDecryptor> mDecryptor;
     226             :   RefPtr<CDMWrapper> mCDM;
     227             :   void* mContext;
     228             : };
     229             : 
     230             : void
     231           0 : WidevineDecryptor::SetTimer(int64_t aDelayMs, void* aContext)
     232             : {
     233           0 :   CDM_LOG("Decryptor::SetTimer(delay_ms=%" PRId64 ", context=0x%p)", aDelayMs, aContext);
     234           0 :   if (mCDM) {
     235           0 :     GMPSetTimerOnMainThread(new TimerTask(this, mCDM, aContext), aDelayMs);
     236             :   }
     237           0 : }
     238             : 
     239             : Time
     240           0 : WidevineDecryptor::GetCurrentWallTime()
     241             : {
     242           0 :   return base::Time::Now().ToDoubleT();
     243             : }
     244             : 
     245             : void
     246           0 : WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
     247             :                                               const char* aSessionId,
     248             :                                               uint32_t aSessionIdSize)
     249             : {
     250           0 :   if (!mCallback) {
     251           0 :     CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
     252           0 :     return;
     253             :   }
     254             : 
     255             :   // This is laid out in the API. If we fail to load a session we should
     256             :   // call OnResolveNewSessionPromise with nullptr as the sessionId.
     257             :   // We can safely assume this means that we have failed to load a session
     258             :   // as the other methods specify calling 'OnRejectPromise' when they fail.
     259           0 :   if (!aSessionId) {
     260           0 :     CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) Failed to load session", aPromiseId);
     261           0 :     mCallback->ResolveLoadSessionPromise(aPromiseId, false);
     262           0 :     return;
     263             :   }
     264             : 
     265           0 :   CDM_LOG("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId);
     266           0 :   auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId);
     267           0 :   if (iter == mPromiseIdToNewSessionTokens.end()) {
     268           0 :     CDM_LOG("FAIL: Decryptor::OnResolveNewSessionPromise(aPromiseId=%d) unknown aPromiseId", aPromiseId);
     269           0 :     return;
     270             :   }
     271           0 :   mCallback->SetSessionId(iter->second, aSessionId, aSessionIdSize);
     272           0 :   mCallback->ResolvePromise(aPromiseId);
     273           0 :   mPromiseIdToNewSessionTokens.erase(iter);
     274             : }
     275             : 
     276             : void
     277           0 : WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId)
     278             : {
     279           0 :   if (!mCallback) {
     280           0 :     CDM_LOG("Decryptor::OnResolvePromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
     281           0 :     return;
     282             :   }
     283           0 :   CDM_LOG("Decryptor::OnResolvePromise(aPromiseId=%d)", aPromiseId);
     284           0 :   mCallback->ResolvePromise(aPromiseId);
     285             : }
     286             : 
     287             : static GMPDOMException
     288           0 : ToGMPDOMException(cdm::Error aError)
     289             : {
     290           0 :   switch (aError) {
     291           0 :     case kNotSupportedError: return kGMPNotSupportedError;
     292           0 :     case kInvalidStateError: return kGMPInvalidStateError;
     293             :     case kInvalidAccessError:
     294             :       // Note: Chrome converts kInvalidAccessError to TypeError, since the
     295             :       // Chromium CDM API doesn't have a type error enum value. The EME spec
     296             :       // requires TypeError in some places, so we do the same conversion.
     297             :       // See bug 1313202.
     298           0 :       return kGMPTypeError;
     299           0 :     case kQuotaExceededError: return kGMPQuotaExceededError;
     300           0 :     case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder.
     301           0 :     case kClientError: return kGMPAbortError; // Note: Unique placeholder.
     302           0 :     case kOutputError: return kGMPSecurityError; // Note: Unique placeholder.
     303             :   };
     304           0 :   return kGMPTimeoutError; // Note: Unique placeholder.
     305             : }
     306             : 
     307             : void
     308           0 : WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId,
     309             :                                    Error aError,
     310             :                                    uint32_t aSystemCode,
     311             :                                    const char* aErrorMessage,
     312             :                                    uint32_t aErrorMessageSize)
     313             : {
     314           0 :   if (!mCallback) {
     315           0 :     CDM_LOG("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback",
     316             :             aPromiseId, (int)aError, aSystemCode, aErrorMessage);
     317           0 :     return;
     318             :   }
     319           0 :   CDM_LOG("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)",
     320             :           aPromiseId, (int)aError, aSystemCode, aErrorMessage);
     321           0 :   mCallback->RejectPromise(aPromiseId,
     322             :                            ToGMPDOMException(aError),
     323             :                            !aErrorMessageSize ? "" : aErrorMessage,
     324           0 :                            aErrorMessageSize);
     325             : }
     326             : 
     327             : static GMPSessionMessageType
     328           0 : ToGMPMessageType(MessageType message_type)
     329             : {
     330           0 :   switch (message_type) {
     331           0 :     case kLicenseRequest: return kGMPLicenseRequest;
     332           0 :     case kLicenseRenewal: return kGMPLicenseRenewal;
     333           0 :     case kLicenseRelease: return kGMPLicenseRelease;
     334             :   }
     335           0 :   return kGMPMessageInvalid;
     336             : }
     337             : 
     338             : void
     339           0 : WidevineDecryptor::OnSessionMessage(const char* aSessionId,
     340             :                                     uint32_t aSessionIdSize,
     341             :                                     MessageType aMessageType,
     342             :                                     const char* aMessage,
     343             :                                     uint32_t aMessageSize,
     344             :                                     const char* aLegacyDestinationUrl,
     345             :                                     uint32_t aLegacyDestinationUrlLength)
     346             : {
     347           0 :   if (!mCallback) {
     348           0 :     CDM_LOG("Decryptor::OnSessionMessage() FAIL; !mCallback");
     349           0 :     return;
     350             :   }
     351           0 :   CDM_LOG("Decryptor::OnSessionMessage()");
     352           0 :   mCallback->SessionMessage(aSessionId,
     353             :                             aSessionIdSize,
     354             :                             ToGMPMessageType(aMessageType),
     355             :                             reinterpret_cast<const uint8_t*>(aMessage),
     356           0 :                             aMessageSize);
     357             : }
     358             : 
     359             : static GMPMediaKeyStatus
     360           0 : ToGMPKeyStatus(KeyStatus aStatus)
     361             : {
     362           0 :   switch (aStatus) {
     363           0 :     case kUsable: return kGMPUsable;
     364           0 :     case kInternalError: return kGMPInternalError;
     365           0 :     case kExpired: return kGMPExpired;
     366           0 :     case kOutputRestricted: return kGMPOutputRestricted;
     367           0 :     case kOutputDownscaled: return kGMPOutputDownscaled;
     368           0 :     case kStatusPending: return kGMPStatusPending;
     369           0 :     case kReleased: return kGMPReleased;
     370             :   }
     371           0 :   return kGMPUnknown;
     372             : }
     373             : 
     374             : void
     375           0 : WidevineDecryptor::OnSessionKeysChange(const char* aSessionId,
     376             :                                        uint32_t aSessionIdSize,
     377             :                                        bool aHasAdditionalUsableKey,
     378             :                                        const KeyInformation* aKeysInfo,
     379             :                                        uint32_t aKeysInfoCount)
     380             : {
     381           0 :   if (!mCallback) {
     382           0 :     CDM_LOG("Decryptor::OnSessionKeysChange() FAIL; !mCallback");
     383           0 :     return;
     384             :   }
     385           0 :   CDM_LOG("Decryptor::OnSessionKeysChange()");
     386             : 
     387           0 :   nsTArray<GMPMediaKeyInfo> key_infos;
     388           0 :   for (uint32_t i = 0; i < aKeysInfoCount; i++) {
     389           0 :     key_infos.AppendElement(GMPMediaKeyInfo(aKeysInfo[i].key_id,
     390           0 :                                             aKeysInfo[i].key_id_size,
     391           0 :                                             ToGMPKeyStatus(aKeysInfo[i].status)));
     392             :   }
     393           0 :   mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdSize,
     394           0 :                                      key_infos.Elements(), key_infos.Length());
     395             : }
     396             : 
     397             : static GMPTimestamp
     398           0 : ToGMPTime(Time aCDMTime)
     399             : {
     400           0 :   return static_cast<GMPTimestamp>(aCDMTime * 1000);
     401             : }
     402             : 
     403             : void
     404           0 : WidevineDecryptor::OnExpirationChange(const char* aSessionId,
     405             :                                       uint32_t aSessionIdSize,
     406             :                                       Time aNewExpiryTime)
     407             : {
     408           0 :   if (!mCallback) {
     409           0 :     CDM_LOG("Decryptor::OnExpirationChange(sid=%s) t=%lf FAIL; !mCallback",
     410             :             aSessionId, aNewExpiryTime);
     411           0 :     return;
     412             :   }
     413           0 :   CDM_LOG("Decryptor::OnExpirationChange(sid=%s) t=%lf", aSessionId, aNewExpiryTime);
     414           0 :   mCallback->ExpirationChange(aSessionId, aSessionIdSize, ToGMPTime(aNewExpiryTime));
     415             : }
     416             : 
     417             : void
     418           0 : WidevineDecryptor::OnSessionClosed(const char* aSessionId,
     419             :                                    uint32_t aSessionIdSize)
     420             : {
     421           0 :   if (!mCallback) {
     422           0 :     CDM_LOG("Decryptor::OnSessionClosed(sid=%s) FAIL; !mCallback", aSessionId);
     423           0 :     return;
     424             :   }
     425           0 :   CDM_LOG("Decryptor::OnSessionClosed(sid=%s)", aSessionId);
     426           0 :   mCallback->SessionClosed(aSessionId, aSessionIdSize);
     427             : }
     428             : 
     429             : void
     430           0 : WidevineDecryptor::OnLegacySessionError(const char* aSessionId,
     431             :                                         uint32_t aSessionIdLength,
     432             :                                         Error aError,
     433             :                                         uint32_t aSystemCode,
     434             :                                         const char* aErrorMessage,
     435             :                                         uint32_t aErrorMessageLength)
     436             : {
     437           0 :   if (!mCallback) {
     438           0 :     CDM_LOG("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback",
     439             :             aSessionId, (int)aError);
     440           0 :     return;
     441             :   }
     442           0 :   CDM_LOG("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError);
     443           0 :   mCallback->SessionError(aSessionId,
     444             :                           aSessionIdLength,
     445             :                           ToGMPDOMException(aError),
     446             :                           aSystemCode,
     447             :                           aErrorMessage,
     448           0 :                           aErrorMessageLength);
     449             : }
     450             : 
     451             : void
     452           0 : WidevineDecryptor::SendPlatformChallenge(const char* aServiceId,
     453             :                                          uint32_t aServiceIdSize,
     454             :                                          const char* aChallenge,
     455             :                                          uint32_t aChallengeSize)
     456             : {
     457           0 :   CDM_LOG("Decryptor::SendPlatformChallenge(service_id=%s)", aServiceId);
     458           0 : }
     459             : 
     460             : void
     461           0 : WidevineDecryptor::EnableOutputProtection(uint32_t aDesiredProtectionMask)
     462             : {
     463           0 :   CDM_LOG("Decryptor::EnableOutputProtection(mask=0x%x)", aDesiredProtectionMask);
     464           0 : }
     465             : 
     466             : void
     467           0 : WidevineDecryptor::QueryOutputProtectionStatus()
     468             : {
     469           0 :   CDM_LOG("Decryptor::QueryOutputProtectionStatus()");
     470           0 : }
     471             : 
     472             : void
     473           0 : WidevineDecryptor::OnDeferredInitializationDone(StreamType aStreamType,
     474             :                                                 Status aDecoderStatus)
     475             : {
     476           0 :   CDM_LOG("Decryptor::OnDeferredInitializationDone()");
     477           0 : }
     478             : 
     479             : FileIO*
     480           0 : WidevineDecryptor::CreateFileIO(FileIOClient* aClient)
     481             : {
     482           0 :   CDM_LOG("Decryptor::CreateFileIO()");
     483           0 :   if (!mPersistentStateRequired) {
     484           0 :     return nullptr;
     485             :   }
     486           0 :   return new WidevineFileIO(aClient);
     487             : }
     488             : 
     489           9 : } // namespace mozilla

Generated by: LCOV version 1.13