Bug 1531303 - Refactored tests using SitePermissions URI methods for PermissionTestUtils and principals. r=johannh
authorPaul Zuehlcke <pzuhlcke@mozilla.com>
Thu, 15 Aug 2019 14:35:38 +0000
changeset 488255 20ecb90e7155b6281998498813ea374fdb076c2c
parent 488254 31b2a7bf293285a063d76cb84e46de08d10d5f5c
child 488256 a8e1c8f886fb76d41d6c0aa06e3ab8c52ba6962a
push id113906
push userncsoregi@mozilla.com
push dateFri, 16 Aug 2019 04:07:24 +0000
treeherdermozilla-inbound@d887276421d3 [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 SitePermissions URI methods for PermissionTestUtils and principals. r=johannh Differential Revision: https://phabricator.services.mozilla.com/D41490
browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
browser/base/content/test/permissions/browser_autoplay_blocked.js
browser/base/content/test/permissions/browser_permissions.js
browser/base/content/test/permissions/browser_temporary_permissions.js
browser/base/content/test/permissions/browser_temporary_permissions_expiry.js
browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
browser/base/content/test/permissions/browser_temporary_permissions_tabs.js
browser/base/content/test/popups/browser_popup_blocker_identity_block.js
browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
browser/base/content/test/webrtc/browser_devices_get_user_media.js
browser/base/content/test/webrtc/browser_devices_get_user_media_default_permissions.js
browser/base/content/test/webrtc/browser_devices_get_user_media_queue_request.js
browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access.js
browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access_in_frame.js
browser/components/preferences/in-content/tests/browser_permissions_dialog.js
browser/components/preferences/in-content/tests/siteData/browser_clearSiteData.js
browser/modules/test/browser/browser_PermissionUI.js
browser/modules/test/browser/browser_PermissionUI_prompts.js
toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
toolkit/content/tests/browser/browser_autoplay_policy_webRTC_permission.js
toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
--- a/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
+++ b/browser/base/content/test/pageinfo/browser_pageinfo_permissions.js
@@ -20,64 +20,66 @@ async function testPermissions(defaultPe
     let radioGroup = pageInfo.document.getElementById("geoRadioGroup");
     let defaultRadioButton = pageInfo.document.getElementById(
       "geo#" + defaultPermission
     );
     let blockRadioButton = pageInfo.document.getElementById("geo#2");
 
     ok(defaultCheckbox.checked, "The default checkbox should be checked.");
 
-    SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.BLOCK);
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "geo",
+      Services.perms.DENY_ACTION
+    );
 
     ok(!defaultCheckbox.checked, "The default checkbox should not be checked.");
 
     defaultCheckbox.checked = true;
     defaultCheckbox.dispatchEvent(new Event("command"));
 
-    is(
-      SitePermissions.get(gBrowser.currentURI, "geo").state,
-      defaultPermission,
+    ok(
+      !PermissionTestUtils.getPermissionObject(gBrowser.currentURI, "geo"),
       "Checking the default checkbox should reset the permission."
     );
 
     defaultCheckbox.checked = false;
     defaultCheckbox.dispatchEvent(new Event("command"));
 
-    is(
-      SitePermissions.get(gBrowser.currentURI, "geo").state,
-      defaultPermission,
+    ok(
+      !PermissionTestUtils.getPermissionObject(gBrowser.currentURI, "geo"),
       "Unchecking the default checkbox should pick the default permission."
     );
     is(
       radioGroup.selectedItem,
       defaultRadioButton,
       "The unknown radio button should be selected."
     );
 
     radioGroup.selectedItem = blockRadioButton;
     blockRadioButton.dispatchEvent(new Event("command"));
 
     is(
-      SitePermissions.get(gBrowser.currentURI, "geo").state,
-      SitePermissions.BLOCK,
+      PermissionTestUtils.getPermissionObject(gBrowser.currentURI, "geo")
+        .capability,
+      Services.perms.DENY_ACTION,
       "Selecting a value in the radio group should set the corresponding permission"
     );
 
     radioGroup.selectedItem = defaultRadioButton;
     defaultRadioButton.dispatchEvent(new Event("command"));
 
-    is(
-      SitePermissions.get(gBrowser.currentURI, "geo").state,
-      defaultPermission,
+    ok(
+      !PermissionTestUtils.getPermissionObject(gBrowser.currentURI, "geo"),
       "Selecting the default value should reset the permission."
     );
     ok(defaultCheckbox.checked, "The default checkbox should be checked.");
 
     pageInfo.close();
-    SitePermissions.remove(gBrowser.currentURI, "geo");
+    PermissionTestUtils.remove(gBrowser.currentURI, "geo");
   });
 }
 
 // Test displaying website permissions on certificate error pages.
 add_task(async function test_CertificateError() {
   let browser;
   let pageLoaded;
   await BrowserTestUtils.openNewForegroundTab(
@@ -176,26 +178,26 @@ add_task(async function test_NetworkErro
   );
 
   pageInfo.close();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 // Test some standard operations in the permission tab.
 add_task(async function test_geo_permission() {
-  await testPermissions(SitePermissions.UNKNOWN);
+  await testPermissions(Services.perms.UNKNOWN_ACTION);
 });
 
 // Test some standard operations in the permission tab, falling back to a custom
 // default permission instead of UNKNOWN.
 add_task(async function test_default_geo_permission() {
   await SpecialPowers.pushPrefEnv({
     set: [["permissions.default.geo", SitePermissions.ALLOW]],
   });
-  await testPermissions(SitePermissions.ALLOW);
+  await testPermissions(Services.perms.ALLOW_ACTION);
 });
 
 // Test special behavior for cookie permissions.
 add_task(async function test_cookie_permission() {
   await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function(browser) {
     let pageInfo = BrowserPageInfo(TEST_ORIGIN, "permTab");
     await BrowserTestUtils.waitForEvent(pageInfo, "load");
 
@@ -251,11 +253,11 @@ add_task(async function test_cookie_perm
     );
     is(
       radioGroup.selectedItem,
       null,
       "For cookies, no item should be selected when the checkbox is checked."
     );
 
     pageInfo.close();
-    SitePermissions.remove(gBrowser.currentURI, "cookie");
+    PermissionTestUtils.remove(gBrowser.currentURI, "cookie");
   });
 });
--- a/browser/base/content/test/permissions/browser_autoplay_blocked.js
+++ b/browser/base/content/test/permissions/browser_autoplay_blocked.js
@@ -133,47 +133,71 @@ add_task(async function testMainViewVisi
     let menuitem = menulist.getElementsByTagName("menuitem")[0];
     Assert.equal(menuitem.getAttribute("label"), "Allow Audio and Video");
 
     menuitem.click();
     menulist.menupopup.hidePopup();
     await closeIdentityPopup();
 
     let uri = Services.io.newURI(AUTOPLAY_PAGE);
-    let state = SitePermissions.get(uri, AUTOPLAY_PERM).state;
-    Assert.equal(state, SitePermissions.ALLOW);
+    let state = PermissionTestUtils.getPermissionObject(uri, AUTOPLAY_PERM)
+      .capability;
+    Assert.equal(state, Services.perms.ALLOW_ACTION);
   });
 
   Services.perms.removeAll();
 });
 
 add_task(async function testGloballyBlockedOnNewWindow() {
   Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
 
-  let uri = Services.io.newURI(AUTOPLAY_PAGE);
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    AUTOPLAY_PAGE
+  );
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
+  let tab = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    AUTOPLAY_PAGE
+  );
   await blockedIconShown();
 
-  Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
-    state: SitePermissions.BLOCK,
-    scope: SitePermissions.SCOPE_PERSISTENT,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(
+      principal,
+      AUTOPLAY_PERM,
+      tab.linkedBrowser
+    ),
+    {
+      state: SitePermissions.BLOCK,
+      scope: SitePermissions.SCOPE_PERSISTENT,
+    }
+  );
 
   let promiseWin = BrowserTestUtils.waitForNewWindow();
   gBrowser.replaceTabWithWindow(tab);
   let win = await promiseWin;
   tab = win.gBrowser.selectedTab;
 
-  Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
-    state: SitePermissions.BLOCK,
-    scope: SitePermissions.SCOPE_PERSISTENT,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(
+      principal,
+      AUTOPLAY_PERM,
+      tab.linkedBrowser
+    ),
+    {
+      state: SitePermissions.BLOCK,
+      scope: SitePermissions.SCOPE_PERSISTENT,
+    }
+  );
 
-  SitePermissions.remove(uri, AUTOPLAY_PERM, tab.linkedBrowser);
+  SitePermissions.removeFromPrincipal(
+    principal,
+    AUTOPLAY_PERM,
+    tab.linkedBrowser
+  );
   await BrowserTestUtils.closeWindow(win);
 });
 
 add_task(async function testBFCache() {
   Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
 
   await BrowserTestUtils.withNewTab("about:home", async function(browser) {
     await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE);
--- a/browser/base/content/test/permissions/browser_permissions.js
+++ b/browser/base/content/test/permissions/browser_permissions.js
@@ -37,17 +37,21 @@ add_task(async function testMainViewVisi
     let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
 
     await openIdentityPopup();
 
     ok(!BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is empty");
 
     await closeIdentityPopup();
 
-    SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.ALLOW);
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "camera",
+      Services.perms.ALLOW_ACTION
+    );
 
     await openIdentityPopup();
 
     ok(
       BrowserTestUtils.is_hidden(emptyLabel),
       "List of permissions is not empty"
     );
 
@@ -61,75 +65,91 @@ add_task(async function testMainViewVisi
     let img = permissionsList.querySelector(
       "image.identity-popup-permission-icon"
     );
     ok(img, "There is an image for the permissions");
     ok(img.classList.contains("camera-icon"), "proper class is in image class");
 
     await closeIdentityPopup();
 
-    SitePermissions.remove(gBrowser.currentURI, "camera");
+    PermissionTestUtils.remove(gBrowser.currentURI, "camera");
 
     await openIdentityPopup();
 
     ok(!BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is empty");
 
     await closeIdentityPopup();
   });
 });
 
 add_task(async function testIdentityIcon() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, function() {
-    SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.ALLOW);
-
-    ok(
-      gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
-      "identity-box signals granted permissions"
-    );
-
-    SitePermissions.remove(gBrowser.currentURI, "geo");
-
-    ok(
-      !gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
-      "identity-box doesn't signal granted permissions"
-    );
-
-    SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.BLOCK);
-
-    ok(
-      !gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
-      "identity-box doesn't signal granted permissions"
-    );
-
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
-      "cookie",
-      SitePermissions.ALLOW_COOKIES_FOR_SESSION
+      "geo",
+      Services.perms.ALLOW_ACTION
     );
 
     ok(
       gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
       "identity-box signals granted permissions"
     );
 
