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 112082 f710f9f6f7ec0c76a0153f076a1358be4bb4938c
parent 112081 75fa1f74f17474213bb8c4bd79ca0414108fce8a
child 112083 c0d55648fbf56818b28f6b85999bdf9d01b15933
push id23790
push userryanvm@gmail.com
push dateFri, 02 Nov 2012 01:26:40 +0000
treeherdermozilla-central@556b9cfb269f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe, doublec
bugs806369
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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