LCOV - code coverage report
Current view: top level - dom/media/gmp - GMPChild.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 149 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 24 0.0 %
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 "GMPChild.h"
       7             : #include "GMPContentChild.h"
       8             : #include "GMPProcessChild.h"
       9             : #include "GMPLoader.h"
      10             : #include "GMPVideoDecoderChild.h"
      11             : #include "GMPVideoEncoderChild.h"
      12             : #include "GMPDecryptorChild.h"
      13             : #include "GMPVideoHost.h"
      14             : #include "nsDebugImpl.h"
      15             : #include "nsIFile.h"
      16             : #include "nsXULAppAPI.h"
      17             : #include "gmp-video-decode.h"
      18             : #include "gmp-video-encode.h"
      19             : #include "GMPPlatform.h"
      20             : #include "mozilla/ipc/CrashReporterClient.h"
      21             : #include "mozilla/ipc/ProcessChild.h"
      22             : #include "GMPUtils.h"
      23             : #include "prio.h"
      24             : #include "base/task.h"
      25             : #include "widevine-adapter/WidevineAdapter.h"
      26             : #include "ChromiumCDMAdapter.h"
      27             : 
      28             : using namespace mozilla::ipc;
      29             : 
      30             : #ifdef XP_WIN
      31             : #include <stdlib.h> // for _exit()
      32             : #else
      33             : #include <unistd.h> // for _exit()
      34             : #endif
      35             : 
      36             : #if defined(MOZ_GMP_SANDBOX)
      37             : #if defined(XP_MACOSX)
      38             : #include "mozilla/Sandbox.h"
      39             : #endif
      40             : #endif
      41             : 
      42             : namespace mozilla {
      43             : 
      44             : #undef LOG
      45             : #undef LOGD
      46             : 
      47             : extern LogModule* GetGMPLog();
      48             : #define LOG(level, x, ...) MOZ_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
      49             : #define LOGD(x, ...) LOG(mozilla::LogLevel::Debug, "GMPChild[pid=%d] " x, (int)base::GetCurrentProcId(), ##__VA_ARGS__)
      50             : 
      51             : namespace gmp {
      52             : 
      53           0 : GMPChild::GMPChild()
      54           0 :   : mGMPMessageLoop(MessageLoop::current())
      55           0 :   , mGMPLoader(nullptr)
      56             : {
      57           0 :   LOGD("GMPChild ctor");
      58           0 :   nsDebugImpl::SetMultiprocessMode("GMP");
      59           0 : }
      60             : 
      61           0 : GMPChild::~GMPChild()
      62             : {
      63           0 :   LOGD("GMPChild dtor");
      64           0 : }
      65             : 
      66             : static bool
      67           0 : GetFileBase(const nsAString& aPluginPath,
      68             :             nsCOMPtr<nsIFile>& aLibDirectory,
      69             :             nsCOMPtr<nsIFile>& aFileBase,
      70             :             nsAutoString& aBaseName)
      71             : {
      72           0 :   nsresult rv = NS_NewLocalFile(aPluginPath,
      73           0 :                                 true, getter_AddRefs(aFileBase));
      74           0 :   if (NS_FAILED(rv)) {
      75           0 :     return false;
      76             :   }
      77             : 
      78           0 :   if (NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory)))) {
      79           0 :     return false;
      80             :   }
      81             : 
      82           0 :   nsCOMPtr<nsIFile> parent;
      83           0 :   rv = aFileBase->GetParent(getter_AddRefs(parent));
      84           0 :   if (NS_FAILED(rv)) {
      85           0 :     return false;
      86             :   }
      87             : 
      88           0 :   nsAutoString parentLeafName;
      89           0 :   rv = parent->GetLeafName(parentLeafName);
      90           0 :   if (NS_FAILED(rv)) {
      91           0 :     return false;
      92             :   }
      93             : 
      94           0 :   aBaseName = Substring(parentLeafName,
      95             :                         4,
      96           0 :                         parentLeafName.Length() - 1);
      97           0 :   return true;
      98             : }
      99             : 
     100             : static bool
     101           0 : GetPluginFile(const nsAString& aPluginPath,
     102             :               nsCOMPtr<nsIFile>& aLibDirectory,
     103             :               nsCOMPtr<nsIFile>& aLibFile)
     104             : {
     105           0 :   nsAutoString baseName;
     106           0 :   GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
     107             : 
     108             : #if defined(XP_MACOSX)
     109             :   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".dylib");
     110             : #elif defined(OS_POSIX)
     111           0 :   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".so");
     112             : #elif defined(XP_WIN)
     113             :   nsAutoString binaryName =                            baseName + NS_LITERAL_STRING(".dll");
     114             : #else
     115             : #error not defined
     116             : #endif
     117           0 :   aLibFile->AppendRelativePath(binaryName);
     118           0 :   return true;
     119             : }
     120             : 
     121             : #if !defined(XP_MACOSX) || !defined(MOZ_GMP_SANDBOX)
     122             : static bool
     123           0 : GetPluginFile(const nsAString& aPluginPath,
     124             :               nsCOMPtr<nsIFile>& aLibFile)
     125             : {
     126           0 :   nsCOMPtr<nsIFile> unusedlibDir;
     127           0 :   return GetPluginFile(aPluginPath, unusedlibDir, aLibFile);
     128             : }
     129             : #endif
     130             : 
     131             : #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
     132             : static nsCString
     133             : GetNativeTarget(nsIFile* aFile)
     134             : {
     135             :   bool isLink;
     136             :   nsCString path;
     137             :   aFile->IsSymlink(&isLink);
     138             :   if (isLink) {
     139             :     aFile->GetNativeTarget(path);
     140             :   } else {
     141             :     aFile->GetNativePath(path);
     142             :   }
     143             :   return path;
     144             : }
     145             : 
     146             : static bool
     147             : GetPluginPaths(const nsAString& aPluginPath,
     148             :                nsCString &aPluginDirectoryPath,
     149             :                nsCString &aPluginFilePath)
     150             : {
     151             :   nsCOMPtr<nsIFile> libDirectory, libFile;
     152             :   if (!GetPluginFile(aPluginPath, libDirectory, libFile)) {
     153             :     return false;
     154             :   }
     155             : 
     156             :   // Mac sandbox rules expect paths to actual files and directories -- not
     157             :   // soft links.
     158             :   libDirectory->Normalize();
     159             :   aPluginDirectoryPath = GetNativeTarget(libDirectory);
     160             : 
     161             :   libFile->Normalize();
     162             :   aPluginFilePath = GetNativeTarget(libFile);
     163             : 
     164             :   return true;
     165             : }
     166             : 
     167             : static bool
     168             : GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
     169             : {
     170             :   nsAutoCString appPath;
     171             :   nsAutoCString appBinaryPath(
     172             :     (CommandLine::ForCurrentProcess()->argv()[0]).c_str());
     173             : 
     174             :   nsAutoCString::const_iterator start, end;
     175             :   appBinaryPath.BeginReading(start);
     176             :   appBinaryPath.EndReading(end);
     177             :   if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
     178             :     end = start;
     179             :     ++end; ++end; ++end; ++end;
     180             :     appBinaryPath.BeginReading(start);
     181             :     appPath.Assign(Substring(start, end));
     182             :   } else {
     183             :     return false;
     184             :   }
     185             : 
     186             :   nsCOMPtr<nsIFile> app, appBinary;
     187             :   nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
     188             :                                 true, getter_AddRefs(app));
     189             :   if (NS_FAILED(rv)) {
     190             :     return false;
     191             :   }
     192             :   rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appBinaryPath),
     193             :                        true, getter_AddRefs(appBinary));
     194             :   if (NS_FAILED(rv)) {
     195             :     return false;
     196             :   }
     197             : 
     198             :   // Mac sandbox rules expect paths to actual files and directories -- not
     199             :   // soft links.
     200             :   aAppPath = GetNativeTarget(app);
     201             :   appBinaryPath = GetNativeTarget(appBinary);
     202             : 
     203             :   return true;
     204             : }
     205             : 
     206             : bool
     207             : GMPChild::SetMacSandboxInfo(MacSandboxPluginType aPluginType)
     208             : {
     209             :   if (!mGMPLoader) {
     210             :     return false;
     211             :   }
     212             :   nsAutoCString pluginDirectoryPath, pluginFilePath;
     213             :   if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
     214             :     return false;
     215             :   }
     216             :   nsAutoCString appPath, appBinaryPath;
     217             :   if (!GetAppPaths(appPath, appBinaryPath)) {
     218             :     return false;
     219             :   }
     220             : 
     221             :   MacSandboxInfo info;
     222             :   info.type = MacSandboxType_Plugin;
     223             :   info.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
     224             :                    PR_GetEnv("MOZ_SANDBOX_LOGGING");
     225             :   info.pluginInfo.type = aPluginType;
     226             :   info.pluginInfo.pluginPath.assign(pluginDirectoryPath.get());
     227             :   info.pluginInfo.pluginBinaryPath.assign(pluginFilePath.get());
     228             :   info.appPath.assign(appPath.get());
     229             :   info.appBinaryPath.assign(appBinaryPath.get());
     230             : 
     231             :   mGMPLoader->SetSandboxInfo(&info);
     232             :   return true;
     233             : }
     234             : #endif // XP_MACOSX && MOZ_GMP_SANDBOX
     235             : 
     236             : bool
     237           0 : GMPChild::Init(const nsAString& aPluginPath,
     238             :                base::ProcessId aParentPid,
     239             :                MessageLoop* aIOLoop,
     240             :                IPC::Channel* aChannel)
     241             : {
     242           0 :   LOGD("%s pluginPath=%s", __FUNCTION__, NS_ConvertUTF16toUTF8(aPluginPath).get());
     243             : 
     244           0 :   if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
     245           0 :     return false;
     246             :   }
     247             : 
     248             : #ifdef MOZ_CRASHREPORTER
     249           0 :   CrashReporterClient::InitSingleton(this);
     250             : #endif
     251             : 
     252           0 :   mPluginPath = aPluginPath;
     253             : 
     254           0 :   return true;
     255             : }
     256             : 
     257             : GMPErr
     258           0 : GMPChild::GetAPI(const char* aAPIName,
     259             :                  void* aHostAPI,
     260             :                  void** aPluginAPI,
     261             :                  uint32_t aDecryptorId)
     262             : {
     263           0 :   if (!mGMPLoader) {
     264           0 :     return GMPGenericErr;
     265             :   }
     266           0 :   return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
     267             : }
     268             : 
     269             : mozilla::ipc::IPCResult
     270           0 : GMPChild::RecvPreloadLibs(const nsCString& aLibs)
     271             : {
     272             : #ifdef XP_WIN
     273             :   // Pre-load DLLs that need to be used by the EME plugin but that can't be
     274             :   // loaded after the sandbox has started
     275             :   // Items in this must be lowercase!
     276             :   static const char *const whitelist[] = {
     277             :     "dxva2.dll", // Get monitor information
     278             :     "evr.dll", // MFGetStrideForBitmapInfoHeader
     279             :     "mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer, MFCreateMediaType
     280             :     "msmpeg2vdec.dll", // H.264 decoder
     281             :   };
     282             : 
     283             :   nsTArray<nsCString> libs;
     284             :   SplitAt(", ", aLibs, libs);
     285             :   for (nsCString lib : libs) {
     286             :     ToLowerCase(lib);
     287             :     for (const char* whiteListedLib : whitelist) {
     288             :       if (lib.EqualsASCII(whiteListedLib)) {
     289             :         LoadLibraryA(lib.get());
     290             :         break;
     291             :       }
     292             :     }
     293             :   }
     294             : #endif
     295           0 :   return IPC_OK();
     296             : }
     297             : 
     298             : bool
     299           0 : GMPChild::GetUTF8LibPath(nsACString& aOutLibPath)
     300             : {
     301             : #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
     302             :   nsAutoCString pluginDirectoryPath, pluginFilePath;
     303             :   if (!GetPluginPaths(mPluginPath, pluginDirectoryPath, pluginFilePath)) {
     304             :     MOZ_CRASH("Error scanning plugin path");
     305             :   }
     306             :   aOutLibPath.Assign(pluginFilePath);
     307             :   return true;
     308             : #else
     309           0 :   nsCOMPtr<nsIFile> libFile;
     310           0 :   if (!GetPluginFile(mPluginPath, libFile)) {
     311           0 :     return false;
     312             :   }
     313             : 
     314           0 :   if (!FileExists(libFile)) {
     315           0 :     NS_WARNING("Can't find GMP library file!");
     316           0 :     return false;
     317             :   }
     318             : 
     319           0 :   nsAutoString path;
     320           0 :   libFile->GetPath(path);
     321           0 :   aOutLibPath = NS_ConvertUTF16toUTF8(path);
     322             : 
     323           0 :   return true;
     324             : #endif
     325             : }
     326             : 
     327             : mozilla::ipc::IPCResult
     328           0 : GMPChild::AnswerStartPlugin(const nsString& aAdapter)
     329             : {
     330           0 :   LOGD("%s", __FUNCTION__);
     331             : 
     332           0 :   nsCString libPath;
     333           0 :   if (!GetUTF8LibPath(libPath)) {
     334           0 :     return IPC_FAIL_NO_REASON(this);
     335             :   }
     336             : 
     337           0 :   auto platformAPI = new GMPPlatformAPI();
     338           0 :   InitPlatformAPI(*platformAPI, this);
     339             : 
     340           0 :   mGMPLoader = MakeUnique<GMPLoader>();
     341             : #if defined(MOZ_GMP_SANDBOX)
     342             :   if (!mGMPLoader->CanSandbox()) {
     343             :     LOGD("%s Can't sandbox GMP, failing", __FUNCTION__);
     344             :     delete platformAPI;
     345             :     return IPC_FAIL_NO_REASON(this);
     346             :   }
     347             : #endif
     348             : 
     349           0 :   bool isWidevine = aAdapter.EqualsLiteral("widevine");
     350           0 :   bool isChromium = aAdapter.EqualsLiteral("chromium");
     351             : #if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
     352             :   MacSandboxPluginType pluginType = MacSandboxPluginType_GMPlugin_Default;
     353             :   if (isWidevine || isChromium) {
     354             :     pluginType = MacSandboxPluginType_GMPlugin_EME_Widevine;
     355             :   }
     356             :   if (!SetMacSandboxInfo(pluginType)) {
     357             :     NS_WARNING("Failed to set Mac GMP sandbox info");
     358             :     delete platformAPI;
     359             :     return IPC_FAIL_NO_REASON(this);
     360             :   }
     361             : #endif
     362             : 
     363           0 :   GMPAdapter* adapter = nullptr;
     364           0 :   if (isWidevine) {
     365           0 :     adapter = new WidevineAdapter();
     366           0 :   } else if (isChromium) {
     367           0 :     adapter = new ChromiumCDMAdapter();
     368             :   }
     369             : 
     370           0 :   if (!mGMPLoader->Load(libPath.get(),
     371             :                         libPath.Length(),
     372             :                         platformAPI,
     373             :                         adapter)) {
     374           0 :     NS_WARNING("Failed to load GMP");
     375             :     delete platformAPI;
     376           0 :     return IPC_FAIL_NO_REASON(this);
     377             :   }
     378             : 
     379           0 :   return IPC_OK();
     380             : }
     381             : 
     382             : MessageLoop*
     383           0 : GMPChild::GMPMessageLoop()
     384             : {
     385           0 :   return mGMPMessageLoop;
     386             : }
     387             : 
     388             : void
     389           0 : GMPChild::ActorDestroy(ActorDestroyReason aWhy)
     390             : {
     391           0 :   LOGD("%s reason=%d", __FUNCTION__, aWhy);
     392             : 
     393           0 :   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
     394           0 :     MOZ_ASSERT_IF(aWhy == NormalShutdown, !mGMPContentChildren[i - 1]->IsUsed());
     395           0 :     mGMPContentChildren[i - 1]->Close();
     396             :   }
     397             : 
     398           0 :   if (mGMPLoader) {
     399           0 :     mGMPLoader->Shutdown();
     400             :   }
     401           0 :   if (AbnormalShutdown == aWhy) {
     402           0 :     NS_WARNING("Abnormal shutdown of GMP process!");
     403           0 :     ProcessChild::QuickExit();
     404             :   }
     405             : 
     406             : #ifdef MOZ_CRASHREPORTER
     407           0 :   CrashReporterClient::DestroySingleton();
     408             : #endif
     409           0 :   XRE_ShutdownChildProcess();
     410           0 : }
     411             : 
     412             : void
     413           0 : GMPChild::ProcessingError(Result aCode, const char* aReason)
     414             : {
     415           0 :   switch (aCode) {
     416             :     case MsgDropped:
     417           0 :       _exit(0); // Don't trigger a crash report.
     418             :     case MsgNotKnown:
     419           0 :       MOZ_CRASH("aborting because of MsgNotKnown");
     420             :     case MsgNotAllowed:
     421           0 :       MOZ_CRASH("aborting because of MsgNotAllowed");
     422             :     case MsgPayloadError:
     423           0 :       MOZ_CRASH("aborting because of MsgPayloadError");
     424             :     case MsgProcessingError:
     425           0 :       MOZ_CRASH("aborting because of MsgProcessingError");
     426             :     case MsgRouteError:
     427           0 :       MOZ_CRASH("aborting because of MsgRouteError");
     428             :     case MsgValueError:
     429           0 :       MOZ_CRASH("aborting because of MsgValueError");
     430             :     default:
     431           0 :       MOZ_CRASH("not reached");
     432             :   }
     433             : }
     434             : 
     435             : PGMPTimerChild*
     436           0 : GMPChild::AllocPGMPTimerChild()
     437             : {
     438           0 :   return new GMPTimerChild(this);
     439             : }
     440             : 
     441             : bool
     442           0 : GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor)
     443             : {
     444           0 :   MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor));
     445           0 :   mTimerChild = nullptr;
     446           0 :   return true;
     447             : }
     448             : 
     449             : GMPTimerChild*
     450           0 : GMPChild::GetGMPTimers()
     451             : {
     452           0 :   if (!mTimerChild) {
     453           0 :     PGMPTimerChild* sc = SendPGMPTimerConstructor();
     454           0 :     if (!sc) {
     455           0 :       return nullptr;
     456             :     }
     457           0 :     mTimerChild = static_cast<GMPTimerChild*>(sc);
     458             :   }
     459           0 :   return mTimerChild;
     460             : }
     461             : 
     462             : PGMPStorageChild*
     463           0 : GMPChild::AllocPGMPStorageChild()
     464             : {
     465           0 :   return new GMPStorageChild(this);
     466             : }
     467             : 
     468             : bool
     469           0 : GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor)
     470             : {
     471           0 :   mStorage = nullptr;
     472           0 :   return true;
     473             : }
     474             : 
     475             : GMPStorageChild*
     476           0 : GMPChild::GetGMPStorage()
     477             : {
     478           0 :   if (!mStorage) {
     479           0 :     PGMPStorageChild* sc = SendPGMPStorageConstructor();
     480           0 :     if (!sc) {
     481           0 :       return nullptr;
     482             :     }
     483           0 :     mStorage = static_cast<GMPStorageChild*>(sc);
     484             :   }
     485           0 :   return mStorage;
     486             : }
     487             : 
     488             : mozilla::ipc::IPCResult
     489           0 : GMPChild::RecvCrashPluginNow()
     490             : {
     491           0 :   MOZ_CRASH();
     492             :   return IPC_OK();
     493             : }
     494             : 
     495             : mozilla::ipc::IPCResult
     496           0 : GMPChild::RecvCloseActive()
     497             : {
     498           0 :   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
     499           0 :     mGMPContentChildren[i - 1]->CloseActive();
     500             :   }
     501           0 :   return IPC_OK();
     502             : }
     503             : 
     504             : mozilla::ipc::IPCResult
     505           0 : GMPChild::RecvInitGMPContentChild(Endpoint<PGMPContentChild>&& aEndpoint)
     506             : {
     507             :   GMPContentChild* child =
     508           0 :     mGMPContentChildren.AppendElement(new GMPContentChild(this))->get();
     509           0 :   aEndpoint.Bind(child);
     510           0 :   return IPC_OK();
     511             : }
     512             : 
     513             : void
     514           0 : GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild)
     515             : {
     516           0 :   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
     517           0 :     UniquePtr<GMPContentChild>& toDestroy = mGMPContentChildren[i - 1];
     518           0 :     if (toDestroy.get() == aGMPContentChild) {
     519           0 :       SendPGMPContentChildDestroyed();
     520             :       RefPtr<DeleteTask<GMPContentChild>> task =
     521           0 :         new DeleteTask<GMPContentChild>(toDestroy.release());
     522           0 :       MessageLoop::current()->PostTask(task.forget());
     523           0 :       mGMPContentChildren.RemoveElementAt(i - 1);
     524           0 :       break;
     525             :     }
     526             :   }
     527           0 : }
     528             : 
     529             : } // namespace gmp
     530             : } // namespace mozilla
     531             : 
     532             : #undef LOG
     533             : #undef LOGD

Generated by: LCOV version 1.13