Bug 806369 - Stagefright blacklisting. Also extends Android Gfxinfo to support blacklist rules by Android API version, Model, Product, Hardware, Manufacturer - r=joe,doublec
authorBenoit Jacob <bjacob@mozilla.com>
Thu, 01 Nov 2012 17:13:10 -0400
changeset 112080 f710f9f6f7ec0c76a0153f076a1358be4bb4938c
parent 112079 75fa1f74f17474213bb8c4bd79ca0414108fce8a
child 112081 c0d55648fbf56818b28f6b85999bdf9d01b15933
push id1997
push userakeybl@mozilla.com
push dateMon, 07 Jan 2013 21:25:26 +0000
treeherdermozilla-esr52@cf8750abee06 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe, doublec
bugs806369
milestone19.0a1
Bug 806369 - Stagefright blacklisting. Also extends Android Gfxinfo to support blacklist rules by Android API version, Model, Product, Hardware, Manufacturer - r=joe,doublec
content/media/plugins/nsMediaPluginHost.cpp
modules/libpref/src/init/all.js
widget/android/GfxInfo.cpp
widget/android/GfxInfo.h
widget/cocoa/GfxInfo.h
widget/nsIGfxInfo.idl
widget/windows/GfxInfo.h
widget/xpwidgets/GfxDriverInfo.cpp
widget/xpwidgets/GfxDriverInfo.h
widget/xpwidgets/GfxInfoBase.cpp
widget/xpwidgets/GfxInfoBase.h
--- a/content/media/plugins/nsMediaPluginHost.cpp
+++ b/content/media/plugins/nsMediaPluginHost.cpp
@@ -8,16 +8,17 @@
 #include "nsTimeRanges.h"
 #include "MediaResource.h"
 #include "nsHTMLMediaElement.h"
 #include "nsMediaPluginHost.h"
 #include "nsXPCOMStrings.h"
 #include "nsISeekableStream.h"
 #include "pratom.h"
 #include "nsMediaPluginReader.h"
+#include "nsIGfxInfo.h"
 
 #include "MPAPI.h"
 
 using namespace MPAPI;
 using namespace mozilla;
 
 static MediaResource *GetResource(Decoder *aDecoder)
 {
@@ -82,16 +83,39 @@ static PluginHost sPluginHost = {
   GetLength,
   SetMetaDataReadMode,
   SetPlaybackReadMode,
   GetIntPref
 };
 
 void nsMediaPluginHost::TryLoad(const char *name)
 {
+  bool forceEnabled =
+      Preferences::GetBool("stagefright.force-enabled", false);
+  bool disabled =
+      Preferences::GetBool("stagefright.disabled", false);
+
+  if (disabled) {
+    NS_WARNING("XXX stagefright disabled\n");
+    return;
+  }
+
+  if (!forceEnabled) {
+    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
+    if (gfxInfo) {
+      int32_t status;
+      if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, &status))) {
+        if (status != nsIGfxInfo::FEATURE_NO_INFO) {
+          NS_WARNING("XXX stagefright blacklisted\n");
+          return;
+        }
+      }
+    }
+  }
+
   PRLibrary *lib = PR_LoadLibrary(name);
   if (lib) {
     Manifest *manifest = static_cast<Manifest *>(PR_FindSymbol(lib, "MPAPI_MANIFEST"));
     if (manifest)
       mPlugins.AppendElement(manifest);
   }
 }
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3624,16 +3624,20 @@ pref("webgl.prefer-native-gl", false);
 pref("webgl.min_capability_mode", false);
 pref("webgl.disable-extensions", false);
 pref("webgl.msaa-level", 2);
 pref("webgl.msaa-force", false);
 pref("webgl.prefer-16bpp", false);
 pref("webgl.default-no-alpha", false);
 pref("webgl.force-layers-readback", false);
 