-    SitePermissions.remove(gBrowser.currentURI, "geo");
-    SitePermissions.remove(gBrowser.currentURI, "camera");
-    SitePermissions.remove(gBrowser.currentURI, "cookie");
+    PermissionTestUtils.remove(gBrowser.currentURI, "geo");
+
+    ok(
+      !gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
+      "identity-box doesn't signal granted permissions"
+    );
+
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "camera",
+      Services.perms.DENY_ACTION
+    );
+
+    ok(
+      !gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
+      "identity-box doesn't signal granted permissions"
+    );
+
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "cookie",
+      Ci.nsICookiePermission.ACCESS_SESSION
+    );
+
+    ok(
+      gIdentityHandler._identityBox.classList.contains("grantedPermissions"),
+      "identity-box signals granted permissions"
+    );
+
+    PermissionTestUtils.remove(gBrowser.currentURI, "geo");
+    PermissionTestUtils.remove(gBrowser.currentURI, "camera");
+    PermissionTestUtils.remove(gBrowser.currentURI, "cookie");
   });
 });
 
 add_task(async function testCancelPermission() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function() {
     let permissionsList = document.getElementById(
       "identity-popup-permission-list"
     );
     let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
 
-    SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.ALLOW);
-    SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.BLOCK);
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "geo",
+      Services.perms.ALLOW_ACTION
+    );
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "camera",
+      Services.perms.DENY_ACTION
+    );
 
     await openIdentityPopup();
 
     ok(
       BrowserTestUtils.is_hidden(emptyLabel),
       "List of permissions is not empty"
     );
 
@@ -173,28 +193,36 @@ add_task(async function testPermissionHi
 
     await openIdentityPopup();
 
     ok(!BrowserTestUtils.is_hidden(emptyHint), "Empty hint is visible");
     ok(BrowserTestUtils.is_hidden(reloadHint), "Reload hint is hidden");
 
     await closeIdentityPopup();
 
-    SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.ALLOW);
-    SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.BLOCK);
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "geo",
+      Services.perms.ALLOW_ACTION
+    );
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "camera",
+      Services.perms.DENY_ACTION
+    );
 
     await openIdentityPopup();
 
     ok(BrowserTestUtils.is_hidden(emptyHint), "Empty hint is hidden");
     ok(BrowserTestUtils.is_hidden(reloadHint), "Reload hint is hidden");
 
     let cancelButtons = permissionsList.querySelectorAll(
       ".identity-popup-permission-remove-button"
     );
-    SitePermissions.remove(gBrowser.currentURI, "camera");
+    PermissionTestUtils.remove(gBrowser.currentURI, "camera");
 
     cancelButtons[0].click();
     ok(BrowserTestUtils.is_hidden(emptyHint), "Empty hint is hidden");
     ok(!BrowserTestUtils.is_hidden(reloadHint), "Reload hint is visible");
 
     cancelButtons[1].click();
     ok(BrowserTestUtils.is_hidden(emptyHint), "Empty hint is hidden");
     ok(!BrowserTestUtils.is_hidden(reloadHint), "Reload hint is visible");
@@ -215,40 +243,48 @@ add_task(async function testPermissionHi
     );
 
     await closeIdentityPopup();
   });
 });
 
 add_task(async function testPermissionIcons() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, function() {
-    SitePermissions.set(gBrowser.currentURI, "camera", SitePermissions.ALLOW);
-    SitePermissions.set(gBrowser.currentURI, "geo", SitePermissions.BLOCK);
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "camera",
+      Services.perms.ALLOW_ACTION
+    );
+    PermissionTestUtils.add(
+      gBrowser.currentURI,
+      "geo",
+      Services.perms.DENY_ACTION
+    );
 
     let geoIcon = gIdentityHandler._identityBox.querySelector(
       ".blocked-permission-icon[data-permission-id='geo']"
     );
     ok(geoIcon.hasAttribute("showing"), "blocked permission icon is shown");
 
     let cameraIcon = gIdentityHandler._identityBox.querySelector(
       ".blocked-permission-icon[data-permission-id='camera']"
     );
     ok(
       !cameraIcon.hasAttribute("showing"),
       "allowed permission icon is not shown"
     );
 
-    SitePermissions.remove(gBrowser.currentURI, "geo");
+    PermissionTestUtils.remove(gBrowser.currentURI, "geo");
 
     ok(
       !geoIcon.hasAttribute("showing"),
       "blocked permission icon is not shown after reset"
     );
 
-    SitePermissions.remove(gBrowser.currentURI, "camera");
+    PermissionTestUtils.remove(gBrowser.currentURI, "camera");
   });
 });
 
 add_task(async function testPermissionShortcuts() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function(browser) {
     browser.focus();
 
     await new Promise(r => {
@@ -283,72 +319,72 @@ add_task(async function testPermissionSh
           expectedValue,
           "keypress event should be fired even for shortcut key, " + desc
         );
       }
     }
 
     await tryKey("pressed with default permissions", 1);
 
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
       "shortcuts",
-      SitePermissions.BLOCK
+      Services.perms.DENY_ACTION
     );
     await tryKey("pressed when site blocked", 1);
 
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
       "shortcuts",
-      SitePermissions.ALLOW
+      PermissionTestUtils.ALLOW
     );
     await tryKey("pressed when site allowed", 2);
 
-    SitePermissions.remove(gBrowser.currentURI, "shortcuts");
+    PermissionTestUtils.remove(gBrowser.currentURI, "shortcuts");
     await new Promise(r => {
       SpecialPowers.pushPrefEnv(
         { set: [["permissions.default.shortcuts", 2]] },
         r
       );
     });
 
     await tryKey("pressed when globally blocked", 2);
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
       "shortcuts",
-      SitePermissions.ALLOW
+      Services.perms.ALLOW_ACTION
     );
     await tryKey("pressed when globally blocked but site allowed", 3);
 
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
       "shortcuts",
-      SitePermissions.BLOCK
+      Services.perms.DENY_ACTION
     );
     await tryKey("pressed when globally blocked and site blocked", 3);
 
