content/media/plugins/MediaPluginHost.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/Preferences.h"
     7 #include "mozilla/dom/TimeRanges.h"
     8 #include "MediaResource.h"
     9 #include "mozilla/dom/HTMLMediaElement.h"
    10 #include "MediaPluginHost.h"
    11 #include "nsXPCOMStrings.h"
    12 #include "nsISeekableStream.h"
    13 #include "MediaPluginReader.h"
    14 #include "nsIGfxInfo.h"
    15 #include "gfxCrashReporterUtils.h"
    16 #include "prmem.h"
    17 #include "prlink.h"
    18 #include "MediaResourceServer.h"
    19 #include "nsServiceManagerUtils.h"
    21 #include "MPAPI.h"
    23 #include "nsIPropertyBag2.h"
    25 #if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
    26 #include "android/log.h"
    27 #define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "MediaPluginHost" , ## args)
    28 #else
    29 #define ALOG(args...) /* do nothing */
    30 #endif
    32 using namespace MPAPI;
    34 Decoder::Decoder() :
    35   mResource(nullptr), mPrivate(nullptr)
    36 {
    37 }
    39 namespace mozilla {
    41 static char* GetResource(Decoder *aDecoder)
    42 {
    43   return static_cast<char*>(aDecoder->mResource);
    44 }
    46 class GetIntPrefEvent : public nsRunnable {
    47 public:
    48   GetIntPrefEvent(const char* aPref, int32_t* aResult)
    49     : mPref(aPref), mResult(aResult) {}
    50   NS_IMETHOD Run() {
    51     return Preferences::GetInt(mPref, mResult);
    52   }
    53 private:
    54   const char* mPref;
    55   int32_t*    mResult;
    56 };
    58 static bool GetIntPref(const char* aPref, int32_t* aResult)
    59 {
    60   // GetIntPref() is called on the decoder thread, but the Preferences API
    61   // can only be called on the main thread. Post a runnable and wait.
    62   NS_ENSURE_TRUE(aPref, false);
    63   NS_ENSURE_TRUE(aResult, false);
    64   nsCOMPtr<nsIRunnable> event = new GetIntPrefEvent(aPref, aResult);
    65   return NS_SUCCEEDED(NS_DispatchToMainThread(event, NS_DISPATCH_SYNC));
    66 }
    68 static bool
    69 GetSystemInfoString(const char *aKey, char *aResult, size_t aResultLength)
    70 {
    71   NS_ENSURE_TRUE(aKey, false);
    72   NS_ENSURE_TRUE(aResult, false);
    74   nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
    75   NS_ASSERTION(infoService, "Could not find a system info service");
    77   nsAutoCString key(aKey);
    78   nsAutoCString info;
    79   nsresult rv = infoService->GetPropertyAsACString(NS_ConvertUTF8toUTF16(key),
    80                                                   info);
    82   NS_ENSURE_SUCCESS(rv, false);
    84   strncpy(aResult, info.get(), aResultLength);
    86   return true;
    87 }
    89 static PluginHost sPluginHost = {
    90   nullptr,
    91   nullptr,
    92   nullptr,
    93   nullptr,
    94   GetIntPref,
    95   GetSystemInfoString
    96 };
    98 // Return true if Omx decoding is supported on the device. This checks the
    99 // built in whitelist/blacklist and preferences to see if that is overridden.
   100 static bool IsOmxSupported()
   101 {
   102   bool forceEnabled =
   103       Preferences::GetBool("stagefright.force-enabled", false);
   104   bool disabled =
   105       Preferences::GetBool("stagefright.disabled", false);
   107   if (disabled) {
   108     NS_WARNING("XXX stagefright disabled\n");
   109     return false;
   110   }
   112   ScopedGfxFeatureReporter reporter("Stagefright", forceEnabled);
   114   if (!forceEnabled) {
   115     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   116     if (gfxInfo) {
   117       int32_t status;
   118       if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, &status))) {
   119         if (status != nsIGfxInfo::FEATURE_NO_INFO) {
   120           NS_WARNING("XXX stagefright blacklisted\n");
   121           return false;
   122         }
   123       }
   124     }
   125   }
   127   reporter.SetSuccessful();
   128   return true;
   129 }
   131 // Return the name of the shared library that implements Omx based decoding. This varies
   132 // depending on libstagefright version installed on the device and whether it is B2G vs Android.
   133 // nullptr is returned if Omx decoding is not supported on the device,
   134 static const char* GetOmxLibraryName()
   135 {
   136 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   137   nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
   138   NS_ASSERTION(infoService, "Could not find a system info service");
   140   int32_t version;
   141   nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("version"), &version);
   142   if (NS_SUCCEEDED(rv)) {
   143     ALOG("Android Version is: %d", version);
   144   }
   146   nsAutoString release_version;
   147   rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("release_version"), release_version);
   148   if (NS_SUCCEEDED(rv)) {
   149     ALOG("Android Release Version is: %s", NS_LossyConvertUTF16toASCII(release_version).get());
   150   }
   152   nsAutoString device;
   153   rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("device"), device);
   154   if (NS_SUCCEEDED(rv)) {
   155     ALOG("Android Device is: %s", NS_LossyConvertUTF16toASCII(device).get());
   156   }
   158   nsAutoString manufacturer;
   159   rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), manufacturer);
   160   if (NS_SUCCEEDED(rv)) {
   161     ALOG("Android Manufacturer is: %s", NS_LossyConvertUTF16toASCII(manufacturer).get());
   162   }
   164   nsAutoString hardware;
   165   rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("hardware"), hardware);
   166   if (NS_SUCCEEDED(rv)) {
   167     ALOG("Android Hardware is: %s", NS_LossyConvertUTF16toASCII(hardware).get());
   168   }
   169 #endif
   171   if (!IsOmxSupported())
   172     return nullptr;
   174 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   175   if (version >= 17) {
   176     return "libomxpluginkk.so";
   177   }
   178   else if (version == 13 || version == 12 || version == 11) {
   179     return "libomxpluginhc.so";
   180   }
   181   else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.6")) {
   182     // Gingerbread versions from 2.3.6 and above have a different DataSource
   183     // layout to those on 2.3.5 and below.
   184     return "libomxplugingb.so";
   185   }
   186   else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.4") &&
   187            device.Find("HTC") == 0) {
   188     // HTC devices running Gingerbread 2.3.4+ (HTC Desire HD, HTC Evo Design, etc) seem to
   189     // use a newer version of Gingerbread libstagefright than other 2.3.4 devices.
   190     return "libomxplugingb.so";
   191   }
   192   else if (version == 9 || (version == 10 && release_version <= NS_LITERAL_STRING("2.3.5"))) {
   193     // Gingerbread versions from 2.3.5 and below have a different DataSource
   194     // than 2.3.6 and above.
   195     return "libomxplugingb235.so";
   196   }
   197   else if (version == 8) {
   198     // Froyo
   199     return "libomxpluginfroyo.so";
   200   }
   201   else if (version < 8) {
   202     // Below Froyo not supported
   203     return nullptr;
   204   }
   206   // Ice Cream Sandwich and Jellybean
   207   return "libomxplugin.so";
   209 #elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
   210   return "libomxplugin.so";
   211 #else
   212   return nullptr;
   213 #endif
   214 }
   216 MediaPluginHost::MediaPluginHost() {
   217   MOZ_COUNT_CTOR(MediaPluginHost);
   219   mResourceServer = MediaResourceServer::Start();
   221   const char* name = GetOmxLibraryName();
   222   ALOG("Loading OMX Plugin: %s", name ? name : "nullptr");
   223   if (name) {
   224     char *path = PR_GetLibraryFilePathname("libxul.so", (PRFuncPtr) GetOmxLibraryName);
   225     PRLibrary *lib = nullptr;
   226     if (path) {
   227       nsAutoCString libpath(path);
   228       PR_Free(path);
   229       int32_t slash = libpath.RFindChar('/');
   230       if (slash != kNotFound) {
   231         libpath.Truncate(slash + 1);
   232         libpath.Append(name);
   233         lib = PR_LoadLibrary(libpath.get());
   234       }
   235     }
   236     if (!lib)
   237       lib = PR_LoadLibrary(name);
   239     if (lib) {
   240       Manifest *manifest = static_cast<Manifest *>(PR_FindSymbol(lib, "MPAPI_MANIFEST"));
   241       if (manifest) {
   242         mPlugins.AppendElement(manifest);
   243         ALOG("OMX plugin successfully loaded");
   244      }
   245     }
   246   }
   247 }
   249 MediaPluginHost::~MediaPluginHost() {
   250   mResourceServer->Stop();
   251   MOZ_COUNT_DTOR(MediaPluginHost);
   252 }
   254 bool MediaPluginHost::FindDecoder(const nsACString& aMimeType, const char* const** aCodecs)
   255 {
   256   const char *chars;
   257   size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
   258   for (size_t n = 0; n < mPlugins.Length(); ++n) {
   259     Manifest *plugin = mPlugins[n];
   260     const char* const *codecs;
   261     if (plugin->CanDecode(chars, len, &codecs)) {
   262       if (aCodecs)
   263         *aCodecs = codecs;
   264       return true;
   265     }
   266   }
   267   return false;
   268 }
   270 MPAPI::Decoder *MediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType)
   271 {
   272   NS_ENSURE_TRUE(aResource, nullptr);
   274   nsAutoPtr<Decoder> decoder(new Decoder());
   275   if (!decoder) {
   276     return nullptr;
   277   }
   279   const char *chars;
   280   size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
   281   for (size_t n = 0; n < mPlugins.Length(); ++n) {
   282     Manifest *plugin = mPlugins[n];
   283     const char* const *codecs;
   284     if (!plugin->CanDecode(chars, len, &codecs)) {
   285       continue;
   286     }
   288     nsCString url;
   289     nsresult rv = mResourceServer->AddResource(aResource, url);
   290     if (NS_FAILED (rv)) continue;
   292     decoder->mResource = strdup(url.get());
   293     if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
   294       aResource->AddRef();
   295       return decoder.forget();
   296     }
   297   }
   299   return nullptr;
   300 }
   302 void MediaPluginHost::DestroyDecoder(Decoder *aDecoder)
   303 {
   304   aDecoder->DestroyDecoder(aDecoder);
   305   char* resource = GetResource(aDecoder);
   306   if (resource) {
   307     // resource *shouldn't* be null, but check anyway just in case the plugin
   308     // decoder does something stupid.
   309     mResourceServer->RemoveResource(nsCString(resource));
   310     free(resource);
   311   }
   312   delete aDecoder;
   313 }
   315 MediaPluginHost *sMediaPluginHost = nullptr;
   316 MediaPluginHost *GetMediaPluginHost()
   317 {
   318   if (!sMediaPluginHost) {
   319     sMediaPluginHost = new MediaPluginHost();
   320   }
   321   return sMediaPluginHost;
   322 }
   324 void MediaPluginHost::Shutdown()
   325 {
   326   delete sMediaPluginHost;
   327   sMediaPluginHost = nullptr;
   328 }
   330 } // namespace mozilla

mercurial