Bug 1257565 - switch gfx blocklist over to kinto-based storage, r?leplatrem,dthayer draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Wed, 16 May 2018 16:20:32 +0100
changeset 812459 56a0084646d98f1872258498192a8742924460e2
parent 812281 8f49b2a0e003fe63da04aab9714ddc62bcb7a65c
child 812460 bc2d34a71f8dab7c267b322555e5c0558b7f3963
push id114555
push userbmo:gijskruitbosch+bugs@gmail.com
push dateFri, 29 Jun 2018 11:55:35 +0000
reviewersleplatrem, dthayer
bugs1257565
milestone63.0a1
Bug 1257565 - switch gfx blocklist over to kinto-based storage, r?leplatrem,dthayer MozReview-Commit-ID: K7SqXRY7Ia9
browser/components/nsBrowserGlue.js
services/common/blocklist-clients.js
services/common/tests/unit/test_blocklist_clients.js
toolkit/mozapps/extensions/Blocklist.jsm
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.json
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.json
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.json
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.json
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_gfx.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1270,19 +1270,22 @@ BrowserGlue.prototype = {
         JawsScreenReaderVersionCheck.onWindowsRestored();
       });
     }
 
     Services.tm.idleDispatchToMainThread(() => {
       LanguagePrompt.init();
     });
 
-    Services.tm.idleDispatchToMainThread(() => {
+    ChromeUtils.idleDispatch(() => {
       Blocklist.loadBlocklistAsync();
     });
+    ChromeUtils.idleDispatch(() => {
+      Blocklist.checkForGfxBlocklistEntries();
+    });
 
     Services.tm.idleDispatchToMainThread(() => {
       SavantShieldStudy.init();
     });
   },
 
   /**
    * Use this function as an entry point to schedule tasks that need
--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = [
-  "initialize",
+  "BlocklistRemoteSettings",
 ];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm", {});
 
 ChromeUtils.defineModuleGetter(this, "RemoteSettings", "resource://services-settings/remote-settings.js");
 ChromeUtils.defineModuleGetter(this, "jexlFilterFunc", "resource://services-settings/remote-settings.js");
 
@@ -24,19 +24,16 @@ const PREF_BLOCKLIST_ADDONS_SIGNER      
 const PREF_BLOCKLIST_PLUGINS_COLLECTION      = "services.blocklist.plugins.collection";
 const PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS = "services.blocklist.plugins.checked";
 const PREF_BLOCKLIST_PLUGINS_SIGNER          = "services.blocklist.plugins.signer";
 const PREF_BLOCKLIST_PINNING_ENABLED         = "services.blocklist.pinning.enabled";
 const PREF_BLOCKLIST_PINNING_BUCKET          = "services.blocklist.pinning.bucket";
 const PREF_BLOCKLIST_PINNING_COLLECTION      = "services.blocklist.pinning.collection";
 const PREF_BLOCKLIST_PINNING_CHECKED_SECONDS = "services.blocklist.pinning.checked";
 const PREF_BLOCKLIST_PINNING_SIGNER          = "services.blocklist.pinning.signer";
-const PREF_BLOCKLIST_GFX_COLLECTION          = "services.blocklist.gfx.collection";
-const PREF_BLOCKLIST_GFX_CHECKED_SECONDS     = "services.blocklist.gfx.checked";
-const PREF_BLOCKLIST_GFX_SIGNER              = "services.blocklist.gfx.signer";
 
 /**
  * Revoke the appropriate certificates based on the records from the blocklist.
  *
  * @param {Object} data   Current records in the local db.
  */
 async function updateCertBlocklist({ data: { current: records } }) {
   const certList = Cc["@mozilla.org/security/certblocklist;1"]
@@ -187,17 +184,16 @@ async function targetAppFilter(entry, en
       }
     }
   }
   // Skip this entry.
   return null;
 }
 
 var AddonBlocklistClient;
-var GfxBlocklistClient;
 var OneCRLBlocklistClient;
 var PinningBlocklistClient;
 var PluginBlocklistClient;
 
 function initialize() {
   OneCRLBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_ONECRL_COLLECTION), {
     bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
     lastCheckTimePref: PREF_BLOCKLIST_ONECRL_CHECKED_SECONDS,
@@ -216,23 +212,20 @@ function initialize() {
   PluginBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_COLLECTION), {
     bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
     lastCheckTimePref: PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS,
     signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_SIGNER),
     filterFunc: targetAppFilter,
   });
   PluginBlocklistClient.on("sync", updateJSONBlocklist.bind(null, PluginBlocklistClient));
 
-  GfxBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_COLLECTION), {
-    bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
-    lastCheckTimePref: PREF_BLOCKLIST_GFX_CHECKED_SECONDS,
-    signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_SIGNER),
-    filterFunc: targetAppFilter,
-  });
-  GfxBlocklistClient.on("sync", updateJSONBlocklist.bind(null, GfxBlocklistClient));
-
   PinningBlocklistClient = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_COLLECTION), {
     bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_BUCKET),
     lastCheckTimePref: PREF_BLOCKLIST_PINNING_CHECKED_SECONDS,
     signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_SIGNER),
   });
   PinningBlocklistClient.on("sync", updatePinningList);
 }
+
+let BlocklistRemoteSettings = {
+  initialize,
+  targetAppFilter,
+};
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -51,16 +51,18 @@ function run_test() {
                              `http://localhost:${server.identity.primaryPort}/v1`);
   // Ensure that signature verification is disabled to prevent interference
   // with basic certificate sync tests
   Services.prefs.setBoolPref("services.settings.verify_signature", false);
 
   // This will initialize the remote settings clients for blocklists.
   BlocklistClients.initialize();
 