+// Stagefright prefs
+pref("stagefright.force-enabled", false);
+pref("stagefright.disabled", false);
+
 #ifdef XP_WIN
 // The default TCP send window on Windows is too small, and autotuning only occurs on receive
 pref("network.tcp.sendbuffer", 131072);
 #endif
 
 // Asynchonous video compositing using the ImageBridge IPDL protocol.
 // requires off-main-thread compositing.
 pref("layers.async-video.enabled",false);
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -117,37 +117,36 @@ GfxInfo::EnsureInitializedFromGfxInfoDat
                                    mRenderer.get(),
                                    mVersion.get());
 
   // Now we append general (non-gfx) device information. The only reason why this code is still here
   // is that this used to be all we had in GfxInfo on Android, and we can't trivially remove it
   // as it's useful information that isn't given anywhere else in about:support of in crash reports.
   // But we should really move this out of GfxInfo.
   if (mozilla::AndroidBridge::Bridge()) {
-    nsAutoString str;
-    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", str)) {
-      mAdapterDescription.AppendPrintf(" -- Model: %s",  NS_LossyConvertUTF16toASCII(str).get());
+    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", mModel)) {
+      mAdapterDescription.AppendPrintf(" -- Model: %s",  NS_LossyConvertUTF16toASCII(mModel).get());
     }
 
-    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "PRODUCT", str)) {
-      mAdapterDescription.AppendPrintf(", Product: %s", NS_LossyConvertUTF16toASCII(str).get());
+    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "PRODUCT", mProduct)) {
+      mAdapterDescription.AppendPrintf(", Product: %s", NS_LossyConvertUTF16toASCII(mProduct).get());
     }
 
-    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", str)) {
-      mAdapterDescription.AppendPrintf(", Manufacturer: %s", NS_LossyConvertUTF16toASCII(str).get());
+    if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", mManufacturer)) {
+      mAdapterDescription.AppendPrintf(", Manufacturer: %s", NS_LossyConvertUTF16toASCII(mManufacturer).get());
     }
 
-    int32_t version; // the HARDWARE field isn't available on Android SDK < 8
-    if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &version))
-      version = 0;
+    int32_t signedVersion;
+    if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &signedVersion))
+      signedVersion = 0;
+    mOSVersion = signedVersion;
 
-    if (version >= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str)) {
-      if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", str)) {
-        mAdapterDescription.AppendPrintf(", Hardware: %s", NS_LossyConvertUTF16toASCII(str).get());
-      }
+    // the HARDWARE field isn't available on Android SDK < 8
+    if (mOSVersion >= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", mHardware)) {
+      mAdapterDescription.AppendPrintf(", Hardware: %s", NS_LossyConvertUTF16toASCII(mHardware).get());
     }
   }
 
   AddCrashReportAnnotations();
 }
 
 /* readonly attribute DOMString adapterDescription; */
 NS_IMETHODIMP
@@ -304,17 +303,17 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
                               int32_t *aStatus, 
                               nsAString & aSuggestedDriverVersion,
                               const nsTArray<GfxDriverInfo>& aDriverInfo, 
                               OperatingSystem* aOS /* = nullptr */)
 {
   NS_ENSURE_ARG_POINTER(aStatus);
   aSuggestedDriverVersion.SetIsVoid(true);
   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
-  OperatingSystem os = DRIVER_OS_ANDROID;
+  OperatingSystem os = mOS;
   if (aOS)
     *aOS = os;
 
   EnsureInitializedFromGfxInfoData();
 
   if (!mError.IsEmpty()) {
     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
     return NS_OK;
@@ -325,16 +324,37 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
     if (aFeature == FEATURE_WEBGL_OPENGL) {
       if (mRenderer.Find("Adreno 200") != -1 ||
           mRenderer.Find("Adreno 205") != -1)
       {
         *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
         return NS_OK;
       }
     }
+
+    if (aFeature == FEATURE_STAGEFRIGHT) {
+      NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer);
+      NS_LossyConvertUTF16toASCII cModel(mModel);
+      if (mOSVersion < 14 /* Before version 4.0 */ )
+      {
+        *aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
+        return NS_OK;
+      }
+      else if (mOSVersion < 16 /* Before version 4.1 */ )
+      {
+        bool isWhitelisted =
+          cManufacturer.Equals("samsung", nsCaseInsensitiveCStringComparator()) ||
+          cModel.Equals("galaxy nexus", nsCaseInsensitiveCStringComparator()); // some Galaxy Nexus have manufacturer=amazon
+
+        if (!isWhitelisted) {
+          *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+          return NS_OK;
+        }
+      }
+    }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os);
 }
 
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
@@ -361,12 +381,34 @@ NS_IMETHODIMP GfxInfo::SpoofDriverVersio
   EnsureInitializedFromGfxInfoData(); // initialization from GfxInfo data overwrites mVersion
   mVersion = NS_LossyConvertUTF16toASCII(aDriverVersion);
   return NS_OK;
 }
 
 /* void spoofOSVersion (in unsigned long aVersion); */
 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
 {
+  EnsureInitializedFromGfxInfoData(); // initialization from GfxInfo data overwrites mOSVersion
+  mOSVersion = aVersion;
   return NS_OK;
 }
 
 #endif