-    SitePermissions.remove(gBrowser.currentURI, "shortcuts");
+    PermissionTestUtils.remove(gBrowser.currentURI, "shortcuts");
   });
 });
 
 // Test the control center UI when policy permissions are set.
 add_task(async function testPolicyPermission() {
   await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function() {
     await SpecialPowers.pushPrefEnv({
       set: [["dom.disable_open_during_load", true]],
     });
 
     let permissionsList = document.getElementById(
       "identity-popup-permission-list"
     );
-    SitePermissions.set(
+    PermissionTestUtils.add(
       gBrowser.currentURI,
       "popup",
-      SitePermissions.ALLOW,
-      SitePermissions.SCOPE_POLICY
+      Services.perms.ALLOW_ACTION,
+      Services.perms.EXPIRE_POLICY
     );
 
     await openIdentityPopup();
 
     // Check if the icon, nameLabel and stateLabel are visible.
     let img, labelText, labels;
 
     img = permissionsList.querySelector("image.identity-popup-permission-icon");
--- a/browser/base/content/test/permissions/browser_temporary_permissions.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions.js
@@ -12,56 +12,62 @@ const PERMISSIONS_PAGE =
   getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
   "permissions.html";
 const SUBFRAME_PAGE =
   getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
   "temporary_permissions_subframe.html";
 
 // Test that setting temp permissions triggers a change in the identity block.
 add_task(async function testTempPermissionChangeEvents() {
-  let uri = NetUtil.newURI(ORIGIN);
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    ORIGIN
+  );
   let id = "geo";
 
-  await BrowserTestUtils.withNewTab(uri.spec, function(browser) {
-    SitePermissions.set(
-      uri,
+  await BrowserTestUtils.withNewTab(ORIGIN, function(browser) {
+    SitePermissions.setForPrincipal(
+      principal,
       id,
       SitePermissions.BLOCK,
       SitePermissions.SCOPE_TEMPORARY,
       browser
     );
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
 
     let geoIcon = document.querySelector(
       ".blocked-permission-icon[data-permission-id=geo]"
     );
 
     Assert.notEqual(
       geoIcon.getBoundingClientRect().width,
       0,
       "geo anchor should be visible"
     );
 
-    SitePermissions.remove(uri, id, browser);
+    SitePermissions.removeFromPrincipal(principal, id, browser);
 
     Assert.equal(
       geoIcon.getBoundingClientRect().width,
       0,
       "geo anchor should not be visible"
     );
   });
 });
 
 // Test that temp blocked permissions requested by subframes (with a different URI) affect the whole page.
 add_task(async function testTempPermissionSubframes() {
   let uri = NetUtil.newURI(ORIGIN);
+  let principal = Services.scriptSecurityManager.createContentPrincipal(
+    uri,
+    {}
+  );
   let id = "geo";
 
   await BrowserTestUtils.withNewTab(SUBFRAME_PAGE, async function(browser) {
     let popupshown = BrowserTestUtils.waitForEvent(
       PopupNotifications.panel,
       "popupshown"
     );
 
@@ -85,14 +91,14 @@ add_task(async function testTempPermissi
       "popuphidden"
     );
 
     let notification = PopupNotifications.panel.firstElementChild;
     EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
 
     await popuphidden;
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
   });
 });
--- a/browser/base/content/test/permissions/browser_temporary_permissions_expiry.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions_expiry.js
@@ -23,51 +23,59 @@ const TIMEOUT_MS = 500;
 add_task(async function testTempPermissionRequestAfterExpiry() {
   await SpecialPowers.pushPrefEnv({
     set: [
       ["privacy.temporary_permission_expire_time_ms", EXPIRE_TIME_MS],
       ["media.navigator.permission.fake", true],
     ],
   });
 
-  let uri = NetUtil.newURI(ORIGIN);
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    ORIGIN
+  );
   let ids = ["geo", "camera"];
 
   for (let id of ids) {
     await BrowserTestUtils.withNewTab(PERMISSIONS_PAGE, async function(
       browser
     ) {
       let blockedIcon = gIdentityHandler._identityBox.querySelector(
         `.blocked-permission-icon[data-permission-id='${id}']`
       );
 
-      SitePermissions.set(
-        uri,
+      SitePermissions.setForPrincipal(
+        principal,
         id,
         SitePermissions.BLOCK,
         SitePermissions.SCOPE_TEMPORARY,
         browser
       );
 
-      Assert.deepEqual(SitePermissions.get(uri, id, browser), {
-        state: SitePermissions.BLOCK,
-        scope: SitePermissions.SCOPE_TEMPORARY,
-      });
+      Assert.deepEqual(
+        SitePermissions.getForPrincipal(principal, id, browser),
+        {
+          state: SitePermissions.BLOCK,
+          scope: SitePermissions.SCOPE_TEMPORARY,
+        }
+      );
 
       ok(
         blockedIcon.hasAttribute("showing"),
         "blocked permission icon is shown"
       );
 
       await new Promise(c => setTimeout(c, TIMEOUT_MS));
 
-      Assert.deepEqual(SitePermissions.get(uri, id, browser), {
-        state: SitePermissions.UNKNOWN,
-        scope: SitePermissions.SCOPE_PERSISTENT,
-      });
+      Assert.deepEqual(
+        SitePermissions.getForPrincipal(principal, id, browser),
+        {
+          state: SitePermissions.UNKNOWN,
+          scope: SitePermissions.SCOPE_PERSISTENT,
+        }
+      );
 
       let popupshown = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
 
       // Request a permission;
       await BrowserTestUtils.synthesizeMouseAtCenter(`#${id}`, {}, browser);
@@ -84,12 +92,12 @@ add_task(async function testTempPermissi
         "popuphidden"
       );
 
       let notification = PopupNotifications.panel.firstElementChild;
       EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
 
       await popuphidden;
 
-      SitePermissions.remove(uri, id, browser);
+      SitePermissions.removeFromPrincipal(principal, id, browser);
     });
   }
 });
--- a/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
@@ -1,66 +1,69 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that temporary permissions are removed on user initiated reload only.
 add_task(async function testTempPermissionOnReload() {
-  let uri = NetUtil.newURI("https://example.com");
+  let origin = "https://example.com/";
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
   let id = "geo";
 
-  await BrowserTestUtils.withNewTab(uri.spec, async function(browser) {
+  await BrowserTestUtils.withNewTab(origin, async function(browser) {
     let reloadButton = document.getElementById("reload-button");
 
-    SitePermissions.set(
-      uri,
+    SitePermissions.setForPrincipal(
+      principal,
       id,
       SitePermissions.BLOCK,
       SitePermissions.SCOPE_TEMPORARY,
       browser
     );
 
-    let reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
+    let reloaded = BrowserTestUtils.browserLoaded(browser, false, origin);
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
 
     // Reload through the page (should not remove the temp permission).
     await ContentTask.spawn(browser, {}, () =>
       content.document.location.reload()
     );
 
     await reloaded;
     await BrowserTestUtils.waitForCondition(() => {
       return !reloadButton.disabled;
     });
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
 
-    reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
+    reloaded = BrowserTestUtils.browserLoaded(browser, false, origin);
 
     // Reload as a user (should remove the temp permission).
     EventUtils.synthesizeMouseAtCenter(reloadButton, {});
 
     await reloaded;
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.UNKNOWN,
       scope: SitePermissions.SCOPE_PERSISTENT,
     });
 
     // Set the permission again.
-    SitePermissions.set(
-      uri,
+    SitePermissions.setForPrincipal(
+      principal,
       id,
       SitePermissions.BLOCK,
       SitePermissions.SCOPE_TEMPORARY,
       browser
     );
 
     // Open the tab context menu.
     let contextMenu = document.getElementById("tabContextMenu");
@@ -74,40 +77,43 @@ add_task(async function testTempPermissi
     EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {
       type: "contextmenu",
       button: 2,
     });
     await popupShownPromise;
 
     let reloadMenuItem = document.getElementById("context_reloadTab");
 
-    reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
+    reloaded = BrowserTestUtils.browserLoaded(browser, false, origin);
 
     // Reload as a user through the context menu (should remove the temp permission).
     EventUtils.synthesizeMouseAtCenter(reloadMenuItem, {});
 
     await reloaded;
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.UNKNOWN,
       scope: SitePermissions.SCOPE_PERSISTENT,
     });
 
-    SitePermissions.remove(uri, id, browser);
+    SitePermissions.removeFromPrincipal(principal, id, browser);
   });
 });
 
 // Test that temporary permissions are not removed when reloading all tabs.
 add_task(async function testTempPermissionOnReloadAllTabs() {
-  let uri = NetUtil.newURI("https://example.com");
+  let origin = "https://example.com/";
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
   let id = "geo";
 
-  await BrowserTestUtils.withNewTab(uri.spec, async function(browser) {
-    SitePermissions.set(
-      uri,
+  await BrowserTestUtils.withNewTab(origin, async function(browser) {
+    SitePermissions.setForPrincipal(
+      principal,
       id,
       SitePermissions.BLOCK,
       SitePermissions.SCOPE_TEMPORARY,
       browser
     );
 
     // Select all tabs before opening the context menu.
     gBrowser.selectAllTabs();
@@ -132,40 +138,43 @@ add_task(async function testTempPermissi
     let reloaded = Promise.all(
       gBrowser.visibleTabs.map(tab =>
         BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab))
       )
     );
     EventUtils.synthesizeMouseAtCenter(reloadMenuItem, {});
     await reloaded;
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
 
-    SitePermissions.remove(uri, id, browser);
+    SitePermissions.removeFromPrincipal(principal, id, browser);
   });
 });
 
 // Test that temporary permissions are persisted through navigation in a tab.
 add_task(async function testTempPermissionOnNavigation() {
-  let uri = NetUtil.newURI("https://example.com/");
+  let origin = "https://example.com/";
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
   let id = "geo";
 
-  await BrowserTestUtils.withNewTab(uri.spec, async function(browser) {
-    SitePermissions.set(
-      uri,
+  await BrowserTestUtils.withNewTab(origin, async function(browser) {
+    SitePermissions.setForPrincipal(
+      principal,
       id,
       SitePermissions.BLOCK,
       SitePermissions.SCOPE_TEMPORARY,
       browser
     );
 
-    Assert.deepEqual(SitePermissions.get(uri, id, browser), {
+    Assert.deepEqual(SitePermissions.getForPrincipal(principal, id, browser), {
       state: SitePermissions.BLOCK,
       scope: SitePermissions.SCOPE_TEMPORARY,
     });
 
     let loaded = BrowserTestUtils.browserLoaded(
       browser,
       false,
       "https://example.org/"
@@ -176,33 +185,39 @@ add_task(async function testTempPermissi
       browser,
       {},
       () => (content.document.location = "https://example.org/")
     );
 
     await loaded;
 
     // The temporary permissions for the current URI should be reset.
-    Assert.deepEqual(SitePermissions.get(browser.currentURI, id, browser), {
-      state: SitePermissions.UNKNOWN,
-      scope: SitePermissions.SCOPE_PERSISTENT,
-    });
+    Assert.deepEqual(
+      SitePermissions.getForPrincipal(browser.contentPrincipal, id, browser),
+      {
+        state: SitePermissions.UNKNOWN,
+        scope: SitePermissions.SCOPE_PERSISTENT,
+      }
+    );
 
-    loaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
+    loaded = BrowserTestUtils.browserLoaded(browser, false, origin);
 
     // Navigate to the original domain.
     await ContentTask.spawn(
       browser,
       {},
       () => (content.document.location = "https://example.com/")
     );
 
     await loaded;
 
     // The temporary permissions for the original URI should still exist.
-    Assert.deepEqual(SitePermissions.get(browser.currentURI, id, browser), {
-      state: SitePermissions.BLOCK,
-      scope: SitePermissions.SCOPE_TEMPORARY,
-    });
+    Assert.deepEqual(
+      SitePermissions.getForPrincipal(browser.contentPrincipal, id, browser),
+      {
+        state: SitePermissions.BLOCK,
+        scope: SitePermissions.SCOPE_TEMPORARY,
+      }
+    );
 
-    SitePermissions.remove(uri, id, browser);
+    SitePermissions.removeFromPrincipal(browser.contentPrincipal, id, browser);
   });
 });
--- a/browser/base/content/test/permissions/browser_temporary_permissions_tabs.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions_tabs.js
@@ -1,72 +1,90 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that temp permissions are persisted through moving tabs to new windows.
 add_task(async function testTempPermissionOnTabMove() {
-  let uri = NetUtil.newURI("https://example.com");
+  let origin = "https://example.com/";
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
   let id = "geo";
 
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, origin);
 
-  SitePermissions.set(
-    uri,
+  SitePermissions.setForPrincipal(
+    principal,
     id,
     SitePermissions.BLOCK,
     SitePermissions.SCOPE_TEMPORARY,
     tab.linkedBrowser
   );
 
-  Assert.deepEqual(SitePermissions.get(uri, id, tab.linkedBrowser), {
-    state: SitePermissions.BLOCK,
-    scope: SitePermissions.SCOPE_TEMPORARY,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(principal, id, tab.linkedBrowser),
+    {
+      state: SitePermissions.BLOCK,
+      scope: SitePermissions.SCOPE_TEMPORARY,
+    }
+  );
 
   let promiseWin = BrowserTestUtils.waitForNewWindow();
   gBrowser.replaceTabWithWindow(tab);
   let win = await promiseWin;
   tab = win.gBrowser.selectedTab;
 
-  Assert.deepEqual(SitePermissions.get(uri, id, tab.linkedBrowser), {
-    state: SitePermissions.BLOCK,
-    scope: SitePermissions.SCOPE_TEMPORARY,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(principal, id, tab.linkedBrowser),
+    {
+      state: SitePermissions.BLOCK,
+      scope: SitePermissions.SCOPE_TEMPORARY,
+    }
+  );
 
-  SitePermissions.remove(uri, id, tab.linkedBrowser);
+  SitePermissions.removeFromPrincipal(principal, id, tab.linkedBrowser);
   await BrowserTestUtils.closeWindow(win);
 });
 
 // Test that temp permissions don't affect other tabs of the same URI.
 add_task(async function testTempPermissionMultipleTabs() {
-  let uri = NetUtil.newURI("https://example.com");
+  let origin = "https://example.com/";
+  let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+    origin
+  );
   let id = "geo";
 
-  let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
-  let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
+  let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, origin);
+  let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, origin);
 
-  SitePermissions.set(
-    uri,
+  SitePermissions.setForPrincipal(
+    principal,
     id,
     SitePermissions.BLOCK,
     SitePermissions.SCOPE_TEMPORARY,
     tab2.linkedBrowser
   );
 
-  Assert.deepEqual(SitePermissions.get(uri, id, tab2.linkedBrowser), {
-    state: SitePermissions.BLOCK,
-    scope: SitePermissions.SCOPE_TEMPORARY,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(principal, id, tab2.linkedBrowser),
+    {
+      state: SitePermissions.BLOCK,
+      scope: SitePermissions.SCOPE_TEMPORARY,
+    }
+  );
 
-  Assert.deepEqual(SitePermissions.get(uri, id, tab1.linkedBrowser), {
-    state: SitePermissions.UNKNOWN,
-    scope: SitePermissions.SCOPE_PERSISTENT,
-  });
+  Assert.deepEqual(
+    SitePermissions.getForPrincipal(principal, id, tab1.linkedBrowser),
+    {
+      state: SitePermissions.UNKNOWN,
+      scope: SitePermissions.SCOPE_PERSISTENT,
+    }
+  );
 
   let geoIcon = document.querySelector(
     ".blocked-permission-icon[data-permission-id=geo]"
   );
 
   Assert.notEqual(
     geoIcon.getBoundingClientRect().width,
     0,
@@ -76,12 +94,12 @@ add_task(async function testTempPermissi
   await BrowserTestUtils.switchTab(gBrowser, tab1);
 
   Assert.equal(
     geoIcon.getBoundingClientRect().width,
     0,
     "geo anchor should not be visible"
   );
 
-  SitePermissions.remove(uri, id, tab2.linkedBrowser);
+  SitePermissions.removeFromPrincipal(principal, id, tab2.linkedBrowser);
   BrowserTestUtils.removeTab(tab1);
   BrowserTestUtils.removeTab(tab2);
 });
--- a/browser/base/content/test/popups/browser_popup_blocker_identity_block.js
+++ b/browser/base/content/test/popups/browser_popup_blocker_identity_block.js
@@ -12,16 +12,20 @@ const { PermissionTestUtils } = ChromeUt
 );
 
 const baseURL = getRootDirectory(gTestPath).replace(
   "chrome://mochitests/content",
   "http://example.com"
 );
 const URL = baseURL + "popup_blocker2.html";
 const URI = Services.io.newURI(URL);
+const PRINCIPAL = Services.scriptSecurityManager.createContentPrincipal(
+  URI,
+  {}
+);
 
 function openIdentityPopup() {
   let promise = BrowserTestUtils.waitForEvent(
     gIdentityHandler._identityPopup,
     "popupshown"
   );
   gIdentityHandler._identityBox.click();
   return promise;
@@ -133,17 +137,18 @@ add_task(async function check_popup_show
   gBrowser.removeTab(tab);
 });
 
 // Test if changing menulist values of blocked popup indicator changes permission state and popup behavior.
 add_task(async function check_permission_state_change() {
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
 
   // Initially the permission state is BLOCK for popups (set by the prefs).
-  let state = SitePermissions.get(URI, "popup", gBrowser).state;
+  let state = SitePermissions.getForPrincipal(PRINCIPAL, "popup", gBrowser)
+    .state;
   Assert.equal(state, SitePermissions.BLOCK);
 
   await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
     let open = content.document.getElementById("pop");
     open.click();
   });
 
   // Wait for popup block.
@@ -154,17 +159,17 @@ add_task(async function check_permission
   // Open identity popup and change permission state to allow.
   await openIdentityPopup();
   let menulist = document.getElementById("identity-popup-popup-menulist");
   menulist.menupopup.openPopup(); // Open the allow/block menu
   let menuitem = menulist.getElementsByTagName("menuitem")[0];
   menuitem.click();
   await closeIdentityPopup();
 
-  state = SitePermissions.get(URI, "popup", gBrowser).state;
+  state = SitePermissions.getForPrincipal(PRINCIPAL, "popup", gBrowser).state;
   Assert.equal(state, SitePermissions.ALLOW);
 
   // Store the popup that opens in this array.
   let popup;
   function onTabOpen(event) {
     popup = event.target;
   }
   gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen);
@@ -194,17 +199,17 @@ add_task(async function check_permission
   menulist = document.getElementById("identity-popup-popup-menulist");
   menulist.menupopup.openPopup(); // Open the allow/block menu
   menuitem = menulist.getElementsByTagName("menuitem")[1];
   menuitem.click();
   await closeIdentityPopup();
 
   // Clicking on the "Block" menuitem should remove the permission object(same behavior as UNKNOWN state).
   // We have already confirmed that popups are blocked when the permission state is BLOCK.
-  state = SitePermissions.get(URI, "popup", gBrowser).state;
+  state = SitePermissions.getForPrincipal(PRINCIPAL, "popup", gBrowser).state;
   Assert.equal(state, SitePermissions.BLOCK);
 
   gBrowser.removeTab(tab);
 });
 
 // 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() {
@@ -215,19 +220,19 @@ add_task(async function check_explicit_d
   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);
+  PermissionTestUtils.add(URI, "popup", Services.perms.ALLOW_ACTION);
 
   await openIdentityPopup();
   menulist = document.getElementById("identity-popup-popup-menulist");
   Assert.equal(menulist.value, "1");
   Assert.equal(menulist.label, "Allow");
   await closeIdentityPopup();
 
-  SitePermissions.remove(URI, "popup");
+  PermissionTestUtils.remove(URI, "popup");
   gBrowser.removeTab(tab);
 });
--- a/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
+++ b/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
@@ -1,22 +1,29 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 ChromeUtils.import("resource:///modules/PermissionUI.jsm", this);
 ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const CP = Cc["@mozilla.org/content-pref/service;1"].getService(
   Ci.nsIContentPrefService2
 );
 
 const EXAMPLE_PAGE_URL = "https://example.com";
 const EXAMPLE_PAGE_URI = Services.io.newURI(EXAMPLE_PAGE_URL);
+const EXAMPLE_PAGE_PRINCIPAL = Services.scriptSecurityManager.createContentPrincipal(
+  EXAMPLE_PAGE_URI,
+  {}
+);
 const GEO_CONTENT_PREF_KEY = "permissions.geoLocation.lastAccess";
 const POLL_INTERVAL_FALSE_STATE = 50;
 
 async function testGeoSharingIconVisible(state = true) {
   let sharingIcon = document.getElementById("geo-sharing-icon");
   ok(sharingIcon, "Geo sharing icon exists");
 
   try {
@@ -223,21 +230,21 @@ add_task(function test_indicator_and_tim
   return testIndicatorExplicitAllow(false);
 });
 add_task(function test_indicator_and_timestamp_after_explicit_allow_remember() {
   return testIndicatorExplicitAllow(true);
 });
 
 // Indicator and identity popup entry shown after auto PermissionUI geolocation allow
 add_task(async function test_indicator_and_timestamp_after_implicit_allow() {
-  SitePermissions.set(
+  PermissionTestUtils.add(
     EXAMPLE_PAGE_URI,
     "geo",
-    SitePermissions.ALLOW,
-    SitePermissions.SCOPE_PERSISTENT
+    Services.perms.ALLOW_ACTION,
+    Services.perms.EXPIRE_NEVER
   );
   let tab = await openExamplePage();
   let result = await requestGeoLocation(tab.linkedBrowser);
   ok(result, "Request should be allowed");
 
   await Promise.all([
     testGeoSharingIconVisible(true),
     testIdentityPopupGeoContainer(true, true),
@@ -254,21 +261,21 @@ add_task(function test_indicator_sharing
 
 // Indicator not shown when manually setting sharing state to false
 add_task(function test_indicator_sharing_state_inactive() {
   return testIndicatorGeoSharingState(false);
 });
 
 // Identity popup shows permission if geo permission is set to persistent allow
 add_task(async function test_identity_popup_permission_scope_permanent() {
-  SitePermissions.set(
+  PermissionTestUtils.add(
     EXAMPLE_PAGE_URI,
     "geo",
-    SitePermissions.ALLOW,
-    SitePermissions.SCOPE_PERSISTENT
+    Services.perms.ALLOW_ACTION,
+    Services.perms.EXPIRE_NEVER
   );
   let tab = await openExamplePage();
 
   await testIdentityPopupGeoContainer(true, false); // Expect permission to be visible, but not lastAccess indicator
 
   await cleanup(tab);
 });
 
@@ -291,21 +298,21 @@ add_task(
     await testIdentityPopupGeoContainer(true, true);
 
     await cleanup(tab);
   }
 );
 
 // Clicking permission clear button clears permission and resets geo sharing state
 add_task(async function test_identity_popup_permission_clear() {
-  SitePermissions.set(
+  PermissionTestUtils.add(
     EXAMPLE_PAGE_URI,
     "geo",
-    SitePermissions.ALLOW,
-    SitePermissions.SCOPE_PERSISTENT
+    Services.perms.ALLOW_ACTION,
+    Services.perms.EXPIRE_NEVER
   );
   let tab = await openExamplePage();
   gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
 
   await openIdentityPopup();
 
   let clearButton = document.querySelector(
     "#identity-popup-geo-container button"
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.js
@@ -138,27 +138,35 @@ var gTests = [
       await checkNotSharing();
 
       // Verify that we set 'Temporarily blocked' permissions.
       let browser = gBrowser.selectedBrowser;
       let blockedPerms = document.getElementById(
         "blocked-permissions-container"
       );
 
-      let { state, scope } = SitePermissions.get(null, "camera", browser);
+      let { state, scope } = SitePermissions.getForPrincipal(
+        null,
+        "camera",
+        browser
+      );
       Assert.equal(state, SitePermissions.BLOCK);
       Assert.equal(scope, SitePermissions.SCOPE_TEMPORARY);
       ok(
         blockedPerms.querySelector(
           ".blocked-permission-icon.camera-icon[showing=true]"
         ),
         "the blocked camera icon is shown"
       );
 
-      ({ state, scope } = SitePermissions.get(null, "microphone", browser));
+      ({ state, scope } = SitePermissions.getForPrincipal(
+        null,
+        "microphone",
+        browser
+      ));
       Assert.equal(state, SitePermissions.BLOCK);
       Assert.equal(scope, SitePermissions.SCOPE_TEMPORARY);
       ok(
         blockedPerms.querySelector(
           ".blocked-permission-icon.microphone-icon[showing=true]"
         ),
         "the blocked microphone icon is shown"
       );
@@ -167,18 +175,26 @@ var gTests = [
       promise = promiseMessage(permissionError);
       await promiseRequestDevice(true, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
 
-      SitePermissions.remove(browser.currentURI, "camera", browser);
-      SitePermissions.remove(browser.currentURI, "microphone", browser);
+      SitePermissions.removeFromPrincipal(
+        browser.contentPrincipal,
+        "camera",
+        browser
+      );
+      SitePermissions.removeFromPrincipal(
+        browser.contentPrincipal,
+        "microphone",
+        browser
+      );
     },
   },
 
   {
     desc: "getUserMedia audio+video: stop sharing",
     run: async function checkStopSharing() {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
@@ -215,19 +231,31 @@ var gTests = [
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia audio+video: reloading the page removes all gUM UI",
     run: async function checkReloading() {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
@@ -261,19 +289,31 @@ var gTests = [
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia prompt: Always/Never Share",
     run: async function checkRememberCheckbox() {
       let elt = id => document.getElementById(id);
 
@@ -424,18 +464,18 @@ var gTests = [
 
           // Deny the request to cleanup...
           await promiseMessage(permissionError, () => {
             activateSecondaryAction(kActionDeny);
           });
           await expectObserverCalled("getUserMedia:response:deny");
           await expectObserverCalled("recording-window-ended");
           let browser = gBrowser.selectedBrowser;
-          SitePermissions.remove(null, "camera", browser);
-          SitePermissions.remove(null, "microphone", browser);
+          SitePermissions.removeFromPrincipal(null, "camera", browser);
+          SitePermissions.removeFromPrincipal(null, "microphone", browser);
         } else {
           let expectedMessage = aExpectStream ? "ok" : permissionError;
           let promise = promiseMessage(expectedMessage);
           await promiseRequestDevice(aRequestAudio, aRequestVideo);
           await promise;
 
           if (expectedMessage == "ok") {
             await expectObserverCalled("getUserMedia:request");
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_default_permissions.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_default_permissions.js
@@ -66,32 +66,36 @@ var gTests = [
   },
 
   {
     desc: "getUserMedia video: globally blocking camera + local exception",
     run: async function checkAudioVideo() {
       let browser = gBrowser.selectedBrowser;
       Services.prefs.setIntPref(CAMERA_PREF, SitePermissions.BLOCK);
       // Overwrite the permission for that URI, requesting video should work again.
-      SitePermissions.set(browser.currentURI, "camera", SitePermissions.ALLOW);
+      PermissionTestUtils.add(
+        browser.currentURI,
+        "camera",
+        Services.perms.ALLOW_ACTION
+      );
 
       // Requesting video should work.
       let indicator = promiseIndicatorWindow();
       let promise = promiseMessage("ok");
       await promiseRequestDevice(false, true);
       await promise;
 
       await expectObserverCalled("getUserMedia:request");
       await expectObserverCalled("getUserMedia:response:allow");
       await expectObserverCalled("recording-device-events");
       await indicator;
       await checkSharingUI({ video: true });
       await closeStream();
 
-      SitePermissions.remove(browser.currentURI, "camera");
+      PermissionTestUtils.remove(browser.currentURI, "camera");
       Services.prefs.clearUserPref(CAMERA_PREF);
     },
   },
 
   {
     desc: "getUserMedia audio+video: globally blocking microphone",
     run: async function checkAudioVideo() {
       Services.prefs.setIntPref(MICROPHONE_PREF, SitePermissions.BLOCK);
@@ -147,35 +151,35 @@ var gTests = [
   },
 
   {
     desc: "getUserMedia audio: globally blocking microphone + local exception",
     run: async function checkAudioVideo() {
       let browser = gBrowser.selectedBrowser;
       Services.prefs.setIntPref(MICROPHONE_PREF, SitePermissions.BLOCK);
       // Overwrite the permission for that URI, requesting video should work again.
-      SitePermissions.set(
+      PermissionTestUtils.add(
         browser.currentURI,
         "microphone",
-        SitePermissions.ALLOW
+        Services.perms.ALLOW_ACTION
       );
 
       // Requesting audio should work.
       let indicator = promiseIndicatorWindow();
       let promise = promiseMessage("ok");
       await promiseRequestDevice(true);
       await promise;
 
       await expectObserverCalled("getUserMedia:request");
       await expectObserverCalled("getUserMedia:response:allow");
       await expectObserverCalled("recording-device-events");
       await indicator;
       await checkSharingUI({ audio: true });
       await closeStream();
 
-      SitePermissions.remove(browser.currentURI, "microphone");
+      PermissionTestUtils.remove(browser.currentURI, "microphone");
       Services.prefs.clearUserPref(MICROPHONE_PREF);
     },
   },
 ];
 add_task(async function test() {
   await runTests(gTests);
 });
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_queue_request.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_queue_request.js
@@ -39,17 +39,21 @@ var gTests = [
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(true, false);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // close all streams
       await closeStream();
     },
   },
 
   {
     desc: "test queueing allow video behind deny audio",
@@ -83,17 +87,21 @@ var gTests = [
       Assert.deepEqual(
         await getMediaCaptureState(),
         { video: true },
         "expected camera to be shared"
       );
       await indicator;
       await checkSharingUI({ audio: false, video: true });
 
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // close all streams
       await closeStream();
     },
   },
 
   {
     desc: "test queueing allow audio behind allow video with error",
@@ -158,16 +166,20 @@ var gTests = [
       promise = promiseSpecificMessageReceived(permissionError, 2);
       activateSecondaryAction(kActionDeny);
       await promise;
 
       await expectObserverCalled("getUserMedia:request");
       await expectObserverCalled("getUserMedia:response:deny", 2);
       await expectObserverCalled("recording-window-ended");
 
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 ];
 
 add_task(async function test() {
   await runTests(gTests);
 });
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
@@ -173,17 +173,21 @@ var gTests = [
       );
       checkDeviceSelectors(false, false, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
       await closeStream();
     },
   },
 
   {
     desc: "getUserMedia window/screen picking window",
     run: async function checkWindowOrScreen() {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
@@ -457,18 +461,26 @@ var gTests = [
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia audio + window/screen: stop sharing",
     run: async function checkStopSharing() {
       if (AppConstants.platform == "macosx") {
         todo(
@@ -631,18 +643,21 @@ var gTests = [
       await closeStream();
     },
   },
 
   {
     desc: "Only persistent block is possible for screen sharing",
     run: async function checkPersistentPermissions() {
       let browser = gBrowser.selectedBrowser;
-      let uri = browser.documentURI;
-      let devicePerms = SitePermissions.get(uri, "screen", browser);
+      let devicePerms = SitePermissions.getForPrincipal(
+        browser.contentPrincipal,
+        "screen",
+        browser
+      );
       is(
         devicePerms.state,
         SitePermissions.UNKNOWN,
         "starting without screen persistent permissions"
       );
 
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(false, true, null, "screen");
@@ -675,32 +690,40 @@ var gTests = [
       // Click "Don't Allow" to save a persistent block permission.
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
 
-      let permission = SitePermissions.get(uri, "screen", browser);
+      let permission = SitePermissions.getForPrincipal(
+        browser.contentPrincipal,
+        "screen",
+        browser
+      );
       is(permission.state, SitePermissions.BLOCK, "screen sharing is blocked");
       is(
         permission.scope,
         SitePermissions.SCOPE_PERSISTENT,
         "screen sharing is persistently blocked"
       );
 
       // Request screensharing again, expect an immediate failure.
       promise = promiseMessage(permissionError);
       await promiseRequestDevice(false, true, null, "screen");
       await promise;
       await expectObserverCalled("recording-window-ended");
 
       // Now set the permission to allow and expect a prompt.
-      SitePermissions.set(uri, "screen", SitePermissions.ALLOW);
+      SitePermissions.setForPrincipal(
+        browser.contentPrincipal,
+        "screen",
+        SitePermissions.ALLOW
+      );
 
       // Request devices and expect a prompt despite the saved 'Allow' permission.
       promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(false, true, null, "screen");
       await promise;
       await expectObserverCalled("getUserMedia:request");
 
       // The 'remember' checkbox shouldn't be checked anymore.
@@ -714,17 +737,21 @@ var gTests = [
       ok(!checkbox.checked, "checkbox is not checked");
 
       // Deny the request to cleanup...
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
-      SitePermissions.remove(uri, "screen", browser);
+      SitePermissions.removeFromPrincipal(
+        browser.contentPrincipal,
+        "screen",
+        browser
+      );
     },
   },
 
   {
     desc:
       "Switching between menu options maintains correct main action state while window sharing",
     run: async function checkDoorhangerState() {
       let win = await BrowserTestUtils.openNewBrowserWindow();
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access.js
@@ -61,38 +61,62 @@ var gTests = [
       );
       checkDeviceSelectors(false, false, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // After closing all streams, gUM(audio+camera) causes a prompt.
       await closeStream();
       promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(true, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
       await checkNotSharing();
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia camera",
     run: async function checkAudioVideoWhileLiveTracksExist_camera() {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(false, true);
@@ -122,35 +146,59 @@ var gTests = [
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(true, false);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // gUM(audio+camera) causes a prompt;
       promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(true, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // gUM(screen) causes a prompt;
       promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(false, true, null, "screen");
       await promise;
       await expectObserverCalled("getUserMedia:request");
 
       is(
@@ -160,19 +208,31 @@ var gTests = [
       );
       checkDeviceSelectors(false, false, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // gUM(camera) returns a stream without prompting.
       promise = promiseMessage("ok");
       await promiseRequestDevice(false, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       await promiseNoPopupNotification("webRTC-shareDevices");
       await expectObserverCalled("getUserMedia:response:allow");
@@ -222,35 +282,59 @@ var gTests = [
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(false, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // gUM(audio+camera) causes a prompt;
       promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       checkDeviceSelectors(true, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // gUM(audio) returns a stream without prompting.
       promise = promiseMessage("ok");
       await promiseRequestDevice(true, false);
       await promise;
       await expectObserverCalled("getUserMedia:request");
       await promiseNoPopupNotification("webRTC-shareDevices");
       await expectObserverCalled("getUserMedia:response:allow");
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access_in_frame.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_unprompted_access_in_frame.js
@@ -40,19 +40,31 @@ var gTests = [
       checkDeviceSelectors(true, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
 
       // If there's an active audio+camera stream in frame 1,
       // gUM(audio+camera) in frame 1 returns a stream without prompting;
       promise = promiseMessage("ok");
       await promiseRequestDevice(true, true, "frame1");
       await promise;
       await expectObserverCalled("getUserMedia:request");
       await promiseNoPopupNotification("webRTC-shareDevices");
@@ -101,19 +113,31 @@ var gTests = [
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
 
       // close the stream
       await closeStream(false, "frame1");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia audio+camera in frame 1 - reload",
     run: async function checkAudioVideoWhileLiveTracksExist_frame_reload() {
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
       await promiseRequestDevice(true, true, "frame1");
@@ -156,19 +180,31 @@ var gTests = [
       checkDeviceSelectors(true, true);
 
       await promiseMessage(permissionError, () => {
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 
   {
     desc: "getUserMedia audio+camera at the top level window",
     run: async function checkAudioVideoWhileLiveTracksExist_topLevel() {
       // create an active audio+camera stream at the top level window
       let promise = promisePopupNotificationShown("webRTC-shareDevices");
@@ -205,18 +241,30 @@ var gTests = [
         activateSecondaryAction(kActionDeny);
       });
 
       await expectObserverCalled("getUserMedia:response:deny");
       await expectObserverCalled("recording-window-ended");
 
       // close the stream
       await closeStream();
-      SitePermissions.remove(null, "screen", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "camera", gBrowser.selectedBrowser);
-      SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
+      SitePermissions.removeFromPrincipal(
+        null,
+        "screen",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "camera",
+        gBrowser.selectedBrowser
+      );
+      SitePermissions.removeFromPrincipal(
+        null,
+        "microphone",
+        gBrowser.selectedBrowser
+      );
     },
   },
 ];
 
 add_task(async function test() {
   await runTests(gTests, { relativeURI: "get_user_media_in_frame.html" });
 });
--- a/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
+++ b/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
@@ -2,16 +2,17 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
+
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const PERMISSIONS_URL =
   "chrome://browser/content/preferences/sitePermissions.xul";
 const URL = "http://www.example.com";
 const URI = Services.io.newURI(URL);
 var sitePermissionsDialog;
 
@@ -50,240 +51,305 @@ add_task(async function addPermission() 
   // First item in the richlistbox contains column headers.
   Assert.equal(
     richlistbox.itemCount,
     0,
     "Number of permission items is 0 initially"
   );
 
   // Add notification permission for a website.
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Observe the added permission changes in the dialog UI.
   Assert.equal(richlistbox.itemCount, 1);
   checkPermissionItem(URL, Services.perms.ALLOW_ACTION);
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 });
 
 add_task(async function observePermissionChange() {
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Change the permission.
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.BLOCK);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.DENY_ACTION
+  );
 
   checkPermissionItem(URL, Services.perms.DENY_ACTION);
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 });
 
 add_task(async function observePermissionDelete() {
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   Assert.equal(
     richlistbox.itemCount,
     1,
     "The box contains one permission item initially"
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 
   Assert.equal(richlistbox.itemCount, 0);
 });
 
 add_task(async function onPermissionChange() {
   let doc = sitePermissionsDialog.document;
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Change the permission state in the UI.
   doc.getElementsByAttribute("value", SitePermissions.BLOCK)[0].click();
 
   Assert.equal(
-    SitePermissions.get(URI, "desktop-notification").state,
-    SitePermissions.ALLOW,
+    PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION,
     "Permission state does not change before saving changes"
   );
 
   doc.getElementById("btnApplyChanges").click();
 
   await TestUtils.waitForCondition(
     () =>
-      SitePermissions.get(URI, "desktop-notification").state ==
-      SitePermissions.BLOCK
+      PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+        .capability == Services.perms.DENY_ACTION
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 });
 
 add_task(async function onPermissionDelete() {
   await openPermissionsDialog();
 
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   richlistbox.selectItem(richlistbox.getItemAtIndex(0));
   doc.getElementById("removePermission").click();
 
   await TestUtils.waitForCondition(() => richlistbox.itemCount == 0);
 
   Assert.equal(
-    SitePermissions.get(URI, "desktop-notification").state,
-    SitePermissions.ALLOW,
+    PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION,
     "Permission is not deleted before saving changes"
   );
 
   doc.getElementById("btnApplyChanges").click();
 
   await TestUtils.waitForCondition(
     () =>
-      SitePermissions.get(URI, "desktop-notification").state ==
-      SitePermissions.UNKNOWN
+      PermissionTestUtils.getPermissionObject(URI, "desktop-notification") ==
+      null
   );
 });
 
 add_task(async function onAllPermissionsDelete() {
   await openPermissionsDialog();
 
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
   let u = Services.io.newURI("http://www.test.com");
-  SitePermissions.set(u, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    u,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   doc.getElementById("removeAllPermissions").click();
   await TestUtils.waitForCondition(() => richlistbox.itemCount == 0);
 
   Assert.equal(
-    SitePermissions.get(URI, "desktop-notification").state,
-    SitePermissions.ALLOW
+    PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION
   );
   Assert.equal(
-    SitePermissions.get(u, "desktop-notification").state,
-    SitePermissions.ALLOW,
+    PermissionTestUtils.getPermissionObject(u, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION,
     "Permissions are not deleted before saving changes"
   );
 
   doc.getElementById("btnApplyChanges").click();
 
   await TestUtils.waitForCondition(
     () =>
-      SitePermissions.get(URI, "desktop-notification").state ==
-        SitePermissions.UNKNOWN &&
-      SitePermissions.get(u, "desktop-notification").state ==
-        SitePermissions.UNKNOWN
+      PermissionTestUtils.getPermissionObject(URI, "desktop-notification") ==
+        null &&
+      PermissionTestUtils.getPermissionObject(u, "desktop-notification") == null
   );
 });
 
 add_task(async function onPermissionChangeAndDelete() {
   await openPermissionsDialog();
 
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Change the permission state in the UI.
   doc.getElementsByAttribute("value", SitePermissions.BLOCK)[0].click();
 
   // Remove that permission by clicking the "Remove" button.
   richlistbox.selectItem(richlistbox.getItemAtIndex(0));
   doc.getElementById("removePermission").click();
 
   await TestUtils.waitForCondition(() => richlistbox.itemCount == 0);
 
   doc.getElementById("btnApplyChanges").click();
 
   await TestUtils.waitForCondition(
     () =>
-      SitePermissions.get(URI, "desktop-notification").state ==
-      SitePermissions.UNKNOWN
+      PermissionTestUtils.getPermissionObject(URI, "desktop-notification") ==
+      null
   );
 });
 
 add_task(async function onPermissionChangeCancel() {
   await openPermissionsDialog();
 
   let doc = sitePermissionsDialog.document;
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Change the permission state in the UI.
   doc.getElementsByAttribute("value", SitePermissions.BLOCK)[0].click();
 
   doc.getElementById("cancel").click();
 
   Assert.equal(
-    SitePermissions.get(URI, "desktop-notification").state,
-    SitePermissions.ALLOW,
+    PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION,
     "Permission state does not change on clicking cancel"
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 });
 
 add_task(async function onPermissionDeleteCancel() {
   await openPermissionsDialog();
 
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Remove that permission by clicking the "Remove" button.
   richlistbox.selectItem(richlistbox.getItemAtIndex(0));
   doc.getElementById("removePermission").click();
 
   await TestUtils.waitForCondition(() => richlistbox.itemCount == 0);
 
   doc.getElementById("cancel").click();
 
   Assert.equal(
-    SitePermissions.get(URI, "desktop-notification").state,
-    SitePermissions.ALLOW,
+    PermissionTestUtils.getPermissionObject(URI, "desktop-notification")
+      .capability,
+    Services.perms.ALLOW_ACTION,
     "Permission state does not change on clicking cancel"
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
 });
 
 add_task(async function onSearch() {
   await openPermissionsDialog();
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
   let searchBox = doc.getElementById("searchBox");
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
   searchBox.value = "www.example.com";
 
   let u = Services.io.newURI("http://www.test.com");
-  SitePermissions.set(u, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    u,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   Assert.equal(
     doc.getElementsByAttribute("origin", "http://www.test.com")[0],
     null
   );
   Assert.equal(
     doc.getElementsByAttribute("origin", "http://www.example.com")[0],
     richlistbox.getItemAtIndex(0)
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
-  SitePermissions.remove(u, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(u, "desktop-notification");
 
   doc.getElementById("cancel").click();
 });
 
 add_task(async function onPermissionsSort() {
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
   let u = Services.io.newURI("http://www.test.com");
-  SitePermissions.set(u, "desktop-notification", SitePermissions.BLOCK);
+  PermissionTestUtils.add(
+    u,
+    "desktop-notification",
+    Services.perms.DENY_ACTION
+  );
 
   await openPermissionsDialog();
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
   // Test default arrangement(Allow followed by Block).
   Assert.equal(
     richlistbox.getItemAtIndex(0).getAttribute("origin"),
@@ -325,18 +391,18 @@ add_task(async function onPermissionsSor
     richlistbox.getItemAtIndex(0).getAttribute("origin"),
     "http://www.test.com"
   );
   Assert.equal(
     richlistbox.getItemAtIndex(1).getAttribute("origin"),
     "http://www.example.com"
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
-  SitePermissions.remove(u, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(u, "desktop-notification");
 
   doc.getElementById("cancel").click();
 });
 
 add_task(async function onPermissionDisable() {
   // Enable desktop-notification permission prompts.
   Services.prefs.setIntPref(
     "permissions.default.desktop-notification",
@@ -423,19 +489,27 @@ add_task(async function checkDefaultPerm
 
 add_task(async function testTabBehaviour() {
   // Test tab behaviour inside the permissions setting dialog when site permissions are selected.
   // Only selected items in the richlistbox should be tabable for accessibility reasons.
 
   // Force tabfocus for all elements on OSX.
   SpecialPowers.pushPrefEnv({ set: [["accessibility.tabfocus", 7]] });
 
-  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    URI,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
   let u = Services.io.newURI("http://www.test.com");
-  SitePermissions.set(u, "desktop-notification", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    u,
+    "desktop-notification",
+    Services.perms.ALLOW_ACTION
+  );
 
   await openPermissionsDialog();
   let doc = sitePermissionsDialog.document;
 
   EventUtils.synthesizeKey("KEY_Tab", {}, sitePermissionsDialog);
   let richlistbox = doc.getElementById("permissionsBox");
   is(
     richlistbox,
@@ -457,17 +531,17 @@ add_task(async function testTabBehaviour
   EventUtils.synthesizeKey("KEY_Tab", {}, sitePermissionsDialog);
   let removeButton = doc.getElementById("removePermission");
   is(
     removeButton,
     doc.activeElement,
     "The focus moves outside the richlistbox and onto the remove button"
   );
 
-  SitePermissions.remove(URI, "desktop-notification");
-  SitePermissions.remove(u, "desktop-notification");
+  PermissionTestUtils.remove(URI, "desktop-notification");
+  PermissionTestUtils.remove(u, "desktop-notification");
 
   doc.getElementById("cancel").click();
 });
 
 add_task(async function removeTab() {
   gBrowser.removeCurrentTab();
 });
--- a/browser/components/preferences/in-content/tests/siteData/browser_clearSiteData.js
+++ b/browser/components/preferences/in-content/tests/siteData/browser_clearSiteData.js
@@ -1,20 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 var { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 async function testClearData(clearSiteData, clearCache) {
-  let quotaURI = Services.io.newURI(TEST_QUOTA_USAGE_ORIGIN);
-  SitePermissions.set(quotaURI, "persistent-storage", SitePermissions.ALLOW);
+  PermissionTestUtils.add(
+    TEST_QUOTA_USAGE_ORIGIN,
+    "persistent-storage",
+    Services.perms.ALLOW_ACTION
+  );
 
   // Open a test site which saves into appcache.
   await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL);
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
   // Fill indexedDB with test data.
   // Don't wait for the page to load, to register the content event handler as quickly as possible.
   // If this test goes intermittent, we might have to tell the page to wait longer before
@@ -173,23 +179,23 @@ async function testClearData(clearSiteDa
         await ContentTaskUtils.waitForCondition(
           () => sizeLabel.textContent != opts.initialSizeLabelValue,
           "Site data size label should have updated."
         );
       }
     );
   }
 
-  let desiredPermissionState = clearSiteData
-    ? SitePermissions.UNKNOWN
-    : SitePermissions.ALLOW;
-  let permission = SitePermissions.get(quotaURI, "persistent-storage");
+  let permission = PermissionTestUtils.getPermissionObject(
+    TEST_QUOTA_USAGE_ORIGIN,
+    "persistent-storage"
+  );
   is(
-    permission.state,
-    desiredPermissionState,
+    clearSiteData ? permission : permission.capability,
+    clearSiteData ? null : Services.perms.ALLOW_ACTION,
     "Should have the correct permission state."
   );
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await SiteDataManager.removeAll();
 }
 
 // Test opening the "Clear All Data" dialog and cancelling.
--- a/browser/modules/test/browser/browser_PermissionUI.js
+++ b/browser/modules/test/browser/browser_PermissionUI.js
@@ -4,16 +4,19 @@
  * add-ons can introduce their own permission prompts.
  */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/Integration.jsm", this);
 ChromeUtils.import("resource:///modules/PermissionUI.jsm", this);
 ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 /**
  * Tests the PermissionPromptForRequest prototype to ensure that a prompt
  * can be displayed. Does not test permission handling.
  */
 add_task(async function test_permission_prompt_for_request() {
   await BrowserTestUtils.withNewTab(
     {
@@ -192,17 +195,17 @@ add_task(async function test_with_permis
         callback() {
           denied = true;
         },
       };
 
       let mockRequest = makeMockPermissionRequest(browser);
       let principal = mockRequest.principal;
       registerCleanupFunction(function() {
-        SitePermissions.remove(principal.URI, kTestPermissionKey);
+        PermissionTestUtils.remove(principal.URI, kTestPermissionKey);
       });
 
       let TestPrompt = {
         __proto__: PermissionUI.PermissionPromptForRequestPrototype,
         request: mockRequest,
         notificationID: kTestNotificationID,
         permissionKey: kTestPermissionKey,
         message: kTestMessage,
@@ -223,18 +226,18 @@ add_task(async function test_with_permis
       TestPrompt.prompt();
       await shownPromise;
       let notification = PopupNotifications.getNotification(
         kTestNotificationID,
         browser
       );
       Assert.ok(notification, "Should have gotten the notification");
 
-      let curPerm = SitePermissions.get(
-        principal.URI,
+      let curPerm = SitePermissions.getForPrincipal(
+        principal,
         kTestPermissionKey,
         browser
       );
       Assert.equal(
         curPerm.state,
         SitePermissions.UNKNOWN,
         "Should be no permission set to begin with."
       );
@@ -244,48 +247,56 @@ add_task(async function test_with_permis
       popupNotification.checkbox.checked = false;
 
       Assert.equal(
         notification.secondaryActions.length,
         1,
         "There should only be 1 secondary action"
       );
       await clickSecondaryAction();
-      curPerm = SitePermissions.get(principal.URI, kTestPermissionKey, browser);
+      curPerm = SitePermissions.getForPrincipal(
+        principal,
+        kTestPermissionKey,
+        browser
+      );
       Assert.deepEqual(
         curPerm,
         {
           state: SitePermissions.BLOCK,
           scope: SitePermissions.SCOPE_TEMPORARY,
         },
         "Should have denied the action temporarily"
       );
       // Try getting the permission without passing the browser object (should fail).
-      curPerm = SitePermissions.get(principal.URI, kTestPermissionKey);
-      Assert.deepEqual(
+      curPerm = PermissionTestUtils.getPermissionObject(
+        principal.URI,
+        kTestPermissionKey
+      );
+      Assert.equal(
         curPerm,
-        {
-          state: SitePermissions.UNKNOWN,
-          scope: SitePermissions.SCOPE_PERSISTENT,
-        },
+        null,
         "Should have made no permanent permission entry"
       );
       Assert.ok(denied, "The secondaryAction callback should have fired");
       Assert.ok(!allowed, "The mainAction callback should not have fired");
       Assert.ok(
         mockRequest._cancelled,
         "The request should have been cancelled"
       );
       Assert.ok(
         !mockRequest._allowed,
         "The request should not have been allowed"
       );
 
       // Clear the permission and pretend we never denied
-      SitePermissions.remove(principal.URI, kTestPermissionKey, browser);
+      SitePermissions.removeFromPrincipal(
+        principal,
+        kTestPermissionKey,
+        browser
+      );
       denied = false;
       mockRequest._cancelled = false;
 
       // Bring the PopupNotification back up now...
       shownPromise = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
@@ -294,60 +305,62 @@ add_task(async function test_with_permis
 
       // Test denying the permission request.
       Assert.equal(
         notification.secondaryActions.length,
         1,
         "There should only be 1 secondary action"
       );
       await clickSecondaryAction();
-      curPerm = SitePermissions.get(principal.URI, kTestPermissionKey);
-      Assert.deepEqual(
-        curPerm,
-        {
-          state: SitePermissions.BLOCK,
-          scope: SitePermissions.SCOPE_PERSISTENT,
-        },
+      curPerm = PermissionTestUtils.getPermissionObject(
+        principal.URI,
+        kTestPermissionKey
+      );
+      Assert.equal(
+        curPerm.capability,
+        Services.perms.DENY_ACTION,
         "Should have denied the action"
       );
+      Assert.equal(curPerm.expireTime, 0, "Deny should be permanent");
       Assert.ok(denied, "The secondaryAction callback should have fired");
       Assert.ok(!allowed, "The mainAction callback should not have fired");
       Assert.ok(
         mockRequest._cancelled,
         "The request should have been cancelled"
       );
       Assert.ok(
         !mockRequest._allowed,
         "The request should not have been allowed"
       );
 
       // Clear the permission and pretend we never denied
-      SitePermissions.remove(principal.URI, kTestPermissionKey);
+      PermissionTestUtils.remove(principal.URI, kTestPermissionKey);
       denied = false;
       mockRequest._cancelled = false;
 
       // Bring the PopupNotification back up now...
       shownPromise = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
       TestPrompt.prompt();
       await shownPromise;
 
       // Test allowing the permission request.
       await clickMainAction();
-      curPerm = SitePermissions.get(principal.URI, kTestPermissionKey);
-      Assert.deepEqual(
-        curPerm,
-        {
-          state: SitePermissions.ALLOW,
-          scope: SitePermissions.SCOPE_PERSISTENT,
-        },
+      curPerm = PermissionTestUtils.getPermissionObject(
+        principal.URI,
+        kTestPermissionKey
+      );
+      Assert.equal(
+        curPerm.capability,
+        Services.perms.ALLOW_ACTION,
         "Should have allowed the action"
       );
+      Assert.equal(curPerm.expireTime, 0, "Allow should be permanent");
       Assert.ok(!denied, "The secondaryAction callback should not have fired");
       Assert.ok(allowed, "The mainAction callback should have fired");
       Assert.ok(
         !mockRequest._cancelled,
         "The request should not have been cancelled"
       );
       Assert.ok(mockRequest._allowed, "The request should have been allowed");
     }
--- a/browser/modules/test/browser/browser_PermissionUI_prompts.js
+++ b/browser/modules/test/browser/browser_PermissionUI_prompts.js
@@ -4,16 +4,19 @@
  * add-ons can introduce their own permission prompts.
  */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/Integration.jsm", this);
 ChromeUtils.import("resource:///modules/PermissionUI.jsm", this);
 ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 // Tests that GeolocationPermissionPrompt works as expected
 add_task(async function test_geo_permission_prompt() {
   await testPrompt(PermissionUI.GeolocationPermissionPrompt);
 });
 
 // Tests that DesktopNotificationPermissionPrompt works as expected
 add_task(async function test_desktop_notification_permission_prompt() {
@@ -52,17 +55,17 @@ async function testPrompt(Prompt) {
       let mockRequest = makeMockPermissionRequest(browser);
       let principal = mockRequest.principal;
       let TestPrompt = new Prompt(mockRequest);
       let permissionKey =
         TestPrompt.usePermissionManager && TestPrompt.permissionKey;
 
       registerCleanupFunction(function() {
         if (permissionKey) {
-          SitePermissions.remove(principal.URI, permissionKey);
+          PermissionTestUtils.remove(principal.URI, permissionKey);
         }
       });
 
       let shownPromise = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
       TestPrompt.prompt();
@@ -70,17 +73,21 @@ async function testPrompt(Prompt) {
       let notification = PopupNotifications.getNotification(
         TestPrompt.notificationID,
         browser
       );
       Assert.ok(notification, "Should have gotten the notification");
 
       let curPerm;
       if (permissionKey) {
-        curPerm = SitePermissions.get(principal.URI, permissionKey, browser);
+        curPerm = SitePermissions.getForPrincipal(
+          principal,
+          permissionKey,
+          browser
+        );
         Assert.equal(
           curPerm.state,
           SitePermissions.UNKNOWN,
           "Should be no permission set to begin with."
         );
       }
 
       // First test denying the permission request without the checkbox checked.
@@ -104,17 +111,21 @@ async function testPrompt(Prompt) {
         notification.secondaryActions.length,
         expectedSecondaryActionsCount,
         "There should only be " +
           expectedSecondaryActionsCount +
           " secondary action(s)"
       );
       await clickSecondaryAction();
       if (permissionKey) {
-        curPerm = SitePermissions.get(principal.URI, permissionKey, browser);
+        curPerm = SitePermissions.getForPrincipal(
+          principal,
+          permissionKey,
+          browser
+        );
         Assert.deepEqual(
           curPerm,
           {
             state: SitePermissions.BLOCK,
             scope: SitePermissions.SCOPE_TEMPORARY,
           },
           "Should have denied the action temporarily"
         );
@@ -123,17 +134,17 @@ async function testPrompt(Prompt) {
           mockRequest._cancelled,
           "The request should have been cancelled"
         );
         Assert.ok(
           !mockRequest._allowed,
           "The request should not have been allowed"
         );
 
-        SitePermissions.remove(principal.URI, permissionKey, browser);
+        SitePermissions.removeFromPrincipal(principal, permissionKey, browser);
         mockRequest._cancelled = false;
       }
 
       // Bring the PopupNotification back up now...
       shownPromise = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
@@ -154,37 +165,38 @@ async function testPrompt(Prompt) {
         notification.secondaryActions.length,
         expectedSecondaryActionsCount,
         "There should only be " +
           expectedSecondaryActionsCount +
           " secondary action(s)"
       );
       await clickSecondaryAction(secondaryActionToClickIndex);
       if (permissionKey) {
-        curPerm = SitePermissions.get(principal.URI, permissionKey);
-        Assert.deepEqual(
-          curPerm,
-          {
-            state: SitePermissions.BLOCK,
-            scope: SitePermissions.SCOPE_PERSISTENT,
-          },
-          "Should have denied the action permanently"
+        curPerm = PermissionTestUtils.getPermissionObject(
+          principal.URI,
+          permissionKey
         );
+        Assert.equal(
+          curPerm.capability,
+          Services.perms.DENY_ACTION,
+          "Should have denied the action"
+        );
+        Assert.equal(curPerm.expireTime, 0, "Deny should be permanent");
         Assert.ok(
           mockRequest._cancelled,
           "The request should have been cancelled"
         );
         Assert.ok(
           !mockRequest._allowed,
           "The request should not have been allowed"
         );
       }
 
       if (permissionKey) {
-        SitePermissions.remove(principal.URI, permissionKey);
+        PermissionTestUtils.remove(principal.URI, permissionKey);
         mockRequest._cancelled = false;
       }
 
       // Bring the PopupNotification back up now...
       shownPromise = BrowserTestUtils.waitForEvent(
         PopupNotifications.panel,
         "popupshown"
       );
@@ -192,25 +204,26 @@ async function testPrompt(Prompt) {
       await shownPromise;
 
       // Test allowing the permission request with the checkbox checked.
       popupNotification = getPopupNotificationNode();
       popupNotification.checkbox.checked = true;
 
       await clickMainAction();
       if (permissionKey) {
-        curPerm = SitePermissions.get(principal.URI, permissionKey);
-        Assert.deepEqual(
-          curPerm,
-          {
-            state: SitePermissions.ALLOW,
-            scope: SitePermissions.SCOPE_PERSISTENT,
-          },
-          "Should have allowed the action permanently"
+        curPerm = PermissionTestUtils.getPermissionObject(
+          principal.URI,
+          permissionKey
         );
+        Assert.equal(
+          curPerm.capability,
+          Services.perms.ALLOW_ACTION,
+          "Should have allowed the action"
+        );
+        Assert.equal(curPerm.expireTime, 0, "Allow should be permanent");
         Assert.ok(
           !mockRequest._cancelled,
           "The request should not have been cancelled"
         );
         Assert.ok(mockRequest._allowed, "The request should have been allowed");
       }
     }
   );
--- a/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_request_permission.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 "use strict";
 
-ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
 
 const VIDEO_PAGE =
   "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
 
 function setTestingPreferences(defaultSetting) {
   info(`set default autoplay setting to '${defaultSetting}'`);
   let defaultValue =
     defaultSetting == "blocked"
@@ -30,28 +32,28 @@ async function testAutoplayExistingPermi
     {
       gBrowser,
       url: VIDEO_PAGE,
     },
     async browser => {
       let promptShowing = () =>
         PopupNotifications.getNotification("autoplay-media", browser);
 
-      SitePermissions.set(
+      PermissionTestUtils.add(
         browser.currentURI,
         "autoplay-media",
         args.permission
       );
       ok(!promptShowing(), "Should not be showing permission prompt yet");
 
       await loadAutoplayVideo(browser, args);
       await checkVideoDidPlay(browser, args);
 
       // Reset permission.
-      SitePermissions.remove(browser.currentURI, "autoplay-media");
+      PermissionTestUtils.remove(browser.currentURI, "autoplay-media");
 
       info("- Finished '" + args.name + "' -");
     }
   );
 }
 
 async function testAutoplayExistingPermissionAgainstDefaultSetting(args) {
   await setTestingPreferences(args.defaultSetting);
@@ -60,54 +62,54 @@ async function testAutoplayExistingPermi
 
 // Test the simple ALLOW/BLOCK cases; when permission is already set to ALLOW,
 // we shoud be able to autoplay via calling play(), or via the autoplay attribute,
 // and when it's set to BLOCK, we should not.
 add_task(async () => {
   await setTestingPreferences("blocked" /* default setting */);
   await testAutoplayExistingPermission({
     name: "Prexisting allow permission autoplay attribute",
-    permission: SitePermissions.ALLOW,
+    permission: Services.perms.ALLOW_ACTION,
     shouldPlay: true,
     mode: "autoplay attribute",
   });
   await testAutoplayExistingPermission({
     name: "Prexisting allow permission call play",
-    permission: SitePermissions.ALLOW,
+    permission: Services.perms.ALLOW_ACTION,
     shouldPlay: true,
     mode: "call play",
   });
   await testAutoplayExistingPermission({
     name: "Prexisting block permission autoplay attribute",
-    permission: SitePermissions.BLOCK,
+    permission: Services.perms.DENY_ACTION,
     shouldPlay: false,
     mode: "autoplay attribute",
   });
   await testAutoplayExistingPermission({
     name: "Prexisting block permission call play",
-    permission: SitePermissions.BLOCK,
+    permission: Services.perms.DENY_ACTION,
     shouldPlay: false,
     mode: "call play",
   });
 });
 
 /**
  * These tests are used to ensure the autoplay setting for specific site can
  * always override the default autoplay setting.
  */
 add_task(async () => {
   await testAutoplayExistingPermissionAgainstDefaultSetting({
     name:
       "Site has prexisting allow permission but default setting is 'blocked'",
-    permission: SitePermissions.ALLOW,
+    permission: Services.perms.ALLOW_ACTION,
     defaultSetting: "blocked",
     shouldPlay: true,
     mode: "autoplay attribute",
   });
   await testAutoplayExistingPermissionAgainstDefaultSetting({
     name:
       "Site has prexisting block permission but default setting is 'allowed'",
-    permission: SitePermissions.BLOCK,
+    permission: Services.perms.DENY_ACTION,
     defaultSetting: "allowed",
     shouldPlay: false,
     mode: "autoplay attribute",
   });
 });
--- a/toolkit/content/tests/browser/browser_autoplay_policy_webRTC_permission.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_webRTC_permission.js
@@ -1,15 +1,18 @@
 /**
  * This test is used to ensure site which has granted 'camera' or 'microphone'
  * or 'screen' permission could be allowed to autoplay.
  */
 "use strict";
 
-ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const VIDEO_PAGE =
   "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
 
 add_task(() => {
   return SpecialPowers.pushPrefEnv({
     set: [
       ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
       ["media.autoplay.enabled.user-gestures-needed", true],
@@ -21,27 +24,27 @@ add_task(() => {
 async function testAutoplayWebRTCPermission(args) {
   info(`- Starting ${args.name} -`);
   await BrowserTestUtils.withNewTab(
     {
       gBrowser,
       url: VIDEO_PAGE,
     },
     async browser => {
-      SitePermissions.set(
+      PermissionTestUtils.add(
         browser.currentURI,
         args.permission,
-        SitePermissions.ALLOW
+        Services.perms.ALLOW_ACTION
       );
 
       await loadAutoplayVideo(browser, args);
       await checkVideoDidPlay(browser, args);
 
       // Reset permission.
-      SitePermissions.remove(browser.currentURI, args.permission);
+      PermissionTestUtils.remove(browser.currentURI, args.permission);
 
       info(`- Finished ${args.name} -`);
     }
   );
 }
 
 add_task(async function start_test() {
   await testAutoplayWebRTCPermission({
--- a/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
+++ b/toolkit/content/tests/browser/browser_autoplay_policy_web_audio.js
@@ -3,17 +3,20 @@
  * different scenarios, such as
  * 1) site has existing 'autoplay-media' permission for allowing autoplay
  * 2) site has existing 'autoplay-media' permission for blocking autoplay
  * 3) site doesn't have permission, start audio context by calling resume() or
  *    AudioScheduledNode.start() after granting user activation.
  */
 "use strict";
 
-ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
+const { PermissionTestUtils } = ChromeUtils.import(
+  "resource://testing-common/PermissionTestUtils.jsm"
+);
+
 const PAGE =
   "https://example.com/browser/toolkit/content/tests/browser/file_empty.html";
 
 function setup_test_preference() {
   return SpecialPowers.pushPrefEnv({
     set: [
       ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
       ["media.autoplay.enabled.user-gestures-needed", true],
@@ -116,51 +119,51 @@ async function testAutoplayExistingPermi
     window.gBrowser,
     PAGE
   );
   const browser = tab.linkedBrowser;
 
   info(`- set the 'autoplay-media' permission -`);
   const promptShow = () =>
     PopupNotifications.getNotification("autoplay-media", browser);
-  SitePermissions.set(browser.currentURI, "autoplay-media", permission);
+  PermissionTestUtils.add(browser.currentURI, "autoplay-media", permission);
   ok(!promptShow(), `should not be showing permission prompt yet`);
 
   info(`- create audio context -`);
   loadFrameScript(browser, createAudioContext);
 
   info(`- check AudioContext status -`);
-  const isAllowedToStart = permission === SitePermissions.ALLOW;
+  const isAllowedToStart = permission === Services.perms.ALLOW_ACTION;
   await ContentTask.spawn(
     browser,
     isAllowedToStart,
     checkIfAudioContextIsAllowedToStart
   );
   await ContentTask.spawn(browser, isAllowedToStart, resumeAudioContext);
 
   info(`- remove tab -`);
-  SitePermissions.remove(browser.currentURI, "autoplay-media");
+  PermissionTestUtils.remove(browser.currentURI, "autoplay-media");
   await BrowserTestUtils.removeTab(tab);
 }
 
 async function testAutoplayUnknownPermission({ name, method }) {
   info(`- starting \"${name}\" -`);
   const tab = await BrowserTestUtils.openNewForegroundTab(
     window.gBrowser,
     PAGE
   );
   const browser = tab.linkedBrowser;
 
   info(`- set the 'autoplay-media' permission to UNKNOWN -`);
   const promptShow = () =>
     PopupNotifications.getNotification("autoplay-media", browser);
-  SitePermissions.set(
+  PermissionTestUtils.add(
     browser.currentURI,
     "autoplay-media",
-    SitePermissions.UNKNOWN
+    Services.perms.UNKNOWN_ACTION
   );
   ok(!promptShow(), `should not be showing permission prompt yet`);
 
   info(`- create AudioContext which should not start -`);
   loadFrameScript(browser, createAudioContext);
   await ContentTask.spawn(browser, false, checkIfAudioContextIsAllowedToStart);
 
   info(`- simulate user activate the page -`);
@@ -179,31 +182,31 @@ async function testAutoplayUnknownPermis
   );
   await ContentTask.spawn(
     browser,
     true /* allow to start */,
     resumeAudioContext
   );
 
   info(`- remove tab -`);
-  SitePermissions.remove(browser.currentURI, "autoplay-media");
+  PermissionTestUtils.remove(browser.currentURI, "autoplay-media");
   await BrowserTestUtils.removeTab(tab);
 }
 
 add_task(async function start_tests() {
   info("- setup test preference -");
   await setup_test_preference();
 
   await testAutoplayExistingPermission({
     name: "Prexisting allow permission",
-    permission: SitePermissions.ALLOW,
+    permission: Services.perms.ALLOW_ACTION,
   });
   await testAutoplayExistingPermission({
     name: "Prexisting block permission",
-    permission: SitePermissions.BLOCK,
+    permission: Services.perms.DENY_ACTION,
   });
   const startMethods = [
     "AudioContext",
     "AudioBufferSourceNode",
     "ConstantSourceNode",
     "OscillatorNode",
   ];
   for (let method of startMethods) {
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js
@@ -429,32 +429,28 @@ var TESTS = [
     is(
       installPerm,
       Ci.nsIPermissionManager.DENY_ACTION,
       "Addon installation should be blocked for site"
     );
 
     await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
-    SitePermissions.remove(NetUtil.newURI(target), "install");
+    PermissionTestUtils.remove(target, "install");
   },
 
   async function test_permaBlockedInstallNoPrompt() {
     let triggers = encodeURIComponent(
       JSON.stringify({
         XPI: "amosigned.xpi",
       })
     );
     let target = TESTROOT + "installtrigger.html?" + triggers;
 
-    SitePermissions.set(
-      NetUtil.newURI(target),
-      "install",
-      SitePermissions.BLOCK
-    );
+    PermissionTestUtils.add(target, "install", Services.perms.DENY_ACTION);
     await BrowserTestUtils.openNewForegroundTab(gBrowser, target);
 
     let panelOpened;
     try {
       panelOpened = await TestUtils.waitForCondition(
         () => PopupNotifications.isPanelOpen,
         100,
         10
@@ -464,17 +460,17 @@ var TESTS = [
     }
     is(panelOpened, false, "Addon prompt should not open");
 
     let installs = await AddonManager.getAllInstalls();
     is(installs.length, 0, "Should be no pending installs");
 
     await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
-    SitePermissions.remove(NetUtil.newURI(target), "install");
+    PermissionTestUtils.remove(target, "install");
   },
 
   async function test_whitelistedInstall() {
     Services.prefs.setBoolPref(
       "extensions.allowPrivateBrowsingByDefault",
       false
     );
     let originalTab = gBrowser.selectedTab;