+  // FIXME: once all the clients are migrated to Blocklist.jsm, we should move
+  // the test there, too. This note is here so I don't forget.
   gBlocklistClients = [
     {client: BlocklistClients.AddonBlocklistClient, testData: ["i808", "i720", "i539"]},
     {client: BlocklistClients.PluginBlocklistClient, testData: ["p1044", "p32", "p28"]},
     {client: BlocklistClients.GfxBlocklistClient, testData: ["g204", "g200", "g36"]},
   ];
 
   // Setup server fake responses.
   function handleResponse(request, response) {
--- a/toolkit/mozapps/extensions/Blocklist.jsm
+++ b/toolkit/mozapps/extensions/Blocklist.jsm
@@ -78,31 +78,27 @@ ChromeUtils.defineModuleGetter(this, "Se
 #      </emItems>
 #      <pluginItems>
 #        <pluginItem blockID="i4">
 #          <!-- All match tags must match a plugin to blocklist a plugin -->
 #          <match name="name" exp="some plugin"/>
 #          <match name="description" exp="1[.]2[.]3"/>
 #        </pluginItem>
 #      </pluginItems>
-#      <gfxItems>
-#        <gfxItem ... />
-#      </gfxItems>
 #    </blocklist>
    */
 
 // The remote settings updater is the new system in charge of fetching remote data
 // securely and efficiently. It will replace the current XML-based system.
 // See Bug 1257565 and Bug 1252456.
-const BlocklistClients = {};
-ChromeUtils.defineModuleGetter(BlocklistClients, "initialize",
+ChromeUtils.defineModuleGetter(this, "BlocklistRemoteSettings",
                                "resource://services-common/blocklist-clients.js");
 XPCOMUtils.defineLazyGetter(this, "RemoteSettings", function() {
   // Instantiate blocklist clients.
-  BlocklistClients.initialize();
+  BlocklistRemoteSettings.initialize();
   // Import RemoteSettings for ``pollChanges()``
   const { RemoteSettings } = ChromeUtils.import("resource://services-settings/remote-settings.js", {});
   return RemoteSettings;
 });
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
@@ -126,16 +122,144 @@ const URI_BLOCKLIST_DIALOG            = 
 const DEFAULT_SEVERITY                = 3;
 const DEFAULT_LEVEL                   = 2;
 const MAX_BLOCK_LEVEL                 = 3;
 const SEVERITY_OUTDATED               = 0;
 const VULNERABILITYSTATUS_NONE             = 0;
 const VULNERABILITYSTATUS_UPDATE_AVAILABLE = 1;
 const VULNERABILITYSTATUS_NO_UPDATE        = 2;
 
+// Kinto blocklist constants
+const PREF_BLOCKLIST_BUCKET                  = "services.blocklist.bucket";
+const PREF_BLOCKLIST_GFX_COLLECTION          = "services.blocklist.gfx.collection";
+const PREF_BLOCKLIST_GFX_CHECKED_SECONDS     = "services.blocklist.gfx.checked";
+const PREF_BLOCKLIST_GFX_SIGNER              = "services.blocklist.gfx.signer";
+
+/**
+ * The Graphics blocklist implementation. The JSON objects for graphics blocks look
+ * something like:
+ *
+ * {
+ *  "blockID": "g35",
+ *  "os": "WINNT 6.1",
+ *  "vendor": "0xabcd",
+ *  "devices": [
+ *    "0x2783",
+ *    "0x1234",
+ *  ],
+ *  "feature": " DIRECT2D ",
+ *  "featureStatus": " BLOCKED_DRIVER_VERSION ",
+ *  "driverVersion": " 8.52.322.2202 ",
+ *  "driverVersionComparator": " LESS_THAN ",
+ *  "versionRange": {"minVersion": "5.0", "maxVersion: "25.0"},
+ * }
+ *
+ * The RemoteSetttings client takes care of filtering out versions that don't apply.
+ * The code here stores entries in memory and sends them to the gfx component in
+ * serialized text form, using ',', '\t' and '\n' as separators.
+ *
+ * Note: we assign to the global to allow tests to reach the object directly.
+ */
+this.GfxBlocklist = {
+  _ensureInitialized() {
+    if (this._initialized || !gBlocklistEnabled) {
+      return;
+    }
+    this._initialized = true;
+    this._client = RemoteSettings(Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_COLLECTION), {
+      bucketName: Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
+      lastCheckTimePref: PREF_BLOCKLIST_GFX_CHECKED_SECONDS,
+      signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_SIGNER),
+      filterFunc: BlocklistRemoteSettings.targetAppFilter,
+    });
+    this._client.on("sync", () => {
+      this.checkForEntries();
+    });
+  },
+
+  async checkForEntries() {
+    this._ensureInitialized();
+    if (!gBlocklistEnabled) {
+      return []; // return value expected by tests.
+    }
+    let entries = await this._client.get();
+    // Trim helper (spaces, tabs, no-break spaces..)
+    const trim = (s) => (s || "").replace(/(^[\s\uFEFF\xA0]+)|([\s\uFEFF\xA0]+$)/g, "");
+
+    entries = entries.map(entry => {
+      let props = [
+        "blockID", "driverVersion", "driverVersionMax", "driverVersionComparator",
+        "feature", "featureStatus", "os", "vendor", "devices"
+      ];
+      let rv = {};
+      for (let p of props) {
+        let val = entry[p];
+        // Ignore falsy values or empty arrays.
+        if (!val || (Array.isArray(val) && !val.length)) {
+          continue;
+        }
+        if (typeof val == "string") {
+          val = trim(val);
+        } else if (p == "devices") {
+          let invalidDevices = [];
+          let validDevices = [];
+          // We serialize the array of devices as a comma-separated string, so
+          // we need to ensure that none of the entries contain commas, also in
+          // the future.
+          val.forEach(v => v.includes(",") ? invalidDevices.push(v) : validDevices.push(v));
+          for (let dev of invalidDevices) {
+            const e = new Error(`Block ${entry.blockID} contains unsupported device: ${dev}`);
+            Cu.reportError(e);
+          }
+          if (!validDevices) {
+            continue;
+          }
+          val = validDevices;
+        }
+        rv[p] = val;
+      }
+      if (entry.versionRange) {
+        rv.versionRange = {
+          minVersion: trim(entry.versionRange.minVersion) || "0",
+          maxVersion: trim(entry.versionRange.maxVersion) || "*",
+        };
+      }
+      return rv;
+    });
+    if (entries.length) {
+      let sortedProps = [
+        "blockID", "devices", "driverVersion", "driverVersionComparator", "driverVersionMax",
+        "feature", "featureStatus", "hardware", "manufacturer", "model", "os", "osversion",
+        "product", "vendor", "versionRange",
+      ];
+      // Notify `GfxInfoBase`, by passing a string serialization.
+      let payload = [];
+      for (let gfxEntry of entries) {
+        let entryLines = [];
+        for (let key of sortedProps) {
+          if (gfxEntry[key]) {
+            let value = gfxEntry[key];
+            if (Array.isArray(value)) {
+              value = value.join(",");
+            } else if (value.maxVersion) {
+              // Both minVersion and maxVersion are always set on each entry.
+              value = value.minVersion + "," + value.maxVersion;
+            }
+            entryLines.push(key + ":" + value);
+          }
+        }
+        payload.push(entryLines.join("\t"));
+      }
+      Services.obs.notifyObservers(null, "blocklist-data-gfxItems", payload.join("\n"));
+    }
+    // The return value is only used by tests.
+    return entries;
+  },
+};
+
 const EXTENSION_BLOCK_FILTERS = ["id", "name", "creator", "homepageURL", "updateURL"];
 
 var gLoggingEnabled = null;
 var gBlocklistEnabled = true;
 var gBlocklistLevel = DEFAULT_LEVEL;
 
 /**
  * @class nsIBlocklistPrompt
@@ -334,17 +458,16 @@ var Blocklist = {
    *                 Each value in the version range array is a JS Object that
    *                 has the following properties:
    *                   "minVersion"  The minimum version in a version range
    *                                 (default = 0)
    *                   "maxVersion"  The maximum version in a version range
    *                                 (default = *)
    */
   _addonEntries: null,
-  _gfxEntries: null,
   _pluginEntries: null,
 
   shutdown() {
     Services.obs.removeObserver(this, "xpcom-shutdown");
     Services.prefs.removeObserver("extensions.blocklist.", this);
     Services.prefs.removeObserver(PREF_EM_LOGGING_ENABLED, this);
   },
 
@@ -353,16 +476,17 @@ var Blocklist = {
     case "xpcom-shutdown":
       this.shutdown();
       break;
     case "profile-after-change":
       // We're only called here on non-Desktop-Firefox, and use this opportunity to try to
       // load the blocklist asynchronously. On desktop Firefox, we load the list from
       // nsBrowserGlue after sessionstore-windows-restored.
       this.loadBlocklistAsync();
+      this.checkForGfxBlocklistEntries();
       break;
     case "nsPref:changed":
       switch (aData) {
         case PREF_EM_LOGGING_ENABLED:
           gLoggingEnabled = Services.prefs.getBoolPref(PREF_EM_LOGGING_ENABLED, false);
           break;
         case PREF_BLOCKLIST_ENABLED:
           gBlocklistEnabled = Services.prefs.getBoolPref(PREF_BLOCKLIST_ENABLED, true);
@@ -371,31 +495,36 @@ var Blocklist = {
           // enforce that they are applied sequentially.
           // So we only update once the previous `_blocklistUpdated` call finishes running.
           let lastUpdate = this._lastUpdate || undefined;
           let newUpdate = this._lastUpdate = (async () => {
             await lastUpdate;
             this._clear();
             await this.loadBlocklistAsync();
             await this._blocklistUpdated(null, null);
+            this.checkForGfxBlocklistEntries();
             if (newUpdate == this._lastUpdate) {
               delete this._lastUpdate;
             }
           })().catch(Cu.reportError);
           break;
         case PREF_BLOCKLIST_LEVEL:
           gBlocklistLevel = Math.min(Services.prefs.getIntPref(PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
                                      MAX_BLOCK_LEVEL);
           this._blocklistUpdated(null, null);
           break;
       }
       break;
     }
   },
 
+  checkForGfxBlocklistEntries() {
+    GfxBlocklist.checkForEntries();
+  },
+
   /**
    * Determine the blocklist state of an add-on
    * @param {Addon} addon
    *        The addon item to be checked.
    * @param {string?} appVersion
    *        The version of the application we are checking in the blocklist.
    *        If this parameter is null, the version of the running application
    *        is used.
@@ -765,23 +894,22 @@ var Blocklist = {
     LOG("Blocklist:onError: There was an error loading the blocklist file\r\n" +
         statusText);
   },
 
   /**
    * Whether or not we've finished loading the blocklist.
    */
   get isLoaded() {
-    return this._addonEntries != null && this._gfxEntries != null && this._pluginEntries != null;
+    return this._addonEntries != null && this._pluginEntries != null;
   },
 
   /* Used for testing */
   _clear() {
     this._addonEntries = null;
-    this._gfxEntries = null;
     this._pluginEntries = null;
     delete this._loadPromise;
   },
 
   /**
    * Trigger loading the blocklist content asynchronously.
    */
   async loadBlocklistAsync() {
@@ -811,17 +939,16 @@ var Blocklist = {
     } catch (e) {
       LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e);
     }
 
     LOG("Blocklist::loadBlocklistAsync: no XML File found");
     // Neither file is present, so we just add empty lists, to avoid JS errors fetching
     // blocklist information otherwise.
     this._addonEntries = [];
-    this._gfxEntries = [];
     this._pluginEntries = [];
   },
 
   async _loadFileInternal(file) {
     if (this.isLoaded) {
       return;
     }
 
@@ -862,42 +989,33 @@ var Blocklist = {
         }
         resolve();
       });
     });
   },
 
   async _loadBlocklistFromXML(doc) {
     this._addonEntries = [];
-    this._gfxEntries = [];
     this._pluginEntries = [];
     try {
       var children = doc.documentElement.children;
       for (let element of children) {
         switch (element.localName) {
         case "emItems":
           this._addonEntries = await this._processItemNodes(element.children, "emItem",
                                                             this._handleEmItemNode);
           break;
         case "pluginItems":
           this._pluginEntries = await this._processItemNodes(element.children, "pluginItem",
                                                              this._handlePluginItemNode);
           break;
-        case "gfxItems":
-          // Parse as simple list of objects.
-          this._gfxEntries = await this._processItemNodes(element.children, "gfxBlacklistEntry",
-                                                          this._handleGfxBlacklistNode);
-          break;
         default:
           LOG("Blocklist::_loadBlocklistFromXML: ignored entries " + element.localName);
         }
       }
-      if (this._gfxEntries.length > 0) {
-        this._notifyObserversBlocklistGFX();
-      }
     } catch (e) {
       LOG("Blocklist::_loadBlocklistFromXML: Error constructing blocklist " + e);
     }
     // Dispatch to mainthread because consumers may try to construct nsIPluginHost
     // again based on this notification, while we were called from nsIPluginHost
     // anyway, leading to re-entrancy.
     Services.tm.dispatchToMainThread(function() {
       Services.obs.notifyObservers(null, "blocklist-loaded");
@@ -1010,76 +1128,16 @@ var Blocklist = {
     if (blockEntry.versions.length == 0)
       blockEntry.versions.push(new BlocklistItemData(null));
 
     blockEntry.blockID = blocklistElement.getAttribute("blockID");
 
     result.push(blockEntry);
   },
 
-  // <gfxBlacklistEntry blockID="g60">
-  //   <os>WINNT 6.0</os>
-  //   <osversion>14</osversion> currently only used for Android
-  //   <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-  //   <vendor>0x8086</vendor>
-  //   <devices>
-  //     <device>0x2582</device>
-  //     <device>0x2782</device>
-  //   </devices>
-  //   <feature> DIRECT3D_10_LAYERS </feature>
-  //   <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-  //   <driverVersion> 8.52.322.2202 </driverVersion>
-  //   <driverVersionMax> 8.52.322.2202 </driverVersionMax>
-  //   <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
-  //   <model>foo</model>
-  //   <product>foo</product>
-  //   <manufacturer>foo</manufacturer>
-  //   <hardware>foo</hardware>
-  // </gfxBlacklistEntry>
-  _handleGfxBlacklistNode(blocklistElement, result) {
-    const blockEntry = {};
-
-    // The blockID attribute is always present in the actual data produced on server
-    // (see https://github.com/mozilla/addons-server/blob/2016.05.05/src/olympia/blocklist/templates/blocklist/blocklist.xml#L74)
-    // But it is sometimes missing in test fixtures.
-    if (blocklistElement.hasAttribute("blockID")) {
-      blockEntry.blockID = blocklistElement.getAttribute("blockID");
-    }
-
-    for (let matchElement of blocklistElement.children) {
-      let value;
-      if (matchElement.localName == "devices") {
-        value = [];
-        for (let childElement of matchElement.children) {
-          const childValue = (childElement.textContent || "").trim();
-          // Make sure no empty value is added.
-          if (childValue) {
-            if (/,/.test(childValue)) {
-              // Devices can't contain comma.
-              // (c.f serialization in _notifyObserversBlocklistGFX)
-              const e = new Error(`Unsupported device name ${childValue}`);
-              Cu.reportError(e);
-            } else {
-              value.push(childValue);
-            }
-          }
-        }
-      } else if (matchElement.localName == "versionRange") {
-        value = {minVersion: (matchElement.getAttribute("minVersion") || "").trim() || "0",
-                 maxVersion: (matchElement.getAttribute("maxVersion") || "").trim() || "*"};
-      } else {
-        value = (matchElement.textContent || "").trim();
-      }
-      if (value) {
-        blockEntry[matchElement.localName] = value;
-      }
-    }
-    result.push(blockEntry);
-  },
-
   /* See nsIBlocklistService */
   async getPluginBlocklistState(plugin, appVersion, toolkitVersion) {
     if (AppConstants.platform == "android") {
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
     }
     await this.loadBlocklistAsync();
     return this._getPluginBlocklistState(plugin, this._pluginEntries,
                                          appVersion, toolkitVersion);
@@ -1198,44 +1256,16 @@ var Blocklist = {
     let blockEntry = r.entry;
     if (!blockEntry.blockID) {
       return null;
     }
 
     return blockEntry.infoURL || this._createBlocklistURL(blockEntry.blockID);
   },
 
-  _notifyObserversBlocklistGFX() {
-    let sortedProps = [
-      "blockID", "devices", "driverVersion", "driverVersionComparator", "driverVersionMax",
-      "feature", "featureStatus", "hardware", "manufacturer", "model", "os", "osversion",
-      "product", "vendor", "versionRange",
-    ];
-    // Notify `GfxInfoBase`, by passing a string serialization.
-    // This way we avoid spreading XML structure logics there.
-    let payload = [];
-    for (let gfxEntry of this._gfxEntries) {
-      let entryLines = [];
-      for (let key of sortedProps) {
-        if (gfxEntry[key]) {
-          let value = gfxEntry[key];
-          if (Array.isArray(value)) {
-            value = value.join(",");
-          } else if (value.maxVersion) {
-            // When XML is parsed, both minVersion and maxVersion are set.
-            value = value.minVersion + "," + value.maxVersion;
-          }
-          entryLines.push(key + ":" + value);
-        }
-      }
-      payload.push(entryLines.join("\t"));
-    }
-    Services.obs.notifyObservers(null, "blocklist-data-gfxItems", payload.join("\n"));
-  },
-
   _notifyObserversBlocklistUpdated() {
     Services.obs.notifyObservers(this, "blocklist-updated");
   },
 
   async _blocklistUpdated(oldAddonEntries, oldPluginEntries) {
     var addonList = [];
 
     // A helper function that reverts the prefs passed to default values.
rename from toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.xml
rename to toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.json
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.json
@@ -1,319 +1,316 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-  <gfxItems>
-    <gfxBlacklistEntry blockID="g35">
-      <os>WINNT 6.1</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.0</os>
-      <vendor>0xdcba</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry blockID="g36">
-      <os>WINNT 6.1</os>
-      <vendor>0xabab</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> GREATER_THAN_OR_EQUAL </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.1</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1111 </driverVersion>
-      <driverVersionComparator> EQUAL </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>abcd</vendor>
-      <devices>
-        <device>wxyz</device>
-        <device>asdf</device>
-        <device>erty</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 5 </driverVersion>
-      <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>dcdc</vendor>
-      <devices>
-        <device>uiop</device>
-        <device>vbnm</device>
-        <device>hjkl</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 5 </driverVersion>
-      <driverVersionComparator> EQUAL </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>abab</vendor>
-      <devices>
-        <device>ghjk</device>
-        <device>cvbn</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 7 </driverVersion>
-      <driverVersionComparator> GREATER_THAN_OR_EQUAL </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.1</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x6666</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DEVICE </featureStatus>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x6666</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DEVICE </featureStatus>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x6666</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DEVICE </featureStatus>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x6666</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DEVICE </featureStatus>
-    </gfxBlacklistEntry>
+[
+  {
+    "blockID": "g35",
+    "os": "WINNT 6.1",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  },
+  {
+    "os": "WINNT 6.0",
+    "vendor": "0xdcba",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  },
+  {
+    "blockID": "g36",
+    "os": "WINNT 6.1",
+    "vendor": "0xabab",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " GREATER_THAN_OR_EQUAL "
+  },
+  {
+    "os": "WINNT 6.1",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1111 ",
+    "driverVersionComparator": " EQUAL "
+  },
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
+  {
+    "os": "Android",
+    "vendor": "abcd",
+    "devices": [
+      "wxyz",
+      "asdf",
+      "erty"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 5 ",
+    "driverVersionComparator": " LESS_THAN_OR_EQUAL "
+  },
+  {
+    "os": "Android",
+    "vendor": "dcdc",
+    "devices": [
+      "uiop",
+      "vbnm",
+      "hjkl"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 5 ",
+    "driverVersionComparator": " EQUAL "
+  },
+  {
+    "os": "Android",
+    "vendor": "abab",
+    "devices": [
+      "ghjk",
+      "cvbn"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 7 ",
+    "driverVersionComparator": " GREATER_THAN_OR_EQUAL "
+  },
+  {
+    "os": "WINNT 6.1",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x6666"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DEVICE "
+  },
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x6666"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DEVICE "
+  },
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x6666"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DEVICE "
+  },
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x6666"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DEVICE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1112 </driverVersion>
-      <driverVersionMax> 8.52.323.1000 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_EXCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1112 ",
+    "driverVersionMax": " 8.52.323.1000 ",
+    "driverVersionComparator": " BETWEEN_EXCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.50.322.1000 </driverVersion>
-      <driverVersionMax> 8.52.322.1112 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_EXCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.50.322.1000 ",
+    "driverVersionMax": " 8.52.322.1112 ",
+    "driverVersionComparator": " BETWEEN_EXCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 9.52.322.1000 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_EXCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 9.52.322.1000 ",
+    "driverVersionComparator": " BETWEEN_EXCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> HARDWARE_VIDEO_DECODING </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 7.82.322.1000 </driverVersion>
-      <driverVersionMax> 9.25.322.1001 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " HARDWARE_VIDEO_DECODING ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 7.82.322.1000 ",
+    "driverVersionMax": " 9.25.322.1001 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1112 </driverVersion>
-      <driverVersionMax> 9.52.322.1300 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1112 ",
+    "driverVersionMax": " 9.52.322.1300 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 8.52.322.1112 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_DECODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 8.52.322.1112 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1112 </driverVersion>
-      <driverVersionMax> 8.52.322.1200 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE_START </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_MSAA </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 8.52.322.1200 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE_START </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_ENCODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1112 ",
+    "driverVersionMax": " 8.52.322.1200 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE_START "
+  },
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_MSAA ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 8.52.322.1200 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE_START "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 8.52.322.1112 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE_START </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 8.52.322.1112 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE_START "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL2 </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 8.52.322.1112 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_INCLUSIVE_START </driverVersionComparator>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL2 ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 8.52.322.1112 ",
+    "driverVersionComparator": " BETWEEN_INCLUSIVE_START "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xdcdc</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> CANVAS2D_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.1000 </driverVersion>
-      <driverVersionMax> 9.52.322.1000 </driverVersionMax>
-      <driverVersionComparator> BETWEEN_EXCLUSIVE </driverVersionComparator>
-    </gfxBlacklistEntry>
-
-  </gfxItems>
-</blocklist>
+  {
+    "os": "All",
+    "vendor": "0xdcdc",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " CANVAS2D_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.1000 ",
+    "driverVersionMax": " 9.52.322.1000 ",
+    "driverVersionComparator": " BETWEEN_EXCLUSIVE "
+  }
+]
rename from toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.xml
rename to toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.json
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.json
@@ -1,31 +1,27 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-  <gfxItems>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.1</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.0</os>
-      <vendor>0xdcba</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-  </gfxItems>
-</blocklist>
+[
+  {
+    "os": "WINNT 6.1",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  },
+  {
+    "os": "WINNT 6.0",
+    "vendor": "0xdcba",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  }
+]
rename from toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
rename to toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.json
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.json
@@ -1,831 +1,837 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-  <gfxItems>
-
-    <gfxBlacklistEntry blockID="g1">
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+[
+  {
+    "blockID": "g1",
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g2">
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="22.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g2",
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "22.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_LAYERS</feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_LAYERS",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1" maxVersion="22.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_1_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1", "maxVersion": "22.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_1_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
+
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g11",
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "14.0b2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_OPENGL ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g11">
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="14.0b2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_OPENGL </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL2 </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL2 ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_MSAA </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_MSAA ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> STAGEFRIGHT </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " STAGEFRIGHT ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_ENCODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_DECODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="17.2a2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "17.2a2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="13.2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> HARDWARE_VIDEO_DECODING </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "13.2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " HARDWARE_VIDEO_DECODING ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>All</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="10.5" maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "All",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "10.5", "maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g1">
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g1",
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g2">
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="22.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g2",
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "22.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_LAYERS</feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_LAYERS",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1" maxVersion="22.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_1_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1", "maxVersion": "22.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_1_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g11">
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="14.0b2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_OPENGL </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g11",
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "14.0b2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_OPENGL ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL2 </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL2 ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_MSAA </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_MSAA ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> STAGEFRIGHT </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " STAGEFRIGHT ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_ENCODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_DECODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="17.2a2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "17.2a2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="13.2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> HARDWARE_VIDEO_DECODING </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "13.2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " HARDWARE_VIDEO_DECODING ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
+
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "10.5", "maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="10.5" maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g1",
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g1">
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g2",
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "22.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g2">
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="22.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_LAYERS",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_LAYERS</feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1", "maxVersion": "22.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_1_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1" maxVersion="22.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_1_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g11",
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "14.0b2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_OPENGL ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g11">
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="14.0b2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_OPENGL </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL2 </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL2 ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_MSAA </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_MSAA ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> STAGEFRIGHT </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " STAGEFRIGHT ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_ENCODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_DECODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="17.2a2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "17.2a2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="13.2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> HARDWARE_VIDEO_DECODING </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "13.2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " HARDWARE_VIDEO_DECODING ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
+
+  {
+    "os": "Linux",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "10.5", "maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Linux</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="10.5" maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g1",
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g1">
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g2",
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "22.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_9_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g2">
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="22.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_9_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_LAYERS",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_LAYERS</feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "16.0a1", "maxVersion": "22.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_10_1_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="16.0a1" maxVersion="22.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_10_1_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "blockID": "g11",
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "14.0b2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_OPENGL ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry blockID="g11">
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="14.0b2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_OPENGL </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL2 ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL2 </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "12.0", "maxVersion": "16.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBGL_MSAA ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="12.0" maxVersion="16.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBGL_MSAA </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " STAGEFRIGHT ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> STAGEFRIGHT </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_ENCODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "42.0", "maxVersion": "13.0b2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " WEBRTC_HW_ACCELERATION_DECODE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "17.2a2", "maxVersion": "15.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="17.2a2" maxVersion="15.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "15.0", "maxVersion": "13.2"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " HARDWARE_VIDEO_DECODING ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  },
 
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="15.0" maxVersion="13.2"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> HARDWARE_VIDEO_DECODING </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-
-    <gfxBlacklistEntry>
-      <os>Android</os>
-      <vendor>0xabcd</vendor>
-      <versionRange minVersion="10.5" maxVersion="13.0"/>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT3D_11_ANGLE </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-    </gfxBlacklistEntry>
-
-  </gfxItems>
-</blocklist>
+  {
+    "os": "Android",
+    "vendor": "0xabcd",
+    "versionRange": {"minVersion": "10.5", "maxVersion": "13.0"},
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT3D_11_ANGLE ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION "
+  }
+]
rename from toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml
rename to toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.json
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.json
@@ -1,32 +1,28 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-  <gfxItems>
-    <gfxBlacklistEntry>
-      <os>WINNT 6.2</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> DIRECT2D </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-    <gfxBlacklistEntry>
-      <os>Darwin 13</os>
-      <vendor>0xabcd</vendor>
-      <devices>
-        <device>0x2783</device>
-        <device>0x1234</device>
-        <device>0x2782</device>
-      </devices>
-      <feature> OPENGL_LAYERS </feature>
-      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
-      <driverVersion> 8.52.322.2202 </driverVersion>
-      <driverVersionComparator> LESS_THAN </driverVersionComparator>
-    </gfxBlacklistEntry>
-  </gfxItems>
-</blocklist>
+[
+  {
+    "os": "WINNT 6.2",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " DIRECT2D ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  },
+  {
+    "os": "Darwin 13",
+    "vendor": "0xabcd",
+    "devices": [
+      "0x2783",
+      "0x1234",
+      "0x2782"
+    ],
+    "feature": " OPENGL_LAYERS ",
+    "featureStatus": " BLOCKED_DRIVER_VERSION ",
+    "driverVersion": " 8.52.322.2202 ",
+    "driverVersionComparator": " LESS_THAN "
+  }
+]
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -4,17 +4,17 @@
 
 /* eslint no-unused-vars: ["error", {vars: "local", args: "none"}] */
 
 if (!_TEST_FILE[0].includes("toolkit/mozapps/extensions/test/xpcshell/")) {
   ok(false, ("head_addons.js may not be loaded by tests outside of " +
              "the add-on manager component."));
 }
 
-Cu.importGlobalProperties(["TextEncoder"]);
+Cu.importGlobalProperties(["TextEncoder", "fetch"]);
 
 const PREF_EM_CHECK_UPDATE_SECURITY   = "extensions.checkUpdateSecurity";
 const PREF_EM_STRICT_COMPATIBILITY    = "extensions.strictCompatibility";
 const PREF_GETADDONS_BYIDS               = "extensions.getAddons.get.url";
 const PREF_COMPAT_OVERRIDES              = "extensions.getAddons.compatOverides.url";
 const PREF_XPI_SIGNATURES_REQUIRED    = "xpinstall.signatures.required";
 const PREF_SYSTEM_ADDON_SET           = "extensions.systemAddonSet";
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
@@ -57,16 +57,18 @@ ChromeUtils.defineModuleGetter(this, "Ht
 ChromeUtils.defineModuleGetter(this, "MockAsyncShutdown",
                                "resource://testing-common/AddonTestUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "MockRegistrar",
                                "resource://testing-common/MockRegistrar.jsm");
 ChromeUtils.defineModuleGetter(this, "MockRegistry",
                                "resource://testing-common/MockRegistry.jsm");
 ChromeUtils.defineModuleGetter(this, "PromiseTestUtils",
                                "resource://testing-common/PromiseTestUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "RemoteSettings",
+                               "resource://services-common/remote-settings.js");
 ChromeUtils.defineModuleGetter(this, "TestUtils",
                                "resource://testing-common/TestUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
                                    "@mozilla.org/addons/addon-manager-startup;1",
                                    "amIAddonManagerStartup");
 
 const {
@@ -1269,16 +1271,41 @@ function copyBlocklistToProfile(blocklis
   var dest = gProfD.clone();
   dest.append("blocklist.xml");
   if (dest.exists())
     dest.remove(false);
   blocklistFile.copyTo(gProfD, "blocklist.xml");
   dest.lastModifiedTime = Date.now();
 }
 
+async function mockGfxBlocklistItemsFromDisk(path) {
+  let response = await fetch(Services.io.newFileURI(do_get_file(path)).spec);
+  let json = await response.json();
+  return mockGfxBlocklistItems(json);
+}
+
+async function mockGfxBlocklistItems(items) {
+  const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+  let bsPass = ChromeUtils.import("resource://gre/modules/Blocklist.jsm", {});
+  const client = RemoteSettings("gfx", { bucketName: "blocklists" });
+  const collection = await client.openCollection();
+  await collection.clear();
+  await collection.loadDump(items.map(item => {
+    if (item.id && item.last_modified) {
+      return item;
+    }
+    return Object.assign({
+      id: generateUUID().toString().replace(/[{}]/g, ""),
+      last_modified: Date.now(),
+    }, item);
+  }));
+  let rv = await bsPass.GfxBlocklist.checkForEntries();
+  return rv;
+}
+
 // Throw a failure and attempt to abandon the test if it looks like it is going
 // to timeout
 function timeout() {
   timer = null;
   do_throw("Test ran longer than " + TIMEOUT_MS + "ms");
 
   // Attempt to bail out of the test
   do_test_finished();
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_gfx.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_gfx.js
@@ -1,14 +1,11 @@
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser"]);
-
-const gParser = new DOMParser();
 
 const EVENT_NAME = "blocklist-data-gfxItems";
 
 const SAMPLE_GFX_RECORD = {
   "driverVersionComparator": "LESS_THAN_OR_EQUAL",
   "driverVersion": "8.17.12.5896",
   "vendor": "0x10de",
   "blockID": "g36",
@@ -16,128 +13,83 @@ const SAMPLE_GFX_RECORD = {
   "devices": ["0x0a6c", "geforce"],
   "featureStatus": "BLOCKED_DRIVER_VERSION",
   "last_modified": 1458035931837,
   "os": "WINNT 6.1",
   "id": "3f947f16-37c2-4e96-d356-78b26363729b",
   "versionRange": {"minVersion": 0, "maxVersion": "*"}
 };
 
-
-function getBlocklist() {
-  Blocklist._clear();
-  return Blocklist;
-}
-
-async function updateBlocklistWithInput(input) {
-  let blocklist = getBlocklist();
-  let promiseObserved = TestUtils.topicObserved(EVENT_NAME);
-  blocklist._loadBlocklistFromXML(gParser.parseFromString(input, "text/xml"));
-  let [, received] = await promiseObserved;
-  return [blocklist, received];
-}
-
-
 add_task(async function test_sends_serialized_data() {
-  const blocklist = getBlocklist();
-  blocklist._gfxEntries = [SAMPLE_GFX_RECORD];
-
   const expected = "blockID:g36\tdevices:0x0a6c,geforce\tdriverVersion:8.17.12.5896\t" +
                    "driverVersionComparator:LESS_THAN_OR_EQUAL\tfeature:DIRECT3D_9_LAYERS\t" +
                    "featureStatus:BLOCKED_DRIVER_VERSION\tos:WINNT 6.1\tvendor:0x10de\t" +
                    "versionRange:0,*";
-  let promiseObserved = TestUtils.topicObserved(EVENT_NAME);
-  blocklist._notifyObserversBlocklistGFX();
-  let [, received] = await promiseObserved;
+  let received;
+  const observe = (subject, topic, data) => { received = data; };
+  Services.obs.addObserver(observe, EVENT_NAME);
+  await mockGfxBlocklistItems([SAMPLE_GFX_RECORD]);
+
   equal(received, expected);
 });
 
 
-add_task(async function test_parsing_fails_if_devices_contains_comma() {
-  const input = "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
-  "<gfxItems>" +
-  " <gfxBlacklistEntry>" +
-  "   <devices>" +
-  "     <device>0x2,582</device>" +
-  "     <device>0x2782</device>" +
-  "   </devices>" +
-  " </gfxBlacklistEntry>" +
-  "</gfxItems>" +
-  "</blocklist>";
-  let [blocklist] = await updateBlocklistWithInput(input);
-
-  equal(blocklist._gfxEntries[0].devices.length, 1);
-  equal(blocklist._gfxEntries[0].devices[0], "0x2782");
+add_task(async function test_parsing_skips_devices_with_comma() {
+  let clonedItem = Cu.cloneInto(SAMPLE_GFX_RECORD, this);
+  clonedItem.devices[0] = "0x2,582";
+  let rv = await mockGfxBlocklistItems([clonedItem]);
+  equal(rv[0].devices.length, 1);
+  equal(rv[0].devices[0], "geforce");
 });
 
 
 add_task(async function test_empty_values_are_ignored() {
-  const input = "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
-  "<gfxItems>" +
-  " <gfxBlacklistEntry>" +
-  "   <os></os>" +
-  " </gfxBlacklistEntry>" +
-  "</gfxItems>" +
-  "</blocklist>";
-  let [, received] = await updateBlocklistWithInput(input);
-  ok(received.indexOf("os" < 0));
+  let received;
+  const observe = (subject, topic, data) => { received = data; };
+  Services.obs.addObserver(observe, EVENT_NAME);
+  let clonedItem = Cu.cloneInto(SAMPLE_GFX_RECORD, this);
+  clonedItem.os = "";
+  await mockGfxBlocklistItems([clonedItem]);
+  ok(!received.includes("os"), "Shouldn't send empty values");
+  Services.obs.removeObserver(observe, EVENT_NAME);
 });
 
 add_task(async function test_empty_devices_are_ignored() {
-  const input = "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
-  "<gfxItems>" +
-  " <gfxBlacklistEntry>" +
-  "   <devices></devices>" +
-  " </gfxBlacklistEntry>" +
-  "</gfxItems>" +
-  "</blocklist>";
-  let [, received] = await updateBlocklistWithInput(input);
-  ok(received.indexOf("devices" < 0));
+  let received;
+  const observe = (subject, topic, data) => { received = data; };
+  Services.obs.addObserver(observe, EVENT_NAME);
+  let clonedItem = Cu.cloneInto(SAMPLE_GFX_RECORD, this);
+  clonedItem.devices = [];
+  await mockGfxBlocklistItems([clonedItem]);
+  ok(!received.includes("devices"), "Shouldn't send empty values");
+  Services.obs.removeObserver(observe, EVENT_NAME);
 });
 
 add_task(async function test_version_range_default_values() {
-  const input = "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
-  "<gfxItems>" +
-  " <gfxBlacklistEntry>" +
-  "   <versionRange minVersion=\"13.0b2\" maxVersion=\"42.0\"/>" +
-  " </gfxBlacklistEntry>" +
-  " <gfxBlacklistEntry>" +
-  "   <versionRange maxVersion=\"2.0\"/>" +
-  " </gfxBlacklistEntry>" +
-  " <gfxBlacklistEntry>" +
-  "   <versionRange minVersion=\"1.0\"/>" +
-  " </gfxBlacklistEntry>" +
-  " <gfxBlacklistEntry>" +
-  "   <versionRange minVersion=\"  \"/>" +
-  " </gfxBlacklistEntry>" +
-  " <gfxBlacklistEntry>" +
-  "   <versionRange/>" +
-  " </gfxBlacklistEntry>" +
-  "</gfxItems>" +
-  "</blocklist>";
-  let [blocklist] = await updateBlocklistWithInput(input);
-  equal(blocklist._gfxEntries[0].versionRange.minVersion, "13.0b2");
-  equal(blocklist._gfxEntries[0].versionRange.maxVersion, "42.0");
-  equal(blocklist._gfxEntries[1].versionRange.minVersion, "0");
-  equal(blocklist._gfxEntries[1].versionRange.maxVersion, "2.0");
-  equal(blocklist._gfxEntries[2].versionRange.minVersion, "1.0");
-  equal(blocklist._gfxEntries[2].versionRange.maxVersion, "*");
-  equal(blocklist._gfxEntries[3].versionRange.minVersion, "0");
-  equal(blocklist._gfxEntries[3].versionRange.maxVersion, "*");
-  equal(blocklist._gfxEntries[4].versionRange.minVersion, "0");
-  equal(blocklist._gfxEntries[4].versionRange.maxVersion, "*");
+  const input = [
+    {versionRange: {minVersion: "13.0b2", maxVersion: "42.0"}},
+    {versionRange: {maxVersion: "2.0"}},
+    {versionRange: {minVersion: "1.0"}},
+    {versionRange: {minVersion: "  "}},
+    {versionRange: {}},
+  ];
+  let parsedEntries = await mockGfxBlocklistItems(input);
+  equal(parsedEntries[0].versionRange.minVersion, "13.0b2");
+  equal(parsedEntries[0].versionRange.maxVersion, "42.0");
+  equal(parsedEntries[1].versionRange.minVersion, "0");
+  equal(parsedEntries[1].versionRange.maxVersion, "2.0");
+  equal(parsedEntries[2].versionRange.minVersion, "1.0");
+  equal(parsedEntries[2].versionRange.maxVersion, "*");
+  equal(parsedEntries[3].versionRange.minVersion, "0");
+  equal(parsedEntries[3].versionRange.maxVersion, "*");
+  equal(parsedEntries[4].versionRange.minVersion, "0");
+  equal(parsedEntries[4].versionRange.maxVersion, "*");
 });
 
 add_task(async function test_blockid_attribute() {
-  const input = "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
-  "<gfxItems>" +
-  " <gfxBlacklistEntry blockID=\"g60\">" +
-  "   <vendor> 0x10de </vendor>" +
-  " </gfxBlacklistEntry>" +
-  " <gfxBlacklistEntry>" +
-  "   <feature> DIRECT3D_9_LAYERS </feature>" +
-  " </gfxBlacklistEntry>" +
-  "</gfxItems>" +
-  "</blocklist>";
-  let [blocklist] = await updateBlocklistWithInput(input);
-  equal(blocklist._gfxEntries[0].blockID, "g60");
-  ok(!blocklist._gfxEntries[1].hasOwnProperty("blockID"));
+  const input = [
+    {blockID: "g60", vendor: " 0x10de "},
+    {feature: " DIRECT3D_9_LAYERS "}
+  ];
+  let parsedEntries = await mockGfxBlocklistItems(input);
+  equal(parsedEntries[0].blockID, "g60");
+  ok(!parsedEntries[1].hasOwnProperty("blockID"));
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which differs only on device ID, but otherwise
 // exactly matches the blacklist entry, is not blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -75,10 +67,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a new-enough driver bypasses the blacklist, even if the rest of
 // the attributes match the blacklist entry.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -71,10 +63,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which is newer than the equal
 // blacklist entry is allowed.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -102,10 +94,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js
@@ -1,30 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which is older than the equal
 // blacklist entry is correctly allowed.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -73,10 +65,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which exactly matches the equal
 // blacklist entry is successfully blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -72,10 +64,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which is lower than the greater-than-or-equal
 // blacklist entry is allowed.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -72,10 +64,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which exactly matches the greater-than-or-equal
 // blacklist entry is successfully blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -72,10 +64,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which exactly matches the blacklist entry is
 // successfully blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -68,10 +60,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which exactly matches the blacklist entry is
 // successfully blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -73,10 +65,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which differs only on OS version, but otherwise
 // exactly matches the blacklist entry, is not blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -72,10 +64,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js
@@ -1,28 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether new OS versions are matched properly.
-// Uses test_gfxBlacklist_OS.xml
+// Uses test_gfxBlacklist_OSVersion.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -74,10 +66,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist_OSVersion.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist_OSVersion.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether blocklists specifying new OSeswcorrectly don't block if driver
 // versions are appropriately up-to-date.
-// Uses test_gfxBlacklist_OS.xml
+// Uses test_gfxBlacklist_OSVersion.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -74,10 +66,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist_OSVersion.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist_OSVersion.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether old OS versions are not matched when the blacklist contains
 // only new OS versions.
-// Uses test_gfxBlacklist_OS.xml
+// Uses test_gfxBlacklist_OSVersion.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -75,10 +67,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist_OSVersion.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist_OSVersion.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js
@@ -1,29 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This should eventually be moved to head_addons.js
 // Test whether a machine which differs only on vendor, but otherwise
 // exactly matches the blacklist entry, is not blocked.
-// Uses test_gfxBlacklist.xml
+// Uses test_gfxBlacklist.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -72,10 +64,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
@@ -1,28 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Test whether a machine which exactly matches the blacklist entry is
 // successfully blocked.
-// Uses test_gfxBlacklist_AllOS.xml
+// Uses test_gfxBlacklist_AllOS.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
 
   // We can't do anything if we can't spoof the stuff we need.
   if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) {
     do_test_finished();
     return;
@@ -128,10 +120,10 @@ async function run_test() {
   }
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(checkBlacklist);
   }, "blocklist-data-gfxItems");
 
-  load_blocklist("test_gfxBlacklist_AllOS.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist_AllOS.json");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js
@@ -1,28 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Test whether the blacklist successfully adds and removes the prefs that store
 // its decisions when the remote blacklist is changed.
-// Uses test_gfxBlacklist.xml and test_gfxBlacklist2.xml
+// Uses test_gfxBlacklist.json and test_gfxBlacklist2.json
 
 var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = gTestserver.identity.primaryPort;
 gTestserver.registerDirectory("/data/", do_get_file("data"));
 
-function load_blocklist(file) {
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + file);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
 // Performs the initial setup
 async function run_test() {
   try {
     var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
   } catch (e) {
     do_test_finished();
     return;
   }
@@ -78,17 +70,17 @@ async function run_test() {
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT3D_9_LAYERS);
     Assert.equal(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
 
     Assert.equal(Services.prefs.getIntPref("gfx.blacklist.direct2d"),
                  Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION);
 
     Services.obs.removeObserver(blacklistAdded, "blocklist-data-gfxItems");
     Services.obs.addObserver(blacklistRemoved, "blocklist-data-gfxItems");
-    load_blocklist("test_gfxBlacklist2.xml");
+    mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist2.json");
   }
 
   function blacklistRemoved(aSubject, aTopic, aData) {
     // If we wait until after we go through the event loop, gfxInfo is sure to
     // have processed the gfxItems event.
     executeSoon(ensureBlacklistUnset);
   }
   function ensureBlacklistUnset() {
@@ -106,10 +98,10 @@ async function run_test() {
     } catch (e) {}
 
     Assert.ok(!exists);
 
     do_test_finished();
   }
 
   Services.obs.addObserver(blacklistAdded, "blocklist-data-gfxItems");
-  load_blocklist("test_gfxBlacklist.xml");
+  mockGfxBlocklistItemsFromDisk("data/test_gfxBlacklist.json");
 }