+
+const nsAString& GfxInfo::Model() const
+{
+  return mModel;
+}
+
+const nsAString& GfxInfo::Hardware() const
+{
+  return mHardware;
+}
+
+const nsAString& GfxInfo::Product() const
+{
+  return mProduct;
+}
+
+const nsAString& GfxInfo::Manufacturer() const
+{
+  return mManufacturer;
+}
--- a/widget/android/GfxInfo.h
+++ b/widget/android/GfxInfo.h
@@ -43,21 +43,28 @@ public:
   NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
   NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   void EnsureInitializedFromGfxInfoData();
 
+  virtual const nsAString& Model() const;
+  virtual const nsAString& Hardware() const;
+  virtual const nsAString& Product() const;
+  virtual const nsAString& Manufacturer() const;
+
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIGFXINFODEBUG
 #endif
 
+  virtual uint32_t OperatingSystemVersion() const { return mOSVersion; }
+
 protected:
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, 
                                         int32_t *aStatus, 
                                         nsAString & aSuggestedDriverVersion, 
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
                                         OperatingSystem* aOS = nullptr);
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo();
@@ -71,14 +78,19 @@ private:
   // the GL strings
   nsCString mVendor;
   nsCString mRenderer;
   nsCString mVersion;
   // a possible error message produced by the data source (e.g. if EGL initialization failed)
   nsCString mError;
 
   nsCString mAdapterDescription;
+
+  OperatingSystem mOS;
+  uint32_t mOSVersion;
+
+  nsString mModel, mHardware, mManufacturer, mProduct;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif /* __mozilla_widget_GfxInfo_h__ */
--- a/widget/cocoa/GfxInfo.h
+++ b/widget/cocoa/GfxInfo.h
@@ -48,16 +48,18 @@ public:
 
   virtual nsresult Init();
 
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIGFXINFODEBUG
 #endif
 
+  virtual uint32_t OperatingSystemVersion() const { return mOSXVersion; }
+
 protected:
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, 
                                         int32_t *aStatus, 
                                         nsAString & aSuggestedDriverVersion, 
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
                                         OperatingSystem* aOS = nullptr);
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo();
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -3,17 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /* NOTE: this interface is completely undesigned, not stable and likely to change */
 
-[scriptable, uuid(a67c77af-2952-4028-93ab-e7bc3b43cf81)]
+[scriptable, uuid(8a9797ae-22d4-431d-a628-18fd5900c53c)]
 interface nsIGfxInfo : nsISupports
 {
   /*
    * These are win32-specific
    */
   readonly attribute boolean D2DEnabled;
   readonly attribute boolean DWriteEnabled;
   readonly attribute DOMString DWriteVersion;
@@ -72,16 +72,18 @@ interface nsIGfxInfo : nsISupports
   /* Whether OpenGL is supported for layers */
   const long FEATURE_OPENGL_LAYERS = 5;
   /* Whether WebGL is supported via OpenGL. */
   const long FEATURE_WEBGL_OPENGL = 6;
   /* Whether WebGL is supported via ANGLE (D3D9 -- does not check for the presence of ANGLE libs). */
   const long FEATURE_WEBGL_ANGLE = 7;
   /* Whether WebGL antialiasing is supported. */
   const long FEATURE_WEBGL_MSAA = 8;
+  /* Whether Stagefright is supported */
+  const long FEATURE_STAGEFRIGHT = 9;
 
   /*
    * A set of return values from GetFeatureStatus
    */
 
   /* We don't explicitly block or discourage the feature. Which means we'll try getting it from the
    * hardware, and see what happens. */
   const long FEATURE_NO_INFO = 1;
--- a/widget/windows/GfxInfo.h
+++ b/widget/windows/GfxInfo.h
@@ -40,16 +40,18 @@ public:
   NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
   NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active);
   using GfxInfoBase::GetFeatureStatus;
   using GfxInfoBase::GetFeatureSuggestedDriverVersion;
   using GfxInfoBase::GetWebGLParameter;
 
   virtual nsresult Init();
 
