Bug 1531303 - Refactored tests using PermissionManager URI methods to use PermissionTestUtils. r=johannh
authorPaul Zuehlcke <pzuhlcke@mozilla.com>
Thu, 15 Aug 2019 14:32:48 +0000
changeset 488254 31b2a7bf293285a063d76cb84e46de08d10d5f5c
parent 488253 e6b0f70a739a593bad874f550c600aef312c8083
child 488255 20ecb90e7155b6281998498813ea374fdb076c2c
push id36440
push userncsoregi@mozilla.com
push dateFri, 16 Aug 2019 03:57:48 +0000
treeherdermozilla-central@a58b7dc85887 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1531303
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531303 - Refactored tests using PermissionManager URI methods to use PermissionTestUtils. r=johannh Differential Revision: https://phabricator.services.mozilla.com/D41029
browser/base/content/test/alerts/browser_notification_close.js
browser/base/content/test/alerts/browser_notification_remove_permission.js
browser/base/content/test/alerts/browser_notification_tab_switching.js
browser/base/content/test/general/browser_bug578534.js
browser/base/content/test/general/browser_remoteTroubleshoot.js
browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
browser/base/content/test/permissions/browser_permissions_event_telemetry.js
browser/base/content/test/permissions/browser_permissions_postPrompt.js
browser/base/content/test/permissions/head.js
browser/base/content/test/popups/browser_popup_blocker_identity_block.js
browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js
browser/base/content/test/sanitize/browser_cookiePermission_subDomains.js
browser/base/content/test/sanitize/browser_sanitize-sitepermissions.js
browser/base/content/test/sanitize/head.js
browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
browser/base/content/test/trackingUI/browser_trackingUI_trackers_subview.js
browser/base/content/test/webextensions/browser_permissions_unsigned.js
browser/base/content/test/webextensions/head.js
browser/base/content/test/webrtc/browser_devices_get_user_media.js
browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
browser/base/content/test/webrtc/head.js
browser/components/enterprisepolicies/tests/xpcshell/head.js
browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js
browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons_flash.js
browser/components/originattributes/test/browser/browser_permissions.js
browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
browser/components/preferences/in-content/tests/head.js
browser/components/translation/test/browser_translation_exceptions.js
browser/components/uitour/test/browser_no_tabs.js
browser/components/uitour/test/head.js
browser/modules/test/unit/test_SiteDataManager.js
dom/indexedDB/test/unit/test_idle_maintenance.js
dom/indexedDB/test/unit/test_storageOption_pref.js
dom/notification/test/browser/browser_permission_dismiss.js
dom/push/test/xpcshell/head.js
dom/push/test/xpcshell/test_drop_expired.js
dom/push/test/xpcshell/test_quota_observer.js
dom/push/test/xpcshell/test_record.js
dom/serviceworkers/test/browser_storage_permission.js
netwerk/cookie/test/browser/head.js
netwerk/test/unit/test_bug767025.js
netwerk/test/unit/test_pinned_app_cache.js
toolkit/components/antitracking/test/browser/browser_allowListSeparationInPrivateAndNormalWindows.js
toolkit/components/antitracking/test/browser/browser_allowPermissionForTracker.js
toolkit/components/antitracking/test/browser/browser_denyPermissionForTracker.js
toolkit/components/antitracking/test/browser/browser_permissionInNormalWindows.js
toolkit/components/antitracking/test/browser/browser_permissionInPrivateWindows.js
toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
toolkit/components/antitracking/test/browser/browser_userInteraction.js
toolkit/components/antitracking/test/browser/head.js
toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js
toolkit/components/passwordmgr/test/unit/test_storage_mozStorage.js
toolkit/components/telemetry/tests/browser/browser_HybridContentTelemetry.js
toolkit/modules/tests/xpcshell/test_PermissionsUtils.js
toolkit/modules/tests/xpcshell/test_web_channel.js
toolkit/mozapps/extensions/test/xpcshell/test_permissions.js
toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger.js
toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger_iframe.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth2.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
toolkit/mozapps/extensions/test/xpinstall/browser_badhash.js
toolkit/mozapps/extensions/test/xpinstall/browser_badhashtype.js
toolkit/mozapps/extensions/test/xpinstall/browser_bug540558.js
toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js
toolkit/mozapps/extensions/test/xpinstall/browser_containers.js
toolkit/mozapps/extensions/test/xpinstall/browser_cookies.js
toolkit/mozapps/extensions/test/xpinstall/browser_cookies2.js
toolkit/mozapps/extensions/test/xpinstall/browser_cookies3.js
toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js
toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js
toolkit/mozapps/extensions/test/xpinstall/browser_datauri.js
toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
toolkit/mozapps/extensions/test/xpinstall/browser_empty.js
toolkit/mozapps/extensions/test/xpinstall/browser_hash.js
toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash2.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash4.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js
toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js
toolkit/mozapps/extensions/test/xpinstall/browser_installchrome.js
toolkit/mozapps/extensions/test/xpinstall/browser_newwindow.js
toolkit/mozapps/extensions/test/xpinstall/browser_offline.js
toolkit/mozapps/extensions/test/xpinstall/browser_privatebrowsing.js
toolkit/mozapps/extensions/test/xpinstall/browser_relative.js
toolkit/mozapps/extensions/test/xpinstall/browser_signed_trigger.js
toolkit/mozapps/extensions/test/xpinstall/browser_softwareupdate.js
toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js
toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js
toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js
toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js
toolkit/mozapps/extensions/test/xpinstall/head.js
--- a/browser/base/content/test/alerts/browser_notification_close.js
+++ b/browser/base/content/test/alerts/browser_notification_close.js
@@ -1,14 +1,18 @@
 "use strict";
 
 const { PlacesTestUtils } = ChromeUtils.import(
   "resource://testing-common/PlacesTestUtils.jsm"
 );
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 let notificationURL =
   "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
 let oldShowFavicons;
 
 add_task(async function test_notificationClose() {
   let notificationURI = makeURI(notificationURL);
   await addNotificationPermission(notificationURL);
 
@@ -92,13 +96,13 @@ add_task(async function test_notificatio
           ", actually closed at " +
           currentTime
       );
     }
   );
 });
 
 add_task(async function cleanup() {
-  Services.perms.remove(makeURI(notificationURL), "desktop-notification");
+  PermissionTestUtils.remove(notificationURL, "desktop-notification");
   if (typeof oldShowFavicons == "boolean") {
     Services.prefs.setBoolPref("alerts.showFavicons", oldShowFavicons);
   }
 });
