LCOV - code coverage report
Current view: top level - dom/media/gmp - GMPParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 78 451 17.3 %
Date: 2017-07-14 16:53:18 Functions: 9 55 16.4 %
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 "GMPParent.h"
       7             : #include "mozilla/Logging.h"
       8             : #include "nsComponentManagerUtils.h"
       9             : #include "nsComponentManagerUtils.h"
      10             : #include "nsThreadUtils.h"
      11             : #include "nsIRunnable.h"
      12             : #include "nsIWritablePropertyBag2.h"
      13             : #include "mozIGeckoMediaPluginService.h"
      14             : #include "mozilla/AbstractThread.h"
      15             : #include "mozilla/ipc/GeckoChildProcessHost.h"
      16             : #include "mozilla/SSE.h"
      17             : #include "mozilla/SyncRunnable.h"
      18             : #include "mozilla/Unused.h"
      19             : #include "nsIObserverService.h"
      20             : #include "GMPTimerParent.h"
      21             : #include "runnable_utils.h"
      22             : #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
      23             : #include "mozilla/SandboxInfo.h"
      24             : #endif
      25             : #include "GMPContentParent.h"
      26             : #include "MediaPrefs.h"
      27             : #include "VideoUtils.h"
      28             : 
      29             : using mozilla::ipc::GeckoChildProcessHost;
      30             : 
      31             : #ifdef MOZ_CRASHREPORTER
      32             : #include "nsPrintfCString.h"
      33             : #include "mozilla/ipc/CrashReporterHost.h"
      34             : using CrashReporter::AnnotationTable;
      35             : using CrashReporter::GetIDFromMinidump;
      36             : #endif
      37             : 
      38             : #include "mozilla/Telemetry.h"
      39             : 
      40             : #ifdef XP_WIN
      41             : #include "WMFDecoderModule.h"
      42             : #endif
      43             : 
      44             : #include "mozilla/dom/WidevineCDMManifestBinding.h"
      45             : #include "widevine-adapter/WidevineAdapter.h"
      46             : #include "ChromiumCDMAdapter.h"
      47             : 
      48             : namespace mozilla {
      49             : 
      50             : #undef LOG
      51             : #undef LOGD
      52             : 
      53             : extern LogModule* GetGMPLog();
      54             : #define LOG(level, x, ...) MOZ_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
      55             : #define LOGD(x, ...) LOG(mozilla::LogLevel::Debug, "GMPParent[%p|childPid=%d] " x, this, mChildPid, ##__VA_ARGS__)
      56             : 
      57             : #ifdef __CLASS__
      58             : #undef __CLASS__
      59             : #endif
      60             : #define __CLASS__ "GMPParent"
      61             : 
      62             : namespace gmp {
      63             : 
      64           1 : GMPParent::GMPParent(AbstractThread* aMainThread)
      65             :   : mState(GMPStateNotLoaded)
      66             :   , mProcess(nullptr)
      67             :   , mDeleteProcessOnlyOnUnload(false)
      68             :   , mAbnormalShutdownInProgress(false)
      69             :   , mIsBlockingDeletion(false)
      70             :   , mCanDecrypt(false)
      71             :   , mGMPContentChildCount(0)
      72             :   , mChildPid(0)
      73             :   , mHoldingSelfRef(false)
      74           1 :   , mMainThread(aMainThread)
      75             : {
      76           1 :   mPluginId = GeckoChildProcessHost::GetUniqueID();
      77           1 :   LOGD("GMPParent ctor id=%u", mPluginId);
      78           1 : }
      79             : 
      80           0 : GMPParent::~GMPParent()
      81             : {
      82           0 :   LOGD("GMPParent dtor id=%u", mPluginId);
      83           0 :   MOZ_ASSERT(!mProcess);
      84           0 : }
      85             : 
      86             : nsresult
      87           0 : GMPParent::CloneFrom(const GMPParent* aOther)
      88             : {
      89           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
      90           0 :   MOZ_ASSERT(aOther->mDirectory && aOther->mService, "null plugin directory");
      91             : 
      92           0 :   mService = aOther->mService;
      93           0 :   mDirectory = aOther->mDirectory;
      94           0 :   mName = aOther->mName;
      95           0 :   mVersion = aOther->mVersion;
      96           0 :   mDescription = aOther->mDescription;
      97           0 :   mDisplayName = aOther->mDisplayName;
      98             : #ifdef XP_WIN
      99             :   mLibs = aOther->mLibs;
     100             : #endif
     101           0 :   for (const GMPCapability& cap : aOther->mCapabilities) {
     102           0 :     mCapabilities.AppendElement(cap);
     103             :   }
     104           0 :   mAdapter = aOther->mAdapter;
     105           0 :   return NS_OK;
     106             : }
     107             : 
     108             : RefPtr<GenericPromise>
     109           1 : GMPParent::Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir)
     110             : {
     111           1 :   MOZ_ASSERT(aPluginDir);
     112           1 :   MOZ_ASSERT(aService);
     113           1 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     114             : 
     115           1 :   mService = aService;
     116           1 :   mDirectory = aPluginDir;
     117             : 
     118             :   // aPluginDir is <profile-dir>/<gmp-plugin-id>/<version>
     119             :   // where <gmp-plugin-id> should be gmp-gmpopenh264
     120           2 :   nsCOMPtr<nsIFile> parent;
     121           1 :   nsresult rv = aPluginDir->GetParent(getter_AddRefs(parent));
     122           1 :   if (NS_FAILED(rv)) {
     123           0 :     return GenericPromise::CreateAndReject(rv, __func__);
     124             :   }
     125           2 :   nsAutoString parentLeafName;
     126           1 :   rv = parent->GetLeafName(parentLeafName);
     127           1 :   if (NS_FAILED(rv)) {
     128           0 :     return GenericPromise::CreateAndReject(rv, __func__);
     129             :   }
     130           1 :   LOGD("%s: for %s", __FUNCTION__, NS_LossyConvertUTF16toASCII(parentLeafName).get());
     131             : 
     132           1 :   MOZ_ASSERT(parentLeafName.Length() > 4);
     133           1 :   mName = Substring(parentLeafName, 4);
     134             : 
     135           1 :   return ReadGMPMetaData();
     136             : }
     137             : 
     138             : void
     139           0 : GMPParent::Crash()
     140             : {
     141           0 :   if (mState != GMPStateNotLoaded) {
     142           0 :     Unused << SendCrashPluginNow();
     143             :   }
     144           0 : }
     145             : 
     146             : nsresult
     147           0 : GMPParent::LoadProcess()
     148             : {
     149           0 :   MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
     150           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     151           0 :   MOZ_ASSERT(mState == GMPStateNotLoaded);
     152             : 
     153           0 :   nsAutoString path;
     154           0 :   if (NS_FAILED(mDirectory->GetPath(path))) {
     155           0 :     return NS_ERROR_FAILURE;
     156             :   }
     157           0 :   LOGD("%s: for %s", __FUNCTION__, NS_ConvertUTF16toUTF8(path).get());
     158             : 
     159           0 :   if (!mProcess) {
     160           0 :     mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
     161           0 :     if (!mProcess->Launch(30 * 1000)) {
     162           0 :       LOGD("%s: Failed to launch new child process", __FUNCTION__);
     163           0 :       mProcess->Delete();
     164           0 :       mProcess = nullptr;
     165           0 :       return NS_ERROR_FAILURE;
     166             :     }
     167             : 
     168           0 :     mChildPid = base::GetProcId(mProcess->GetChildProcessHandle());
     169           0 :     LOGD("%s: Launched new child process", __FUNCTION__);
     170             : 
     171           0 :     bool opened = Open(mProcess->GetChannel(),
     172           0 :                        base::GetProcId(mProcess->GetChildProcessHandle()));
     173           0 :     if (!opened) {
     174           0 :       LOGD("%s: Failed to open channel to new child process", __FUNCTION__);
     175           0 :       mProcess->Delete();
     176           0 :       mProcess = nullptr;
     177           0 :       return NS_ERROR_FAILURE;
     178             :     }
     179           0 :     LOGD("%s: Opened channel to new child process", __FUNCTION__);
     180             : 
     181             : #ifdef XP_WIN
     182             :     if (!mLibs.IsEmpty()) {
     183             :       bool ok = SendPreloadLibs(mLibs);
     184             :       if (!ok) {
     185             :         LOGD("%s: Failed to send preload-libs to child process", __FUNCTION__);
     186             :         return NS_ERROR_FAILURE;
     187             :       }
     188             :       LOGD("%s: Sent preload-libs ('%s') to child process", __FUNCTION__, mLibs.get());
     189             :     }
     190             : #endif
     191             : 
     192             :     // Intr call to block initialization on plugin load.
     193           0 :     if (!CallStartPlugin(mAdapter)) {
     194           0 :       LOGD("%s: Failed to send start to child process", __FUNCTION__);
     195           0 :       return NS_ERROR_FAILURE;
     196             :     }
     197           0 :     LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
     198             :   }
     199             : 
     200           0 :   mState = GMPStateLoaded;
     201             : 
     202             :   // Hold a self ref while the child process is alive. This ensures that
     203             :   // during shutdown the GMPParent stays alive long enough to
     204             :   // terminate the child process.
     205           0 :   MOZ_ASSERT(!mHoldingSelfRef);
     206           0 :   mHoldingSelfRef = true;
     207           0 :   AddRef();
     208             : 
     209           0 :   return NS_OK;
     210             : }
     211             : 
     212             : mozilla::ipc::IPCResult
     213           0 : GMPParent::RecvPGMPContentChildDestroyed()
     214             : {
     215           0 :   --mGMPContentChildCount;
     216           0 :   if (!IsUsed()) {
     217           0 :     CloseIfUnused();
     218             :   }
     219           0 :   return IPC_OK();
     220             : }
     221             : 
     222             : void
     223           0 : GMPParent::CloseIfUnused()
     224             : {
     225           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     226           0 :   LOGD("%s", __FUNCTION__);
     227             : 
     228           0 :   if ((mDeleteProcessOnlyOnUnload ||
     229           0 :        mState == GMPStateLoaded ||
     230           0 :        mState == GMPStateUnloading) &&
     231           0 :       !IsUsed()) {
     232             :     // Ensure all timers are killed.
     233           0 :     for (uint32_t i = mTimers.Length(); i > 0; i--) {
     234           0 :       mTimers[i - 1]->Shutdown();
     235             :     }
     236             : 
     237             :     // Shutdown GMPStorage. Given that all protocol actors must be shutdown
     238             :     // (!Used() is true), all storage operations should be complete.
     239           0 :     for (size_t i = mStorage.Length(); i > 0; i--) {
     240           0 :       mStorage[i - 1]->Shutdown();
     241             :     }
     242           0 :     Shutdown();
     243             :   }
     244           0 : }
     245             : 
     246             : void
     247           0 : GMPParent::CloseActive(bool aDieWhenUnloaded)
     248             : {
     249           0 :   LOGD("%s: state %d", __FUNCTION__, mState);
     250           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     251             : 
     252           0 :   if (aDieWhenUnloaded) {
     253           0 :     mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
     254             :   }
     255           0 :   if (mState == GMPStateLoaded) {
     256           0 :     mState = GMPStateUnloading;
     257             :   }
     258           0 :   if (mState != GMPStateNotLoaded && IsUsed()) {
     259           0 :     Unused << SendCloseActive();
     260           0 :     CloseIfUnused();
     261             :   }
     262           0 : }
     263             : 
     264             : void
     265           0 : GMPParent::MarkForDeletion()
     266             : {
     267           0 :   mDeleteProcessOnlyOnUnload = true;
     268           0 :   mIsBlockingDeletion = true;
     269           0 : }
     270             : 
     271             : bool
     272           0 : GMPParent::IsMarkedForDeletion()
     273             : {
     274           0 :   return mIsBlockingDeletion;
     275             : }
     276             : 
     277             : void
     278           0 : GMPParent::Shutdown()
     279             : {
     280           0 :   LOGD("%s", __FUNCTION__);
     281           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     282             : 
     283           0 :   if (mAbnormalShutdownInProgress) {
     284           0 :     return;
     285             :   }
     286             : 
     287           0 :   MOZ_ASSERT(!IsUsed());
     288           0 :   if (mState == GMPStateNotLoaded || mState == GMPStateClosing) {
     289           0 :     return;
     290             :   }
     291             : 
     292           0 :   RefPtr<GMPParent> self(this);
     293           0 :   DeleteProcess();
     294             : 
     295             :   // XXX Get rid of mDeleteProcessOnlyOnUnload and this code when
     296             :   // Bug 1043671 is fixed
     297           0 :   if (!mDeleteProcessOnlyOnUnload) {
     298             :     // Destroy ourselves and rise from the fire to save memory
     299           0 :     mService->ReAddOnGMPThread(self);
     300             :   } // else we've been asked to die and stay dead
     301           0 :   MOZ_ASSERT(mState == GMPStateNotLoaded);
     302             : }
     303             : 
     304           0 : class NotifyGMPShutdownTask : public Runnable {
     305             : public:
     306           0 :   explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
     307           0 :     : Runnable("NotifyGMPShutdownTask")
     308           0 :     , mNodeId(aNodeId)
     309             :   {
     310           0 :   }
     311           0 :   NS_IMETHOD Run() override {
     312           0 :     MOZ_ASSERT(NS_IsMainThread());
     313           0 :     nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
     314           0 :     MOZ_ASSERT(obsService);
     315           0 :     if (obsService) {
     316           0 :       obsService->NotifyObservers(nullptr, "gmp-shutdown", mNodeId.get());
     317             :     }
     318           0 :     return NS_OK;
     319             :   }
     320             :   nsString mNodeId;
     321             : };
     322             : 
     323             : void
     324           0 : GMPParent::ChildTerminated()
     325             : {
     326           0 :   RefPtr<GMPParent> self(this);
     327           0 :   nsCOMPtr<nsISerialEventTarget> gmpEventTarget = GMPEventTarget();
     328             : 
     329           0 :   if (!gmpEventTarget) {
     330             :     // Bug 1163239 - this can happen on shutdown.
     331             :     // PluginTerminated removes the GMP from the GMPService.
     332             :     // On shutdown we can have this case where it is already been
     333             :     // removed so there is no harm in not trying to remove it again.
     334           0 :     LOGD("%s::%s: GMPEventTarget() returned nullptr.", __CLASS__, __FUNCTION__);
     335             :   } else {
     336           0 :     gmpEventTarget->Dispatch(NewRunnableMethod<RefPtr<GMPParent>>(
     337             :                                "gmp::GeckoMediaPluginServiceParent::PluginTerminated",
     338             :                                mService,
     339             :                                &GeckoMediaPluginServiceParent::PluginTerminated,
     340             :                                self),
     341           0 :                              NS_DISPATCH_NORMAL);
     342             :   }
     343           0 : }
     344             : 
     345             : void
     346           0 : GMPParent::DeleteProcess()
     347             : {
     348           0 :   LOGD("%s", __FUNCTION__);
     349             : 
     350           0 :   if (mState != GMPStateClosing) {
     351             :     // Don't Close() twice!
     352             :     // Probably remove when bug 1043671 is resolved
     353           0 :     mState = GMPStateClosing;
     354           0 :     Close();
     355             :   }
     356           0 :   mProcess->Delete(NewRunnableMethod(
     357           0 :     "gmp::GMPParent::ChildTerminated", this, &GMPParent::ChildTerminated));
     358           0 :   LOGD("%s: Shut down process", __FUNCTION__);
     359           0 :   mProcess = nullptr;
     360           0 :   mState = GMPStateNotLoaded;
     361             : 
     362             :   nsCOMPtr<nsIRunnable> r
     363           0 :     = new NotifyGMPShutdownTask(NS_ConvertUTF8toUTF16(mNodeId));
     364           0 :   mMainThread->Dispatch(r.forget());
     365             : 
     366           0 :   if (mHoldingSelfRef) {
     367           0 :     Release();
     368           0 :     mHoldingSelfRef = false;
     369             :   }
     370           0 : }
     371             : 
     372             : GMPState
     373           0 : GMPParent::State() const
     374             : {
     375           0 :   return mState;
     376             : }
     377             : 
     378             : nsCOMPtr<nsISerialEventTarget>
     379           1 : GMPParent::GMPEventTarget()
     380             : {
     381             :   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     382           2 :     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
     383           1 :   MOZ_ASSERT(mps);
     384           1 :   if (!mps) {
     385           0 :     return nullptr;
     386             :   }
     387             :   // Note: GeckoMediaPluginService::GetThread() is threadsafe, and returns
     388             :   // nullptr if the GeckoMediaPluginService has started shutdown.
     389           2 :   nsCOMPtr<nsIThread> gmpThread;
     390           1 :   mps->GetThread(getter_AddRefs(gmpThread));
     391           1 :   return gmpThread ? gmpThread->SerialEventTarget() : nullptr;
     392             : }
     393             : 
     394             : /* static */
     395             : bool
     396           0 : GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities,
     397             :                         const nsCString& aAPI,
     398             :                         const nsTArray<nsCString>& aTags)
     399             : {
     400           0 :   for (const nsCString& tag : aTags) {
     401           0 :     if (!GMPCapability::Supports(aCapabilities, aAPI, tag)) {
     402           0 :       return false;
     403             :     }
     404             :   }
     405           0 :   return true;
     406             : }
     407             : 
     408             : /* static */
     409             : bool
     410           0 : GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities,
     411             :                         const nsCString& aAPI,
     412             :                         const nsCString& aTag)
     413             : {
     414           0 :   for (const GMPCapability& capabilities : aCapabilities) {
     415           0 :     if (!capabilities.mAPIName.Equals(aAPI)) {
     416           0 :       continue;
     417             :     }
     418           0 :     for (const nsCString& tag : capabilities.mAPITags) {
     419           0 :       if (tag.Equals(aTag)) {
     420             : #ifdef XP_WIN
     421             :         // Clearkey on Windows advertises that it can decode in its GMP info
     422             :         // file, but uses Windows Media Foundation to decode. That's not present
     423             :         // on Windows XP, and on some Vista, Windows N, and KN variants without
     424             :         // certain services packs.
     425             :         if (tag.Equals(kEMEKeySystemClearkey)) {
     426             :           if (capabilities.mAPIName.EqualsLiteral(GMP_API_VIDEO_DECODER)) {
     427             :             if (!WMFDecoderModule::HasH264()) {
     428             :               continue;
     429             :             }
     430             :           }
     431             :         }
     432             : #endif
     433           0 :         return true;
     434             :       }
     435             :     }
     436             :   }
     437           0 :   return false;
     438             : }
     439             : 
     440             : bool
     441           0 : GMPParent::EnsureProcessLoaded()
     442             : {
     443           0 :   if (mState == GMPStateLoaded) {
     444           0 :     return true;
     445             :   }
     446           0 :   if (mState == GMPStateClosing ||
     447           0 :       mState == GMPStateUnloading) {
     448           0 :     return false;
     449             :   }
     450             : 
     451           0 :   nsresult rv = LoadProcess();
     452             : 
     453           0 :   return NS_SUCCEEDED(rv);
     454             : }
     455             : 
     456             : #ifdef MOZ_CRASHREPORTER
     457             : void
     458           0 : GMPParent::WriteExtraDataForMinidump()
     459             : {
     460           0 :   mCrashReporter->AddNote(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1"));
     461           0 :   mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), NS_ConvertUTF16toUTF8(mName));
     462           0 :   mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mDisplayName);
     463           0 :   mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mVersion);
     464           0 : }
     465             : 
     466             : bool
     467           0 : GMPParent::GetCrashID(nsString& aResult)
     468             : {
     469           0 :   if (!mCrashReporter) {
     470           0 :     return false;
     471             :   }
     472             : 
     473           0 :   WriteExtraDataForMinidump();
     474           0 :   if (!mCrashReporter->GenerateCrashReport(OtherPid())) {
     475           0 :     return false;
     476             :   }
     477             : 
     478           0 :   aResult = mCrashReporter->MinidumpID();
     479           0 :   return true;
     480             : }
     481             : 
     482             : static void
     483           0 : GMPNotifyObservers(const uint32_t aPluginID, const nsACString& aPluginName, const nsAString& aPluginDumpID)
     484             : {
     485           0 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     486             :   nsCOMPtr<nsIWritablePropertyBag2> propbag =
     487           0 :     do_CreateInstance("@mozilla.org/hash-property-bag;1");
     488           0 :   if (obs && propbag) {
     489           0 :     propbag->SetPropertyAsUint32(NS_LITERAL_STRING("pluginID"), aPluginID);
     490           0 :     propbag->SetPropertyAsACString(NS_LITERAL_STRING("pluginName"), aPluginName);
     491           0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"), aPluginDumpID);
     492           0 :     obs->NotifyObservers(propbag, "gmp-plugin-crash", nullptr);
     493             :   }
     494             : 
     495             :   RefPtr<gmp::GeckoMediaPluginService> service =
     496           0 :     gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
     497           0 :   if (service) {
     498           0 :     service->RunPluginCrashCallbacks(aPluginID, aPluginName);
     499             :   }
     500           0 : }
     501             : #endif
     502             : void
     503           0 : GMPParent::ActorDestroy(ActorDestroyReason aWhy)
     504             : {
     505           0 :   LOGD("%s: (%d)", __FUNCTION__, (int)aWhy);
     506             : #ifdef MOZ_CRASHREPORTER
     507           0 :   if (AbnormalShutdown == aWhy) {
     508           0 :     Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
     509           0 :                           NS_LITERAL_CSTRING("gmplugin"), 1);
     510           0 :     nsString dumpID;
     511           0 :     if (!GetCrashID(dumpID)) {
     512           0 :       NS_WARNING("GMP crash without crash report");
     513           0 :       dumpID = mName;
     514           0 :       dumpID += '-';
     515           0 :       AppendUTF8toUTF16(mVersion, dumpID);
     516             :     }
     517             : 
     518             :     // NotifyObservers is mainthread-only
     519           0 :     nsCOMPtr<nsIRunnable> r = WrapRunnableNM(
     520           0 :       &GMPNotifyObservers, mPluginId, mDisplayName, dumpID);
     521           0 :     mMainThread->Dispatch(r.forget());
     522             :   }
     523             : #endif
     524             :   // warn us off trying to close again
     525           0 :   mState = GMPStateClosing;
     526           0 :   mAbnormalShutdownInProgress = true;
     527           0 :   CloseActive(false);
     528             : 
     529             :   // Normal Shutdown() will delete the process on unwind.
     530           0 :   if (AbnormalShutdown == aWhy) {
     531           0 :     RefPtr<GMPParent> self(this);
     532             :     // Must not call Close() again in DeleteProcess(), as we'll recurse
     533             :     // infinitely if we do.
     534           0 :     MOZ_ASSERT(mState == GMPStateClosing);
     535           0 :     DeleteProcess();
     536             :     // Note: final destruction will be Dispatched to ourself
     537           0 :     mService->ReAddOnGMPThread(self);
     538             :   }
     539           0 : }
     540             : 
     541             : mozilla::ipc::IPCResult
     542           0 : GMPParent::RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId)
     543             : {
     544             : #ifdef MOZ_CRASHREPORTER
     545           0 :   mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
     546             :     GeckoProcessType_GMPlugin,
     547             :     aShmem,
     548           0 :     aThreadId);
     549             : #endif
     550           0 :   return IPC_OK();
     551             : }
     552             : 
     553             : PGMPStorageParent*
     554           0 : GMPParent::AllocPGMPStorageParent()
     555             : {
     556           0 :   GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
     557           0 :   mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent.
     558           0 :   return p;
     559             : }
     560             : 
     561             : bool
     562           0 : GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor)
     563             : {
     564           0 :   GMPStorageParent* p = static_cast<GMPStorageParent*>(aActor);
     565           0 :   p->Shutdown();
     566           0 :   mStorage.RemoveElement(p);
     567           0 :   return true;
     568             : }
     569             : 
     570             : mozilla::ipc::IPCResult
     571           0 : GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* aActor)
     572             : {
     573           0 :   GMPStorageParent* p  = (GMPStorageParent*)aActor;
     574           0 :   if (NS_WARN_IF(NS_FAILED(p->Init()))) {
     575           0 :     return IPC_FAIL_NO_REASON(this);
     576             :   }
     577           0 :   return IPC_OK();
     578             : }
     579             : 
     580             : mozilla::ipc::IPCResult
     581           0 : GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor)
     582             : {
     583           0 :   return IPC_OK();
     584             : }
     585             : 
     586             : PGMPTimerParent*
     587           0 : GMPParent::AllocPGMPTimerParent()
     588             : {
     589           0 :   nsCOMPtr<nsISerialEventTarget> target = GMPEventTarget();
     590           0 :   GMPTimerParent* p = new GMPTimerParent(target);
     591           0 :   mTimers.AppendElement(p); // Released in DeallocPGMPTimerParent, or on shutdown.
     592           0 :   return p;
     593             : }
     594             : 
     595             : bool
     596           0 : GMPParent::DeallocPGMPTimerParent(PGMPTimerParent* aActor)
     597             : {
     598           0 :   GMPTimerParent* p = static_cast<GMPTimerParent*>(aActor);
     599           0 :   p->Shutdown();
     600           0 :   mTimers.RemoveElement(p);
     601           0 :   return true;
     602             : }
     603             : 
     604             : bool
     605           0 : ReadInfoField(GMPInfoFileParser& aParser, const nsCString& aKey, nsACString& aOutValue)
     606             : {
     607           0 :   if (!aParser.Contains(aKey) || aParser.Get(aKey).IsEmpty()) {
     608           0 :     return false;
     609             :   }
     610           0 :   aOutValue = aParser.Get(aKey);
     611           0 :   return true;
     612             : }
     613             : 
     614             : RefPtr<GenericPromise>
     615           1 : GMPParent::ReadGMPMetaData()
     616             : {
     617           1 :   MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
     618           1 :   MOZ_ASSERT(!mName.IsEmpty(), "Plugin mName cannot be empty!");
     619             : 
     620           2 :   nsCOMPtr<nsIFile> infoFile;
     621           1 :   nsresult rv = mDirectory->Clone(getter_AddRefs(infoFile));
     622           1 :   if (NS_FAILED(rv)) {
     623           0 :     return GenericPromise::CreateAndReject(rv, __func__);
     624             :   }
     625           1 :   infoFile->AppendRelativePath(mName + NS_LITERAL_STRING(".info"));
     626             : 
     627           1 :   if (FileExists(infoFile)) {
     628           0 :     return ReadGMPInfoFile(infoFile);
     629             :   }
     630             : 
     631             :   // Maybe this is the Widevine adapted plugin?
     632           2 :   nsCOMPtr<nsIFile> manifestFile;
     633           1 :   rv = mDirectory->Clone(getter_AddRefs(manifestFile));
     634           1 :   if (NS_FAILED(rv)) {
     635           0 :     return GenericPromise::CreateAndReject(rv, __func__);
     636             :   }
     637           1 :   manifestFile->AppendRelativePath(NS_LITERAL_STRING("manifest.json"));
     638           1 :   return ReadChromiumManifestFile(manifestFile);
     639             : }
     640             : 
     641             : RefPtr<GenericPromise>
     642           0 : GMPParent::ReadGMPInfoFile(nsIFile* aFile)
     643             : {
     644           0 :   GMPInfoFileParser parser;
     645           0 :   if (!parser.Init(aFile)) {
     646           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     647             :   }
     648             : 
     649           0 :   nsAutoCString apis;
     650           0 :   if (!ReadInfoField(parser, NS_LITERAL_CSTRING("name"), mDisplayName) ||
     651           0 :       !ReadInfoField(parser, NS_LITERAL_CSTRING("description"), mDescription) ||
     652           0 :       !ReadInfoField(parser, NS_LITERAL_CSTRING("version"), mVersion) ||
     653           0 :       !ReadInfoField(parser, NS_LITERAL_CSTRING("apis"), apis)) {
     654           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     655             :   }
     656             : 
     657             : #ifdef XP_WIN
     658             :   // "Libraries" field is optional.
     659             :   ReadInfoField(parser, NS_LITERAL_CSTRING("libraries"), mLibs);
     660             : #endif
     661             : 
     662           0 :   nsTArray<nsCString> apiTokens;
     663           0 :   SplitAt(", ", apis, apiTokens);
     664           0 :   for (nsCString api : apiTokens) {
     665           0 :     int32_t tagsStart = api.FindChar('[');
     666           0 :     if (tagsStart == 0) {
     667             :       // Not allowed to be the first character.
     668             :       // API name must be at least one character.
     669           0 :       continue;
     670             :     }
     671             : 
     672           0 :     GMPCapability cap;
     673           0 :     if (tagsStart == -1) {
     674             :       // No tags.
     675           0 :       cap.mAPIName.Assign(api);
     676             :     } else {
     677           0 :       auto tagsEnd = api.FindChar(']');
     678           0 :       if (tagsEnd == -1 || tagsEnd < tagsStart) {
     679             :         // Invalid syntax, skip whole capability.
     680           0 :         continue;
     681             :       }
     682             : 
     683           0 :       cap.mAPIName.Assign(Substring(api, 0, tagsStart));
     684             : 
     685           0 :       if ((tagsEnd - tagsStart) > 1) {
     686           0 :         const nsDependentCSubstring ts(Substring(api, tagsStart + 1, tagsEnd - tagsStart - 1));
     687           0 :         nsTArray<nsCString> tagTokens;
     688           0 :         SplitAt(":", ts, tagTokens);
     689           0 :         for (nsCString tag : tagTokens) {
     690           0 :           cap.mAPITags.AppendElement(tag);
     691             :         }
     692             :       }
     693             :     }
     694             : 
     695           0 :     if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
     696           0 :       mCanDecrypt = true;
     697             : 
     698             : #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
     699             :       if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
     700             :         nsPrintfCString msg(
     701             :           "GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
     702             :           " but this system can't sandbox it; not loading.",
     703             :           mDisplayName.get());
     704             :         printf_stderr("%s\n", msg.get());
     705             :         LOGD("%s", msg.get());
     706             :         return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     707             :       }
     708             : #endif
     709             :     }
     710             : 
     711           0 :     mCapabilities.AppendElement(Move(cap));
     712             :   }
     713             : 
     714           0 :   if (mCapabilities.IsEmpty()) {
     715           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     716             :   }
     717             : 
     718           0 :   return GenericPromise::CreateAndResolve(true, __func__);
     719             : }
     720             : 
     721             : RefPtr<GenericPromise>
     722           1 : GMPParent::ReadChromiumManifestFile(nsIFile* aFile)
     723             : {
     724           2 :   nsAutoCString json;
     725           1 :   if (!ReadIntoString(aFile, json, 5 * 1024)) {
     726           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     727             :   }
     728             : 
     729             :   // DOM JSON parsing needs to run on the main thread.
     730             :   return InvokeAsync(
     731             :     mMainThread, this, __func__,
     732           1 :     &GMPParent::ParseChromiumManifest, NS_ConvertUTF8toUTF16(json));
     733             : }
     734             : 
     735             : static bool
     736           1 : IsCDMAPISupported(const mozilla::dom::WidevineCDMManifest& aManifest)
     737             : {
     738             :   nsresult ignored; // Note: ToInteger returns 0 on failure.
     739           1 :   int32_t moduleVersion = aManifest.mX_cdm_module_versions.ToInteger(&ignored);
     740             :   int32_t interfaceVersion =
     741           1 :     aManifest.mX_cdm_interface_versions.ToInteger(&ignored);
     742           1 :   int32_t hostVersion = aManifest.mX_cdm_host_versions.ToInteger(&ignored);
     743           1 :   if (MediaPrefs::EMEChromiumAPIEnabled()) {
     744             :     return ChromiumCDMAdapter::Supports(
     745           1 :       moduleVersion, interfaceVersion, hostVersion);
     746             :   }
     747             :   return WidevineAdapter::Supports(
     748           0 :     moduleVersion, interfaceVersion, hostVersion);
     749             : }
     750             : 
     751             : RefPtr<GenericPromise>
     752           1 : GMPParent::ParseChromiumManifest(const nsAString& aJSON)
     753             : {
     754           1 :   LOGD("%s: for '%s'", __FUNCTION__, NS_LossyConvertUTF16toASCII(aJSON).get());
     755             : 
     756           1 :   MOZ_ASSERT(NS_IsMainThread());
     757           2 :   mozilla::dom::WidevineCDMManifest m;
     758           1 :   if (!m.Init(aJSON)) {
     759           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     760             :   }
     761             : 
     762           1 :   if (!IsCDMAPISupported(m)) {
     763           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     764             :   }
     765             : 
     766           1 :   mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
     767           1 :   mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
     768           1 :   mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
     769             : 
     770             : #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
     771             :   if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
     772             :     nsPrintfCString msg(
     773             :       "GMPParent::ParseChromiumManifest: Plugin \"%s\" is an EME CDM"
     774             :       " but this system can't sandbox it; not loading.",
     775             :       mDisplayName.get());
     776             :     printf_stderr("%s\n", msg.get());
     777             :     LOGD("%s", msg.get());
     778             :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     779             :   }
     780             : #endif
     781             : 
     782           2 :   nsCString kEMEKeySystem;
     783             : 
     784             :   // We hard code a few of the settings because they can't be stored in the
     785             :   // widevine manifest without making our API different to widevine's.
     786           1 :   if (mDisplayName.EqualsASCII("clearkey")) {
     787           1 :     kEMEKeySystem = kEMEKeySystemClearkey;
     788             : #if XP_WIN
     789             :     mLibs = NS_LITERAL_CSTRING("dxva2.dll, msmpeg2vdec.dll, evr.dll, mfh264dec.dll, mfplat.dll");
     790             : #endif
     791           0 :   } else if (mDisplayName.EqualsASCII("WidevineCdm")) {
     792           0 :     kEMEKeySystem = kEMEKeySystemWidevine;
     793             : #if XP_WIN
     794             :     mLibs = NS_LITERAL_CSTRING("dxva2.dll");
     795             : #endif
     796             :   } else {
     797           0 :     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     798             :   }
     799             : 
     800           2 :   GMPCapability video;
     801             : 
     802           2 :   nsCString codecsString = NS_ConvertUTF16toUTF8(m.mX_cdm_codecs);
     803           2 :   nsTArray<nsCString> codecs;
     804           1 :   SplitAt(",", codecsString, codecs);
     805             : 
     806           1 :   for (const nsCString& chromiumCodec : codecs) {
     807           0 :     nsCString codec;
     808           0 :     if (chromiumCodec.EqualsASCII("vp8")) {
     809           0 :       codec = NS_LITERAL_CSTRING("vp8");
     810           0 :     } else if (chromiumCodec.EqualsASCII("vp9.0")) {
     811           0 :       codec = NS_LITERAL_CSTRING("vp9");
     812           0 :     } else if (chromiumCodec.EqualsASCII("avc1")) {
     813           0 :       codec = NS_LITERAL_CSTRING("h264");
     814             :     } else {
     815           0 :       return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     816             :     }
     817             : 
     818           0 :     video.mAPITags.AppendElement(codec);
     819             :   }
     820             : 
     821           1 :   video.mAPITags.AppendElement(kEMEKeySystem);
     822             : 
     823           1 :   if (MediaPrefs::EMEChromiumAPIEnabled()) {
     824           1 :     video.mAPIName = NS_LITERAL_CSTRING(CHROMIUM_CDM_API);
     825           1 :     mAdapter = NS_LITERAL_STRING("chromium");
     826             :   } else {
     827           0 :     video.mAPIName = NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER);
     828           0 :     mAdapter = NS_LITERAL_STRING("widevine");
     829             : 
     830           0 :     GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
     831           0 :     decrypt.mAPITags.AppendElement(kEMEKeySystem);
     832           0 :     mCapabilities.AppendElement(Move(decrypt));
     833             :   }
     834           1 :   mCapabilities.AppendElement(Move(video));
     835             : 
     836           1 :   return GenericPromise::CreateAndResolve(true, __func__);
     837             : }
     838             : 
     839             : bool
     840           0 : GMPParent::CanBeSharedCrossNodeIds() const
     841             : {
     842           0 :   return mNodeId.IsEmpty() &&
     843             :          // XXX bug 1159300 hack -- maybe remove after openh264 1.4
     844             :          // We don't want to use CDM decoders for non-encrypted playback
     845             :          // just yet; especially not for WebRTC. Don't allow CDMs to be used
     846             :          // without a node ID.
     847           0 :          !mCanDecrypt;
     848             : }
     849             : 
     850             : bool
     851           0 : GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const
     852             : {
     853           0 :   return mNodeId == aNodeId;
     854             : }
     855             : 
     856             : void
     857           0 : GMPParent::SetNodeId(const nsACString& aNodeId)
     858             : {
     859           0 :   MOZ_ASSERT(!aNodeId.IsEmpty());
     860           0 :   mNodeId = aNodeId;
     861           0 : }
     862             : 
     863             : const nsCString&
     864           0 : GMPParent::GetDisplayName() const
     865             : {
     866           0 :   return mDisplayName;
     867             : }
     868             : 
     869             : const nsCString&
     870           3 : GMPParent::GetVersion() const
     871             : {
     872           3 :   return mVersion;
     873             : }
     874             : 
     875             : uint32_t
     876           0 : GMPParent::GetPluginId() const
     877             : {
     878           0 :   return mPluginId;
     879             : }
     880             : 
     881             : void
     882           0 : GMPParent::ResolveGetContentParentPromises()
     883             : {
     884           0 :   nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>> promises;
     885           0 :   promises.SwapElements(mGetContentParentPromises);
     886           0 :   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
     887           0 :   RefPtr<GMPContentParent::CloseBlocker> blocker(new GMPContentParent::CloseBlocker(mGMPContentParent));
     888           0 :   for (auto& holder : promises) {
     889           0 :     holder->Resolve(blocker, __func__);
     890             :   }
     891           0 : }
     892             : 
     893             : bool
     894           0 : GMPParent::OpenPGMPContent()
     895             : {
     896           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     897           0 :   MOZ_ASSERT(!mGMPContentParent);
     898             : 
     899           0 :   Endpoint<PGMPContentParent> parent;
     900           0 :   Endpoint<PGMPContentChild> child;
     901           0 :   if (NS_FAILED(PGMPContent::CreateEndpoints(base::GetCurrentProcId(),
     902             :                                              OtherPid(), &parent, &child))) {
     903           0 :     return false;
     904             :   }
     905             : 
     906           0 :   mGMPContentParent = new GMPContentParent(this);
     907             : 
     908           0 :   if (!parent.Bind(mGMPContentParent)) {
     909           0 :     return false;
     910             :   }
     911             : 
     912           0 :   if (!SendInitGMPContentChild(Move(child))) {
     913           0 :     return false;
     914             :   }
     915             : 
     916           0 :   ResolveGetContentParentPromises();
     917             : 
     918           0 :   return true;
     919             : }
     920             : 
     921             : void
     922           0 : GMPParent::RejectGetContentParentPromises()
     923             : {
     924           0 :   nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>> promises;
     925           0 :   promises.SwapElements(mGetContentParentPromises);
     926           0 :   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
     927           0 :   for (auto& holder : promises) {
     928           0 :     holder->Reject(NS_ERROR_FAILURE, __func__);
     929             :   }
     930           0 : }
     931             : 
     932             : void
     933           0 : GMPParent::GetGMPContentParent(UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>&& aPromiseHolder)
     934             : {
     935           0 :   LOGD("%s %p", __FUNCTION__, this);
     936           0 :   MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
     937             : 
     938           0 :   if (mGMPContentParent) {
     939           0 :     RefPtr<GMPContentParent::CloseBlocker> blocker(new GMPContentParent::CloseBlocker(mGMPContentParent));
     940           0 :     aPromiseHolder->Resolve(blocker, __func__);
     941             :   } else {
     942           0 :     mGetContentParentPromises.AppendElement(Move(aPromiseHolder));
     943             :     // If we don't have a GMPContentParent and we try to get one for the first
     944             :     // time (mGetContentParentPromises.Length() == 1) then call PGMPContent::Open. If more
     945             :     // calls to GetGMPContentParent happen before mGMPContentParent has been
     946             :     // set then we should just store them, so that they get called when we set
     947             :     // mGMPContentParent as a result of the PGMPContent::Open call.
     948           0 :     if (mGetContentParentPromises.Length() == 1) {
     949           0 :       if (!EnsureProcessLoaded() || !OpenPGMPContent()) {
     950           0 :         RejectGetContentParentPromises();
     951           0 :         return;
     952             :       }
     953             :       // We want to increment this as soon as possible, to avoid that we'd try
     954             :       // to shut down the GMP process while we're still trying to get a
     955             :       // PGMPContentParent actor.
     956           0 :       ++mGMPContentChildCount;
     957             :     }
     958             :   }
     959             : }
     960             : 
     961             : already_AddRefed<GMPContentParent>
     962           0 : GMPParent::ForgetGMPContentParent()
     963             : {
     964           0 :   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
     965           0 :   return Move(mGMPContentParent.forget());
     966             : }
     967             : 
     968             : bool
     969           0 : GMPParent::EnsureProcessLoaded(base::ProcessId* aID)
     970             : {
     971           0 :   if (!EnsureProcessLoaded()) {
     972           0 :     return false;
     973             :   }
     974           0 :   *aID = OtherPid();
     975           0 :   return true;
     976             : }
     977             : 
     978             : void
     979           0 : GMPParent::IncrementGMPContentChildCount()
     980             : {
     981           0 :   ++mGMPContentChildCount;
     982           0 : }
     983             : 
     984             : nsString
     985           3 : GMPParent::GetPluginBaseName() const
     986             : {
     987           3 :   return NS_LITERAL_STRING("gmp-") + mName;
     988             : }
     989             : 
     990             : } // namespace gmp
     991             : } // namespace mozilla
     992             : 
     993             : #undef LOG
     994             : #undef LOGD

Generated by: LCOV version 1.13