tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MFCDMChild.cpp (19846B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "MFCDMChild.h"
      6 
      7 #include "RemoteMediaManagerChild.h"
      8 #include "mozilla/EMEUtils.h"
      9 #include "mozilla/KeySystemConfig.h"
     10 #include "mozilla/RefPtr.h"
     11 #include "mozilla/StaticString.h"
     12 #include "mozilla/WMFCDMProxyCallback.h"
     13 #include "nsString.h"
     14 
     15 namespace mozilla {
     16 
     17 #define LOG(msg, ...) \
     18  EME_LOG("MFCDMChild[%p]@%s: " msg, this, __func__, ##__VA_ARGS__)
     19 #define SLOG(msg, ...) EME_LOG("MFCDMChild@%s: " msg, __func__, ##__VA_ARGS__)
     20 
     21 #define HANDLE_PENDING_PROMISE(method, callsite, promise, promiseId)         \
     22  do {                                                                       \
     23    promise->Then(                                                           \
     24        self->mManagerThread, callsite,                                      \
     25        [self, promiseId, callsite](                                         \
     26            PMFCDMChild::method##Promise::ResolveOrRejectValue&& result) {   \
     27          MutexAutoLock lock(self->mMutex);                                  \
     28          auto iter = self->mPendingGenericPromises.find(promiseId);         \
     29          if (iter == self->mPendingGenericPromises.end()) {                 \
     30            return;                                                          \
     31          }                                                                  \
     32          auto& promiseHolder = iter->second;                                \
     33          if (result.IsResolve()) {                                          \
     34            if (NS_SUCCEEDED(result.ResolveValue())) {                       \
     35              promiseHolder.ResolveIfExists(true, callsite);                 \
     36            } else {                                                         \
     37              promiseHolder.RejectIfExists(result.ResolveValue(), callsite); \
     38            }                                                                \
     39          } else {                                                           \
     40            /* IPC die */                                                    \
     41            promiseHolder.RejectIfExists(NS_ERROR_FAILURE, callsite);        \
     42          }                                                                  \
     43          self->mPendingGenericPromises.erase(iter);                         \
     44        });                                                                  \
     45  } while (0)
     46 
     47 #define INVOKE_ASYNC(method, promiseId, param1)                      \
     48  do {                                                               \
     49    StaticString callsite = __func__;                                \
     50    using ParamType = std::remove_reference<decltype(param1)>::type; \
     51    mManagerThread->Dispatch(NS_NewRunnableFunction(                 \
     52        callsite, [self = RefPtr{this}, callsite, promiseId,         \
     53                   param_1 = std::forward<ParamType>(param1)] {      \
     54          auto p = self->Send##method(param_1);                      \
     55          HANDLE_PENDING_PROMISE(method, callsite, p, promiseId);    \
     56        }));                                                         \
     57  } while (0)
     58 
     59 #define INVOKE_ASYNC2(method, promiseId, param1, param2)              \
     60  do {                                                                \
     61    StaticString callsite = __func__;                                 \
     62    using ParamType1 = std::remove_reference<decltype(param1)>::type; \
     63    using ParamType2 = std::remove_reference<decltype(param2)>::type; \
     64    mManagerThread->Dispatch(NS_NewRunnableFunction(                  \
     65        callsite, [self = RefPtr{this}, callsite, promiseId,          \
     66                   param_1 = std::forward<ParamType1>(param1),        \
     67                   param_2 = std::forward<ParamType2>(param2)] {      \
     68          auto p = self->Send##method(param_1, param_2);              \
     69          HANDLE_PENDING_PROMISE(method, callsite, p, promiseId);     \
     70        }));                                                          \
     71  } while (0)
     72 
     73 MFCDMChild::MFCDMChild(const nsAString& aKeySystem)
     74    : mKeySystem(aKeySystem),
     75      mManagerThread(RemoteMediaManagerChild::GetManagerThread()),
     76      mState(NS_ERROR_NOT_INITIALIZED),
     77      mShutdown(false) {}
     78 
     79 MFCDMChild::~MFCDMChild() {}
     80 
     81 void MFCDMChild::EnsureRemote() {
     82  if (mRemotePromise) {
     83    LOG("already created remote promise");
     84    return;
     85  }
     86 
     87  if (!mManagerThread) {
     88    LOG("no manager thread");
     89    mState = NS_ERROR_NOT_AVAILABLE;
     90    mRemotePromise = RemotePromise::CreateAndReject(mState, __func__);
     91    return;
     92  }
     93 
     94  mRemotePromise = mRemotePromiseHolder.Ensure(__func__);
     95 
     96  RefPtr<MFCDMChild> self = this;
     97  RemoteMediaManagerChild::LaunchUtilityProcessIfNeeded(
     98      RemoteMediaIn::UtilityProcess_MFMediaEngineCDM)
     99      ->Then(
    100          mManagerThread, __func__,
    101          [self, this](bool) {
    102            mRemoteRequest.Complete();
    103            RefPtr<RemoteMediaManagerChild> manager =
    104                RemoteMediaManagerChild::GetSingleton(
    105                    RemoteMediaIn::UtilityProcess_MFMediaEngineCDM);
    106            if (!manager || !manager->CanSend()) {
    107              LOG("manager not exists or can't send");
    108              mState = NS_ERROR_NOT_AVAILABLE;
    109              mRemotePromiseHolder.RejectIfExists(mState, __func__);
    110              return;
    111            }
    112 
    113            mIPDLSelfRef = this;
    114            MOZ_ALWAYS_TRUE(manager->SendPMFCDMConstructor(this, mKeySystem));
    115            mState = NS_OK;
    116            mRemotePromiseHolder.ResolveIfExists(true, __func__);
    117          },
    118          [self, this](nsresult rv) {
    119            mRemoteRequest.Complete();
    120            LOG("fail to launch MFCDM process");
    121            mState = rv;
    122            mRemotePromiseHolder.RejectIfExists(rv, __func__);
    123          })
    124      ->Track(mRemoteRequest);
    125 }
    126 
    127 void MFCDMChild::Shutdown() {
    128  MOZ_ASSERT(!mShutdown);
    129  mShutdown = true;
    130  if (mState == NS_OK) {
    131    mManagerThread->Dispatch(
    132        NS_NewRunnableFunction(__func__, [self = RefPtr{this}, this]() {
    133          mRemoteRequest.DisconnectIfExists();
    134          mInitRequest.DisconnectIfExists();
    135          mProxyCallback = nullptr;
    136 
    137          {
    138            MutexAutoLock lock(mMutex);
    139            for (auto& promise : mPendingSessionPromises) {
    140              promise.second.RejectIfExists(NS_ERROR_ABORT, __func__);
    141            }
    142            mPendingSessionPromises.clear();
    143 
    144            for (auto& promise : mPendingGenericPromises) {
    145              promise.second.RejectIfExists(NS_ERROR_ABORT, __func__);
    146            }
    147            mPendingGenericPromises.clear();
    148          }
    149 
    150          mRemotePromiseHolder.RejectIfExists(NS_ERROR_ABORT, __func__);
    151          mCapabilitiesPromiseHolder.RejectIfExists(NS_ERROR_ABORT, __func__);
    152 
    153          Send__delete__(this);
    154        }));
    155  }
    156 }
    157 
    158 RefPtr<MFCDMChild::CapabilitiesPromise> MFCDMChild::GetCapabilities(
    159    MFCDMCapabilitiesRequest&& aRequest) {
    160  MOZ_ASSERT(mManagerThread);
    161 
    162  if (mShutdown) {
    163    return CapabilitiesPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    164  }
    165 
    166  if (mState != NS_OK && mState != NS_ERROR_NOT_INITIALIZED) {
    167    LOG("error=%x", uint32_t(nsresult(mState)));
    168    return CapabilitiesPromise::CreateAndReject(mState, __func__);
    169  }
    170 
    171  auto doSend = [self = RefPtr{this}, request = std::move(aRequest), this]() {
    172    SendGetCapabilities(request)->Then(
    173        mManagerThread, __func__,
    174        [self, this](MFCDMCapabilitiesResult&& aResult) {
    175          if (aResult.type() == MFCDMCapabilitiesResult::Tnsresult) {
    176            mCapabilitiesPromiseHolder.RejectIfExists(aResult.get_nsresult(),
    177                                                      __func__);
    178            return;
    179          }
    180          mCapabilitiesPromiseHolder.ResolveIfExists(
    181              std::move(aResult.get_MFCDMCapabilitiesIPDL()), __func__);
    182        },
    183        [self, this](const mozilla::ipc::ResponseRejectReason& aReason) {
    184          mCapabilitiesPromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
    185        });
    186  };
    187 
    188  return InvokeAsync(doSend, __func__, mCapabilitiesPromiseHolder);
    189 }
    190 
    191 // Neither error nor shutdown.
    192 void MFCDMChild::AssertSendable() {
    193  MOZ_ASSERT((mState == NS_ERROR_NOT_INITIALIZED || mState == NS_OK) &&
    194             mShutdown == false);
    195 }
    196 
    197 template <typename PromiseType>
    198 already_AddRefed<PromiseType> MFCDMChild::InvokeAsync(
    199    std::function<void()>&& aCall, StaticString aCallerName,
    200    MozPromiseHolder<PromiseType>& aPromise) {
    201  AssertSendable();
    202 
    203  if (mState == NS_OK) {
    204    // mRemotePromise is resolved, send on manager thread.
    205    mManagerThread->Dispatch(
    206        NS_NewRunnableFunction(aCallerName, std::move(aCall)));
    207  } else if (mState == NS_ERROR_NOT_INITIALIZED) {
    208    // mRemotePromise is pending, chain to it.
    209    mRemotePromise->Then(
    210        mManagerThread, __func__, std::move(aCall),
    211        [self = RefPtr{this}, this, &aPromise, aCallerName](nsresult rv) {
    212          LOG("error=%x", uint32_t(rv));
    213          mState = rv;
    214          aPromise.RejectIfExists(rv, aCallerName);
    215        });
    216  }
    217 
    218  return aPromise.Ensure(aCallerName);
    219 }
    220 
    221 RefPtr<MFCDMChild::InitPromise> MFCDMChild::Init(
    222    const nsAString& aOrigin, const CopyableTArray<nsString>& aInitDataTypes,
    223    const KeySystemConfig::Requirement aPersistentState,
    224    const KeySystemConfig::Requirement aDistinctiveID,
    225    const CopyableTArray<MFCDMMediaCapability>& aAudioCapabilities,
    226    const CopyableTArray<MFCDMMediaCapability>& aVideoCapabilities,
    227    WMFCDMProxyCallback* aProxyCallback) {
    228  MOZ_ASSERT(mManagerThread);
    229 
    230  if (mShutdown) {
    231    return InitPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    232  }
    233 
    234  if (mState != NS_OK && mState != NS_ERROR_NOT_INITIALIZED) {
    235    LOG("error=%x", uint32_t(nsresult(mState)));
    236    return InitPromise::CreateAndReject(mState, __func__);
    237  }
    238 
    239  RefPtr<WMFCDMProxyCallback> callback = aProxyCallback;
    240  MFCDMInitParamsIPDL params{nsString(aOrigin),  aInitDataTypes,
    241                             aDistinctiveID,     aPersistentState,
    242                             aAudioCapabilities, aVideoCapabilities};
    243  auto doSend = [self = RefPtr{this}, this, params, callback]() {
    244    SendInit(params)
    245        ->Then(
    246            mManagerThread, __func__,
    247            [self, callback, this](MFCDMInitResult&& aResult) {
    248              mInitRequest.Complete();
    249              if (aResult.type() == MFCDMInitResult::Tnsresult) {
    250                nsresult rv = aResult.get_nsresult();
    251                mInitPromiseHolder.RejectIfExists(rv, __func__);
    252                return;
    253              }
    254              mProxyCallback = callback;
    255              mId = aResult.get_MFCDMInitIPDL().id();
    256              mInitPromiseHolder.ResolveIfExists(aResult.get_MFCDMInitIPDL(),
    257                                                 __func__);
    258            },
    259            [self, this](const mozilla::ipc::ResponseRejectReason& aReason) {
    260              mInitRequest.Complete();
    261              mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
    262            })
    263        ->Track(mInitRequest);
    264  };
    265 
    266  return InvokeAsync(std::move(doSend), __func__, mInitPromiseHolder);
    267 }
    268 
    269 RefPtr<MFCDMChild::SessionPromise> MFCDMChild::CreateSessionAndGenerateRequest(
    270    uint32_t aPromiseId, KeySystemConfig::SessionType aSessionType,
    271    const nsAString& aInitDataType, const nsTArray<uint8_t>& aInitData) {
    272  MOZ_ASSERT(mManagerThread);
    273  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    274 
    275  if (mShutdown) {
    276    return MFCDMChild::SessionPromise::CreateAndReject(NS_ERROR_ABORT,
    277                                                       __func__);
    278  }
    279 
    280  MutexAutoLock lock(mMutex);
    281  MOZ_ASSERT(mPendingSessionPromises.find(aPromiseId) ==
    282             mPendingSessionPromises.end());
    283  mPendingSessionPromises.emplace(aPromiseId,
    284                                  MozPromiseHolder<SessionPromise>{});
    285  mManagerThread->Dispatch(NS_NewRunnableFunction(
    286      __func__, [self = RefPtr{this}, this,
    287                 params =
    288                     MFCDMCreateSessionParamsIPDL{
    289                         aSessionType, nsString{aInitDataType}, aInitData},
    290                 aPromiseId] {
    291        SendCreateSessionAndGenerateRequest(params)->Then(
    292            mManagerThread, __func__,
    293            [self, aPromiseId, this](const MFCDMSessionResult& result) {
    294              MutexAutoLock lock(mMutex);
    295              auto iter = mPendingSessionPromises.find(aPromiseId);
    296              if (iter == mPendingSessionPromises.end()) {
    297                return;
    298              }
    299              auto& promiseHolder = iter->second;
    300              if (result.type() == MFCDMSessionResult::Tnsresult) {
    301                promiseHolder.RejectIfExists(result.get_nsresult(), __func__);
    302              } else {
    303                LOG("session ID=[%zu]%s", result.get_nsString().Length(),
    304                    NS_ConvertUTF16toUTF8(result.get_nsString()).get());
    305                promiseHolder.ResolveIfExists(result.get_nsString(), __func__);
    306              }
    307              mPendingSessionPromises.erase(iter);
    308            },
    309            [self, aPromiseId,
    310             this](const mozilla::ipc::ResponseRejectReason& aReason) {
    311              MutexAutoLock lock(mMutex);
    312              auto iter = mPendingSessionPromises.find(aPromiseId);
    313              if (iter == mPendingSessionPromises.end()) {
    314                return;
    315              }
    316              auto& promiseHolder = iter->second;
    317              promiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
    318              mPendingSessionPromises.erase(iter);
    319            });
    320      }));
    321  return mPendingSessionPromises[aPromiseId].Ensure(__func__);
    322 }
    323 
    324 RefPtr<GenericPromise> MFCDMChild::LoadSession(
    325    uint32_t aPromiseId, const KeySystemConfig::SessionType aSessionType,
    326    const nsAString& aSessionId) {
    327  MOZ_ASSERT(mManagerThread);
    328  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    329 
    330  if (mShutdown) {
    331    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    332  }
    333 
    334  MutexAutoLock lock(mMutex);
    335  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    336             mPendingGenericPromises.end());
    337  mPendingGenericPromises.emplace(aPromiseId,
    338                                  MozPromiseHolder<GenericPromise>{});
    339  INVOKE_ASYNC2(LoadSession, aPromiseId, aSessionType, nsString{aSessionId});
    340  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    341 }
    342 
    343 RefPtr<GenericPromise> MFCDMChild::UpdateSession(uint32_t aPromiseId,
    344                                                 const nsAString& aSessionId,
    345                                                 nsTArray<uint8_t>& aResponse) {
    346  MOZ_ASSERT(mManagerThread);
    347  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    348 
    349  if (mShutdown) {
    350    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    351  }
    352 
    353  MutexAutoLock lock(mMutex);
    354  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    355             mPendingGenericPromises.end());
    356  mPendingGenericPromises.emplace(aPromiseId,
    357                                  MozPromiseHolder<GenericPromise>{});
    358  INVOKE_ASYNC2(UpdateSession, aPromiseId, nsString{aSessionId},
    359                std::move(aResponse));
    360  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    361 }
    362 
    363 RefPtr<GenericPromise> MFCDMChild::CloseSession(uint32_t aPromiseId,
    364                                                const nsAString& aSessionId) {
    365  MOZ_ASSERT(mManagerThread);
    366  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    367 
    368  if (mShutdown) {
    369    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    370  }
    371 
    372  MutexAutoLock lock(mMutex);
    373  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    374             mPendingGenericPromises.end());
    375  mPendingGenericPromises.emplace(aPromiseId,
    376                                  MozPromiseHolder<GenericPromise>{});
    377  INVOKE_ASYNC(CloseSession, aPromiseId, nsString{aSessionId});
    378  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    379 }
    380 
    381 RefPtr<GenericPromise> MFCDMChild::RemoveSession(uint32_t aPromiseId,
    382                                                 const nsAString& aSessionId) {
    383  MOZ_ASSERT(mManagerThread);
    384  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    385 
    386  if (mShutdown) {
    387    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    388  }
    389 
    390  MutexAutoLock lock(mMutex);
    391  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    392             mPendingGenericPromises.end());
    393  mPendingGenericPromises.emplace(aPromiseId,
    394                                  MozPromiseHolder<GenericPromise>{});
    395  INVOKE_ASYNC(RemoveSession, aPromiseId, nsString{aSessionId});
    396  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    397 }
    398 
    399 RefPtr<GenericPromise> MFCDMChild::SetServerCertificate(
    400    uint32_t aPromiseId, nsTArray<uint8_t>& aCert) {
    401  MOZ_ASSERT(mManagerThread);
    402  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    403 
    404  if (mShutdown) {
    405    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    406  }
    407 
    408  MutexAutoLock lock(mMutex);
    409  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    410             mPendingGenericPromises.end());
    411  mPendingGenericPromises.emplace(aPromiseId,
    412                                  MozPromiseHolder<GenericPromise>{});
    413  INVOKE_ASYNC(SetServerCertificate, aPromiseId, std::move(aCert));
    414  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    415 }
    416 
    417 RefPtr<GenericPromise> MFCDMChild::GetStatusForPolicy(
    418    uint32_t aPromiseId, const dom::HDCPVersion& aMinHdcpVersion) {
    419  MOZ_ASSERT(mManagerThread);
    420  MOZ_ASSERT(mId > 0, "Should call Init() first and wait for it");
    421 
    422  if (mShutdown) {
    423    return GenericPromise::CreateAndReject(NS_ERROR_ABORT, __func__);
    424  }
    425 
    426  MutexAutoLock lock(mMutex);
    427  MOZ_ASSERT(mPendingGenericPromises.find(aPromiseId) ==
    428             mPendingGenericPromises.end());
    429  mPendingGenericPromises.emplace(aPromiseId,
    430                                  MozPromiseHolder<GenericPromise>{});
    431  INVOKE_ASYNC(GetStatusForPolicy, aPromiseId, aMinHdcpVersion);
    432  return mPendingGenericPromises[aPromiseId].Ensure(__func__);
    433 }
    434 
    435 mozilla::ipc::IPCResult MFCDMChild::RecvOnSessionKeyMessage(
    436    const MFCDMKeyMessage& aMessage) {
    437  LOG("RecvOnSessionKeyMessage, sessionId=%s",
    438      NS_ConvertUTF16toUTF8(aMessage.sessionId()).get());
    439  MOZ_ASSERT(mManagerThread);
    440  MOZ_ASSERT(mProxyCallback);
    441  mProxyCallback->OnSessionMessage(aMessage);
    442  return IPC_OK();
    443 }
    444 
    445 mozilla::ipc::IPCResult MFCDMChild::RecvOnSessionKeyStatusesChanged(
    446    const MFCDMKeyStatusChange& aKeyStatuses) {
    447  LOG("RecvOnSessionKeyStatusesChanged, sessionId=%s",
    448      NS_ConvertUTF16toUTF8(aKeyStatuses.sessionId()).get());
    449  MOZ_ASSERT(mManagerThread);
    450  MOZ_ASSERT(mProxyCallback);
    451  mProxyCallback->OnSessionKeyStatusesChange(aKeyStatuses);
    452  return IPC_OK();
    453 }
    454 
    455 mozilla::ipc::IPCResult MFCDMChild::RecvOnSessionKeyExpiration(
    456    const MFCDMKeyExpiration& aExpiration) {
    457  LOG("RecvOnSessionKeyExpiration, sessionId=%s",
    458      NS_ConvertUTF16toUTF8(aExpiration.sessionId()).get());
    459  MOZ_ASSERT(mManagerThread);
    460  MOZ_ASSERT(mProxyCallback);
    461  mProxyCallback->OnSessionKeyExpiration(aExpiration);
    462  return IPC_OK();
    463 }
    464 
    465 mozilla::ipc::IPCResult MFCDMChild::RecvOnSessionClosed(
    466    const MFCDMSessionClosedResult& aResult) {
    467  LOG("RecvOnSessionClosed, sessionId=%s",
    468      NS_ConvertUTF16toUTF8(aResult.sessionId()).get());
    469  MOZ_ASSERT(mManagerThread);
    470  MOZ_ASSERT(mProxyCallback);
    471  mProxyCallback->OnSessionClosed(aResult);
    472  return IPC_OK();
    473 }
    474 
    475 void MFCDMChild::IPDLActorDestroyed() {
    476  AssertOnManagerThread();
    477  mIPDLSelfRef = nullptr;
    478  if (!mShutdown) {
    479    LOG("IPDLActorDestroyed, remote process crashed!");
    480    mState = NS_ERROR_NOT_AVAILABLE;
    481    if (mProxyCallback) {
    482      mProxyCallback->OnRemoteProcessCrashed();
    483    }
    484  }
    485 }
    486 
    487 #undef SLOG
    488 #undef LOG
    489 
    490 }  // namespace mozilla