--- a/browser/base/content/test/alerts/browser_notification_remove_permission.js
+++ b/browser/base/content/test/alerts/browser_notification_remove_permission.js
@@ -1,10 +1,14 @@
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 var tab;
 var notificationURL =
   "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
 var alertWindowClosed = false;
 var permRemoved = false;
 
 function test() {
   waitForExplicitFinish();
@@ -30,18 +34,18 @@ function onAlertShowing() {
 
   let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
   if (!alertWindow) {
     ok(true, "Notifications don't use XUL windows on all platforms.");
     closeNotification(tab.linkedBrowser).then(finish);
     return;
   }
   ok(
-    Services.perms.testExactPermission(
-      makeURI(notificationURL),
+    PermissionTestUtils.testExactPermission(
+      notificationURL,
       "desktop-notification"
     ),
     "Permission should exist prior to removal"
   );
   let disableForOriginMenuItem = alertWindow.document.getElementById(
     "disableForOriginMenuItem"
   );
   is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
--- a/browser/base/content/test/alerts/browser_notification_tab_switching.js
+++ b/browser/base/content/test/alerts/browser_notification_tab_switching.js
@@ -1,14 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 var tab;
 var notification;
 var notificationURL =
   "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
 var newWindowOpenedFromTab;
 
 add_task(async function test_notificationPreventDefaultAndSwitchTabs() {
   await addNotificationPermission(notificationURL);
@@ -99,10 +103,10 @@ add_task(async function test_notificatio
       notificationClosed = promiseNotificationEvent("close");
       await closeNotification(aBrowser);
       await notificationClosed;
     }
   );
 });
 
 add_task(async function cleanup() {
-  Services.perms.remove(makeURI(notificationURL), "desktop-notification");
+  PermissionTestUtils.remove(notificationURL, "desktop-notification");
 });
--- a/browser/base/content/test/general/browser_bug578534.js
+++ b/browser/base/content/test/general/browser_bug578534.js
@@ -1,27 +1,30 @@
 /* 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/. */
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 add_task(async function test() {
   let uriString = "http://example.com/";
   let cookieBehavior = "network.cookie.cookieBehavior";
-  let uriObj = Services.io.newURI(uriString);
 
   await SpecialPowers.pushPrefEnv({ set: [[cookieBehavior, 2]] });
-  Services.perms.add(uriObj, "cookie", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(uriString, "cookie", Services.perms.ALLOW_ACTION);
 
   await BrowserTestUtils.withNewTab(
     { gBrowser, url: uriString },
     async function(browser) {
       await ContentTask.spawn(browser, null, function() {
         is(
           content.navigator.cookieEnabled,
           true,
           "navigator.cookieEnabled should be true"
         );
       });
     }
   );
 
-  Services.perms.add(uriObj, "cookie", Services.perms.UNKNOWN_ACTION);
+  PermissionTestUtils.add(uriString, "cookie", Services.perms.UNKNOWN_ACTION);
 });
--- a/browser/base/content/test/general/browser_remoteTroubleshoot.js
+++ b/browser/base/content/test/general/browser_remoteTroubleshoot.js
@@ -1,15 +1,18 @@
 /* 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/. */
 
 var { WebChannel } = ChromeUtils.import(
   "resource://gre/modules/WebChannel.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const TEST_URL_TAIL =
   "example.com/browser/browser/base/content/test/general/test_remoteTroubleshoot.html";
 const TEST_URI_GOOD = Services.io.newURI("https://" + TEST_URL_TAIL);
 const TEST_URI_BAD = Services.io.newURI("http://" + TEST_URL_TAIL);
 const TEST_URI_GOOD_OBJECT = Services.io.newURI(
   "https://" + TEST_URL_TAIL + "?object"
 );
@@ -49,23 +52,23 @@ add_task(async function() {
   let got = await promiseNewChannelResponse(TEST_URI_GOOD);
   // Should return an error.
   Assert.ok(
     got.message.errno === 2,
     "should have failed with errno 2, no such channel"
   );
 
   // Add a permission manager entry for our URI.
-  Services.perms.add(
+  PermissionTestUtils.add(
     TEST_URI_GOOD,
     "remote-troubleshooting",
     Services.perms.ALLOW_ACTION
   );
   registerCleanupFunction(() => {
-    Services.perms.remove(TEST_URI_GOOD, "remote-troubleshooting");
+    PermissionTestUtils.remove(TEST_URI_GOOD, "remote-troubleshooting");
   });
 
   // Try again - now we are expecting a response with the actual data.
   got = await promiseNewChannelResponse(TEST_URI_GOOD);
 
   // Check some keys we expect to always get.
   Assert.ok(got.message.extensions, "should have extensions");
   Assert.ok(got.message.graphics, "should have graphics");
--- a/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
+++ b/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
@@ -1,11 +1,14 @@
 const { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const TEST_ORIGIN = "https://example.com";
 const TEST_ORIGIN_CERT_ERROR = "https://expired.example.com";
 const LOW_TLS_VERSION = "https://tls1.example.com/";
 
 async function testPermissions(defaultPermission) {
   await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function(browser) {
     let pageInfo = BrowserPageInfo(TEST_ORIGIN, "permTab");
@@ -204,50 +207,50 @@ add_task(async function test_cookie_perm
     let blockRadioButton = pageInfo.document.getElementById("cookie#2");
 
     ok(defaultCheckbox.checked, "The default checkbox should be checked.");
 
     defaultCheckbox.checked = false;
     defaultCheckbox.dispatchEvent(new Event("command"));
 
     is(
-      Services.perms.testPermission(gBrowser.currentURI, "cookie"),
+      PermissionTestUtils.testPermission(gBrowser.currentURI, "cookie"),
       SitePermissions.ALLOW,
       "Unchecking the default checkbox should pick the default permission."
     );
     is(
       radioGroup.selectedItem,
       allowRadioButton,
       "The unknown radio button should be selected."
     );
 
     radioGroup.selectedItem = blockRadioButton;
     blockRadioButton.dispatchEvent(new Event("command"));
 
     is(
-      Services.perms.testPermission(gBrowser.currentURI, "cookie"),
+      PermissionTestUtils.testPermission(gBrowser.currentURI, "cookie"),
       SitePermissions.BLOCK,
       "Selecting a value in the radio group should set the corresponding permission"
     );
 
     radioGroup.selectedItem = allowRadioButton;
     allowRadioButton.dispatchEvent(new Event("command"));
 
     is(
-      Services.perms.testPermission(gBrowser.currentURI, "cookie"),
+      PermissionTestUtils.testPermission(gBrowser.currentURI, "cookie"),
       SitePermissions.ALLOW,
       "Selecting a value in the radio group should set the corresponding permission"
     );
     ok(!defaultCheckbox.checked, "The default checkbox should not be checked.");
 
     defaultCheckbox.checked = true;
     defaultCheckbox.dispatchEvent(new Event("command"));
 
     is(
-      Services.perms.testPermission(gBrowser.currentURI, "cookie"),
+      PermissionTestUtils.testPermission(gBrowser.currentURI, "cookie"),
       SitePermissions.UNKNOWN,
       "Checking the default checkbox should reset the permission."
     );
     is(
       radioGroup.selectedItem,
       null,
       "For cookies, no item should be selected when the checkbox is checked."
     );
--- a/browser/base/content/test/permissions/browser_permissions_event_telemetry.js
+++ b/browser/base/content/test/permissions/browser_permissions_event_telemetry.js
@@ -100,21 +100,25 @@ add_task(async function setup() {
   Services.telemetry.canRecordExtended = true;
 
   Services.prefs.setBoolPref("permissions.eventTelemetry.enabled", true);
 
   // Add some example permissions.
   let uri = Services.io.newURI(PERMISSIONS_PAGE);
   let uri2 = Services.io.newURI("https://example.org");
   let uri3 = Services.io.newURI("http://sub.example.org");
-  Services.perms.add(uri, "geo", Services.perms.ALLOW_ACTION);
-  Services.perms.add(uri3, "desktop-notification", Services.perms.ALLOW_ACTION);
-  Services.perms.add(uri2, "microphone", Services.perms.DENY_ACTION);
-  Services.perms.add(uri, "camera", Services.perms.DENY_ACTION);
-  Services.perms.add(uri2, "geo", Services.perms.DENY_ACTION);
+  PermissionTestUtils.add(uri, "geo", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    uri3,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
+  PermissionTestUtils.add(uri2, "microphone", Services.perms.DENY_ACTION);
+  PermissionTestUtils.add(uri, "camera", Services.perms.DENY_ACTION);
+  PermissionTestUtils.add(uri2, "geo", Services.perms.DENY_ACTION);
 
   registerCleanupFunction(() => {
     Services.perms.removeAll();
     Services.prefs.clearUserPref("permissions.eventTelemetry.enabled");
     Services.telemetry.canRecordExtended = oldCanRecord;
   });
 
   Services.telemetry.clearEvents();
@@ -127,39 +131,33 @@ add_task(async function testAccept() {
     checkEventTelemetry("show");
 
     let notification = PopupNotifications.panel.firstElementChild;
     EventUtils.synthesizeMouseAtCenter(notification.button, {});
 
     checkEventTelemetry("accept");
 
     Services.telemetry.clearEvents();
-    Services.perms.remove(
-      Services.io.newURI(PERMISSIONS_PAGE),
-      "desktop-notification"
-    );
+    PermissionTestUtils.remove(PERMISSIONS_PAGE, "desktop-notification");
   });
 });
 
 add_task(async function testDeny() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function(browser) {
     await showPermissionPrompt(browser);
 
     checkEventTelemetry("show");
 
     let notification = PopupNotifications.panel.firstElementChild;
     EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
 
     checkEventTelemetry("deny");
 
     Services.telemetry.clearEvents();
-    Services.perms.remove(
-      Services.io.newURI(PERMISSIONS_PAGE),
-      "desktop-notification"
-    );
+    PermissionTestUtils.remove(PERMISSIONS_PAGE, "desktop-notification");
   });
 });
 
 add_task(async function testLeave() {
   let tab = await BrowserTestUtils.openNewForegroundTab(
     gBrowser,
     PERMISSIONS_PAGE
   );
@@ -169,13 +167,10 @@ add_task(async function testLeave() {
 
   let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
   await BrowserTestUtils.removeTab(tab);
   await tabClosed;
 
   checkEventTelemetry("leave");
 
   Services.telemetry.clearEvents();
-  Services.perms.remove(
-    Services.io.newURI(PERMISSIONS_PAGE),
-    "desktop-notification"
-  );
+  PermissionTestUtils.remove(PERMISSIONS_PAGE, "desktop-notification");
 });
--- a/browser/base/content/test/permissions/browser_permissions_postPrompt.js
+++ b/browser/base/content/test/permissions/browser_permissions_postPrompt.js
@@ -36,22 +36,22 @@ function testPostPrompt(task) {
     await popupshown;
 
     ok(true, "Notification permission prompt was shown");
 
     let notification = PopupNotifications.panel.firstElementChild;
     EventUtils.synthesizeMouseAtCenter(notification.button, {});
 
     is(
-      Services.perms.testPermission(uri, "desktop-notification"),
+      PermissionTestUtils.testPermission(uri, "desktop-notification"),
       Ci.nsIPermissionManager.ALLOW_ACTION,
       "User can override the default deny by using the prompt"
     );
 
-    Services.perms.remove(uri, "desktop-notification");
+    PermissionTestUtils.remove(uri, "desktop-notification");
   });
 }
 
 add_task(async function testNotificationPermission() {
   Services.prefs.setBoolPref(
     "dom.webnotifications.requireuserinteraction",
     true
   );
--- a/browser/base/content/test/permissions/head.js
+++ b/browser/base/content/test/permissions/head.js
@@ -1,1 +1,4 @@
 ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
--- a/browser/base/content/test/popups/browser_popup_blocker_identity_block.js
+++ b/browser/base/content/test/popups/browser_popup_blocker_identity_block.js
@@ -2,16 +2,19 @@
 
 /* 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/. */
 
 const { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const baseURL = getRootDirectory(gTestPath).replace(
   "chrome://mochitests/content",
   "http://example.com"
 );
 const URL = baseURL + "popup_blocker2.html";
 const URI = Services.io.newURI(URL);
 
@@ -204,17 +207,17 @@ add_task(async function check_permission
 
 // Explicitly set the permission to the otherwise default state and check that
 // the label still displays correctly.
 add_task(async function check_explicit_default_permission() {
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
 
   // DENY only works if triggered through Services.perms (it's very edge-casey),
   // since SitePermissions.jsm considers setting default permissions to be removal.
-  Services.perms.add(URI, "popup", Ci.nsIPermissionManager.DENY_ACTION);
+  PermissionTestUtils.add(URI, "popup", Ci.nsIPermissionManager.DENY_ACTION);
 
   await openIdentityPopup();
   let menulist = document.getElementById("identity-popup-popup-menulist");
   Assert.equal(menulist.value, "0");
   Assert.equal(menulist.label, "Block");
   await closeIdentityPopup();
 
   SitePermissions.set(URI, "popup", SitePermissions.ALLOW);
--- a/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js
+++ b/browser/base/content/test/sanitize/browser_cookiePermission_aboutURL.js
@@ -72,17 +72,17 @@ add_task(async function deleteStorageOnl
     set: [
       ["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_NORMALLY],
       ["browser.sanitizer.loglevel", "All"],
     ],
   });
 
   // Custom permission without considering OriginAttributes
   let uri = Services.io.newURI("about:newtab");
-  Services.perms.add(uri, "cookie", Ci.nsICookiePermission.ACCESS_SESSION);
+  PermissionTestUtils.add(uri, "cookie", Ci.nsICookiePermission.ACCESS_SESSION);
 
   // Let's create a tab with some data.
   await SiteDataTestUtils.addToIndexedDB("about:newtab", "foo", "bar", {});
 
   ok(await checkDataForAboutURL(), "We have data for about:newtab");
 
   // Cleaning up.
   await Sanitizer.runSanitizeOnShutdown();
@@ -97,10 +97,10 @@ add_task(async function deleteStorageOnl
   );
   await new Promise(aResolve => {
     let req = Services.qms.clearStoragesForPrincipal(principal);
     req.callback = () => {
       aResolve();
     };
   });
 
-  Services.perms.remove(uri, "cookie");
+  PermissionTestUtils.remove(uri, "cookie");
 });
--- a/browser/base/content/test/sanitize/browser_cookiePermission_subDomains.js
+++ b/browser/base/content/test/sanitize/browser_cookiePermission_subDomains.js
@@ -17,17 +17,21 @@ add_task(async function subDomains() {
     set: [
       ["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_NORMALLY],
       ["browser.sanitizer.loglevel", "All"],
     ],
   });
 
   // Domains and data
   let uriA = Services.io.newURI("https://www.mozilla.org");
-  Services.perms.add(uriA, "cookie", Ci.nsICookiePermission.ACCESS_SESSION);
+  PermissionTestUtils.add(
+    uriA,
+    "cookie",
+    Ci.nsICookiePermission.ACCESS_SESSION
+  );
 
   Services.cookies.add(
     uriA.host,
     "/test",
     "a",
     "b",
     false,
     false,
@@ -35,17 +39,17 @@ add_task(async function subDomains() {
     Date.now() + 24000 * 60 * 60,
     {},
     Ci.nsICookie.SAMESITE_NONE
   );
 
   await createIndexedDB(uriA.host, {});
 
   let uriB = Services.io.newURI("https://mozilla.org");
-  Services.perms.add(uriB, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
+  PermissionTestUtils.add(uriB, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
 
   Services.cookies.add(
     uriB.host,
     "/test",
     "c",
     "d",
     false,
     false,
@@ -80,18 +84,18 @@ add_task(async function subDomains() {
     "We should have cookies for URI: " + uriB.host
   );
   ok(
     await checkIndexedDB(uriB.host, {}),
     "We should have IDB for URI: " + uriB.host
   );
 
   // Cleaning up permissions
-  Services.perms.remove(uriA, "cookie");
-  Services.perms.remove(uriB, "cookie");
+  PermissionTestUtils.remove(uriA, "cookie");
+  PermissionTestUtils.remove(uriB, "cookie");
 });
 
 // session only cookie life-time, 2 domains (mozilla.org, www.mozilla.org),
 // only the latter has a cookie permission.
 add_task(async function subDomains() {
   info("Test subdomains and custom setting with cookieBehavior == 2");
 
   // Let's clean up all the data.
@@ -103,17 +107,17 @@ add_task(async function subDomains() {
     set: [
       ["network.cookie.lifetimePolicy", Ci.nsICookieService.ACCEPT_SESSION],
       ["browser.sanitizer.loglevel", "All"],
     ],
   });
 
   // Domains and data
   let uriA = Services.io.newURI("https://sub.mozilla.org");
-  Services.perms.add(uriA, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
+  PermissionTestUtils.add(uriA, "cookie", Ci.nsICookiePermission.ACCESS_ALLOW);
 
   Services.cookies.add(
     uriA.host,
     "/test",
     "a",
     "b",
     false,
     false,
@@ -165,10 +169,10 @@ add_task(async function subDomains() {
     "We should not have cookies for URI: " + uriB.host
   );
   ok(
     !(await checkIndexedDB(uriB.host, {})),
     "We should not have IDB for URI: " + uriB.host
   );
 
   // Cleaning up permissions
-  Services.perms.remove(uriA, "cookie");
+  PermissionTestUtils.remove(uriA, "cookie");
 });
--- a/browser/base/content/test/sanitize/browser_sanitize-sitepermissions.js
+++ b/browser/base/content/test/sanitize/browser_sanitize-sitepermissions.js
@@ -14,22 +14,25 @@ add_task(async function test() {
   // sanitize before we start so we have a good baseline.
   await Sanitizer.sanitize(["siteSettings"], { ignoreTimespan: false });
 
   // Count how many permissions we start with - some are defaults that
   // will not be sanitized.
   let numAtStart = countPermissions();
 
   // Add a permission entry
-  var pm = Services.perms;
-  pm.add(Services.io.newURI("http://example.com"), "testing", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com",
+    "testing",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Sanity check
   ok(
-    pm.enumerator.hasMoreElements(),
+    Services.perms.enumerator.hasMoreElements(),
     "Permission manager should have elements, since we just added one"
   );
 
   // Clear it
   await Sanitizer.sanitize(["siteSettings"], { ignoreTimespan: false });
 
   // Make sure it's gone
   is(
--- a/browser/base/content/test/sanitize/head.js
+++ b/browser/base/content/test/sanitize/head.js
@@ -3,16 +3,17 @@ var { XPCOMUtils } = ChromeUtils.import(
 );
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Downloads: "resource://gre/modules/Downloads.jsm",
   FormHistory: "resource://gre/modules/FormHistory.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   Sanitizer: "resource:///modules/Sanitizer.jsm",
   SiteDataTestUtils: "resource://testing-common/SiteDataTestUtils.jsm",
+  PermissionTestUtils: "resource://testing-common/PermissionTestUtils.jsm",
 });
 
 function createIndexedDB(host, originAttributes) {
   let uri = Services.io.newURI("https://" + host);
   let principal = Services.scriptSecurityManager.createContentPrincipal(
     uri,
     originAttributes
   );
@@ -93,17 +94,17 @@ async function deleteOnShutdown(opt) {
       ["network.cookie.lifetimePolicy", opt.lifetimePolicy],
       ["browser.sanitizer.loglevel", "All"],
     ],
   });
 
   // Custom permission without considering OriginAttributes
   if (opt.cookiePermission !== undefined) {
     let uri = Services.io.newURI("https://www.example.com");
-    Services.perms.add(uri, "cookie", opt.cookiePermission);
+    PermissionTestUtils.add(uri, "cookie", opt.cookiePermission);
   }
 
   // Let's create a tab with some data.
   await opt.createData(
     (opt.fullHost ? "www." : "") + "example.org",
     opt.originAttributes
   );
   ok(
@@ -146,17 +147,17 @@ async function deleteOnShutdown(opt) {
     "Do we have data for www.example.com?"
   );
 
   // Clean up.
   await Sanitizer.sanitize(["cookies", "offlineApps"]);
 
   if (opt.cookiePermission !== undefined) {
     let uri = Services.io.newURI("https://www.example.com");
-    Services.perms.remove(uri, "cookie");
+    PermissionTestUtils.remove(uri, "cookie");
   }
 }
 
 function runAllCookiePermissionTests(originAttributes) {
   let tests = [
     { name: "IDB", createData: createIndexedDB, checkData: checkIndexedDB },
     {
       name: "Host Cookie",
--- a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
+++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
@@ -1,10 +1,14 @@
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const ROOT = getRootDirectory(gTestPath).replace(
   "chrome://mochitests/content/",
   "http://example.com/"
 );
 let pageWithAlert = ROOT + "openPromptOffTimeout.html";
 
 registerCleanupFunction(function() {
   Services.perms.removeAll();
@@ -61,20 +65,19 @@ add_task(async function() {
     ourPromptElement
   );
   ourPrompt.onButtonClick(0);
   // Wait for that click to actually be handled completely.
   await new Promise(function(resolve) {
     Services.tm.dispatchToMainThread(resolve);
   });
   // check permission is set
-  let ps = Services.perms;
   is(
-    ps.ALLOW_ACTION,
-    ps.testPermission(makeURI(pageWithAlert), "focus-tab-by-prompt"),
+    Services.perms.ALLOW_ACTION,
+    PermissionTestUtils.testPermission(pageWithAlert, "focus-tab-by-prompt"),
     "Tab switching should now be allowed"
   );
 
   // Check if the control center shows the correct permission.
   let shown = BrowserTestUtils.waitForEvent(
     gIdentityHandler._identityPopup,
     "popupshown"
   );
--- a/browser/base/content/test/trackingUI/browser_trackingUI_trackers_subview.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_trackers_subview.js
@@ -1,14 +1,18 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const TRACKING_PAGE =
   "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 
 const TP_PREF = "privacy.trackingprotection.enabled";
 
 add_task(async function setup() {
   await UrlClassifierTestUtils.addTestTrackers();
 
@@ -108,16 +112,20 @@ add_task(async function testTrackersSubV
   info("Testing trackers subview with TP disabled.");
   Services.prefs.setBoolPref(TP_PREF, false);
   await assertSitesListed(false);
   info("Testing trackers subview with TP enabled.");
   Services.prefs.setBoolPref(TP_PREF, true);
   await assertSitesListed(true);
   info("Testing trackers subview with TP enabled and a CB exception.");
   let uri = Services.io.newURI("https://tracking.example.org");
-  Services.perms.add(uri, "trackingprotection", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    uri,
+    "trackingprotection",
+    Services.perms.ALLOW_ACTION
+  );
   await assertSitesListed(false);
   info("Testing trackers subview with TP enabled and a CB exception removed.");
-  Services.perms.remove(uri, "trackingprotection");
+  PermissionTestUtils.remove(uri, "trackingprotection");
   await assertSitesListed(true);
 
   Services.prefs.clearUserPref(TP_PREF);
 });
--- a/browser/base/content/test/webextensions/browser_permissions_unsigned.js
+++ b/browser/base/content/test/webextensions/browser_permissions_unsigned.js
@@ -7,18 +7,18 @@ add_task(async function test_unsigned() 
   await SpecialPowers.pushPrefEnv({
     set: [
       ["extensions.webapi.testing", true],
       ["extensions.install.requireBuiltInCerts", false],
     ],
   });
 
   let testURI = makeURI("https://example.com/");
-  Services.perms.add(testURI, "install", Services.perms.ALLOW_ACTION);
-  registerCleanupFunction(() => Services.perms.remove(testURI, "install"));
+  PermissionTestUtils.add(testURI, "install", Services.perms.ALLOW_ACTION);
+  registerCleanupFunction(() => PermissionTestUtils.remove(testURI, "install"));
 
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
 
   BrowserTestUtils.loadURI(
     gBrowser.selectedBrowser,
     `${BASE}/file_install_extensions.html`
   );
   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
--- a/browser/base/content/test/webextensions/head.js
+++ b/browser/base/content/test/webextensions/head.js
@@ -22,16 +22,20 @@ XPCOMUtils.defineLazyGetter(this, "Manag
 });
 
 ChromeUtils.import(
   "resource://testing-common/CustomizableUITestUtils.jsm",
   this
 );
 let gCUITestUtils = new CustomizableUITestUtils(window);
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 /**
  * Wait for the given PopupNotification to display
  *
  * @param {string} name
  *        The name of the notification to wait for.
  *
  * @returns {Promise}
  *          Resolves with the notification window.
@@ -304,18 +308,18 @@ async function testInstallMethod(install
     ],
   });
 
   if (telemetryBase !== undefined) {
     hookExtensionsTelemetry();
   }
 
   let testURI = makeURI("https://example.com/");
-  Services.perms.add(testURI, "install", Services.perms.ALLOW_ACTION);
-  registerCleanupFunction(() => Services.perms.remove(testURI, "install"));
+  PermissionTestUtils.add(testURI, "install", Services.perms.ALLOW_ACTION);
+  registerCleanupFunction(() => PermissionTestUtils.remove(testURI, "install"));
 
   async function runOnce(filename, cancel) {
     let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
 
     let installPromise = new Promise(resolve => {
       let listener = {
         onDownloadCancelled() {
           AddonManager.removeInstallListener(listener);
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.js
@@ -323,44 +323,48 @@ var gTests = [
         }
         Assert.deepEqual(
           await getMediaCaptureState(),
           expected,
           "expected " + Object.keys(expected).join(" and ") + " to be shared"
         );
 
         function checkDevicePermissions(aDevice, aExpected) {
-          let Perms = Services.perms;
           let uri = gBrowser.selectedBrowser.documentURI;
-          let devicePerms = Perms.testExactPermission(uri, aDevice);
+          let devicePerms = PermissionTestUtils.testExactPermission(
+            uri,
+            aDevice
+          );
           if (aExpected === undefined) {
             is(
               devicePerms,
-              Perms.UNKNOWN_ACTION,
+              Services.perms.UNKNOWN_ACTION,
               "no " + aDevice + " persistent permissions"
             );
           } else {
             is(
               devicePerms,
-              aExpected ? Perms.ALLOW_ACTION : Perms.DENY_ACTION,
+              aExpected
+                ? Services.perms.ALLOW_ACTION
+                : Services.perms.DENY_ACTION,
               aDevice + " persistently " + (aExpected ? "allowed" : "denied")
             );
           }
-          Perms.remove(uri, aDevice);
+          PermissionTestUtils.remove(uri, aDevice);
         }
         checkDevicePermissions("microphone", aExpectedAudioPerm);
         checkDevicePermissions("camera", aExpectedVideoPerm);
 
         if (expectedMessage == "ok") {
           await closeStream();
         }
       }
 
       // 3 cases where the user accepts the device prompt.
-      info("audio+video, user grants, expect both perms set to allow");
+      info("audio+video, user grants, expect both Services.perms set to allow");
       await checkPerm(true, true, true, true);
       info(
         "audio only, user grants, check audio perm set to allow, video perm not set"
       );
       await checkPerm(true, false, true, undefined);
       info(
         "video only, user grants, check video perm set to allow, audio perm not set"
       );
@@ -370,46 +374,49 @@ var gTests = [
       info(
         "audio only, user denies, expect audio perm set to deny, video not set"
       );
       await checkPerm(true, false, false, undefined, true);
       info(
         "video only, user denies, expect video perm set to deny, audio perm not set"
       );
       await checkPerm(false, true, undefined, false, true);
-      info("audio+video, user denies, expect both perms set to deny");
+      info("audio+video, user denies, expect both Services.perms set to deny");
       await checkPerm(true, true, false, false, true);
     },
   },
 
   {
     desc: "getUserMedia without prompt: use persistent permissions",
     run: async function checkUsePersistentPermissions() {
       async function usePerm(
         aAllowAudio,
         aAllowVideo,
         aRequestAudio,
         aRequestVideo,
         aExpectStream
       ) {
-        let Perms = Services.perms;
         let uri = gBrowser.selectedBrowser.documentURI;
 
         if (aAllowAudio !== undefined) {
-          Perms.add(
+          PermissionTestUtils.add(
             uri,
             "microphone",
-            aAllowAudio ? Perms.ALLOW_ACTION : Perms.DENY_ACTION
+            aAllowAudio
+              ? Services.perms.ALLOW_ACTION
+              : Services.perms.DENY_ACTION
           );
         }
         if (aAllowVideo !== undefined) {
-          Perms.add(
+          PermissionTestUtils.add(
             uri,
             "camera",
-            aAllowVideo ? Perms.ALLOW_ACTION : Perms.DENY_ACTION
+            aAllowVideo
+              ? Services.perms.ALLOW_ACTION
+              : Services.perms.DENY_ACTION
           );
         }
 
         if (aExpectStream === undefined) {
           // Check that we get a prompt.
           let promise = promisePopupNotificationShown("webRTC-shareDevices");
           await promiseRequestDevice(aRequestAudio, aRequestVideo);
           await promise;
@@ -453,18 +460,18 @@ var gTests = [
             );
 
             await closeStream();
           } else {
             await expectObserverCalled("recording-window-ended");
           }
         }
 
-        Perms.remove(uri, "camera");
-        Perms.remove(uri, "microphone");
+        PermissionTestUtils.remove(uri, "camera");
+        PermissionTestUtils.remove(uri, "microphone");
       }
 
       // Set both permissions identically
       info("allow audio+video, request audio+video, expect ok (audio+video)");
       await usePerm(true, true, true, true, true);
       info("deny audio+video, request audio+video, expect denied");
       await usePerm(false, false, true, true, false);
 
@@ -517,57 +524,75 @@ var gTests = [
       await usePerm(undefined, false, false, true, false);
     },
   },
 
   {
     desc: "Stop Sharing removes persistent permissions",
     run: async function checkStopSharingRemovesPersistentPermissions() {
       async function stopAndCheckPerm(aRequestAudio, aRequestVideo) {
-        let Perms = Services.perms;
         let uri = gBrowser.selectedBrowser.documentURI;
 
         // Initially set both permissions to 'allow'.
-        Perms.add(uri, "microphone", Perms.ALLOW_ACTION);
-        Perms.add(uri, "camera", Perms.ALLOW_ACTION);
+        PermissionTestUtils.add(uri, "microphone", Services.perms.ALLOW_ACTION);
+        PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
 
         let indicator = promiseIndicatorWindow();
         // Start sharing what's been requested.
         let promise = promiseMessage("ok");
         await promiseRequestDevice(aRequestAudio, aRequestVideo);
         await promise;
 
         await expectObserverCalled("getUserMedia:request");
         await expectObserverCalled("getUserMedia:response:allow");
         await expectObserverCalled("recording-device-events");
         await indicator;
         await checkSharingUI({ video: aRequestVideo, audio: aRequestAudio });
 
         await stopSharing(aRequestVideo ? "camera" : "microphone");
 
         // Check that permissions have been removed as expected.
-        let audioPerm = Perms.testExactPermission(uri, "microphone");
+        let audioPerm = PermissionTestUtils.testExactPermission(
+          uri,
+          "microphone"
+        );
         if (aRequestAudio) {
-          is(audioPerm, Perms.UNKNOWN_ACTION, "microphone permissions removed");
+          is(
+            audioPerm,
+            Services.perms.UNKNOWN_ACTION,
+            "microphone permissions removed"
+          );
         } else {
-          is(audioPerm, Perms.ALLOW_ACTION, "microphone permissions untouched");
+          is(
+            audioPerm,
+            Services.perms.ALLOW_ACTION,
+            "microphone permissions untouched"
+          );
         }
 
-        let videoPerm = Perms.testExactPermission(uri, "camera");
+        let videoPerm = PermissionTestUtils.testExactPermission(uri, "camera");
         if (aRequestVideo) {
-          is(videoPerm, Perms.UNKNOWN_ACTION, "camera permissions removed");
+          is(
+            videoPerm,
+            Services.perms.UNKNOWN_ACTION,
+            "camera permissions removed"
+          );
         } else {
-          is(videoPerm, Perms.ALLOW_ACTION, "camera permissions untouched");
+          is(
+            videoPerm,
+            Services.perms.ALLOW_ACTION,
+            "camera permissions untouched"
+          );
         }
 
         // Cleanup.
         await closeStream(true);
 
-        Perms.remove(uri, "camera");
-        Perms.remove(uri, "microphone");
+        PermissionTestUtils.remove(uri, "camera");
+        PermissionTestUtils.remove(uri, "microphone");
       }
 
       info("request audio+video, stop sharing resets both");
       await stopAndCheckPerm(true, true);
       info("request audio, stop sharing resets audio only");
       await stopAndCheckPerm(true, false);
       info("request video, stop sharing resets video only");
       await stopAndCheckPerm(false, true);
@@ -640,20 +665,19 @@ var gTests = [
       let browser = gBrowser.selectedBrowser;
       BrowserTestUtils.loadURI(
         browser,
         browser.documentURI.spec.replace("https://", "http://")
       );
       await BrowserTestUtils.browserLoaded(browser);
 
       // Initially set both permissions to 'allow'.
-      let Perms = Services.perms;
       let uri = browser.documentURI;
-      Perms.add(uri, "microphone", Perms.ALLOW_ACTION);
-      Perms.add(uri, "camera", Perms.ALLOW_ACTION);
+      PermissionTestUtils.add(uri, "microphone", Services.perms.ALLOW_ACTION);
+      PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
 
       // Request devices and expect a prompt despite the saved 'Allow' permission,
       // because the connection isn't secure.
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
 
@@ -668,17 +692,17 @@ var gTests = [
       ok(notification.button.disabled, "Allow button is disabled");
       ok(
         !notification.hasAttribute("warninghidden"),
         "warning message is shown"
       );
 
       // Cleanup.
       await closeStream(true);
-      Perms.remove(uri, "camera");
-      Perms.remove(uri, "microphone");
+      PermissionTestUtils.remove(uri, "camera");
+      PermissionTestUtils.remove(uri, "microphone");
     },
   },
 ];
 
 add_task(async function test() {
   await runTests(gTests);
 });
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
@@ -60,40 +60,39 @@ var gTests = [
         await getMediaCaptureState(),
         { audio: true, video: true },
         "expected camera and microphone to be shared"
       );
 
       await indicator;
       await checkSharingUI({ video: true, audio: true });
 
-      let Perms = Services.perms;
       let uri = Services.io.newURI("https://example.com/");
       is(
-        Perms.testExactPermission(uri, "microphone"),
-        Perms.ALLOW_ACTION,
+        PermissionTestUtils.testExactPermission(uri, "microphone"),
+        Services.perms.ALLOW_ACTION,
         "microphone persistently allowed"
       );
       is(
-        Perms.testExactPermission(uri, "camera"),
-        Perms.ALLOW_ACTION,
+        PermissionTestUtils.testExactPermission(uri, "camera"),
+        Services.perms.ALLOW_ACTION,
         "camera persistently allowed"
       );
 
       await stopSharing();
 
       // The persistent permissions for the frame should have been removed.
       is(
-        Perms.testExactPermission(uri, "microphone"),
-        Perms.UNKNOWN_ACTION,
+        PermissionTestUtils.testExactPermission(uri, "microphone"),
+        Services.perms.UNKNOWN_ACTION,
         "microphone not persistently allowed"
       );
       is(
-        Perms.testExactPermission(uri, "camera"),
-        Perms.UNKNOWN_ACTION,
+        PermissionTestUtils.testExactPermission(uri, "camera"),
+        Services.perms.UNKNOWN_ACTION,
         "camera not persistently allowed"
       );
 
       // the stream is already closed, but this will do some cleanup anyway
       await closeStream(true, "frame1");
     },
   },
 
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -1,14 +1,17 @@
 var { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 var { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
+var { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const PREF_PERMISSION_FAKE = "media.navigator.permission.fake";
 const PREF_AUDIO_LOOPBACK = "media.audio_loopback_dev";
 const PREF_VIDEO_LOOPBACK = "media.video_loopback_dev";
 const PREF_FAKE_STREAMS = "media.navigator.streams.fake";
 const PREF_FOCUS_SOURCE = "media.getusermedia.window.focus_source.enabled";
 const CONTENT_SCRIPT_HELPER =
   getRootDirectory(gTestPath) + "get_user_media_content_script.js";
--- a/browser/components/enterprisepolicies/tests/xpcshell/head.js
+++ b/browser/components/enterprisepolicies/tests/xpcshell/head.js
@@ -10,16 +10,19 @@ const { Preferences } = ChromeUtils.impo
   "resource://gre/modules/Preferences.jsm"
 );
 const { updateAppInfo, getAppInfo } = ChromeUtils.import(
   "resource://testing-common/AppInfo.jsm"
 );
 const { FileTestUtils } = ChromeUtils.import(
   "resource://testing-common/FileTestUtils.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 updateAppInfo({
   name: "XPCShell",
   ID: "xpcshell@tests.mozilla.org",
   version: "48",
   platformVersion: "48",
 });
 
--- a/browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js
+++ b/browser/components/enterprisepolicies/tests/xpcshell/test_permissions.js
@@ -9,64 +9,64 @@ function URI(str) {
 
 add_task(async function test_setup_preexisting_permissions() {
   // Pre-existing ALLOW permissions that should be overriden
   // with DENY.
 
   // No ALLOW -> DENY override for popup and install permissions,
   // because their policies only supports the Allow parameter.
 
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "camera",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "microphone",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "geo",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "desktop-notification",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
   // Pre-existing DENY permissions that should be overriden
   // with ALLOW.
 
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "camera",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "microphone",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "geo",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "desktop-notification",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 });
 
 add_task(async function test_setup_activate_policies() {
   await setupPolicyEngineWithJson({
@@ -98,23 +98,23 @@ add_task(async function test_setup_activ
   );
 });
 
 function checkPermission(url, expected, permissionName) {
   let expectedValue = Ci.nsIPermissionManager[`${expected}_ACTION`];
   let uri = Services.io.newURI(`https://www.${url}`);
 
   equal(
-    Services.perms.testPermission(uri, permissionName),
+    PermissionTestUtils.testPermission(uri, permissionName),
     expectedValue,
     `Correct (${permissionName}=${expected}) for URL ${url}`
   );
 
   if (expected != "UNKNOWN") {
-    let permission = Services.perms.getPermissionObjectForURI(
+    let permission = PermissionTestUtils.getPermissionObject(
       uri,
       permissionName,
       true
     );
     ok(permission, "Permission object exists");
     equal(
       permission.expireType,
       Ci.nsIPermissionManager.EXPIRE_POLICY,
@@ -148,65 +148,65 @@ add_task(async function test_location_po
 
 add_task(async function test_notifications_policy() {
   checkAllPermissionsForType("desktop-notification");
 });
 
 add_task(async function test_change_permission() {
   // Checks that changing a permission will still retain the
   // value set through the engine.
-  Services.perms.add(
-    URI("https://www.allow.com"),
+  PermissionTestUtils.add(
+    "https://www.allow.com",
     "camera",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.allow.com"),
+  PermissionTestUtils.add(
+    "https://www.allow.com",
     "microphone",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.allow.com"),
+  PermissionTestUtils.add(
+    "https://www.allow.com",
     "geo",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.allow.com"),
+  PermissionTestUtils.add(
+    "https://www.allow.com",
     "desktop-notification",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
   checkPermission("allow.com", "ALLOW", "camera");
   checkPermission("allow.com", "ALLOW", "microphone");
   checkPermission("allow.com", "ALLOW", "geo");
   checkPermission("allow.com", "ALLOW", "desktop-notification");
 
   // Also change one un-managed permission to make sure it doesn't
   // cause any problems to the policy engine or the permission manager.
-  Services.perms.add(
-    URI("https://www.unmanaged.com"),
+  PermissionTestUtils.add(
+    "https://www.unmanaged.com",
     "camera",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.unmanaged.com"),
+  PermissionTestUtils.add(
+    "https://www.unmanaged.com",
     "microphone",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.unmanaged.com"),
+  PermissionTestUtils.add(
+    "https://www.unmanaged.com",
     "geo",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
-  Services.perms.add(
-    URI("https://www.unmanaged.com"),
+  PermissionTestUtils.add(
+    "https://www.unmanaged.com",
     "desktop-notification",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 });
--- a/browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons_flash.js
+++ b/browser/components/enterprisepolicies/tests/xpcshell/test_popups_cookies_addons_flash.js
@@ -9,55 +9,55 @@ function URI(str) {
 
 add_task(async function test_setup_preexisting_permissions() {
   // Pre-existing ALLOW permissions that should be overriden
   // with DENY.
 
   // No ALLOW -> DENY override for popup and install permissions,
   // because their policies only supports the Allow parameter.
 
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "cookie",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
-  Services.perms.add(
-    URI("https://www.pre-existing-allow.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-allow.com",
     "plugin:flash",
     Ci.nsIPermissionManager.ALLOW_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
   // Pre-existing DENY permissions that should be overriden
   // with ALLOW.
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "popup",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "install",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "cookie",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
-  Services.perms.add(
-    URI("https://www.pre-existing-deny.com"),
+  PermissionTestUtils.add(
+    "https://www.pre-existing-deny.com",
     "plugin:flash",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 });
 
 add_task(async function test_setup_activate_policies() {
   await setupPolicyEngineWithJson("config_popups_cookies_addons_flash.json");
@@ -68,23 +68,23 @@ add_task(async function test_setup_activ
   );
 });
 
 function checkPermission(url, expected, permissionName) {
   let expectedValue = Ci.nsIPermissionManager[`${expected}_ACTION`];
   let uri = Services.io.newURI(`https://www.${url}`);
 
   equal(
-    Services.perms.testPermission(uri, permissionName),
+    PermissionTestUtils.testPermission(uri, permissionName),
     expectedValue,
     `Correct (${permissionName}=${expected}) for URL ${url}`
   );
 
   if (expected != "UNKNOWN") {
-    let permission = Services.perms.getPermissionObjectForURI(
+    let permission = PermissionTestUtils.getPermissionObject(
       uri,
       permissionName,
       true
     );
     ok(permission, "Permission object exists");
     equal(
       permission.expireType,
       Ci.nsIPermissionManager.EXPIRE_POLICY,
@@ -118,26 +118,26 @@ add_task(async function test_cookies_pol
 
 add_task(async function test_flash_policy() {
   checkAllPermissionsForType("plugin:flash");
 });
 
 add_task(async function test_change_permission() {
   // Checks that changing a permission will still retain the
   // value set through the engine.
-  Services.perms.add(
-    URI("https://www.allow.com"),
+  PermissionTestUtils.add(
+    "https://www.allow.com",
     "cookie",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 
   checkPermission("allow.com", "ALLOW", "cookie");
 
   // Also change one un-managed permission to make sure it doesn't
   // cause any problems to the policy engine or the permission manager.
-  Services.perms.add(
-    URI("https://www.unmanaged.com"),
+  PermissionTestUtils.add(
+    "https://www.unmanaged.com",
     "cookie",
     Ci.nsIPermissionManager.DENY_ACTION,
     Ci.nsIPermissionManager.EXPIRE_SESSION
   );
 });
--- a/browser/components/originattributes/test/browser/browser_permissions.js
+++ b/browser/components/originattributes/test/browser/browser_permissions.js
@@ -1,20 +1,24 @@
 /**
  * Bug 1282655 - Test if site permissions are universal across origin attributes.
  *
  * This test is testing the cookie "permission" for a specific URI.
  */
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const TEST_PAGE = "http://example.net";
 const uri = Services.io.newURI(TEST_PAGE);
 
 function disableCookies() {
   Services.cookies.removeAll();
-  Services.perms.add(uri, "cookie", Services.perms.DENY_ACTION);
+  PermissionTestUtils.add(uri, "cookie", Services.perms.DENY_ACTION);
 }
 
 function ensureCookieNotSet(aBrowser) {
   ContentTask.spawn(aBrowser, null, async function() {
     content.document.cookie = "key=value";
     is(
       content.document.cookie,
       "",
@@ -28,17 +32,17 @@ IsolationTestTools.runTests(
   TEST_PAGE,
   ensureCookieNotSet,
   () => true,
   disableCookies
 );
 
 function enableCookies() {
   Services.cookies.removeAll();
-  Services.perms.add(uri, "cookie", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(uri, "cookie", Services.perms.ALLOW_ACTION);
 }
 
 function ensureCookieSet(aBrowser) {
   ContentTask.spawn(aBrowser, null, function() {
     content.document.cookie = "key=value";
     is(
       content.document.cookie,
       "key=value",
--- a/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
+++ b/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
@@ -133,25 +133,29 @@ add_task(async function testRemove() {
     }
   );
 });
 
 add_task(async function testAdd() {
   await runTest(
     async (params, observeAllPromise, apply) => {
       let uri = Services.io.newURI("http://test.com");
-      Services.perms.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
+      PermissionTestUtils.add(
+        uri,
+        "popup",
+        Ci.nsIPermissionManager.DENY_ACTION
+      );
 
       info("Adding unrelated permission should not change display.");
       assertListContents(params, []);
 
       apply();
       await observeAllPromise;
 
-      Services.perms.remove(uri, "popup");
+      PermissionTestUtils.remove(uri, "popup");
     },
     params => {
       return [
         {
           type: "popup",
           origin: "http://test.com",
           data: "added",
           capability: Ci.nsIPermissionManager.DENY_ACTION,
@@ -407,17 +411,21 @@ add_task(async function testSort() {
       EventUtils.synthesizeMouseAtCenter(
         params.doc.getElementById("siteCol"),
         {},
         params.doc.defaultView
       );
 
       for (let URL of ["http://a", "http://z", "http://b"]) {
         let URI = Services.io.newURI(URL);
-        Services.perms.add(URI, "cookie", Ci.nsIPermissionManager.ALLOW_ACTION);
+        PermissionTestUtils.add(
+          URI,
+          "cookie",
+          Ci.nsIPermissionManager.ALLOW_ACTION
+        );
       }
 
       assertListContents(params, [
         ["http://a", params.allowL10nId],
         ["http://b", params.allowL10nId],
         ["http://z", params.allowL10nId],
       ]);
 
@@ -434,17 +442,17 @@ add_task(async function testSort() {
         ["http://a", params.allowL10nId],
       ]);
 
       apply();
       await observeAllPromise;
 
       for (let URL of ["http://a", "http://z", "http://b"]) {
         let uri = Services.io.newURI(URL);
-        Services.perms.remove(uri, "cookie");
+        PermissionTestUtils.remove(uri, "cookie");
       }
     },
     params => {
       return [
         {
           type: "cookie",
           origin: "http://a",
           data: "added",
--- a/browser/components/preferences/in-content/tests/head.js
+++ b/browser/components/preferences/in-content/tests/head.js
@@ -1,12 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 ChromeUtils.import("resource://gre/modules/Promise.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const kDefaultWait = 2000;
 
 function is_element_visible(aElement, aMsg) {
   isnot(aElement, null, "Element should not be null, when checking visibility");
   ok(!BrowserTestUtils.is_hidden(aElement), aMsg);
 }
 
--- a/browser/components/translation/test/browser_translation_exceptions.js
+++ b/browser/components/translation/test/browser_translation_exceptions.js
@@ -1,16 +1,19 @@
 /* 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/. */
 
 // tests the translation infobar, using a fake 'Translation' implementation.
 
 var tmp = {};
 ChromeUtils.import("resource:///modules/translation/Translation.jsm", tmp);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 var { Translation } = tmp;
 
 const kLanguagesPref = "browser.translation.neverForLanguages";
 const kShowUIPref = "browser.translation.ui.show";
 
 function test() {
   waitForExplicitFinish();
 
@@ -235,17 +238,17 @@ var gTests = [
       // Open the "options" drop down.
       await openPopup(notif._getAnonElt("options"));
       ok(
         notif._getAnonElt("neverForSite").disabled,
         "The 'Never translate French' item is disabled"
       );
 
       // Cleanup.
-      Services.perms.remove(makeURI("http://example.com"), "translate");
+      PermissionTestUtils.remove("http://example.com", "translate");
       notif.close();
     },
   },
 
   {
     desc: "language exception list",
     run: async function checkLanguageExceptions() {
       // Put 2 languages in the pref before opening the window to check
@@ -302,19 +305,26 @@ var gTests = [
     },
   },
 
   {
     desc: "domains exception list",
     run: async function checkDomainExceptions() {
       // Put 2 exceptions before opening the window to check the list is
       // displayed on load.
-      let perms = Services.perms;
-      perms.add(makeURI("http://example.org"), "translate", perms.DENY_ACTION);
-      perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
+      PermissionTestUtils.add(
+        "http://example.org",
+        "translate",
+        Services.perms.DENY_ACTION
+      );
+      PermissionTestUtils.add(
+        "http://example.com",
+        "translate",
+        Services.perms.DENY_ACTION
+      );
 
       // Open the translation exceptions dialog.
       let win = openDialog(
         "chrome://browser/content/preferences/translation.xul",
         "Browser:TranslationExceptions",
         "",
         null
       );
@@ -334,24 +344,28 @@ var gTests = [
       ok(!remove.disabled, "The 'Remove Site' button is enabled");
 
       // Click the 'Remove' button.
       remove.click();
       is(tree.view.rowCount, 1, "The site exceptions now contains 1 item");
       is(getDomainExceptions().length, 1, "One exception in the permissions");
 
       // Clear the permissions, and check the last item is removed from the display.
-      perms.remove(makeURI("http://example.org"), "translate");
-      perms.remove(makeURI("http://example.com"), "translate");
+      PermissionTestUtils.remove("http://example.org", "translate");
+      PermissionTestUtils.remove("http://example.com", "translate");
       is(tree.view.rowCount, 0, "The site exceptions list is empty");
       ok(remove.disabled, "The 'Remove Site' button is disabled");
       ok(removeAll.disabled, "The 'Remove All Site' button is disabled");
 
       // Add an item and check it appears.
-      perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
+      PermissionTestUtils.add(
+        "http://example.com",
+        "translate",
+        Services.perms.DENY_ACTION
+      );
       is(tree.view.rowCount, 1, "The site exceptions list has 1 item");
       ok(remove.disabled, "The 'Remove Site' button is disabled");
       ok(!removeAll.disabled, "The 'Remove All Sites' button is enabled");
 
       // Click the 'Remove All' button.
       removeAll.click();
       is(tree.view.rowCount, 0, "The site exceptions list is empty");
       ok(remove.disabled, "The 'Remove Site' button is disabled");
--- a/browser/components/uitour/test/browser_no_tabs.js
+++ b/browser/components/uitour/test/browser_no_tabs.js
@@ -55,18 +55,17 @@ function destroyHiddenBrowser(aFrame, aB
  * browsers).
  */
 add_task(async function test_windowless_UITour() {
   // Get the URL for the test page.
   let pageURL = getRootDirectory(gTestPath) + "uitour.html";
 
   // Allow the URL to use the UITour.
   info("Adding UITour permission to the test page.");
-  let pageURI = Services.io.newURI(pageURL);
-  Services.perms.add(pageURI, "uitour", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(gTestPath, "uitour", Services.perms.ALLOW_ACTION);
 
   // UITour's ping will resolve this promise.
   await new Promise(resolve => {
     // Create a windowless browser and test that UITour works in it.
     let browserPromise = createHiddenBrowser(pageURL);
     browserPromise.then(frameInfo => {
       isnot(frameInfo.browser, null, "The browser must exist and not be null.");
 
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -4,16 +4,20 @@
 /* global gTestTab:true, gContentAPI:true, gContentWindow:true, tests:false */
 
 ChromeUtils.defineModuleGetter(
   this,
   "UITour",
   "resource:///modules/UITour.jsm"
 );
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const SINGLE_TRY_TIMEOUT = 100;
 const NUMBER_OF_TRIES = 30;
 
 function waitForConditionPromise(
   condition,
   timeoutMsg,
   tryCount = NUMBER_OF_TRIES
 ) {
@@ -441,37 +445,45 @@ function loadUITourTestPage(callback, ho
 // Wrapper for UITourTest to be used by add_task tests.
 function setup_UITourTest() {
   return UITourTest(true);
 }
 
 // Use `add_task(setup_UITourTest);` instead as we will fold this into `setup_UITourTest` once all tests are using `add_UITour_task`.
 function UITourTest(usingAddTask = false) {
   Services.prefs.setBoolPref("browser.uitour.enabled", true);
-  let testHttpsUri = Services.io.newURI("https://example.org");
-  let testHttpUri = Services.io.newURI("http://example.org");
-  Services.perms.add(testHttpsUri, "uitour", Services.perms.ALLOW_ACTION);
-  Services.perms.add(testHttpUri, "uitour", Services.perms.ALLOW_ACTION);
+  let testHttpsOrigin = "https://example.org";
+  let testHttpOrigin = "http://example.org";
+  PermissionTestUtils.add(
+    testHttpsOrigin,
+    "uitour",
+    Services.perms.ALLOW_ACTION
+  );
+  PermissionTestUtils.add(
+    testHttpOrigin,
+    "uitour",
+    Services.perms.ALLOW_ACTION
+  );
 
   // If a test file is using add_task, we don't need to have a test function or
   // call `waitForExplicitFinish`.
   if (!usingAddTask) {
     waitForExplicitFinish();
   }
 
   registerCleanupFunction(function() {
     delete window.gContentWindow;
     delete window.gContentAPI;
     if (gTestTab) {
       gBrowser.removeTab(gTestTab);
     }
     delete window.gTestTab;
     Services.prefs.clearUserPref("browser.uitour.enabled");
-    Services.perms.remove(testHttpsUri, "uitour");
-    Services.perms.remove(testHttpUri, "uitour");
+    PermissionTestUtils.remove(testHttpsOrigin, "uitour");
+    PermissionTestUtils.remove(testHttpOrigin, "uitour");
   });
 
   // When using tasks, the harness will call the next added task for us.
   if (!usingAddTask) {
     nextTest();
   }
 }
 
--- a/browser/modules/test/unit/test_SiteDataManager.js
+++ b/browser/modules/test/unit/test_SiteDataManager.js
@@ -8,16 +8,19 @@ const EXAMPLE_ORIGIN_2 = "https://exampl
 
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { SiteDataManager } = ChromeUtils.import(
   "resource:///modules/SiteDataManager.jsm"
 );
 const { SiteDataTestUtils } = ChromeUtils.import(
   "resource://testing-common/SiteDataTestUtils.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 ChromeUtils.defineModuleGetter(
   this,
   "setTimeout",
   "resource://gre/modules/Timer.jsm"
 );
 ChromeUtils.defineModuleGetter(
   this,
   "TestUtils",
@@ -114,17 +117,17 @@ add_task(async function testGetTotalUsag
 
   await SiteDataTestUtils.clear();
 });
 
 add_task(async function testRemove() {
   await SiteDataManager.updateSites();
 
   let uri = Services.io.newURI(EXAMPLE_ORIGIN);
-  Services.perms.add(uri, "camera", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
 
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1");
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2");
   await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096);
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar");
   await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048);
   await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2);
 
@@ -146,35 +149,35 @@ add_task(async function testRemove() {
   );
 
   let usage = await SiteDataTestUtils.getQuotaUsage(EXAMPLE_ORIGIN);
   Assert.equal(usage, 0, "Has cleared quota usage for example.com");
 
   let cookies = Services.cookies.countCookiesFromHost("example.com");
   Assert.equal(cookies, 0, "Has cleared cookies for example.com");
 
-  let perm = Services.perms.testPermission(uri, "persistent-storage");
+  let perm = PermissionTestUtils.testPermission(uri, "persistent-storage");
   Assert.equal(
     perm,
     Services.perms.UNKNOWN_ACTION,
     "Cleared the persistent-storage permission."
   );
-  perm = Services.perms.testPermission(uri, "camera");
+  perm = PermissionTestUtils.testPermission(uri, "camera");
   Assert.equal(
     perm,
     Services.perms.ALLOW_ACTION,
     "Did not clear other permissions."
   );
 
-  Services.perms.remove(uri, "camera");
+  PermissionTestUtils.remove(uri, "camera");
 });
 
 add_task(async function testRemoveSiteData() {
   let uri = Services.io.newURI(EXAMPLE_ORIGIN);
-  Services.perms.add(uri, "camera", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
 
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1");
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2");
   await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096);
   SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar");
   await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048);
   await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2);
 
@@ -194,23 +197,23 @@ add_task(async function testRemoveSiteDa
   Assert.equal(usage, 0, "Has cleared quota usage for example.com");
 
   usage = await SiteDataTestUtils.getQuotaUsage(EXAMPLE_ORIGIN_2);
   Assert.equal(usage, 0, "Has cleared quota usage for example.org");
 
   let cookies = Services.cookies.countCookiesFromHost("example.org");
   Assert.equal(cookies, 0, "Has cleared cookies for example.org");
 
-  let perm = Services.perms.testPermission(uri, "persistent-storage");
+  let perm = PermissionTestUtils.testPermission(uri, "persistent-storage");
   Assert.equal(
     perm,
     Services.perms.UNKNOWN_ACTION,
     "Cleared the persistent-storage permission."
   );
-  perm = Services.perms.testPermission(uri, "camera");
+  perm = PermissionTestUtils.testPermission(uri, "camera");
   Assert.equal(
     perm,
     Services.perms.ALLOW_ACTION,
     "Did not clear other permissions."
   );
 
-  Services.perms.remove(uri, "camera");
+  PermissionTestUtils.remove(uri, "camera");
 });
--- a/dom/indexedDB/test/unit/test_idle_maintenance.js
+++ b/dom/indexedDB/test/unit/test_idle_maintenance.js
@@ -10,17 +10,21 @@ function* testSteps() {
   let uri = Services.io.newURI("https://www.example.com");
   let principal = Services.scriptSecurityManager.createContentPrincipal(
     uri,
     {}
   );
 
   info("Setting permissions");
 
-  Services.perms.add(uri, "indexedDB", Ci.nsIPermissionManager.ALLOW_ACTION);
+  Services.perms.addFromPrincipal(
+    principal,
+    "indexedDB",
+    Ci.nsIPermissionManager.ALLOW_ACTION
+  );
 
   // The idle-daily notification is disabled in xpchsell tests, so we don't
   // need to do anything special to disable it for this test.
 
   info("Activating real idle service");
 
   do_get_idle();
 
--- a/dom/indexedDB/test/unit/test_storageOption_pref.js
+++ b/dom/indexedDB/test/unit/test_storageOption_pref.js
@@ -15,27 +15,32 @@ function* testSteps() {
     Services.prefs.clearUserPref("dom.indexedDB.storageOption.enabled");
   });
 
   const name = "Splendid Test";
   const version = 1;
   const origin = "https://example.com";
 
   // Avoid trying to show permission prompts on a window.
-  let uri = Services.io.newURI(origin);
-  Services.perms.add(uri, "indexedDB", Ci.nsIPermissionManager.ALLOW_ACTION);
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
+  Services.perms.addFromPrincipal(
+    principal,
+    "indexedDB",
+    Ci.nsIPermissionManager.ALLOW_ACTION
+  );
 
   const objectStoreName = "Foo";
   const data = { key: 1, value: "bar" };
 
   // Turn the storage option off, content databases should be "default".
   Services.prefs.setBoolPref("dom.indexedDB.storageOption.enabled", false);
 
   // Open a database with content privileges.
-  let principal = getPrincipal(origin);
   let request = indexedDB.openForPrincipal(principal, name, {
     version,
     storage: "persistent",
   });
 
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
--- a/dom/notification/test/browser/browser_permission_dismiss.js
+++ b/dom/notification/test/browser/browser_permission_dismiss.js
@@ -1,10 +1,14 @@
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const ORIGIN_URI = Services.io.newURI("https://example.com");
 const PERMISSION_NAME = "desktop-notification";
 const PROMPT_ALLOW_BUTTON = -1;
 const PROMPT_NOT_NOW_BUTTON = 0;
 const PROMPT_NEVER_BUTTON = 1;
 const TEST_URL =
   "https://example.com/browser/dom/notification/test/browser/notification.html";
 
@@ -40,17 +44,17 @@ function clickDoorhangerButton(aButtonIn
  * and verifies that the expected permission is set.
  *
  * @param {Function} task Task function to run to interact with the prompt.
  * @param {String} permission Expected permission value.
  * @return {Promise} resolving when the task function is done and the tab
  *                   closes.
  */
 function tabWithRequest(task, permission) {
-  Services.perms.remove(ORIGIN_URI, PERMISSION_NAME);
+  PermissionTestUtils.remove(ORIGIN_URI, PERMISSION_NAME);
 
   return BrowserTestUtils.withNewTab(
     {
       gBrowser,
       url: TEST_URL,
     },
     async function(browser) {
       let requestPromise = ContentTask.spawn(
@@ -89,62 +93,62 @@ function tabWithRequest(task, permission
 
 add_task(async function setup() {
   Services.prefs.setBoolPref(
     "dom.webnotifications.requireuserinteraction",
     false
   );
   SimpleTest.registerCleanupFunction(() => {
     Services.prefs.clearUserPref("dom.webnotifications.requireuserinteraction");
-    Services.perms.remove(ORIGIN_URI, PERMISSION_NAME);
+    PermissionTestUtils.remove(ORIGIN_URI, PERMISSION_NAME);
   });
 });
 
 add_task(async function test_requestPermission_granted() {
   await tabWithRequest(function() {
     clickDoorhangerButton(PROMPT_ALLOW_BUTTON);
   }, "granted");
 
   ok(
     !PopupNotifications.getNotification("web-notifications"),
     "Should remove the doorhanger notification icon if granted"
   );
 
   is(
-    Services.perms.testPermission(ORIGIN_URI, PERMISSION_NAME),
+    PermissionTestUtils.testPermission(ORIGIN_URI, PERMISSION_NAME),
     Services.perms.ALLOW_ACTION,
     "Check permission in perm. manager"
   );
 });
 
 add_task(async function test_requestPermission_denied_temporarily() {
   await tabWithRequest(function() {
     clickDoorhangerButton(PROMPT_NOT_NOW_BUTTON);
   }, "default");
 
   ok(
     !PopupNotifications.getNotification("web-notifications"),
     "Should remove the doorhanger notification icon if denied"
   );
 
   is(
-    Services.perms.testPermission(ORIGIN_URI, PERMISSION_NAME),
+    PermissionTestUtils.testPermission(ORIGIN_URI, PERMISSION_NAME),
     Services.perms.UNKNOWN_ACTION,
     "Check permission in perm. manager"
   );
 });
 
 add_task(async function test_requestPermission_denied_permanently() {
   await tabWithRequest(async function() {
     await clickDoorhangerButton(PROMPT_NEVER_BUTTON);
   }, "denied");
 
   ok(
     !PopupNotifications.getNotification("web-notifications"),
     "Should remove the doorhanger notification icon if denied"
   );
 
   is(
-    Services.perms.testPermission(ORIGIN_URI, PERMISSION_NAME),
+    PermissionTestUtils.testPermission(ORIGIN_URI, PERMISSION_NAME),
     Services.perms.DENY_ACTION,
     "Check permission in perm. manager"
   );
 });
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -19,16 +19,19 @@ var { Preferences } = ChromeUtils.import
   "resource://gre/modules/Preferences.jsm"
 );
 var { PlacesUtils } = ChromeUtils.import(
   "resource://gre/modules/PlacesUtils.jsm"
 );
 var { ObjectUtils } = ChromeUtils.import(
   "resource://gre/modules/ObjectUtils.jsm"
 );
+var { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 ChromeUtils.defineModuleGetter(
   this,
   "PlacesTestUtils",
   "resource://testing-common/PlacesTestUtils.jsm"
 );
 ChromeUtils.defineModuleGetter(
   this,
--- a/dom/push/test/xpcshell/test_drop_expired.js
+++ b/dom/push/test/xpcshell/test_drop_expired.js
@@ -18,23 +18,23 @@ function visitURI(uri, timestamp) {
     visitDate: timestamp * 1000,
     transition: Ci.nsINavHistoryService.TRANSITION_LINK,
   });
 }
 
 var putRecord = async function({ scope, perm, quota, lastPush, lastVisit }) {
   let uri = Services.io.newURI(scope);
 
-  Services.perms.add(
+  PermissionTestUtils.add(
     uri,
     "desktop-notification",
     Ci.nsIPermissionManager[perm]
   );
   registerCleanupFunction(() => {
-    Services.perms.remove(uri, "desktop-notification");
+    PermissionTestUtils.remove(uri, "desktop-notification");
   });
 
   await visitURI(uri, lastVisit);
 
   await db.put({
     channelID: uri.pathQueryRef,
     pushEndpoint: "https://example.org/push" + uri.pathQueryRef,
     scope: uri.spec,
@@ -151,16 +151,16 @@ add_task(async function test_site_visite
 });
 
 add_task(async function test_perm_restored() {
   let subChangePromise = promiseObserverNotification(
     PushServiceComponent.subscriptionChangeTopic,
     (subject, data) => data == "https://example.info/expired-perm-revoked"
   );
 
-  Services.perms.add(
+  PermissionTestUtils.add(
     permURI,
     "desktop-notification",
     Ci.nsIPermissionManager.ALLOW_ACTION
   );
 
   await subChangePromise;
 });
--- a/dom/push/test/xpcshell/test_quota_observer.js
+++ b/dom/push/test/xpcshell/test_quota_observer.js
@@ -15,23 +15,23 @@ function run_test() {
     userAgentID,
   });
   run_next_test();
 }
 
 let putRecord = async function(perm, record) {
   let uri = Services.io.newURI(record.scope);
 
-  Services.perms.add(
+  PermissionTestUtils.add(
     uri,
     "desktop-notification",
     Ci.nsIPermissionManager[perm]
   );
   registerCleanupFunction(() => {
-    Services.perms.remove(uri, "desktop-notification");
+    PermissionTestUtils.remove(uri, "desktop-notification");
   });
 
   await db.put(record);
 };
 
 add_task(async function test_expiration_history_observer() {
   db = PushServiceWebSocket.newPushDB();
   registerCleanupFunction(() => db.drop().then(_ => db.close()));
--- a/dom/push/test/xpcshell/test_record.js
+++ b/dom/push/test/xpcshell/test_record.js
@@ -85,28 +85,28 @@ function testPermissionCheck(props) {
       `Origin suffixes should match for ${JSON.stringify(props)}`
     );
   }
   ok(
     !record.hasPermission(),
     `Record ${JSON.stringify(props)} should not have permission yet`
   );
   let permURI = Services.io.newURI(props.scope);
-  Services.perms.add(
+  PermissionTestUtils.add(
     permURI,
     "desktop-notification",
     Ci.nsIPermissionManager.ALLOW_ACTION
   );
   try {
     ok(
       record.hasPermission(),
       `Record ${JSON.stringify(props)} should have permission`
     );
   } finally {
-    Services.perms.remove(permURI, "desktop-notification");
+    PermissionTestUtils.remove(permURI, "desktop-notification");
   }
 }
 
 add_task(async function test_principal_permissions() {
   let testProps = [
     {
       scope: "https://example.com/",
     },
--- a/dom/serviceworkers/test/browser_storage_permission.js
+++ b/dom/serviceworkers/test/browser_storage_permission.js
@@ -1,10 +1,14 @@
 "use strict";
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const BASE_URI = "http://mochi.test:8888/browser/dom/serviceworkers/test/";
 const PAGE_URI = BASE_URI + "empty.html";
 const SCOPE = PAGE_URI + "?storage_permission";
 const SW_SCRIPT = BASE_URI + "empty.js";
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [
@@ -42,18 +46,18 @@ add_task(async function setup() {
       });
     }
   );
 
   BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_allow_permission() {
-  Services.perms.add(
-    Services.io.newURI(PAGE_URI),
+  PermissionTestUtils.add(
+    PAGE_URI,
     "cookie",
     Ci.nsICookiePermission.ACCESS_ALLOW
   );
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
@@ -62,62 +66,62 @@ add_task(async function test_allow_permi
   });
 
   ok(!!controller, "page should be controlled with storage allowed");
 
   BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_deny_permission() {
-  Services.perms.add(
-    Services.io.newURI(PAGE_URI),
+  PermissionTestUtils.add(
+    PAGE_URI,
     "cookie",
     Ci.nsICookiePermission.ACCESS_DENY
   );
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let controller = await ContentTask.spawn(browser, null, async function() {
     return content.navigator.serviceWorker.controller;
   });
 
   is(controller, null, "page should be not controlled with storage denied");
 
   BrowserTestUtils.removeTab(tab);
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 });
 
 add_task(async function test_session_permission() {
-  Services.perms.add(
-    Services.io.newURI(PAGE_URI),
+  PermissionTestUtils.add(
+    PAGE_URI,
     "cookie",
     Ci.nsICookiePermission.ACCESS_SESSION
   );
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let controller = await ContentTask.spawn(browser, null, async function() {
     return content.navigator.serviceWorker.controller;
   });
 
   is(controller, null, "page should be not controlled with session storage");
 
   BrowserTestUtils.removeTab(tab);
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 });
 
 // Test to verify an about:blank iframe successfully inherits the
 // parent's controller when storage is blocked between opening the
 // parent page and creating the iframe.
 add_task(async function test_block_storage_before_blank_iframe() {
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let controller = await ContentTask.spawn(browser, null, async function() {
     return content.navigator.serviceWorker.controller;
   });
@@ -151,17 +155,17 @@ add_task(async function test_block_stora
   await SpecialPowers.popPrefEnv();
   BrowserTestUtils.removeTab(tab);
 });
 
 // Test to verify a blob URL iframe successfully inherits the
 // parent's controller when storage is blocked between opening the
 // parent page and creating the iframe.
 add_task(async function test_block_storage_before_blob_iframe() {
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let controller = await ContentTask.spawn(browser, null, async function() {
     return content.navigator.serviceWorker.controller;
   });
@@ -207,17 +211,17 @@ add_task(async function test_block_stora
 });
 
 // Test to verify a blob worker script does not hit our service
 // worker storage assertions when storage is blocked between opening
 // the parent page and creating the worker.  Note, we cannot
 // explicitly check if the worker is controlled since we don't expose
 // WorkerNavigator.serviceWorkers.controller yet.
 add_task(async function test_block_storage_before_blob_worker() {
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 
   let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let controller = await ContentTask.spawn(browser, null, async function() {
     return content.navigator.serviceWorker.controller;
   });
@@ -260,17 +264,17 @@ add_task(async function test_block_stora
 
   ok(scriptURL2.startsWith("blob:"), "blob URL worker should run");
 
   await SpecialPowers.popPrefEnv();
   BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function cleanup() {
-  Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
+  PermissionTestUtils.remove(PAGE_URI, "cookie");
 
   let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   await ContentTask.spawn(browser, SCOPE, async function(uri) {
     let reg = await content.navigator.serviceWorker.getRegistration(uri);
     let worker = reg.active;
--- a/netwerk/cookie/test/browser/head.js
+++ b/netwerk/cookie/test/browser/head.js
@@ -1,8 +1,12 @@
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const BEHAVIOR_ACCEPT = Ci.nsICookieService.BEHAVIOR_ACCEPT;
 const BEHAVIOR_REJECT = Ci.nsICookieService.BEHAVIOR_REJECT;
 
 const PERM_DEFAULT = Ci.nsICookiePermission.ACCESS_DEFAULT;
 const PERM_ALLOW = Ci.nsICookiePermission.ACCESS_ALLOW;
 const PERM_DENY = Ci.nsICookiePermission.ACCESS_DENY;
 
 const TEST_DOMAIN = "https://example.com/";
@@ -81,20 +85,18 @@ this.CookiePolicyHelper = {
       info("Starting " + testName + ": " + config.toSource());
 
       await SpecialPowers.flushPrefEnv();
 
       if (prefs) {
         await SpecialPowers.pushPrefEnv({ set: prefs });
       }
 
-      let uri = Services.io.newURI(TEST_DOMAIN);
-
       // Let's set the first cookie pref.
-      Services.perms.add(uri, "cookie", config.fromPermission);
+      PermissionTestUtils.add(TEST_DOMAIN, "cookie", config.fromPermission);
       await SpecialPowers.pushPrefEnv({
         set: [["network.cookie.cookieBehavior", config.fromBehavior]],
       });
 
       // Let's open a tab and load content.
       let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
       gBrowser.selectedTab = tab;
 
@@ -128,17 +130,17 @@ this.CookiePolicyHelper = {
           await runnable(content);
 
           let ifr = content.document.getElementById("iframe");
           await runnable(ifr.contentWindow);
         }
       );
 
       // Now, let's change the cookie settings
-      Services.perms.add(uri, "cookie", config.toPermission);
+      PermissionTestUtils.add(TEST_DOMAIN, "cookie", config.toPermission);
       await SpecialPowers.pushPrefEnv({
         set: [["network.cookie.cookieBehavior", config.toBehavior]],
       });
 
       // We still want the good callback to succeed.
       info(
         "Executing the test after setting the cookie behavior to " +
           config.toBehavior +
--- a/netwerk/test/unit/test_bug767025.js
+++ b/netwerk/test/unit/test_bug767025.js
@@ -1,11 +1,14 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 
 const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 /**
  * This is testcase do following steps to make sure bug767025 removing
  * files as expection.
  *
  * STEPS:
  *  - Schedule a offline cache update for app.manifest.
  *    - pages/foo1, pages/foo2, pages/foo3, and pages/foo4 are cached.
@@ -102,17 +105,17 @@ function clean_app_cache() {
   storage.asyncEvictStorage(null);
 }
 
 function do_app_cache(manifestURL, pageURL) {
   let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID].getService(
     Ci.nsIOfflineCacheUpdateService
   );
 
-  Services.perms.add(
+  PermissionTestUtils.add(
     manifestURL,
     "offline-app",
     Ci.nsIPermissionManager.ALLOW_ACTION
   );
 
   let update = update_service.scheduleUpdate(
     manifestURL,
     pageURL,
--- a/netwerk/test/unit/test_pinned_app_cache.js
+++ b/netwerk/test/unit/test_pinned_app_cache.js
@@ -26,16 +26,19 @@
  *     - The offline cache storage has only enough space for one
  *       additional page.  But, this is a pinned request,
  *       nsOfflineCacheService will make more space for this request
  *       by discarding app1 (non-pinned)
  *
  */
 
 const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 // const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID =
   "@mozilla.org/offlinecacheupdate-service;1";
 
 const kManifest1 =
   "CACHE MANIFEST\n" +
@@ -136,17 +139,17 @@ function clean_app_cache() {
   evict_cache_entries("appcache");
 }
 
 function do_app_cache(manifestURL, pageURL, pinned) {
   let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID].getService(
     Ci.nsIOfflineCacheUpdateService
   );
 
-  Services.perms.add(
+  PermissionTestUtils.add(
     manifestURL,
     "pin-app",
     pinned
       ? Ci.nsIPermissionManager.ALLOW_ACTION
       : Ci.nsIPermissionManager.DENY_ACTION
   );
 
   let update = update_service.scheduleUpdate(
--- a/toolkit/components/antitracking/test/browser/browser_allowListSeparationInPrivateAndNormalWindows.js
+++ b/toolkit/components/antitracking/test/browser/browser_allowListSeparationInPrivateAndNormalWindows.js
@@ -10,17 +10,21 @@
 // private windows wouldn't send any blocking notifications as they don't have
 // storage access in the first place.
 
 /* import-globals-from antitracking_head.js */
 
 "use strict";
 add_task(async _ => {
   let uri = Services.io.newURI("https://example.net");
-  Services.perms.add(uri, "trackingprotection-pb", Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    uri,
+    "trackingprotection-pb",
+    Services.perms.ALLOW_ACTION
+  );
 
   registerCleanupFunction(_ => {
     Services.perms.removeAll();
   });
 });
 
 AntiTracking.runTest(
   "Test that we don't honour a private allow list exception in a normal window",
--- a/toolkit/components/antitracking/test/browser/browser_allowPermissionForTracker.js
+++ b/toolkit/components/antitracking/test/browser/browser_allowPermissionForTracker.js
@@ -1,21 +1,21 @@
 // This test works by setting up an exception for the tracker domain, which
 // disables all the anti-tracking tests.
 
 /* import-globals-from antitracking_head.js */
 
 add_task(async _ => {
-  Services.perms.add(
-    Services.io.newURI("https://tracking.example.org"),
+  PermissionTestUtils.add(
+    "https://tracking.example.org",
     "cookie",
     Services.perms.ALLOW_ACTION
   );
-  Services.perms.add(
-    Services.io.newURI("https://tracking.example.com"),
+  PermissionTestUtils.add(
+    "https://tracking.example.com",
     "cookie",
     Services.perms.ALLOW_ACTION
   );
 
   registerCleanupFunction(_ => {
     Services.perms.removeAll();
   });
 });
--- a/toolkit/components/antitracking/test/browser/browser_denyPermissionForTracker.js
+++ b/toolkit/components/antitracking/test/browser/browser_denyPermissionForTracker.js
@@ -1,21 +1,21 @@
 // This test works by setting up an exception for the tracker domain, which
 // disables all the anti-tracking tests.
 
 /* import-globals-from antitracking_head.js */
 
 add_task(async _ => {
-  Services.perms.add(
-    Services.io.newURI("https://tracking.example.org"),
+  PermissionTestUtils.add(
+    "https://tracking.example.org",
     "cookie",
     Services.perms.DENY_ACTION
   );
-  Services.perms.add(
-    Services.io.newURI("https://tracking.example.com"),
+  PermissionTestUtils.add(
+    "https://tracking.example.com",
     "cookie",
     Services.perms.DENY_ACTION
   );
 
   registerCleanupFunction(_ => {
     Services.perms.removeAll();
   });
 });
--- a/toolkit/components/antitracking/test/browser/browser_permissionInNormalWindows.js
+++ b/toolkit/components/antitracking/test/browser/browser_permissionInNormalWindows.js
@@ -8,18 +8,20 @@ AntiTracking.runTest(
   },
 
   // Non blocking callback
   async _ => {
     try {
       let Services = SpecialPowers.Services;
       // We would use TEST_3RD_PARTY_DOMAIN here, except that the variable isn't
       // accessible in the context of the web page...
-      let uri = Services.io.newURI("https://tracking.example.org/");
-      for (let perm of Services.perms.getAllForURI(uri)) {
+      let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+        "https://tracking.example.org/"
+      );
+      for (let perm of Services.perms.getAllForPrincipal(principal)) {
         // Ignore permissions other than storage access
         if (!perm.type.startsWith("3rdPartyStorage^")) {
           continue;
         }
         is(
           perm.expireType,
           Services.perms.EXPIRE_TIME,
           "Permission must expire at a specific time"
--- a/toolkit/components/antitracking/test/browser/browser_permissionInPrivateWindows.js
+++ b/toolkit/components/antitracking/test/browser/browser_permissionInPrivateWindows.js
@@ -8,18 +8,20 @@ AntiTracking.runTest(
   },
 
   // Non blocking callback
   async _ => {
     try {
       let Services = SpecialPowers.Services;
       // We would use TEST_3RD_PARTY_DOMAIN here, except that the variable isn't
       // accessible in the context of the web page...
-      let uri = Services.io.newURI("https://tracking.example.org/");
-      for (let perm of Services.perms.getAllForURI(uri)) {
+      let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+        "https://tracking.example.org/"
+      );
+      for (let perm of Services.perms.getAllForPrincipal(principal)) {
         // Ignore permissions other than storage access
         if (!perm.type.startsWith("3rdPartyStorage^")) {
           continue;
         }
         is(
           perm.expireType,
           Services.perms.EXPIRE_SESSION,
           "Permission must expire at the end of session"
--- a/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
+++ b/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
@@ -237,129 +237,39 @@ async function preparePermissionsFromOth
   info("Faking permissions from other sites");
   let type = "3rdPartyStorage^https://tracking.example.org";
   let permission = Services.perms.ALLOW_ACTION;
   let expireType = Services.perms.EXPIRE_SESSION;
   if (topPage == TEST_TOP_PAGE) {
     // For the first page, don't do anything
   } else if (topPage == TEST_TOP_PAGE_2) {
     // For the second page, only add the permission from the first page
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN),
-      type,
-      permission,
-      expireType,
-      0
-    );
+    PermissionTestUtils.add(TEST_DOMAIN, type, permission, expireType, 0);
   } else if (topPage == TEST_TOP_PAGE_3) {
     // For the third page, add the permissions from the first two pages
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_2),
-      type,
-      permission,
-      expireType,
-      0
-    );
+    PermissionTestUtils.add(TEST_DOMAIN, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_2, type, permission, expireType, 0);
   } else if (topPage == TEST_TOP_PAGE_4) {
     // For the fourth page, add the permissions from the first three pages
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_2),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_3),
-      type,
-      permission,
-      expireType,
-      0
-    );
+    PermissionTestUtils.add(TEST_DOMAIN, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_2, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_3, type, permission, expireType, 0);
   } else if (topPage == TEST_TOP_PAGE_5) {
     // For the fifth page, add the permissions from the first four pages
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_2),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_3),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_4),
-      type,
-      permission,
-      expireType,
-      0
-    );
+    PermissionTestUtils.add(TEST_DOMAIN, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_2, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_3, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_4, type, permission, expireType, 0);
   } else if (topPage == TEST_TOP_PAGE_6) {
     // For the sixth page, add the permissions from the first five pages
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_2),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_3),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_4),
-      type,
-      permission,
-      expireType,
-      0
-    );
-    Services.perms.add(
-      Services.io.newURI(TEST_DOMAIN_5),
-      type,
-      permission,
-      expireType,
-      0
-    );
+    PermissionTestUtils.add(TEST_DOMAIN, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_2, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_3, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_4, type, permission, expireType, 0);
+    PermissionTestUtils.add(TEST_DOMAIN_5, type, permission, expireType, 0);
   } else {
     ok(false, "Unexpected top page: " + topPage);
   }
 }
 
 async function cleanUp() {
   info("Cleaning up.");
   await new Promise(resolve => {
--- a/toolkit/components/antitracking/test/browser/browser_userInteraction.js
+++ b/toolkit/components/antitracking/test/browser/browser_userInteraction.js
@@ -26,17 +26,17 @@ add_task(async function() {
   let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
   gBrowser.selectedTab = tab;
 
   let browser = gBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
 
   let uri = Services.io.newURI(TEST_DOMAIN);
   is(
-    Services.perms.testPermission(uri, "storageAccessAPI"),
+    PermissionTestUtils.testPermission(uri, "storageAccessAPI"),
     Services.perms.UNKNOWN_ACTION,
     "Before user-interaction we don't have a permission"
   );
 
   let promise = TestUtils.topicObserved("perm-changed", (aSubject, aData) => {
     let permission = aSubject.QueryInterface(Ci.nsIPermission);
     return (
       permission.type == "storageAccessAPI" &&
--- a/toolkit/components/antitracking/test/browser/head.js
+++ b/toolkit/components/antitracking/test/browser/head.js
@@ -51,16 +51,20 @@ const BEHAVIOR_REJECT_FOREIGN = Ci.nsICo
 const BEHAVIOR_REJECT_TRACKER = Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER;
 
 requestLongerTimeout(3);
 
 const { UrlClassifierTestUtils } = ChromeUtils.import(
   "resource://testing-common/UrlClassifierTestUtils.jsm"
 );
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/toolkit/components/antitracking/test/browser/antitracking_head.js",
   this
 );
 
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/toolkit/components/antitracking/test/browser/partitionedstorage_head.js",
   this
--- a/toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js
+++ b/toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js
@@ -142,18 +142,23 @@ async function callRequestStorageAccess(
   return [threw, rejected];
 }
 
 async function waitUntilPermission(url, name) {
   await new Promise(resolve => {
     let id = setInterval(_ => {
       let Services = SpecialPowers.Services;
       let uri = Services.io.newURI(url);
+      let principal = Services.scriptSecurityManager.createContentPrincipal(
+        uri,
+        {}
+      );
       if (
-        Services.perms.testPermission(uri, name) == Services.perms.ALLOW_ACTION
+        Services.perms.testPermissionFromPrincipal(principal, name) ==
+        Services.perms.ALLOW_ACTION
       ) {
         clearInterval(id);
         resolve();
       }
     }, 0);
   });
 }
 
@@ -169,16 +174,22 @@ async function interactWithTracker() {
 
   // Wait until the user interaction permission becomes visible in our process
   await waitUntilPermission(window.origin, "storageAccessAPI");
 }
 
 function isOnContentBlockingAllowList() {
   let url = new URL(SpecialPowers.wrap(top).location.href);
   let origin = SpecialPowers.Services.io.newURI("https://" + url.host);
+  let principal = SpecialPowers.Services.scriptSecurityManager.createContentPrincipal(
+    origin,
+    {}
+  );
   let types = ["trackingprotection", "trackingprotection-pb"];
   return types.some(type => {
     return (
-      SpecialPowers.Services.perms.testPermission(origin, type) ==
-      SpecialPowers.Services.perms.ALLOW_ACTION
+      SpecialPowers.Services.perms.testPermissionFromPrincipal(
+        principal,
+        type
+      ) == SpecialPowers.Services.perms.ALLOW_ACTION
     );
   });
 }
--- a/toolkit/components/passwordmgr/test/unit/test_storage_mozStorage.js
+++ b/toolkit/components/passwordmgr/test/unit/test_storage_mozStorage.js
@@ -1,15 +1,19 @@
 /**
  * This test interfaces directly with the mozStorage password storage module,
  * bypassing the normal password manager usage.
  */
 
 /* eslint-disable no-var */
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const ENCTYPE_BASE64 = 0;
 const ENCTYPE_SDR = 1;
 const PERMISSION_SAVE_LOGINS = "login-saving";
 
 // Current schema version used by storage-mozStorage.js. This will need to be
 // kept in sync with the version there (or else the tests fail).
 const CURRENT_SCHEMA = 6;
 
@@ -78,22 +82,24 @@ function getAllDisabledHostsFromPermissi
       disabledHosts.push(perm.principal.URI.prePath);
     }
   }
 
   return disabledHosts;
 }
 
 function setLoginSavingEnabled(origin, enabled) {
-  let uri = Services.io.newURI(origin);
-
   if (enabled) {
-    Services.perms.remove(uri, PERMISSION_SAVE_LOGINS);
+    PermissionTestUtils.remove(origin, PERMISSION_SAVE_LOGINS);
   } else {
-    Services.perms.add(uri, PERMISSION_SAVE_LOGINS, Services.perms.DENY_ACTION);
+    PermissionTestUtils.add(
+      origin,
+      PERMISSION_SAVE_LOGINS,
+      Services.perms.DENY_ACTION
+    );
   }
 }
 
 add_task(async function test_execute() {
   const OUTDIR = OS.Constants.Path.profileDir;
   let testnum = 0;
   let testdesc = "Setup of nsLoginInfo test-users";
 
--- a/toolkit/components/telemetry/tests/browser/browser_HybridContentTelemetry.js
+++ b/toolkit/components/telemetry/tests/browser/browser_HybridContentTelemetry.js
@@ -8,16 +8,19 @@ const { ContentTaskUtils } = ChromeUtils
   "resource://testing-common/ContentTaskUtils.jsm"
 );
 const { TelemetryUtils } = ChromeUtils.import(
   "resource://gre/modules/TelemetryUtils.jsm"
 );
 const { ObjectUtils } = ChromeUtils.import(
   "resource://gre/modules/ObjectUtils.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const HC_PERMISSION = "hc_telemetry";
 
 async function waitForProcessesEvents(
   aProcesses,
   aAdditionalCondition = data => true
 ) {
   await ContentTaskUtils.waitForCondition(() => {
@@ -90,17 +93,21 @@ add_task(async function test_untrusted_h
   // and makes the test fail. We don't expect any message from non secure contexts.
   const messageName = "HybridContentTelemetry:onTelemetryMessage";
   let makeTestFail = () => ok(false, `Received an unexpected ${messageName}.`);
   Services.mm.addMessageListener(messageName, makeTestFail);
 
   // Try to use the API on a non-secure host.
   const testHost = "http://example.org";
   let testHttpUri = Services.io.newURI(testHost);
-  Services.perms.add(testHttpUri, HC_PERMISSION, Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    testHttpUri,
+    HC_PERMISSION,
+    Services.perms.ALLOW_ACTION
+  );
   let url = getRootDirectory(gTestPath) + "hybrid_content.html";
   url = url.replace("chrome://mochitests/content", testHost);
   let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
 
   // Try to use the API. Also record a content event from outside HCT: we'll
   // use this event to know when we can stop waiting for the hybrid content data.
   const TEST_CONTENT_EVENT = ["telemetry.test", "main_and_content", "object1"];
   Services.telemetry.setEventRecordingEnabled("telemetry.test", true);
@@ -122,17 +129,17 @@ add_task(async function test_untrusted_h
     : "parent";
   await waitForEvent(processName, TEST_CONTENT_EVENT);
 
   // This is needed otherwise the test will fail due to missing test passes.
   ok(true, "The untrusted HTTP page was not able to use the API.");
 
   // Finally clean up the listener.
   BrowserTestUtils.removeTab(newTab);
-  Services.perms.remove(testHttpUri, HC_PERMISSION);
+  PermissionTestUtils.remove(testHttpUri, HC_PERMISSION);
   Services.mm.removeMessageListener(messageName, makeTestFail);
   Services.telemetry.setEventRecordingEnabled("telemetry.test", false);
 });
 
 add_task(async function test_secure_unallowed_origin() {
   Services.telemetry.clearEvents();
 
   // Install a custom handler that intercepts hybrid content telemetry messages
@@ -190,17 +197,21 @@ add_task(async function test_trusted_dis
   // and makes the test fail. We don't expect any message when the API is disabled.
   const messageName = "HybridContentTelemetry:onTelemetryMessage";
   let makeTestFail = () => ok(false, `Received an unexpected ${messageName}.`);
   Services.mm.addMessageListener(messageName, makeTestFail);
 
   // Try to use the API on a secure host.
   const testHost = "https://example.org";
   let testHttpsUri = Services.io.newURI(testHost);
-  Services.perms.add(testHttpsUri, HC_PERMISSION, Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    testHttpsUri,
+    HC_PERMISSION,
+    Services.perms.ALLOW_ACTION
+  );
   let url = getRootDirectory(gTestPath) + "hybrid_content.html";
   url = url.replace("chrome://mochitests/content", testHost);
   let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
 
   // Try to use the API. Also record a content event from outside HCT: we'll
   // use this event to know when we can stop waiting for the hybrid content data.
   const TEST_CONTENT_EVENT = ["telemetry.test", "main_and_content", "object1"];
   Services.telemetry.setEventRecordingEnabled("telemetry.test", true);
@@ -223,28 +234,32 @@ add_task(async function test_trusted_dis
   await waitForEvent(processName, TEST_CONTENT_EVENT);
 
   // This is needed otherwise the test will fail due to missing test passes.
   ok(true, "There were no unintended hybrid content API usages.");
 
   // Finally clean up the listener.
   await SpecialPowers.popPrefEnv();
   BrowserTestUtils.removeTab(newTab);
-  Services.perms.remove(testHttpsUri, HC_PERMISSION);
+  PermissionTestUtils.remove(testHttpsUri, HC_PERMISSION);
   Services.mm.removeMessageListener(messageName, makeTestFail);
   Services.telemetry.setEventRecordingEnabled("telemetry.test", false);
 });
 
 add_task(async function test_hybrid_content_with_iframe() {
   Services.telemetry.clearEvents();
 
   // Open a trusted page that can use in the HCT in a new tab.
   const testOuterPageHost = "https://example.com";
   let testHttpsUri = Services.io.newURI(testOuterPageHost);
-  Services.perms.add(testHttpsUri, HC_PERMISSION, Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    testHttpsUri,
+    HC_PERMISSION,
+    Services.perms.ALLOW_ACTION
+  );
   let url = getRootDirectory(gTestPath) + "hybrid_content.html";
   let outerUrl = url.replace("chrome://mochitests/content", testOuterPageHost);
   let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, outerUrl);
 
   // Install a custom handler that intercepts hybrid content telemetry messages
   // and makes the test fail. This needs to be done after the tab is opened.
   const messageName = "HybridContentTelemetry:onTelemetryMessage";
   let makeTestFail = () => ok(false, `Received an unexpected ${messageName}.`);
@@ -292,17 +307,17 @@ add_task(async function test_hybrid_cont
   ok(
     true,
     "There were no unintended hybrid content API usages from the iframe."
   );
 
   // Cleanup permissions and remove the tab.
   BrowserTestUtils.removeTab(newTab);
   Services.mm.removeMessageListener(messageName, makeTestFail);
-  Services.perms.remove(testHttpsUri, HC_PERMISSION);
+  PermissionTestUtils.remove(testHttpsUri, HC_PERMISSION);
   Services.telemetry.setEventRecordingEnabled("telemetry.test", false);
 });
 
 add_task(async function test_hybrid_content_recording() {
   const testHost = "https://example.org";
   const TEST_EVENT_CATEGORY = "telemetry.test.hct";
   const RECORDED_TEST_EVENTS = [
     [TEST_EVENT_CATEGORY, "test1", "object1"],
@@ -320,17 +335,21 @@ add_task(async function test_hybrid_cont
   const NON_RECORDED_TEST_EVENTS = [
     [TEST_EVENT_CATEGORY, "unknown", "unknown"],
   ];
 
   Services.telemetry.clearEvents();
 
   // Give the test host enough privileges to use the API and open the test page.
   let testHttpsUri = Services.io.newURI(testHost);
-  Services.perms.add(testHttpsUri, HC_PERMISSION, Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    testHttpsUri,
+    HC_PERMISSION,
+    Services.perms.ALLOW_ACTION
+  );
   let url = getRootDirectory(gTestPath) + "hybrid_content.html";
   url = url.replace("chrome://mochitests/content", testHost);
   let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
 
   // Register some events and record them in Telemetry.
   await ContentTask.spawn(
     newTab.linkedBrowser,
     [TEST_EVENT_CATEGORY, RECORDED_TEST_EVENTS, NON_RECORDED_TEST_EVENTS],
@@ -393,29 +412,33 @@ add_task(async function test_hybrid_cont
       dynamicEvents[i],
       removeTrailingInvalidEntry(RECORDED_TEST_EVENTS[i]),
       "Should have recorded the expected event."
     );
   }
 
   // Cleanup permissions and remove the tab.
   BrowserTestUtils.removeTab(newTab);
-  Services.perms.remove(testHttpsUri, HC_PERMISSION);
+  PermissionTestUtils.remove(testHttpsUri, HC_PERMISSION);
 });
 
 add_task(async function test_can_upload() {
   const testHost = "https://example.org";
 
   await SpecialPowers.pushPrefEnv({
     set: [[TelemetryUtils.Preferences.FhrUploadEnabled, true]],
   });
 
   // Give the test host enough privileges to use the API and open the test page.
   let testHttpsUri = Services.io.newURI(testHost);
-  Services.perms.add(testHttpsUri, HC_PERMISSION, Services.perms.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    testHttpsUri,
+    HC_PERMISSION,
+    Services.perms.ALLOW_ACTION
+  );
   let url = getRootDirectory(gTestPath) + "hybrid_content.html";
   url = url.replace("chrome://mochitests/content", testHost);
   let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
 
   // Check that CanUpload reports the correct value.
   await ContentTask.spawn(newTab.linkedBrowser, {}, async function() {
     let contentWin = Cu.waiveXrays(content);
 
@@ -440,24 +463,27 @@ add_task(async function test_can_upload(
     ok(
       !canUpload,
       "CanUpload must report 'false' if the preference has that value."
     );
   });
 
   // Cleanup permissions and remove the tab.
   BrowserTestUtils.removeTab(newTab);
-  Services.perms.remove(testHttpsUri, HC_PERMISSION);
+  PermissionTestUtils.remove(testHttpsUri, HC_PERMISSION);
 });
 
 add_task(async function test_hct_for_discopane() {
   const discoHost = "https://discovery.addons.mozilla.org";
 
   let discoHttpsUri = Services.io.newURI(discoHost);
-  let permission = Services.perms.testPermission(discoHttpsUri, HC_PERMISSION);
+  let permission = PermissionTestUtils.testPermission(
+    discoHttpsUri,
+    HC_PERMISSION
+  );
 
   ok(
     permission == Services.perms.ALLOW_ACTION,
     "Disco Pane needs Hybrid Content Permission for Telemetry data upload"
   );
 });
 
 add_task(async function test_init_rejects() {
@@ -491,17 +517,17 @@ add_task(async function test_init_reject
       let canUpload = contentWin.Mozilla.ContentTelemetry.canUpload();
       ok(!canUpload, "CanUpload must report 'false' if init failed.");
     }
   );
 
   // Give the test host HCT privileges and test that init doesn't throw.
   const testHostPrivileges = "https://example.com";
   let testUrlPrivileges = Services.io.newURI(testHostPrivileges);
-  Services.perms.add(
+  PermissionTestUtils.add(
     testUrlPrivileges,
     HC_PERMISSION,
     Services.perms.ALLOW_ACTION
   );
   let urlWithPrivs = getRootDirectory(gTestPath) + "hybrid_content.html";
   urlWithPrivs = urlWithPrivs.replace(
     "chrome://mochitests/content",
     testHostPrivileges
@@ -529,10 +555,10 @@ add_task(async function test_init_reject
     }
   );
 
   await Promise.all([page1Promise, page2Promise]);
 
   // Cleanup permissions and remove the tab.
   BrowserTestUtils.removeTab(newTab);
   BrowserTestUtils.removeTab(otherTab);
-  Services.perms.remove(testUrlPrivileges, HC_PERMISSION);
+  PermissionTestUtils.remove(testUrlPrivileges, HC_PERMISSION);
 });
--- a/toolkit/modules/tests/xpcshell/test_PermissionsUtils.js
+++ b/toolkit/modules/tests/xpcshell/test_PermissionsUtils.js
@@ -8,16 +8,19 @@
 //       converted into permissions on startup.
 
 const PREF_ROOT = "testpermissions.";
 const TEST_PERM = "test-permission";
 
 const { PermissionsUtils } = ChromeUtils.import(
   "resource://gre/modules/PermissionsUtils.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 function run_test() {
   test_importfromPrefs();
 }
 
 function test_importfromPrefs() {
   // Create own preferences to test
   Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.EMPTY", "");
@@ -74,17 +77,17 @@ function test_importfromPrefs() {
     "http://blacklist2-1.example.com",
     "https://whitelist2-2.example.com:8080",
     "https://blacklist2-2.example.com:8080",
   ];
   let unknown = whitelisted.concat(blacklisted).concat(untouched);
   for (let url of unknown) {
     let uri = Services.io.newURI(url);
     Assert.equal(
-      Services.perms.testPermission(uri, TEST_PERM),
+      PermissionTestUtils.testPermission(uri, TEST_PERM),
       Services.perms.UNKNOWN_ACTION
     );
   }
 
   // Import them
   PermissionsUtils.importFromPrefs(PREF_ROOT, TEST_PERM);
 
   // Get list of preferences to check
@@ -94,27 +97,27 @@ function test_importfromPrefs() {
   for (let pref of preferences) {
     Assert.equal(Services.prefs.getCharPref(pref), "");
   }
 
   // Check they were imported into the permissions manager
   for (let url of whitelisted) {
     let uri = Services.io.newURI(url);
     Assert.equal(
-      Services.perms.testPermission(uri, TEST_PERM),
+      PermissionTestUtils.testPermission(uri, TEST_PERM),
       Services.perms.ALLOW_ACTION
     );
   }
   for (let url of blacklisted) {
     let uri = Services.io.newURI(url);
     Assert.equal(
-      Services.perms.testPermission(uri, TEST_PERM),
+      PermissionTestUtils.testPermission(uri, TEST_PERM),
       Services.perms.DENY_ACTION
     );
   }
   for (let url of untouched) {
     let uri = Services.io.newURI(url);
     Assert.equal(
-      Services.perms.testPermission(uri, TEST_PERM),
+      PermissionTestUtils.testPermission(uri, TEST_PERM),
       Services.perms.UNKNOWN_ACTION
     );
   }
 }
--- a/toolkit/modules/tests/xpcshell/test_web_channel.js
+++ b/toolkit/modules/tests/xpcshell/test_web_channel.js
@@ -1,16 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { WebChannel } = ChromeUtils.import(
   "resource://gre/modules/WebChannel.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const ERROR_ID_ORIGIN_REQUIRED =
   "WebChannel id and originOrPermission are required.";
 const VALID_WEB_CHANNEL_ID = "id";
 const URL_STRING = "http://example.com";
 const VALID_WEB_CHANNEL_ORIGIN = Services.io.newURI(URL_STRING);
 const TEST_PERMISSION_NAME = "test-webchannel-permissions";
 
@@ -88,23 +91,23 @@ add_task(function test_web_channel_liste
 });
 
 /**
  * Test channel listening with originOrPermission being a permission string.
  */
 add_task(function test_web_channel_listen_permission() {
   return new Promise((resolve, reject) => {
     // add a new permission
-    Services.perms.add(
+    PermissionTestUtils.add(
       VALID_WEB_CHANNEL_ORIGIN,
       TEST_PERMISSION_NAME,
       Services.perms.ALLOW_ACTION
     );
     registerCleanupFunction(() =>
-      Services.perms.remove(VALID_WEB_CHANNEL_ORIGIN, TEST_PERMISSION_NAME)
+      PermissionTestUtils.remove(VALID_WEB_CHANNEL_ORIGIN, TEST_PERMISSION_NAME)
     );
     let channel = new WebChannel(VALID_WEB_CHANNEL_ID, TEST_PERMISSION_NAME, {
       broker: MockWebChannelBroker,
     });
     let delivered = 0;
     Assert.equal(channel.id, VALID_WEB_CHANNEL_ID);
     Assert.equal(channel._originOrPermission, TEST_PERMISSION_NAME);
     Assert.equal(channel._deliverCallback, null);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_permissions.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_permissions.js
@@ -1,15 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Checks that permissions set in preferences are correctly imported but can
 // be removed by the user.
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const XPI_MIMETYPE = "application/x-xpinstall";
 
 function newPrincipal(uri) {
   return Services.scriptSecurityManager.createContentPrincipal(
     NetUtil.newURI(uri),
     {}
   );
 }
@@ -25,18 +29,18 @@ add_task(async function setup() {
     "xpinstall.whitelist.add.36",
     "https://test3.com,https://www.test4.com"
   );
   Services.prefs.setCharPref(
     "xpinstall.whitelist.add.test5",
     "https://test5.com"
   );
 
-  Services.perms.add(
-    NetUtil.newURI("https://www.test9.com"),
+  PermissionTestUtils.add(
+    "https://www.test9.com",
     "install",
     Ci.nsIPermissionManager.ALLOW_ACTION
   );
 
   await promiseStartupManager();
 
   Assert.ok(
     !AddonManager.isInstallAllowed(
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger.js
@@ -3,18 +3,21 @@
 // content.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         IconURL: TESTROOT + "icon.png",
         toString() {
           return this.URL;
@@ -41,17 +44,17 @@ function install_ended(install, addon) {
     "Got the expected install.installTelemetryInfo"
   );
   install.cancel();
 }
 
 const finish_test = async function(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger_iframe.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger_iframe.js
@@ -4,18 +4,21 @@
 
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var inner_url = encodeURIComponent(
     TESTROOT +
       "installtrigger.html?" +
       encodeURIComponent(
         JSON.stringify({
           "Unsigned XPI": {
             URL: TESTROOT + "amosigned.xpi",
@@ -41,17 +44,17 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 const finish_test = async function(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.frames[0].document.getElementById("return").textContent,
         status: content.frames[0].document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js
@@ -11,18 +11,21 @@ function test() {
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   Services.prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI":
         TESTROOT + "authRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
@@ -46,17 +49,17 @@ function install_ended(install, addon) {
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
   var authMgr = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
     Ci.nsIHttpAuthManager
   );
   authMgr.clearAll();
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   Services.prefs.clearUserPref(
     "network.auth.non-web-content-triggered-resources-http-auth-allow"
   );
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth2.js
@@ -11,18 +11,21 @@ function test() {
 
   requestLongerTimeout(2);
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI":
         TESTROOT + "authRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
@@ -51,17 +54,17 @@ function install_ended(install, addon) {
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   var authMgr = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
     Ci.nsIHttpAuthManager
   );
   authMgr.clearAll();
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   Services.prefs.clearUserPref(
     "network.auth.non-web-content-triggered-resources-http-auth-allow"
   );
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
@@ -10,18 +10,21 @@ function test() {
   );
 
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI":
         TESTROOT + "authRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
@@ -50,17 +53,17 @@ function install_ended(install, addon) {
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   var authMgr = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
     Ci.nsIHttpAuthManager
   );
   authMgr.clearAll();
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   Services.prefs.clearUserPref(
     "network.auth.non-web-content-triggered-resources-http-auth-allow"
   );
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
@@ -9,18 +9,21 @@ function test() {
   );
 
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI":
         TESTROOT + "authRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gNewTab = BrowserTestUtils.addTab(gBrowser);
@@ -49,17 +52,17 @@ function install_ended(install, addon) {
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
   var authMgr = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
     Ci.nsIHttpAuthManager
   );
   authMgr.clearAll();
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   Services.prefs.clearUserPref(
     "network.auth.non-web-content-triggered-resources-http-auth-allow"
   );
 
   gBrowser.removeTab(gNewTab);
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_badhash.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_badhash.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when an invalid hash is included
 // This verifies bug 302284
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         Hash: "sha1:643b08418599ddbd1ea8a511c90696578fb844b9",
         toString() {
           return this.URL;
@@ -28,13 +31,13 @@ function test() {
 }
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_INCORRECT_HASH, "Install should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com/"), "install");
+  PermissionTestUtils.remove("http://example.com/", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_badhashtype.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_badhashtype.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when an unknown hash type is included
 // This verifies bug 302284
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         Hash: "foo:3d0dc22e1f394e159b08aaf5f0f97de4d5c65f4f",
         toString() {
           return this.URL;
@@ -28,13 +31,13 @@ function test() {
 }
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_INCORRECT_HASH, "Install should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com/"), "install");
+  PermissionTestUtils.remove("http://example.com/", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug540558.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug540558.js
@@ -1,25 +1,28 @@
 // ----------------------------------------------------------------------------
 // Tests that calling InstallTrigger.installChrome works
 function test() {
   Harness.installEndedCallback = check_xpi_install;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(gBrowser, TESTROOT + "bug540558.html");
 }
 
 function check_xpi_install(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
@@ -3,18 +3,21 @@
 // content. This should be blocked by the whitelist check.
 // This verifies bug 645699
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installBlockedCallback = allow_blocked;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.org/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.org/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(gBrowser, TESTROOT + "bug645699.html");
 }
 
 function allow_blocked(installInfo) {
   is(
     installInfo.browser,
@@ -31,14 +34,14 @@ function allow_blocked(installInfo) {
 
 function confirm_install(panel) {
   ok(false, "Should not see the install dialog");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "0 Add-ons should have been successfully installed");
-  Services.perms.remove(makeURI("http://addons.mozilla.org"), "install");
+  PermissionTestUtils.remove("http://addons.mozilla.org", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
 // ----------------------------------------------------------------------------
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js
@@ -10,18 +10,21 @@ function test() {
   Harness.installEndedCallback = complete_install;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   gWindowWatcher = Services.ww;
   delete Services.ww;
   is(Services.ww, undefined, "Services.ww should now be undefined");
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
@@ -46,12 +49,12 @@ function complete_install() {
 
 function finish_test(count) {
   is(count, 0, "0 Add-ons should have been successfully installed");
 
   gBrowser.removeCurrentTab();
 
   Services.ww = gWindowWatcher;
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_containers.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_containers.js
@@ -24,18 +24,21 @@ function check_channel(subject) {
 // Tests we send the right cookies when installing through an InstallTrigger call
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         IconURL: TESTROOT + "icon.png",
         toString() {
           return this.URL;
@@ -71,17 +74,17 @@ const finish_test = async function(count
   ok(
     gDidSeeChannel,
     "Should have seen the request for the XPI and verified it was sent the right way."
   );
   is(count, 1, "1 Add-on should have been successfully installed");
 
   Services.obs.removeObserver(check_channel, "http-on-before-connect");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_cookies.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_cookies.js
@@ -2,18 +2,21 @@
 // Test that an install that requires cookies to be sent fails when no cookies
 // are set
 // This verifies bug 462739
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Cookie check":
         TESTROOT + "cookieRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
@@ -24,13 +27,13 @@ function test() {
 }
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_NETWORK_FAILURE, "Install should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_cookies2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_cookies2.js
@@ -15,18 +15,21 @@ function test() {
     false,
     false,
     true,
     Date.now() / 1000 + 60,
     {},
     Ci.nsICookie.SAMESITE_NONE
   );
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Cookie check":
         TESTROOT + "cookieRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
@@ -46,13 +49,13 @@ function finish_test(count) {
   Services.cookies.remove(
     "example.com",
     "xpinstall",
     "/browser/" + RELATIVE_DIR,
     false,
     {}
   );
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_cookies3.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_cookies3.js
@@ -15,18 +15,21 @@ function test() {
     false,
     false,
     true,
     Date.now() / 1000 + 60,
     {},
     Ci.nsICookie.SAMESITE_NONE
   );
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 1);
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Cookie check":
         TESTROOT + "cookieRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
@@ -50,13 +53,13 @@ function finish_test(count) {
     "xpinstall",
     "/browser/" + RELATIVE_DIR,
     false,
     {}
   );
 
   Services.prefs.clearUserPref("network.cookie.cookieBehavior");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js
@@ -16,18 +16,21 @@ function test() {
     false,
     false,
     true,
     Date.now() / 1000 + 60,
     {},
     Ci.nsICookie.SAMESITE_NONE
   );
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 1);
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Cookie check":
         TESTROOT2 + "cookieRedirect.sjs?" + TESTROOT + "amosigned.xpi",
     })
@@ -50,13 +53,13 @@ function finish_test(count) {
     "example.org",
     "xpinstall",
     "/browser/" + RELATIVE_DIR,
     false,
     {}
   );
 
   Services.prefs.clearUserPref("network.cookie.cookieBehavior");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when the xpi is corrupt.
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Corrupt XPI": TESTROOT + "corrupt.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
@@ -22,17 +25,17 @@ function test() {
 }
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_CORRUPT_FILE, "Install should fail");
 }
 
 const finish_test = async function(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_datauri.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_datauri.js
@@ -48,14 +48,14 @@ function install_blocked(installInfo) {
     installInfo.installs[0].installTelemetryInfo,
     { source: "unknown", method: "link" },
     "Got the expected install.installTelemetryInfo"
   );
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
   finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
@@ -417,17 +417,17 @@ var TESTS = [
     await TestUtils.waitForCondition(
       () => !PopupNotifications.isPanelOpen,
       "Waiting for notification to close"
     );
 
     let installs = await AddonManager.getAllInstalls();
     is(installs.length, 0, "Should be no pending installs");
 
-    let installPerm = Services.perms.testPermission(
+    let installPerm = PermissionTestUtils.testPermission(
       gBrowser.currentURI,
       "install"
     );
     is(
       installPerm,
       Ci.nsIPermissionManager.DENY_ACTION,
       "Addon installation should be blocked for site"
     );
@@ -475,18 +475,21 @@ var TESTS = [
   async function test_whitelistedInstall() {
     Services.prefs.setBoolPref(
       "extensions.allowPrivateBrowsingByDefault",
       false
     );
     let originalTab = gBrowser.selectedTab;
     let tab;
     gBrowser.selectedTab = originalTab;
-    let pm = Services.perms;
-    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    PermissionTestUtils.add(
+      "http://example.com/",
+      "install",
+      Services.perms.ALLOW_ACTION
+    );
 
     let progressPromise = waitForProgressNotification();
     let dialogPromise = waitForInstallDialog();
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "amosigned.xpi",
       })
     );
@@ -527,25 +530,28 @@ var TESTS = [
     let policy = WebExtensionPolicy.getByID(addon.id);
     ok(
       !policy.privateBrowsingAllowed,
       "private browsing permission was not granted"
     );
 
     addon.uninstall();
 
-    Services.perms.remove(makeURI("http://example.com/"), "install");
+    PermissionTestUtils.remove("http://example.com/", "install");
 
     Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
     await removeTabAndWaitForNotificationClose();
   },
 
   async function test_failedDownload() {
-    let pm = Services.perms;
-    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    PermissionTestUtils.add(
+      "http://example.com/",
+      "install",
+      Services.perms.ALLOW_ACTION
+    );
 
     let progressPromise = waitForProgressNotification();
     let failPromise = waitForNotification("addon-install-failed");
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "missing.xpi",
       })
     );
@@ -558,23 +564,26 @@ var TESTS = [
 
     let notification = panel.childNodes[0];
     is(
       notification.getAttribute("label"),
       "The add-on could not be downloaded because of a connection failure.",
       "Should have seen the right message"
     );
 
-    Services.perms.remove(makeURI("http://example.com/"), "install");
+    PermissionTestUtils.remove("http://example.com/", "install");
     await removeTabAndWaitForNotificationClose();
   },
 
   async function test_corruptFile() {
-    let pm = Services.perms;
-    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    PermissionTestUtils.add(
+      "http://example.com/",
+      "install",
+      Services.perms.ALLOW_ACTION
+    );
 
     let progressPromise = waitForProgressNotification();
     let failPromise = waitForNotification("addon-install-failed");
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "corrupt.xpi",
       })
     );
@@ -588,23 +597,26 @@ var TESTS = [
     let notification = panel.childNodes[0];
     is(
       notification.getAttribute("label"),
       "The add-on downloaded from this site could not be installed " +
         "because it appears to be corrupt.",
       "Should have seen the right message"
     );
 
-    Services.perms.remove(makeURI("http://example.com/"), "install");
+    PermissionTestUtils.remove("http://example.com/", "install");
     await removeTabAndWaitForNotificationClose();
   },
 
   async function test_incompatible() {
-    let pm = Services.perms;
-    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    PermissionTestUtils.add(
+      "http://example.com/",
+      "install",
+      Services.perms.ALLOW_ACTION
+    );
 
     let progressPromise = waitForProgressNotification();
     let failPromise = waitForNotification("addon-install-failed");
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "incompatible.xpi",
       })
     );
@@ -624,17 +636,17 @@ var TESTS = [
       Services.appinfo.version
     }.`;
     is(
       notification.getAttribute("label"),
       message,
       "Should have seen the right message"
     );
 
-    Services.perms.remove(makeURI("http://example.com/"), "install");
+    PermissionTestUtils.remove("http://example.com/", "install");
     await removeTabAndWaitForNotificationClose();
   },
 
   async function test_localFile() {
     let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
       Ci.nsIChromeRegistry
     );
     let path;
@@ -802,18 +814,21 @@ var TESTS = [
 
     await removeTabAndWaitForNotificationClose(gBrowser.selectedTab);
 
     installs = await AddonManager.getAllInstalls();
     is(installs.length, 0, "Should have cancelled the installs");
   },
 
   async function test_cancel() {
-    let pm = Services.perms;
-    pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+    PermissionTestUtils.add(
+      "http://example.com/",
+      "install",
+      Services.perms.ALLOW_ACTION
+    );
 
     let notificationPromise = waitForNotification(PROGRESS_NOTIFICATION);
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "slowinstall.sjs?file=amosigned.xpi",
       })
     );
     BrowserTestUtils.openNewForegroundTab(
@@ -857,17 +872,17 @@ var TESTS = [
 
     await new Promise(resolve => executeSoon(resolve));
 
     ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
 
     let installs = await AddonManager.getAllInstalls();
     is(installs.length, 0, "Should be no pending install");
 
-    Services.perms.remove(makeURI("http://example.com/"), "install");
+    PermissionTestUtils.remove("http://example.com/", "install");
     BrowserTestUtils.removeTab(gBrowser.selectedTab);
   },
 
   async function test_failedSecurity() {
     Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
     setupRedirect({
       Location: TESTROOT + "amosigned.xpi",
     });
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_empty.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_empty.js
@@ -1,17 +1,20 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when there is no install script present.
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Empty XPI": TESTROOT + "empty.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
@@ -21,13 +24,13 @@ function test() {
 }
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_CORRUPT_FILE, "Install should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test whether an install succeeds when a valid hash is included
 // This verifies bug 302284
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         Hash: "sha1:ee95834ad862245a9ef99ccecc2a857cadc16404",
         toString() {
           return this.URL;
@@ -29,13 +32,13 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test whether an install succeeds using case-insensitive hashes
 // This verifies bug 603021
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         Hash: "sha1:EE95834AD862245A9EF99CCECC2A857CADC16404",
         toString() {
           return this.URL;
@@ -29,13 +32,13 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js
@@ -2,18 +2,21 @@
 // Test whether an install succeeds when a valid hash is included in the HTTPS
 // request
 // This verifies bug 591070
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
   Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
 
   var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url +=
     "?sha1:ee95834ad862245a9ef99ccecc2a857cadc16404|" +
     TESTROOT +
     "amosigned.xpi";
 
@@ -36,14 +39,14 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
   Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash2.js
@@ -2,18 +2,21 @@
 // Test whether an install fails when a invalid hash is included in the HTTPS
 // request
 // This verifies bug 591070
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
   Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
 
   var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi";
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
@@ -33,14 +36,14 @@ function test() {
 
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_INCORRECT_HASH, "Download should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "0 Add-ons should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
   Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Tests that the HTTPS hash is ignored when InstallTrigger is passed a hash.
 // This verifies bug 591070
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
   Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
 
   var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi";
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
@@ -33,14 +36,14 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
   Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash4.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test that hashes are ignored in the headers of HTTP requests
 // This verifies bug 591070
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var url = "http://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi";
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: url,
@@ -31,13 +34,13 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js
@@ -1,18 +1,21 @@
 // ----------------------------------------------------------------------------
 // Test that only the first HTTPS hash is used
 // This verifies bug 591070
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
   Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
 
   var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url += "?sha1:ee95834ad862245a9ef99ccecc2a857cadc16404|";
   url += "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs";
   url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi";
 
   var triggers = encodeURIComponent(
@@ -34,14 +37,14 @@ function test() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
   Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js
@@ -15,18 +15,21 @@ function setup_redirect(aSettings) {
 
 var gInstall = null;
 
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_failed_download;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
   Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
 
   // Set up the redirect to give a bad hash
   setup_redirect({
     "X-Target-Digest": "sha1:foo",
     Location: "http://example.com/browser/" + RELATIVE_DIR + "amosigned.xpi",
   });
 
@@ -88,14 +91,14 @@ function finish_failed_download() {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
   Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_installchrome.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_installchrome.js
@@ -1,30 +1,33 @@
 // ----------------------------------------------------------------------------
 // Tests that calling InstallTrigger.installChrome works
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
     gBrowser,
     TESTROOT +
       "installchrome.html? " +
       encodeURIComponent(TESTROOT + "amosigned.xpi")
   );
 }
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_newwindow.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_newwindow.js
@@ -12,18 +12,17 @@ async function test() {
   Harness.installEndedCallback = install => {
     install.cancel();
   };
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   win = await BrowserTestUtils.openNewBrowserWindow();
   Harness.setup(win);
 
-  const pm = Services.perms;
-  pm.add(exampleURI, "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(exampleURI, "install", Services.perms.ALLOW_ACTION);
 
   const triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         IconURL: TESTROOT + "icon.png",
       },
     })
@@ -40,17 +39,17 @@ async function test() {
 function confirm_install(panel) {
   is(panel.getAttribute("name"), "XPI Test", "Should have seen the name");
   return true;
 }
 
 async function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(exampleURI, "install");
+  PermissionTestUtils.remove(exampleURI, "install");
 
   const results = await ContentTask.spawn(
     win.gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js
@@ -2,18 +2,21 @@ var proxyPrefValue;
 
 // ----------------------------------------------------------------------------
 // Tests that going offline cancels an in progress download.
 function test() {
   Harness.downloadProgressCallback = download_progress;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
@@ -54,12 +57,12 @@ function finish_test(count) {
   }
 
   is(count, 0, "No add-ons should have been installed");
   try {
     Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
     Services.io.offline = false;
   } catch (ex) {}
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   wait_for_online();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_privatebrowsing.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_privatebrowsing.js
@@ -27,18 +27,21 @@ async function test() {
   waitForExplicitFinish(); // have to call this ourselves because we're async.
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   gPrivateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
   Harness.setup(gPrivateWin);
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "amosigned.xpi",
         IconURL: TESTROOT + "icon.png",
         toString() {
           return this.URL;
@@ -78,17 +81,17 @@ const finish_test = async function(count
   ok(
     gDidSeeChannel,
     "Should have seen the request for the XPI and verified it was sent the right way."
   );
   is(count, 1, "1 Add-on should have been successfully installed");
 
   Services.obs.removeObserver(check_channel, "http-on-before-connect");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gPrivateWin.gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_relative.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_relative.js
@@ -2,18 +2,21 @@
 // Tests that InstallTrigger deals with relative urls correctly.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: "amosigned.xpi",
         IconURL: "icon.png",
         toString() {
           return this.URL;
@@ -35,17 +38,17 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 const finish_test = async function(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_signed_trigger.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_signed_trigger.js
@@ -2,18 +2,21 @@
 // Tests installing an signed add-on through an InstallTrigger call in web
 // content.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Signed XPI": TESTROOT + "amosigned.xpi",
     })
   );
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
@@ -29,13 +32,13 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_softwareupdate.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_softwareupdate.js
@@ -1,30 +1,33 @@
 // ----------------------------------------------------------------------------
 // Tests that calling InstallTrigger.startSoftwareUpdate works
 function test() {
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(
     gBrowser,
     TESTROOT +
       "startsoftwareupdate.html? " +
       encodeURIComponent(TESTROOT + "amosigned.xpi")
   );
 }
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js
@@ -2,18 +2,21 @@
 // Tests that the InstallTrigger callback can redirect to a relative url.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.loadURI(gBrowser, TESTROOT + "triggerredirect.html");
 }
 
 function confirm_install(panel) {
   is(panel.getAttribute("name"), "XPI Test", "Should have seen the name");
   return true;
@@ -21,17 +24,17 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 function finish_test(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   is(
     gBrowser.currentURI.spec,
     TESTROOT + "triggerredirect.html#foo",
     "Should have redirected"
   );
 
   gBrowser.removeCurrentTab();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js
@@ -3,18 +3,21 @@
 // content.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var triggers = encodeURIComponent(
     JSON.stringify({
       "Unsigned XPI": {
         URL: TESTROOT + "unsigned.xpi",
         IconURL: TESTROOT + "icon.png",
         toString() {
           return this.URL;
@@ -36,17 +39,17 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 const finish_test = async function(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.document.getElementById("return").textContent,
         status: content.document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js
@@ -4,18 +4,21 @@
 
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var inner_url = encodeURIComponent(
     TESTROOT +
       "installtrigger.html?" +
       encodeURIComponent(
         JSON.stringify({
           "Unsigned XPI": {
             URL: TESTROOT + "unsigned.xpi",
@@ -41,17 +44,17 @@ function confirm_install(panel) {
 
 function install_ended(install, addon) {
   install.cancel();
 }
 
 const finish_test = async function(count) {
   is(count, 1, "1 Add-on should have been successfully installed");
 
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   const results = await ContentTask.spawn(
     gBrowser.selectedBrowser,
     null,
     () => {
       return {
         return: content.frames[0].document.getElementById("return").textContent,
         status: content.frames[0].document.getElementById("status").textContent,
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js
@@ -4,18 +4,21 @@
 var wasOriginBlocked = false;
 
 function test() {
   Harness.installOriginBlockedCallback = install_blocked;
   Harness.installsCompletedCallback = finish_test;
   Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+  PermissionTestUtils.add(
+    "http://example.com/",
+    "install",
+    Services.perms.ALLOW_ACTION
+  );
 
   var inner_url = encodeURIComponent(
     TESTROOT +
       "installtrigger.html?" +
       encodeURIComponent(
         JSON.stringify({
           "Unsigned XPI": {
             URL: TESTROOT + "amosigned.xpi",
@@ -40,13 +43,13 @@ function install_blocked(installInfo) {
 
 function finish_test(count) {
   ok(
     wasOriginBlocked,
     "Should have been blocked due to the cross origin request."
   );
 
   is(count, 0, "No add-ons should have been installed");
-  Services.perms.remove(makeURI("http://example.com"), "install");
+  PermissionTestUtils.remove("http://example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/head.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/head.js
@@ -1,10 +1,14 @@
 /* eslint no-unused-vars: ["error", {vars: "local", args: "none"}] */
 
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/";
 
 const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
 const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR;
 const PROMPT_URL = "chrome://global/content/commonDialog.xul";
 const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul";
 const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
 const PREF_INSTALL_REQUIREBUILTINCERTS =