+  virtual uint32_t OperatingSystemVersion() const { return mWindowsVersion; }
+
 #ifdef DEBUG
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIGFXINFODEBUG
 #endif
 
 protected:
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, 
--- a/widget/xpwidgets/GfxDriverInfo.cpp
+++ b/widget/xpwidgets/GfxDriverInfo.cpp
@@ -12,16 +12,17 @@ int32_t GfxDriverInfo::allFeatures = 0;
 uint64_t GfxDriverInfo::allDriverVersions = ~(uint64_t(0));
 GfxDeviceFamily* const GfxDriverInfo::allDevices = nullptr;
 
 GfxDeviceFamily* GfxDriverInfo::mDeviceFamilies[DeviceFamilyMax];
 nsAString* GfxDriverInfo::mDeviceVendors[DeviceVendorMax];
 
 GfxDriverInfo::GfxDriverInfo()
   : mOperatingSystem(DRIVER_OS_UNKNOWN),
+    mOperatingSystemVersion(0),
     mAdapterVendor(GfxDriverInfo::GetDeviceVendor(VendorAll)),
     mDevices(allDevices),
     mDeleteDevices(false),
     mFeature(allFeatures),
     mFeatureStatus(nsIGfxInfo::FEATURE_NO_INFO),
     mComparisonOp(DRIVER_COMPARISON_IGNORED),
     mDriverVersion(0),
     mDriverVersionMax(0),
@@ -31,29 +32,31 @@ GfxDriverInfo::GfxDriverInfo()
 GfxDriverInfo::GfxDriverInfo(OperatingSystem os, nsAString& vendor,
                              GfxDeviceFamily* devices,
                              int32_t feature, int32_t featureStatus,
                              VersionComparisonOp op,
                              uint64_t driverVersion,
                              const char *suggestedVersion /* = nullptr */,
                              bool ownDevices /* = false */)
   : mOperatingSystem(os),
+    mOperatingSystemVersion(0),
     mAdapterVendor(vendor),
     mDevices(devices),
     mDeleteDevices(ownDevices),
     mFeature(feature),
     mFeatureStatus(featureStatus),
     mComparisonOp(op),
     mDriverVersion(driverVersion),
     mDriverVersionMax(0),
     mSuggestedVersion(suggestedVersion)
 {}
 
 GfxDriverInfo::GfxDriverInfo(const GfxDriverInfo& aOrig)
   : mOperatingSystem(aOrig.mOperatingSystem),
+    mOperatingSystemVersion(aOrig.mOperatingSystemVersion),
     mAdapterVendor(aOrig.mAdapterVendor),
     mFeature(aOrig.mFeature),
     mFeatureStatus(aOrig.mFeatureStatus),
     mComparisonOp(aOrig.mComparisonOp),
     mDriverVersion(aOrig.mDriverVersion),
     mDriverVersionMax(aOrig.mDriverVersionMax),
     mSuggestedVersion(aOrig.mSuggestedVersion)
 {
--- a/widget/xpwidgets/GfxDriverInfo.h
+++ b/widget/xpwidgets/GfxDriverInfo.h
@@ -81,16 +81,17 @@ struct GfxDriverInfo
                 uint64_t driverVersion, const char *suggestedVersion = nullptr,
                 bool ownDevices = false);
 
   GfxDriverInfo();
   GfxDriverInfo(const GfxDriverInfo&);
   ~GfxDriverInfo();
 
   OperatingSystem mOperatingSystem;
+  uint32_t mOperatingSystemVersion;
 
   nsString mAdapterVendor;
 
   static GfxDeviceFamily* const allDevices;
   GfxDeviceFamily* mDevices;
 
   // Whether the mDevices array should be deleted when this structure is
   // deallocated. False by default.
@@ -112,16 +113,18 @@ struct GfxDriverInfo
 
   const char *mSuggestedVersion;
 
   static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
   static GfxDeviceFamily* mDeviceFamilies[DeviceFamilyMax];
 
   static const nsAString& GetDeviceVendor(DeviceVendor id);
   static nsAString* mDeviceVendors[DeviceVendorMax];
+
+  nsString mModel, mHardware, mProduct, mManufacturer;
 };
 
 #define GFX_DRIVER_VERSION(a,b,c,d) \
   ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
 
 static uint64_t
 V(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
 {
--- a/widget/xpwidgets/GfxInfoBase.cpp
+++ b/widget/xpwidgets/GfxInfoBase.cpp
@@ -116,16 +116,19 @@ GetPrefNameForFeature(int32_t aFeature)
       name = BLACKLIST_PREF_BRANCH "webgl.opengl";
       break;
     case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
       name = BLACKLIST_PREF_BRANCH "webgl.angle";
       break;
     case nsIGfxInfo::FEATURE_WEBGL_MSAA:
       name = BLACKLIST_PREF_BRANCH "webgl.msaa";
       break;
+    case nsIGfxInfo::FEATURE_STAGEFRIGHT:
+      name = BLACKLIST_PREF_BRANCH "stagefright";
+      break;
     default:
       break;
   };
 
   return name;
 }
 
 // Returns the value of the pref for the relevant feature in aValue.
@@ -265,17 +268,18 @@ BlacklistFeatureToGfxFeature(const nsASt
   else if (aFeature == NS_LITERAL_STRING("OPENGL_LAYERS"))
     return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
   else if (aFeature == NS_LITERAL_STRING("WEBGL_OPENGL"))
     return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
   else if (aFeature == NS_LITERAL_STRING("WEBGL_ANGLE"))
     return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
   else if (aFeature == NS_LITERAL_STRING("WEBGL_MSAA"))
     return nsIGfxInfo::FEATURE_WEBGL_MSAA;
-
+  else if (aFeature == NS_LITERAL_STRING("STAGEFRIGHT"))
+    return nsIGfxInfo::FEATURE_STAGEFRIGHT;
   return 0;
 }
 
 static int32_t
 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
 {
   if (aStatus == NS_LITERAL_STRING("NO_INFO"))
     return nsIGfxInfo::FEATURE_NO_INFO;
@@ -374,16 +378,23 @@ BlacklistEntryToDriverInfo(nsIDOMNode* a
 
   // <os>WINNT 6.0</os>
   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("os"),
                                   getter_AddRefs(dataNode))) {
     BlacklistNodeToTextValue(dataNode, dataValue);
     aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
   }
 
+  // <osversion>14</osversion> currently only used for Android
+  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("osversion"),
+                                  getter_AddRefs(dataNode))) {
+    BlacklistNodeToTextValue(dataNode, dataValue);
+    aDriverInfo.mOperatingSystemVersion = strtoul(NS_LossyConvertUTF16toASCII(dataValue).get(), NULL, 10);
+  }
+
   // <vendor>0x8086</vendor>
   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("vendor"),
                                   getter_AddRefs(dataNode))) {
     BlacklistNodeToTextValue(dataNode, dataValue);
     aDriverInfo.mAdapterVendor = dataValue;
   }
 
   // <devices>
@@ -435,16 +446,41 @@ BlacklistEntryToDriverInfo(nsIDOMNode* a
 
   // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersionComparator"),
                                   getter_AddRefs(dataNode))) {
     BlacklistNodeToTextValue(dataNode, dataValue);
     aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
   }
 
+  // <model>foo</model>
+  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("model"),
+                                  getter_AddRefs(dataNode))) {
+    BlacklistNodeToTextValue(dataNode, dataValue);
+    aDriverInfo.mModel = dataValue;
+  }
+  // <product>foo</product>
+  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("product"),
+                                  getter_AddRefs(dataNode))) {
+    BlacklistNodeToTextValue(dataNode, dataValue);
+    aDriverInfo.mProduct = dataValue;
+  }
+  // <manufacturer>foo</manufacturer>
+  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("manufacturer"),
+                                  getter_AddRefs(dataNode))) {
+    BlacklistNodeToTextValue(dataNode, dataValue);
+    aDriverInfo.mManufacturer = dataValue;
+  }
+  // <hardware>foo</hardware>
+  if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("hardware"),
+                                  getter_AddRefs(dataNode))) {
+    BlacklistNodeToTextValue(dataNode, dataValue);
+    aDriverInfo.mHardware = dataValue;
+  }
+
   // We explicitly ignore unknown elements.
 
   return true;
 }
 
 static void
 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection* aBlacklistEntries,
                              nsTArray<GfxDriverInfo>& aDriverInfo)
@@ -550,16 +586,20 @@ GfxInfoBase::FindBlocklistedDeviceInList
   uint32_t i = 0;
   for (; i < info.Length(); i++) {
     if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
         info[i].mOperatingSystem != os)
     {
       continue;
     }
 
+    if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
+        continue;
+    }
+
     if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
         !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
       continue;
     }
 
     if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
         bool deviceMatches = false;
         for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
@@ -571,16 +611,29 @@ GfxInfoBase::FindBlocklistedDeviceInList
 
         if (!deviceMatches) {
             continue;
         }
     }
 
     bool match = false;
 
+    if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
+        continue;
+    }
+    if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
+        continue;
+    }
+    if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
+        continue;
+    }
+    if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
+        continue;
+    }
+
 #if defined(XP_WIN) || defined(ANDROID)
     switch (info[i].mComparisonOp) {
     case DRIVER_LESS_THAN:
       match = driverVersion < info[i].mDriverVersion;
       break;
     case DRIVER_LESS_THAN_OR_EQUAL:
       match = driverVersion <= info[i].mDriverVersion;
       break;
@@ -736,16 +789,17 @@ GfxInfoBase::EvaluateDownloadedBlacklist
     nsIGfxInfo::FEATURE_DIRECT2D,
     nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
     nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
     nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
     nsIGfxInfo::FEATURE_OPENGL_LAYERS,
     nsIGfxInfo::FEATURE_WEBGL_OPENGL,
     nsIGfxInfo::FEATURE_WEBGL_ANGLE,
     nsIGfxInfo::FEATURE_WEBGL_MSAA,
+    nsIGfxInfo::FEATURE_STAGEFRIGHT,
     0
   };
 
   // For every feature we know about, we evaluate whether this blacklist has a
   // non-NO_INFO status. If it does, we set the pref we evaluate in
   // GetFeatureStatus above, so we don't need to hold on to this blacklist
   // anywhere permanent.
   int i = 0;
--- a/widget/xpwidgets/GfxInfoBase.h
+++ b/widget/xpwidgets/GfxInfoBase.h
@@ -63,16 +63,22 @@ public:
   NS_IMETHOD_(void) GetData() { }
 
   static void AddCollector(GfxInfoCollectorBase* collector);
   static void RemoveCollector(GfxInfoCollectorBase* collector);
 
   static nsTArray<GfxDriverInfo>* mDriverInfo;
   static bool mDriverInfoObserverInitialized;
 
+  virtual const nsAString& Model() const { return nsString(); }
+  virtual const nsAString& Hardware() const { return nsString(); }
+  virtual const nsAString& Product() const { return nsString(); }
+  virtual const nsAString& Manufacturer() const { return nsString(); }
+  virtual uint32_t OperatingSystemVersion() const { return 0; }
+
 protected:
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
                                         nsAString& aSuggestedDriverVersion,
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
                                         OperatingSystem* aOS = nullptr);
 
   // Gets the driver info table. Used by GfxInfoBase to check for general cases