Backed out 11 changesets (bug 1330467) as requested by xeonchen on IRC. CLOSED TREE
authorMihai Alexandru Michis <malexandru@mozilla.com>
Fri, 17 May 2019 16:19:06 +0300
changeset 474324 3866561a7bae97a6c9ec3c18174747ec36bba090
parent 474323 f72947acdfcd662c26a8e84efac58e703b2ce2ec
child 474325 c94c54aff4669f52cebc76ddad34a76f4fafd03b
push id36027
push usershindli@mozilla.com
push dateFri, 17 May 2019 16:24:38 +0000
treeherdermozilla-central@c94c54aff466 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1330467
milestone68.0a1
backs out0229d5353d503441ed11643c8e5e4e90011261b8
2f2308fe574799b90705b7f55c402b9dd578369d
2cd09bae2bdf579412d83e7a5c11381de18f9e48
2648f5bb180463e213b55a0f1434c51c9853f213
4686eebd8962db7d03d7fbca124cca28069f4a72
b43fa07d5756d6206f41a4f4a7da6758b2a09690
35d96a4ff6592595d15e470fde508f62d5f6fb1e
6ac44130d2bb05cc6cadb5cd642bbe7fe90ca08a
f939c61e051fd2891a79bf1981b018dc454e9b77
0ae215d917586bd3393d2e55f34a6ee57631035d
1d48bdbb4035d38d3d775b6b8da3f067adeada2a
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
Backed out 11 changesets (bug 1330467) as requested by xeonchen on IRC. CLOSED TREE Backed out changeset 0229d5353d50 (bug 1330467) Backed out changeset 2f2308fe5747 (bug 1330467) Backed out changeset 2cd09bae2bdf (bug 1330467) Backed out changeset 2648f5bb1804 (bug 1330467) Backed out changeset 4686eebd8962 (bug 1330467) Backed out changeset b43fa07d5756 (bug 1330467) Backed out changeset 35d96a4ff659 (bug 1330467) Backed out changeset 6ac44130d2bb (bug 1330467) Backed out changeset f939c61e051f (bug 1330467) Backed out changeset 0ae215d91758 (bug 1330467) Backed out changeset 1d48bdbb4035 (bug 1330467)
browser/base/content/browser-siteIdentity.js
browser/base/content/browser.js
browser/base/content/pageinfo/permissions.js
browser/components/preferences/sitePermissions.js
browser/components/translation/Translation.jsm
browser/components/translation/content/translation-notification.js
browser/components/translation/test/browser_translation_exceptions.js
browser/modules/PermissionUI.jsm
browser/modules/SitePermissions.jsm
browser/modules/webrtcUI.jsm
dom/canvas/CanvasUtils.cpp
dom/ipc/BrowserParent.cpp
dom/ipc/BrowserParent.h
dom/ipc/PBrowser.ipdl
extensions/permissions/nsPermission.cpp
extensions/permissions/nsPermission.h
extensions/permissions/nsPermissionManager.cpp
extensions/permissions/test/unit/test_permmanager_defaults.js
extensions/permissions/test/unit/test_permmanager_matches.js
mobile/android/chrome/content/OfflineApps.js
mobile/android/chrome/content/PermissionsHelper.js
mobile/android/chrome/content/browser.js
mobile/android/components/geckoview/GeckoViewPermission.js
mobile/android/modules/WebrtcUI.jsm
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -1152,19 +1152,19 @@ var gIdentityHandler = {
       if (aPermission.state == SitePermissions.getDefault(aPermission.id)) {
         menulist.value = "0";
       } else {
         menulist.value = aPermission.state;
       }
 
       // Avoiding listening to the "select" event on purpose. See Bug 1404262.
       menulist.addEventListener("command", () => {
-        SitePermissions.setForPrincipal(gBrowser.contentPrincipal,
-                                        aPermission.id,
-                                        menulist.selectedItem.value);
+        SitePermissions.set(gBrowser.currentURI,
+                            aPermission.id,
+                            menulist.selectedItem.value);
       });
 
       container.appendChild(img);
       container.appendChild(nameLabel);
       container.appendChild(menulist);
       container.setAttribute("aria-labelledby", nameLabelId);
       block.appendChild(container);
 
@@ -1208,35 +1208,35 @@ var gIdentityHandler = {
           ["camera", "microphone", "screen"].includes(aPermission.id)) {
         let windowId = this._sharingState.windowId;
         if (aPermission.id == "screen") {
           windowId = "screen:" + windowId;
         } else {
           // If we set persistent permissions or the sharing has
           // started due to existing persistent permissions, we need
           // to handle removing these even for frames with different hostnames.
-          let principals = browser._devicePermissionPrincipals || [];
-          for (let principal of principals) {
+          let uris = browser._devicePermissionURIs || [];
+          for (let uri of uris) {
             // It's not possible to stop sharing one of camera/microphone
             // without the other.
             for (let id of ["camera", "microphone"]) {
               if (this._sharingState[id]) {
-                let perm = SitePermissions.getForPrincipal(principal, id);
+                let perm = SitePermissions.get(uri, id);
                 if (perm.state == SitePermissions.ALLOW &&
                     perm.scope == SitePermissions.SCOPE_PERSISTENT) {
-                  SitePermissions.removeFromPrincipal(principal, id);
+                  SitePermissions.remove(uri, id);
                 }
               }
             }
           }
         }
         browser.messageManager.sendAsyncMessage("webrtc:StopSharing", windowId);
         webrtcUI.forgetActivePermissionsFromBrowser(gBrowser.selectedBrowser);
       }
-      SitePermissions.removeFromPrincipal(gBrowser.contentPrincipal, aPermission.id, browser);
+      SitePermissions.remove(gBrowser.currentURI, aPermission.id, browser);
 
       this._permissionReloadHint.removeAttribute("hidden");
       PanelView.forNode(this._identityPopupMainView)
                .descriptionHeightWorkaround();
     });
 
     container.appendChild(button);
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7248,78 +7248,75 @@ var CanvasPermissionPromptHelper = {
   },
 
   uninit() {
     Services.obs.removeObserver(this, this._permissionsPrompt);
     Services.obs.removeObserver(this, this._permissionsPromptHideDoorHanger);
   },
 
   // aSubject is an nsIBrowser (e10s) or an nsIDOMWindow (non-e10s).
-  // aData is an Origin string.
+  // aData is an URL string.
   observe(aSubject, aTopic, aData) {
     if (aTopic != this._permissionsPrompt &&
         aTopic != this._permissionsPromptHideDoorHanger) {
       return;
     }
 
     let browser;
     if (aSubject instanceof Ci.nsIDOMWindow) {
       let contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
       browser = contentWindow.docShell.chromeEventHandler;
     } else {
       browser = aSubject;
     }
 
+    let uri = Services.io.newURI(aData);
     if (gBrowser.selectedBrowser !== browser) {
       // Must belong to some other window.
       return;
     }
 
     let message = gNavigatorBundle.getFormattedString("canvas.siteprompt", ["<>"], 1);
 
-    let principal = Services.scriptSecurityManager
-                            .createCodebasePrincipalFromOrigin(aData);
-
-    function setCanvasPermission(aPerm, aPersistent) {
-      Services.perms.addFromPrincipal(
-        principal, "canvas", aPerm,
-        aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
-                    : Ci.nsIPermissionManager.EXPIRE_SESSION);
+    function setCanvasPermission(aURI, aPerm, aPersistent) {
+      Services.perms.add(aURI, "canvas", aPerm,
+                          aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
+                                      : Ci.nsIPermissionManager.EXPIRE_SESSION);
     }
 
     let mainAction = {
       label: gNavigatorBundle.getString("canvas.allow"),
       accessKey: gNavigatorBundle.getString("canvas.allow.accesskey"),
       callback(state) {
-        setCanvasPermission(Ci.nsIPermissionManager.ALLOW_ACTION,
+        setCanvasPermission(uri, Ci.nsIPermissionManager.ALLOW_ACTION,
                             state && state.checkboxChecked);
       },
     };
 
     let secondaryActions = [{
       label: gNavigatorBundle.getString("canvas.notAllow"),
       accessKey: gNavigatorBundle.getString("canvas.notAllow.accesskey"),
       callback(state) {
-        setCanvasPermission(Ci.nsIPermissionManager.DENY_ACTION,
+        setCanvasPermission(uri, Ci.nsIPermissionManager.DENY_ACTION,
                             state && state.checkboxChecked);
       },
     }];
 
     let checkbox = {
       // In PB mode, we don't want the "always remember" checkbox
       show: !PrivateBrowsingUtils.isWindowPrivate(window),
     };
     if (checkbox.show) {
       checkbox.checked = true;
       checkbox.label = gBrowserBundle.GetStringFromName("canvas.remember");
     }
 
     let options = {
       checkbox,
-      name: principal.URI.host,
+      name: uri.asciiHost,
       learnMoreURL: Services.urlFormatter.formatURLPref("app.support.baseURL") + "fingerprint-permission",
       dismissed: aTopic == this._permissionsPromptHideDoorHanger,
     };
     PopupNotifications.show(browser, this._permissionsPrompt, message,
                             this._notificationIcon, mainAction,
                             secondaryActions, options);
   },
 };
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -1,45 +1,47 @@
 /* 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/. */
 
 /* import-globals-from pageInfo.js */
 
 const {SitePermissions} = ChromeUtils.import("resource:///modules/SitePermissions.jsm");
 
+var gPermURI;
 var gPermPrincipal;
 var gUsageRequest;
 
 // Array of permissionIDs sorted alphabetically by label.
 var gPermissions = SitePermissions.listPermissions()
   .filter(p => SitePermissions.getPermissionLabel(p) != null)
   .sort((a, b) => {
     let firstLabel = SitePermissions.getPermissionLabel(a);
     let secondLabel = SitePermissions.getPermissionLabel(b);
     return firstLabel.localeCompare(secondLabel);
   });
 
 var permissionObserver = {
   observe(aSubject, aTopic, aData) {
     if (aTopic == "perm-changed") {
       var permission = aSubject.QueryInterface(Ci.nsIPermission);
-      if (permission.matches(gPermPrincipal, true) && gPermissions.includes(permission.type)) {
+      if (permission.matchesURI(gPermURI, true) && gPermissions.includes(permission.type)) {
           initRow(permission.type);
       }
     }
   },
 };
 
 function onLoadPermission(uri, principal) {
   var permTab = document.getElementById("permTab");
-  if (SitePermissions.isSupportedPrincipal(principal)) {
+  if (SitePermissions.isSupportedURI(uri)) {
+    gPermURI = uri;
     gPermPrincipal = principal;
     var hostText = document.getElementById("hostText");
-    hostText.value = uri.displayPrePath;
+    hostText.value = gPermURI.displayPrePath;
 
     for (var i of gPermissions) {
       initRow(i);
     }
     Services.obs.addObserver(permissionObserver, "perm-changed");
     onUnloadRegistry.push(onUnloadPermission);
     permTab.hidden = false;
   } else {
@@ -56,17 +58,17 @@ function onUnloadPermission() {
   }
 }
 
 function initRow(aPartId) {
   createRow(aPartId);
 
   var checkbox = document.getElementById(aPartId + "Def");
   var command  = document.getElementById("cmd_" + aPartId + "Toggle");
-  var {state, scope} = SitePermissions.getForPrincipal(gPermPrincipal, aPartId);
+  var {state, scope} = SitePermissions.get(gPermURI, aPartId);
   let defaultState = SitePermissions.getDefault(aPartId);
 
   // Since cookies preferences have many different possible configuration states
   // we don't consider any permission except "no permission" to be default.
   if (aPartId == "cookie") {
     state = Services.perms.testPermissionFromPrincipal(gPermPrincipal, "cookie");
 
     if (state == SitePermissions.UNKNOWN) {
@@ -161,29 +163,29 @@ function createRow(aPartId) {
 
   document.getElementById("permList").appendChild(row);
 }
 
 function onCheckboxClick(aPartId) {
   var command  = document.getElementById("cmd_" + aPartId + "Toggle");
   var checkbox = document.getElementById(aPartId + "Def");
   if (checkbox.checked) {
-    SitePermissions.removeFromPrincipal(gPermPrincipal, aPartId);
+    SitePermissions.remove(gPermURI, aPartId);
     command.setAttribute("disabled", "true");
   } else {
     onRadioClick(aPartId);
     command.removeAttribute("disabled");
   }
 }
 
 function onRadioClick(aPartId) {
   var radioGroup = document.getElementById(aPartId + "RadioGroup");
   var id = radioGroup.selectedItem ? radioGroup.selectedItem.id : "#1";
   var permission = parseInt(id.split("#")[1]);
-  SitePermissions.setForPrincipal(gPermPrincipal, aPartId, permission);
+  SitePermissions.set(gPermURI, aPartId, permission);
 }
 
 function setRadioState(aPartId, aValue) {
   var radio = document.getElementById(aPartId + "#" + aValue);
   if (radio) {
     radio.radioGroup.selectedItem = radio;
   }
 }
--- a/browser/components/preferences/sitePermissions.js
+++ b/browser/components/preferences/sitePermissions.js
@@ -369,21 +369,23 @@ var gSitePermissionsManager = {
 
   onApplyChanges() {
     // Stop observing permission changes since we are about
     // to write out the pending adds/deletes and don't need
     // to update the UI
     this.uninit();
 
     for (let p of this._permissionsToChange.values()) {
-      SitePermissions.setForPrincipal(p.principal, p.type, p.capability);
+      let uri = Services.io.newURI(p.origin);
+      SitePermissions.set(uri, p.type, p.capability);
     }
 
     for (let p of this._permissionsToDelete.values()) {
-      SitePermissions.removeFromPrincipal(p.principal, p.type);
+      let uri = Services.io.newURI(p.origin);
+      SitePermissions.remove(uri, p.type);
     }
 
     if (this._checkbox.checked) {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.BLOCK);
     } else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.UNKNOWN);
     }
 
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -63,17 +63,17 @@ var Translation = {
                                                  : aData.state;
     trUI.detectedLanguage = aData.detectedLanguage;
     trUI.translatedFrom = aData.translatedFrom;
     trUI.translatedTo = aData.translatedTo;
     trUI.originalShown = aData.originalShown;
 
     trUI.showURLBarIcon();
 
-    if (trUI.shouldShowInfoBar(aBrowser.contentPrincipal))
+    if (trUI.shouldShowInfoBar(aBrowser.currentURI))
       trUI.showTranslationInfoBar();
   },
 
   openProviderAttribution() {
     let attribution = this.supportedEngines[this.translationEngine];
     const {BrowserWindowTracker} = ChromeUtils.import("resource:///modules/BrowserWindowTracker.jsm");
     BrowserWindowTracker.getTopWindow().openWebLinkIn(attribution, "tab");
   },
@@ -229,33 +229,33 @@ TranslationUI.prototype = {
     let notificationBox = this.notificationBox;
     let notif = notificationBox.appendNotification("", "translation", null,
       notificationBox.PRIORITY_INFO_HIGH, null, null,
       "translation-notification");
     notif.init(this);
     return notif;
   },
 
-  shouldShowInfoBar(aPrincipal) {
+  shouldShowInfoBar(aURI) {
     // Never show the infobar automatically while the translation
     // service is temporarily unavailable.
     if (Translation.serviceUnavailable)
       return false;
 
     // Check if we should never show the infobar for this language.
     let neverForLangs =
       Services.prefs.getCharPref("browser.translation.neverForLanguages");
     if (neverForLangs.split(",").includes(this.detectedLanguage)) {
       TranslationTelemetry.recordAutoRejectedTranslationOffer();
       return false;
     }
 
     // or if we should never show the infobar for this domain.
     let perms = Services.perms;
-    if (perms.testExactPermissionFromPrincipal(aPrincipal, "translate") == perms.DENY_ACTION) {
+    if (perms.testExactPermission(aURI, "translate") == perms.DENY_ACTION) {
       TranslationTelemetry.recordAutoRejectedTranslationOffer();
       return false;
     }
 
     return true;
   },
 
   receiveMessage(msg) {
--- a/browser/components/translation/content/translation-notification.js
+++ b/browser/components/translation/content/translation-notification.js
@@ -307,40 +307,40 @@ class MozTranslationNotification extends
 
     // We may need to disable the menuitems if they have already been used.
     // Check if translation is already disabled for this language:
     let neverForLangs =
       Services.prefs.getCharPref("browser.translation.neverForLanguages");
     item.disabled = neverForLangs.split(",").includes(lang);
 
     // Check if translation is disabled for the domain:
-    let principal = this.translation.browser.contentPrincipal;
+    let uri = this.translation.browser.currentURI;
     let perms = Services.perms;
     item = this._getAnonElt("neverForSite");
     item.disabled =
-      perms.testExactPermissionFromPrincipal(principal, "translate") == perms.DENY_ACTION;
+      perms.testExactPermission(uri, "translate") == perms.DENY_ACTION;
   }
 
   neverForLanguage() {
     const kPrefName = "browser.translation.neverForLanguages";
 
     let val = Services.prefs.getCharPref(kPrefName);
     if (val)
       val += ",";
     val += this._getAnonElt("neverForLanguage").langCode;
 
     Services.prefs.setCharPref(kPrefName, val);
 
     this.closeCommand();
   }
 
   neverForSite() {
-    let principal = this.translation.browser.contentPrincipal;
+    let uri = this.translation.browser.currentURI;
     let perms = Services.perms;
-    perms.addFromPrincipal(principal, "translate", perms.DENY_ACTION);
+    perms.add(uri, "translate", perms.DENY_ACTION);
 
     this.closeCommand();
   }
 
   openProviderAttribution() {
     Translation.openProviderAttribution();
   }
 }
--- a/browser/components/translation/test/browser_translation_exceptions.js
+++ b/browser/components/translation/test/browser_translation_exceptions.js
@@ -107,18 +107,18 @@ var gTests = [
     // Show the infobar for example.com and fr.
     Translation.documentStateReceived(gBrowser.selectedBrowser,
                                       {state: Translation.STATE_OFFER,
                                        originalShown: true,
                                        detectedLanguage: "fr"});
     let notif = await getInfoBar();
     ok(notif, "the infobar is visible");
     let ui = gBrowser.selectedBrowser.translationUI;
-    let principal = gBrowser.selectedBrowser.contentPrincipal;
-    ok(ui.shouldShowInfoBar(principal, "fr"),
+    let uri = gBrowser.selectedBrowser.currentURI;
+    ok(ui.shouldShowInfoBar(uri, "fr"),
        "check shouldShowInfoBar initially returns true");
 
     // Open the "options" drop down.
     await openPopup(notif._getAnonElt("options"));
     ok(notif._getAnonElt("options").getAttribute("open"),
        "the options menu is open");
 
     // Check that the item is not disabled.
@@ -129,17 +129,17 @@ var gTests = [
     notif._getAnonElt("neverForLanguage").click();
     notif = await getInfoBar();
     ok(!notif, "infobar hidden");
 
     // Check this has been saved to the exceptions list.
     let langs = getLanguageExceptions();
     is(langs.length, 1, "one language in the exception list");
     is(langs[0], "fr", "correct language in the exception list");
-    ok(!ui.shouldShowInfoBar(principal, "fr"),
+    ok(!ui.shouldShowInfoBar(uri, "fr"),
        "the infobar wouldn't be shown anymore");
 
     // Reopen the infobar.
     PopupNotifications.getNotification("translate").anchorElement.click();
     notif = await getInfoBar();
     // Open the "options" drop down.
     await openPopup(notif._getAnonElt("options"));
     ok(notif._getAnonElt("neverForLanguage").disabled,
@@ -157,18 +157,18 @@ var gTests = [
     // Show the infobar for example.com and fr.
     Translation.documentStateReceived(gBrowser.selectedBrowser,
                                       {state: Translation.STATE_OFFER,
                                        originalShown: true,
                                        detectedLanguage: "fr"});
     let notif = await getInfoBar();
     ok(notif, "the infobar is visible");
     let ui = gBrowser.selectedBrowser.translationUI;
-    let principal = gBrowser.selectedBrowser.contentPrincipal;
-    ok(ui.shouldShowInfoBar(principal, "fr"),
+    let uri = gBrowser.selectedBrowser.currentURI;
+    ok(ui.shouldShowInfoBar(uri, "fr"),
        "check shouldShowInfoBar initially returns true");
 
     // Open the "options" drop down.
     await openPopup(notif._getAnonElt("options"));
     ok(notif._getAnonElt("options").getAttribute("open"),
        "the options menu is open");
 
     // Check that the item is not disabled.
@@ -179,17 +179,17 @@ var gTests = [
     notif._getAnonElt("neverForSite").click();
     notif = await getInfoBar();
     ok(!notif, "infobar hidden");
 
     // Check this has been saved to the exceptions list.
     let sites = getDomainExceptions();
     is(sites.length, 1, "one site in the exception list");
     is(sites[0].origin, "http://example.com", "correct site in the exception list");
-    ok(!ui.shouldShowInfoBar(principal, "fr"),
+    ok(!ui.shouldShowInfoBar(uri, "fr"),
        "the infobar wouldn't be shown anymore");
 
     // Reopen the infobar.
     PopupNotifications.getNotification("translate").anchorElement.click();
     notif = await getInfoBar();
     // Open the "options" drop down.
     await openPopup(notif._getAnonElt("options"));
     ok(notif._getAnonElt("neverForSite").disabled,
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -359,19 +359,19 @@ var PermissionPromptPrototype = {
       return;
     }
 
     if (this.usePermissionManager &&
         this.permissionKey) {
       // If we're reading and setting permissions, then we need
       // to check to see if we already have a permission setting
       // for this particular principal.
-      let {state} = SitePermissions.getForPrincipal(this.principal,
-                                                    this.permissionKey,
-                                                    this.browser);
+      let {state} = SitePermissions.get(requestingURI,
+                                        this.permissionKey,
+                                        this.browser);
 
       if (state == SitePermissions.BLOCK) {
         // If this block was done based on a global user setting, we want to show
         // a post prompt to give the user some more granular control without
         // annoying them too much.
         if (this.postPromptEnabled &&
             SitePermissions.getDefault(this.permissionKey) == SitePermissions.BLOCK) {
           this.postPrompt();
@@ -434,29 +434,29 @@ var PermissionPromptPrototype = {
             if ((state && state.checkboxChecked && state.source != "esc-press") ||
                 promptAction.scope == SitePermissions.SCOPE_PERSISTENT) {
               // Permanently store permission.
               let scope = SitePermissions.SCOPE_PERSISTENT;
               // Only remember permission for session if in PB mode.
               if (PrivateBrowsingUtils.isBrowserPrivate(this.browser)) {
                 scope = SitePermissions.SCOPE_SESSION;
               }
-              SitePermissions.setForPrincipal(this.principal,
-                                              this.permissionKey,
-                                              promptAction.action,
-                                              scope);
+              SitePermissions.set(this.principal.URI,
+                                  this.permissionKey,
+                                  promptAction.action,
+                                  scope);
             } else if (promptAction.action == SitePermissions.BLOCK) {
               // Temporarily store BLOCK permissions only
               // SitePermissions does not consider subframes when storing temporary
               // permissions on a tab, thus storing ALLOW could be exploited.
-              SitePermissions.setForPrincipal(this.principal,
-                                              this.permissionKey,
-                                              promptAction.action,
-                                              SitePermissions.SCOPE_TEMPORARY,
-                                              this.browser);
+              SitePermissions.set(this.principal.URI,
+                                  this.permissionKey,
+                                  promptAction.action,
+                                  SitePermissions.SCOPE_TEMPORARY,
+                                  this.browser);
             }
 
             // Grant permission if action is ALLOW.
             // Record buttonAction for telemetry.
             if (promptAction.action == SitePermissions.ALLOW) {
               this._buttonAction = "accept";
               this.allow();
             } else {
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -254,51 +254,34 @@ var SitePermissions = {
   SCOPE_PERSISTENT: "{SitePermissions.SCOPE_PERSISTENT}",
   SCOPE_POLICY: "{SitePermissions.SCOPE_POLICY}",
   SCOPE_GLOBAL: "{SitePermissions.SCOPE_GLOBAL}",
 
   _permissionsArray: null,
   _defaultPrefBranch: Services.prefs.getBranch("permissions.default."),
 
   /**
-   * Deprecated! Please use getAllByPrincipal(principal) instead.
    * Gets all custom permissions for a given URI.
    * Install addon permission is excluded, check bug 1303108.
    *
    * @return {Array} a list of objects with the keys:
    *          - id: the permissionId of the permission
    *          - scope: the scope of the permission (e.g. SitePermissions.SCOPE_TEMPORARY)
    *          - state: a constant representing the current permission state
    *            (e.g. SitePermissions.ALLOW)
    */
   getAllByURI(uri) {
     if (!(uri instanceof Ci.nsIURI))
       throw new Error("uri parameter should be an nsIURI");
-
-    let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null;
-    return this.getAllByPrincipal(principal);
-  },
-
-  /**
-   * Gets all custom permissions for a given principal.
-   * Install addon permission is excluded, check bug 1303108.
-   *
-   * @return {Array} a list of objects with the keys:
-   *          - id: the permissionId of the permission
-   *          - scope: the scope of the permission (e.g. SitePermissions.SCOPE_TEMPORARY)
-   *          - state: a constant representing the current permission state
-   *            (e.g. SitePermissions.ALLOW)
-   */
-  getAllByPrincipal(principal) {
     let result = [];
-    if (!this.isSupportedPrincipal(principal)) {
+    if (!this.isSupportedURI(uri)) {
       return result;
     }
 
-    let permissions = Services.perms.getAllForPrincipal(principal);
+    let permissions = Services.perms.getAllForURI(uri);
     while (permissions.hasMoreElements()) {
       let permission = permissions.getNext();
 
       // filter out unknown permissions
       if (gPermissionObject[permission.type]) {
         // Hide canvas permission when privacy.resistFingerprinting is false.
         if ((permission.type == "canvas") && !this.resistFingerprinting) {
           continue;
@@ -345,17 +328,17 @@ var SitePermissions = {
       permission.scope = this.SCOPE_TEMPORARY;
       permissions[permission.id] = permission;
     }
 
     for (let permission of GloballyBlockedPermissions.getAll(browser)) {
       permissions[permission.id] = permission;
     }
 
-    for (let permission of this.getAllByPrincipal(browser.contentPrincipal)) {
+    for (let permission of this.getAllByURI(browser.currentURI)) {
       permissions[permission.id] = permission;
     }
 
     return Object.values(permissions);
   },
 
   /**
    * Returns a list of objects with detailed information on all permissions
@@ -373,46 +356,30 @@ var SitePermissions = {
    *           - label: the localized label, or null if none is available.
    */
   getAllPermissionDetailsForBrowser(browser) {
     return this.getAllForBrowser(browser).map(({id, scope, state}) =>
       ({id, scope, state, label: this.getPermissionLabel(id)}));
   },
 
   /**
-   * Deprecated! Please use isSupportedPrincipal(principal) instead.
    * Checks whether a UI for managing permissions should be exposed for a given
    * URI. This excludes file URIs, for instance, as they don't have a host,
    * even though nsIPermissionManager can still handle them.
    *
    * @param {nsIURI} uri
    *        The URI to check.
    *
    * @return {boolean} if the URI is supported.
    */
   isSupportedURI(uri) {
     return uri && ["http", "https", "moz-extension"].includes(uri.scheme);
   },
 
   /**
-   * Checks whether a UI for managing permissions should be exposed for a given
-   * principal. This excludes file URIs, for instance, as they don't have a host,
-   * even though nsIPermissionManager can still handle them.
-   *
-   * @param {nsIPrincipal} principal
-   *        The principal to check.
-   *
-   * @return {boolean} if the principal is supported.
-   */
-  isSupportedPrincipal(principal) {
-    return principal && principal.URI &&
-      ["http", "https", "moz-extension"].includes(principal.URI.scheme);
-  },
-
- /**
    * Gets an array of all permission IDs.
    *
    * @return {Array<String>} an array of all permission IDs.
    */
   listPermissions() {
     if (this._permissionsArray === null) {
       let permissions = Object.keys(gPermissionObject);
 
@@ -501,50 +468,25 @@ var SitePermissions = {
    *           - state: The current state of the permission
    *             (e.g. SitePermissions.ALLOW)
    *           - scope: The scope of the permission
    *             (e.g. SitePermissions.SCOPE_PERSISTENT)
    */
   get(uri, permissionID, browser) {
     if ((!uri && !browser) || (uri && !(uri instanceof Ci.nsIURI)))
       throw new Error("uri parameter should be an nsIURI or a browser parameter is needed");
-
-    let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null;
-    return this.getForPrincipal(principal, permissionID, browser);
-  },
-
- /**
-   * Returns the state and scope of a particular permission for a given principal.
-   *
-   * This method will NOT dispatch a "PermissionStateChange" event on the specified
-   * browser if a temporary permission was removed because it has expired.
-   *
-   * @param {nsIPrincipal} principal
-   *        The principal to check.
-   * @param {String} permissionID
-   *        The id of the permission.
-   * @param {Browser} browser (optional)
-   *        The browser object to check for temporary permissions.
-   *
-   * @return {Object} an object with the keys:
-   *           - state: The current state of the permission
-   *             (e.g. SitePermissions.ALLOW)
-   *           - scope: The scope of the permission
-   *             (e.g. SitePermissions.SCOPE_PERSISTENT)
-   */
-  getForPrincipal(principal, permissionID, browser) {
     let defaultState = this.getDefault(permissionID);
     let result = { state: defaultState, scope: this.SCOPE_PERSISTENT };
-    if (this.isSupportedPrincipal(principal)) {
+    if (this.isSupportedURI(uri)) {
       let permission = null;
       if (permissionID in gPermissionObject &&
         gPermissionObject[permissionID].exactHostMatch) {
-        permission = Services.perms.getPermissionObject(principal, permissionID, true);
+        permission = Services.perms.getPermissionObjectForURI(uri, permissionID, true);
       } else {
-        permission = Services.perms.getPermissionObject(principal, permissionID, false);
+        permission = Services.perms.getPermissionObjectForURI(uri, permissionID, false);
       }
 
       if (permission) {
         result.state = permission.capability;
         if (permission.expireType == Services.perms.EXPIRE_SESSION) {
           result.scope = this.SCOPE_SESSION;
         } else if (permission.expireType == Services.perms.EXPIRE_POLICY) {
           result.scope = this.SCOPE_POLICY;
@@ -562,17 +504,16 @@ var SitePermissions = {
         result.scope = this.SCOPE_TEMPORARY;
       }
     }
 
     return result;
   },
 
   /**
-   * Deprecated! Use setForPrincipal(...) instead.
    * Sets the state of a particular permission for a given URI or browser.
    * This method will dispatch a "PermissionStateChange" event on the specified
    * browser if a temporary permission was set
    *
    * @param {nsIURI} uri
    *        The URI to set the permission for.
    *        Note that this will be ignored if the scope is set to SCOPE_TEMPORARY
    * @param {String} permissionID
@@ -583,130 +524,87 @@ var SitePermissions = {
    *        The scope of the permission. Defaults to SCOPE_PERSISTENT.
    * @param {Browser} browser (optional)
    *        The browser object to set temporary permissions on.
    *        This needs to be provided if the scope is SCOPE_TEMPORARY!
    */
   set(uri, permissionID, state, scope = this.SCOPE_PERSISTENT, browser = null) {
     if ((!uri && !browser) || (uri && !(uri instanceof Ci.nsIURI)))
       throw new Error("uri parameter should be an nsIURI or a browser parameter is needed");
-
-    let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null;
-    return this.setForPrincipal(principal, permissionID, state, scope, browser);
-  },
-
-  /**
-   * Sets the state of a particular permission for a given principal or browser.
-   * This method will dispatch a "PermissionStateChange" event on the specified
-   * browser if a temporary permission was set
-   *
-   * @param {nsIPrincipal} principal
-   *        The principal to set the permission for.
-   *        Note that this will be ignored if the scope is set to SCOPE_TEMPORARY
-   * @param {String} permissionID
-   *        The id of the permission.
-   * @param {SitePermissions state} state
-   *        The state of the permission.
-   * @param {SitePermissions scope} scope (optional)
-   *        The scope of the permission. Defaults to SCOPE_PERSISTENT.
-   * @param {Browser} browser (optional)
-   *        The browser object to set temporary permissions on.
-   *        This needs to be provided if the scope is SCOPE_TEMPORARY!
-   */
-  setForPrincipal(principal, permissionID, state, scope = this.SCOPE_PERSISTENT, browser = null) {
     if (scope == this.SCOPE_GLOBAL && state == this.BLOCK) {
       GloballyBlockedPermissions.set(browser, permissionID);
       browser.dispatchEvent(new browser.ownerGlobal.CustomEvent("PermissionStateChange"));
       return;
     }
 
     if (state == this.UNKNOWN || state == this.getDefault(permissionID)) {
       // Because they are controlled by two prefs with many states that do not
       // correspond to the classical ALLOW/DENY/PROMPT model, we want to always
       // allow the user to add exceptions to their cookie rules without removing them.
       if (permissionID != "cookie") {
-        this.removeFromPrincipal(principal, permissionID, browser);
+        this.remove(uri, permissionID, browser);
         return;
       }
     }
 
     if (state == this.ALLOW_COOKIES_FOR_SESSION && permissionID != "cookie") {
       throw new Error("ALLOW_COOKIES_FOR_SESSION can only be set on the cookie permission");
     }
 
     // Save temporary permissions.
     if (scope == this.SCOPE_TEMPORARY) {
       // We do not support setting temp ALLOW for security reasons.
       // In its current state, this permission could be exploited by subframes
       // on the same page. This is because for BLOCK we ignore the request
-      // principal and only consider the current browser principal, to avoid notification spamming.
+      // URI and only consider the current browser URI, to avoid notification spamming.
       //
       // If you ever consider removing this line, you likely want to implement
       // a more fine-grained TemporaryPermissions that temporarily blocks for the
       // entire browser, but temporarily allows only for specific frames.
       if (state != this.BLOCK) {
         throw new Error("'Block' is the only permission we can save temporarily on a browser");
       }
 
       if (!browser) {
         throw new Error("TEMPORARY scoped permissions require a browser object");
       }
 
       TemporaryPermissions.set(browser, permissionID, state);
 
       browser.dispatchEvent(new browser.ownerGlobal
                                        .CustomEvent("PermissionStateChange"));
-    } else if (this.isSupportedPrincipal(principal)) {
+    } else if (this.isSupportedURI(uri)) {
       let perms_scope = Services.perms.EXPIRE_NEVER;
       if (scope == this.SCOPE_SESSION) {
         perms_scope = Services.perms.EXPIRE_SESSION;
       } else if (scope == this.SCOPE_POLICY) {
         perms_scope = Services.perms.EXPIRE_POLICY;
       }
 
-      Services.perms.addFromPrincipal(principal, permissionID, state, perms_scope);
+      Services.perms.add(uri, permissionID, state, perms_scope);
     }
   },
 
   /**
-   * Deprecated! Please use removeFromPrincipal(principal, permissionID, browser).
    * Removes the saved state of a particular permission for a given URI and/or browser.
    * This method will dispatch a "PermissionStateChange" event on the specified
    * browser if a temporary permission was removed.
    *
    * @param {nsIURI} uri
    *        The URI to remove the permission for.
    * @param {String} permissionID
    *        The id of the permission.
    * @param {Browser} browser (optional)
    *        The browser object to remove temporary permissions on.
    */
   remove(uri, permissionID, browser) {
     if ((!uri && !browser) || (uri && !(uri instanceof Ci.nsIURI)))
       throw new Error("uri parameter should be an nsIURI or a browser parameter is needed");
-
-    let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null;
-    return this.removeFromPrincipal(principal, permissionID, browser);
-  },
-
-  /**
-   * Removes the saved state of a particular permission for a given principal and/or browser.
-   * This method will dispatch a "PermissionStateChange" event on the specified
-   * browser if a temporary permission was removed.
-   *
-   * @param {nsIPrincipal} principal
-   *        The principal to remove the permission for.
-   * @param {String} permissionID
-   *        The id of the permission.
-   * @param {Browser} browser (optional)
-   *        The browser object to remove temporary permissions on.
-   */
-  removeFromPrincipal(principal, permissionID, browser) {
-    if (this.isSupportedPrincipal(principal))
-      Services.perms.removeFromPrincipal(principal, permissionID);
+    if (this.isSupportedURI(uri))
+      Services.perms.remove(uri, permissionID);
 
     // TemporaryPermissions.get() deletes expired permissions automatically,
     if (TemporaryPermissions.get(browser, permissionID)) {
       // If it exists but has not expired, remove it explicitly.
       TemporaryPermissions.remove(browser, permissionID);
       // Send a PermissionStateChange event only if the permission hasn't expired.
       browser.dispatchEvent(new browser.ownerGlobal
                                        .CustomEvent("PermissionStateChange"));
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -403,24 +403,30 @@ function stopRecording(aBrowser, aReques
     set.delete(aRequest.windowID + aRequest.mediaSource + aRequest.rawID);
   }
 }
 
 function prompt(aBrowser, aRequest) {
   let { audioDevices, videoDevices, sharingScreen, sharingAudio,
         requestTypes } = aRequest;
 
-  let principal = aBrowser.contentPrincipal;
+  let uri;
+  try {
+    // This fails for principals that serialize to "null", e.g. file URIs.
+    uri = Services.io.newURI(aRequest.origin);
+  } catch (e) {
+    uri = Services.io.newURI(aRequest.documentURI);
+  }
 
   // If the user has already denied access once in this tab,
   // deny again without even showing the notification icon.
   if ((audioDevices.length && SitePermissions
-        .getForPrincipal(principal, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
+        .get(uri, "microphone", aBrowser).state == SitePermissions.BLOCK) ||
       (videoDevices.length && SitePermissions
-        .getForPrincipal(principal, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
+        .get(uri, sharingScreen ? "screen" : "camera", aBrowser).state == SitePermissions.BLOCK)) {
     denyRequest(aBrowser, aRequest);
     return;
   }
 
   // Tell the browser to refresh the identity block display in case there
   // are expired permission states.
   aBrowser.dispatchEvent(new aBrowser.ownerGlobal
                                      .CustomEvent("PermissionStateChange"));
@@ -463,29 +469,29 @@ function prompt(aBrowser, aRequest) {
       accessKey: stringBundle.getString("getUserMedia.dontAllow.accesskey"),
       callback(aState) {
         denyRequest(notification.browser, aRequest);
         let scope = SitePermissions.SCOPE_TEMPORARY;
         if (aState && aState.checkboxChecked) {
           scope = SitePermissions.SCOPE_PERSISTENT;
         }
         if (audioDevices.length)
-          SitePermissions.setForPrincipal(principal, "microphone",
-                                          SitePermissions.BLOCK, scope, notification.browser);
+          SitePermissions.set(uri, "microphone",
+                              SitePermissions.BLOCK, scope, notification.browser);
         if (videoDevices.length)
-          SitePermissions.setForPrincipal(principal, sharingScreen ? "screen" : "camera",
-                                          SitePermissions.BLOCK, scope, notification.browser);
+          SitePermissions.set(uri, sharingScreen ? "screen" : "camera",
+                              SitePermissions.BLOCK, scope, notification.browser);
       },
     },
   ];
 
   let productName = gBrandBundle.GetStringFromName("brandShortName");
 
   let options = {
-    name: getHostOrExtensionName(principal.URI),
+    name: getHostOrExtensionName(uri),
     persistent: true,
     hideClose: true,
     eventCallback(aTopic, aNewBrowser) {
       if (aTopic == "swapping")
         return true;
 
       let doc = this.browser.ownerDocument;
 
@@ -511,25 +517,25 @@ function prompt(aBrowser, aRequest) {
 
       // BLOCK is handled immediately by MediaManager if it has been set
       // persistently in the permission manager. If it has been set on the tab,
       // it is handled synchronously before we add the notification.
       // Handling of ALLOW is delayed until the popupshowing event,
       // to avoid granting permissions automatically to background tabs.
       if (aRequest.secure) {
         let micAllowed =
-          SitePermissions.getForPrincipal(principal, "microphone").state == SitePermissions.ALLOW;
+          SitePermissions.get(uri, "microphone").state == SitePermissions.ALLOW;
         let camAllowed =
-          SitePermissions.getForPrincipal(principal, "camera").state == SitePermissions.ALLOW;
+          SitePermissions.get(uri, "camera").state == SitePermissions.ALLOW;
 
         let perms = Services.perms;
         let mediaManagerPerm =
-          perms.testExactPermissionFromPrincipal(principal, "MediaManagerVideo");
+          perms.testExactPermission(uri, "MediaManagerVideo");
         if (mediaManagerPerm) {
-          perms.removeFromPrincipal(principal, "MediaManagerVideo");
+          perms.remove(uri, "MediaManagerVideo");
         }
 
         // Screen sharing shouldn't follow the camera permissions.
         if (videoDevices.length && sharingScreen)
           camAllowed = false;
 
         let activeCamera;
         let activeMic;
@@ -553,31 +559,31 @@ function prompt(aBrowser, aRequest) {
           }
         }
 
         if ((!audioDevices.length || micAllowed || activeMic) &&
             (!videoDevices.length || camAllowed || activeCamera)) {
           let allowedDevices = [];
           if (videoDevices.length) {
             allowedDevices.push((activeCamera || videoDevices[0]).deviceIndex);
-            Services.perms.addFromPrincipal(principal, "MediaManagerVideo",
-                                            Services.perms.ALLOW_ACTION,
-                                            Services.perms.EXPIRE_SESSION);
+            Services.perms.add(uri, "MediaManagerVideo",
+                               Services.perms.ALLOW_ACTION,
+                               Services.perms.EXPIRE_SESSION);
           }
           if (audioDevices.length) {
             allowedDevices.push((activeMic || audioDevices[0]).deviceIndex);
           }
 
           // Remember on which URIs we found persistent permissions so that we
           // can remove them if the user clicks 'Stop Sharing'. There's no
           // other way for the stop sharing code to know the hostnames of frames
           // using devices until bug 1066082 is fixed.
           let browser = this.browser;
-          browser._devicePermissionPrincipals = browser._devicePermissionPrincipals || [];
-          browser._devicePermissionPrincipals.push(principal);
+          browser._devicePermissionURIs = browser._devicePermissionURIs || [];
+          browser._devicePermissionURIs.push(uri);
 
           let camNeeded = videoDevices.length > 0;
           let micNeeded = audioDevices.length > 0;
           checkOSPermission(camNeeded, micNeeded).then((havePermission) => {
             if (havePermission) {
               let mm = browser.messageManager;
               mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                                    windowID: aRequest.windowID,
@@ -728,19 +734,19 @@ function prompt(aBrowser, aRequest) {
 
             let [pre, post] = string.split("<>");
             warning.textContent = pre;
             warning.appendChild(learnMore);
             warning.appendChild(chromeWin.document.createTextNode(post));
           }
 
           let perms = Services.perms;
-          let chromePrincipal = Services.scriptSecurityManager.getSystemPrincipal();
-          perms.addFromPrincipal(chromePrincipal, "MediaManagerVideo", perms.ALLOW_ACTION,
-                                 perms.EXPIRE_SESSION);
+          let chromeUri = Services.io.newURI(doc.documentURI);
+          perms.add(chromeUri, "MediaManagerVideo", perms.ALLOW_ACTION,
+                    perms.EXPIRE_SESSION);
 
           video.deviceId = deviceId;
           let constraints = { video: { mediaSource: type, deviceId: {exact: deviceId } } };
           chromeWin.navigator.mediaDevices.getUserMedia(constraints).then(stream => {
             if (video.deviceId != deviceId) {
               // The user has selected a different device or closed the panel
               // before getUserMedia finished.
               stream.getTracks().forEach(t => t.stop());
@@ -805,31 +811,31 @@ function prompt(aBrowser, aRequest) {
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = doc.getElementById(listId).value;
           let allowVideoDevice = videoDeviceIndex != "-1";
           if (allowVideoDevice) {
             allowedDevices.push(videoDeviceIndex);
             // Session permission will be removed after use
             // (it's really one-shot, not for the entire session)
-            perms.addFromPrincipal(principal, "MediaManagerVideo", perms.ALLOW_ACTION,
-                                   perms.EXPIRE_SESSION);
+            perms.add(uri, "MediaManagerVideo", perms.ALLOW_ACTION,
+                      perms.EXPIRE_SESSION);
             if (!webrtcUI.activePerms.has(aBrowser.outerWindowID)) {
               webrtcUI.activePerms.set(aBrowser.outerWindowID, new Set());
             }
 
             for (let device of videoDevices) {
               if (device.deviceIndex == videoDeviceIndex) {
                 webrtcUI.activePerms.get(aBrowser.outerWindowID)
                         .add(aRequest.windowID + device.mediaSource + device.id);
                 break;
               }
             }
             if (remember)
-              SitePermissions.setForPrincipal(principal, "camera", SitePermissions.ALLOW);
+              SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
           }
         }
         if (audioDevices.length) {
           if (!sharingAudio) {
             let audioDeviceIndex = doc.getElementById("webRTC-selectMicrophone-menulist").value;
             let allowMic = audioDeviceIndex != "-1";
             if (allowMic) {
               allowedDevices.push(audioDeviceIndex);
@@ -840,34 +846,34 @@ function prompt(aBrowser, aRequest) {
               for (let device of audioDevices) {
                 if (device.deviceIndex == audioDeviceIndex) {
                   webrtcUI.activePerms.get(aBrowser.outerWindowID)
                           .add(aRequest.windowID + device.mediaSource + device.id);
                   break;
                 }
               }
               if (remember)
-                SitePermissions.setForPrincipal(principal, "microphone", SitePermissions.ALLOW);
+                SitePermissions.set(uri, "microphone", SitePermissions.ALLOW);
             }
           } else {
             // Only one device possible for audio capture.
             allowedDevices.push(0);
           }
         }
 
         if (!allowedDevices.length) {
           denyRequest(notification.browser, aRequest);
           return;
         }
 
         if (remember) {
           // Remember on which URIs we set persistent permissions so that we
           // can remove them if the user clicks 'Stop Sharing'.
-          aBrowser._devicePermissionPrincipals = aBrowser._devicePermissionPrincipals || [];
-          aBrowser._devicePermissionPrincipals.push(principal);
+          aBrowser._devicePermissionURIs = aBrowser._devicePermissionURIs || [];
+          aBrowser._devicePermissionURIs.push(uri);
         }
 
         let camNeeded = videoDevices.length > 0;
         let micNeeded = audioDevices.length > 0;
         let havePermission = await checkOSPermission(camNeeded, micNeeded);
         if (!havePermission) {
           denyRequestNoPermission(notification.browser, aRequest);
           return;
--- a/dom/canvas/CanvasUtils.cpp
+++ b/dom/canvas/CanvasUtils.cpp
@@ -119,18 +119,18 @@ bool IsImageExtractionAllowed(Document* 
   // Load Permission Manager service.
   nsCOMPtr<nsIPermissionManager> permissionManager =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
   // Check if the site has permission to extract canvas data.
   // Either permit or block extraction if a stored permission setting exists.
   uint32_t permission;
-  rv = permissionManager->TestPermissionFromPrincipal(
-      principal, PERMISSION_CANVAS_EXTRACT_DATA, &permission);
+  rv = permissionManager->TestPermission(
+      topLevelDocURI, PERMISSION_CANVAS_EXTRACT_DATA, &permission);
   NS_ENSURE_SUCCESS(rv, false);
   switch (permission) {
     case nsIPermissionManager::ALLOW_ACTION:
       return true;
     case nsIPermissionManager::DENY_ACTION:
       return false;
     default:
       break;
@@ -162,34 +162,30 @@ bool IsImageExtractionAllowed(Document* 
         docURISpec.get());
     nsContentUtils::ReportToConsoleNonLocalized(
         message, nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Security"),
         aDocument);
   }
 
   // Prompt the user (asynchronous).
   nsPIDOMWindowOuter* win = aDocument->GetWindow();
-  nsAutoCString origin;
-  rv = principal->GetOrigin(origin);
-  NS_ENSURE_SUCCESS(rv, false);
-
   if (XRE_IsContentProcess()) {
     BrowserChild* browserChild = BrowserChild::GetFrom(win);
     if (browserChild) {
-      browserChild->SendShowCanvasPermissionPrompt(origin,
+      browserChild->SendShowCanvasPermissionPrompt(topLevelDocURISpec,
                                                    isAutoBlockCanvas);
     }
   } else {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->NotifyObservers(win,
                            isAutoBlockCanvas
                                ? TOPIC_CANVAS_PERMISSIONS_PROMPT_HIDE_DOORHANGER
                                : TOPIC_CANVAS_PERMISSIONS_PROMPT,
-                           NS_ConvertUTF8toUTF16(origin).get());
+                           NS_ConvertUTF8toUTF16(topLevelDocURISpec).get());
     }
   }
 
   // We don't extract the image for now -- user may override at prompt.
   return false;
 }
 
 bool GetCanvasContextType(const nsAString& str,
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -3733,33 +3733,33 @@ mozilla::ipc::IPCResult BrowserParent::R
   }
 
   widget->LookUpDictionary(aText, aFontRangeArray, aIsVertical,
                            TransformChildToParent(aPoint));
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
-    const nsCString& aOrigin, const bool& aHideDoorHanger) {
+    const nsCString& aFirstPartyURI, const bool& aHideDoorHanger) {
   nsCOMPtr<nsIBrowser> browser =
       mFrameElement ? mFrameElement->AsBrowser() : nullptr;
   if (!browser) {
     // If the tab is being closed, the browser may not be available.
     // In this case we can ignore the request.
     return IPC_OK();
   }
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (!os) {
     return IPC_FAIL_NO_REASON(this);
   }
   nsresult rv = os->NotifyObservers(
       browser,
       aHideDoorHanger ? "canvas-permissions-prompt-hide-doorhanger"
                       : "canvas-permissions-prompt",
-      NS_ConvertUTF8toUTF16(aOrigin).get());
+      NS_ConvertUTF8toUTF16(aFirstPartyURI).get());
   if (NS_FAILED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(
     const URIParams& aURI, const Maybe<URIParams>& aLastVisitedURI,
--- a/dom/ipc/BrowserParent.h
+++ b/dom/ipc/BrowserParent.h
@@ -705,17 +705,17 @@ class BrowserParent final : public PBrow
 
   mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
                                             const int32_t& aX,
                                             const int32_t& aY,
                                             const int32_t& aCx,
                                             const int32_t& aCy);
 
   mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
-      const nsCString& aOrigin, const bool& aHideDoorHanger);
+      const nsCString& aFirstPartyURI, const bool& aHideDoorHanger);
 
   mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName);
   mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName);
 
   mozilla::ipc::IPCResult RecvVisitURI(const URIParams& aURI,
                                        const Maybe<URIParams>& aLastVisitedURI,
                                        const uint32_t& aFlags);
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -615,19 +615,19 @@ parent:
     // arrive before the BrowserChild attempts to use its cross-process compositor
     // bridge.
     sync EnsureLayersConnected() returns (CompositorOptions compositorOptions);
 
     /**
      * This function is used to notify the parent that it should display a
      * canvas permission prompt.
      *
-     * @param aOrigin origin string of the document that is requesting access.
+     * @param aFirstPartyURI first party of the tab that is requesting access.
      */
-    async ShowCanvasPermissionPrompt(nsCString aOrigin,
+    async ShowCanvasPermissionPrompt(nsCString aFirstPartyURI,
                                      bool aHideDoorHanger);
 
     sync SetSystemFont(nsCString aFontName);
     sync GetSystemFont() returns (nsCString retval);
 
     sync SetPrefersReducedMotionOverrideForTest(bool aValue);
     sync ResetPrefersReducedMotionOverrideForTest();
 
--- a/extensions/permissions/nsPermission.cpp
+++ b/extensions/permissions/nsPermission.cpp
@@ -26,17 +26,18 @@ nsPermission::nsPermission(nsIPrincipal*
       mExpireTime(aExpireTime),
       mModificationTime(aModificationTime) {}
 
 already_AddRefed<nsIPrincipal> nsPermission::ClonePrincipalForPermission(
     nsIPrincipal* aPrincipal) {
   MOZ_ASSERT(aPrincipal);
 
   mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef();
-  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID);
+  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
 
   nsAutoCString originNoSuffix;
   nsresult rv = aPrincipal->GetOriginNoSuffix(originNoSuffix);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   nsCOMPtr<nsIURI> uri;
   rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
   NS_ENSURE_SUCCESS(rv, nullptr);
--- a/extensions/permissions/nsPermission.h
+++ b/extensions/permissions/nsPermission.h
@@ -18,17 +18,18 @@ class nsPermission : public nsIPermissio
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPERMISSION
 
   static already_AddRefed<nsPermission> Create(
       nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aCapability,
       uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime);
 
   // This method creates a new nsIPrincipal with a stripped OriginAttributes (no
-  // userContextId) and a codebase equal to the origin of 'aPrincipal'.
+  // userContextId, and no FirstPartyDomain) and a codebase equal to the origin
+  // of 'aPrincipal'.
   static already_AddRefed<nsIPrincipal> ClonePrincipalForPermission(
       nsIPrincipal* aPrincipal);
 
  protected:
   nsPermission(nsIPrincipal* aPrincipal, const nsACString& aType,
                uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime,
                int64_t aModificationTime);
 
--- a/extensions/permissions/nsPermissionManager.cpp
+++ b/extensions/permissions/nsPermissionManager.cpp
@@ -158,18 +158,19 @@ nsresult GetOriginFromPrincipal(nsIPrinc
     return NS_ERROR_FAILURE;
   }
 
   // mPrivateBrowsingId must be set to false because PermissionManager is not
   // supposed to have any knowledge of private browsing. Allowing it to be true
   // changes the suffix being hashed.
   attrs.mPrivateBrowsingId = 0;
 
-  // Disable userContext for permissions.
-  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID);
+  // Disable userContext and firstParty isolation for permissions.
+  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
 
   attrs.CreateSuffix(suffix);
   aOrigin.Append(suffix);
   return NS_OK;
 }
 
 nsresult GetPrincipalFromOrigin(const nsACString& aOrigin,
                                 nsIPrincipal** aPrincipal) {
@@ -179,18 +180,19 @@ nsresult GetPrincipalFromOrigin(const ns
     return NS_ERROR_FAILURE;
   }
 
   // mPrivateBrowsingId must be set to false because PermissionManager is not
   // supposed to have any knowledge of private browsing. Allowing it to be true
   // changes the suffix being hashed.
   attrs.mPrivateBrowsingId = 0;
 
-  // Disable userContext for permissions.
-  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID);
+  // Disable userContext and firstParty isolation for permissions.
+  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIPrincipal> principal =
       mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
   principal.forget(aPrincipal);
@@ -271,18 +273,19 @@ already_AddRefed<nsIPrincipal> GetNextSu
   nsCOMPtr<nsIURI> newURI = GetNextSubDomainURI(uri);
   if (!newURI) {
     return nullptr;
   }
 
   // Copy the attributes over
   mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef();
 
-  // Disable userContext for permissions.
-  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID);
+  // Disable userContext and firstParty isolation for permissions.
+  attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
 
   nsCOMPtr<nsIPrincipal> principal =
       mozilla::BasePrincipal::CreateCodebasePrincipal(newURI, attrs);
 
   return principal.forget();
 }
 
 class MOZ_STACK_CLASS UpgradeHostToOriginHelper {
@@ -3273,18 +3276,19 @@ void nsPermissionManager::GetKeyForOrigi
     return;
   }
 
   // mPrivateBrowsingId must be set to false because PermissionManager is not
   // supposed to have any knowledge of private browsing. Allowing it to be true
   // changes the suffix being hashed.
   attrs.mPrivateBrowsingId = 0;
 
-  // Disable userContext for permissions.
-  attrs.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID);
+  // Disable userContext and firstParty isolation for permissions.
+  attrs.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
 
 #ifdef DEBUG
   // Parse the origin string into a principal, and extract some useful
   // information from it for assertions.
   nsCOMPtr<nsIPrincipal> dbgPrincipal;
   MOZ_ALWAYS_SUCCEEDS(
       GetPrincipalFromOrigin(aOrigin, getter_AddRefs(dbgPrincipal)));
   nsCOMPtr<nsIURI> dbgUri;
--- a/extensions/permissions/test/unit/test_permmanager_defaults.js
+++ b/extensions/permissions/test/unit/test_permmanager_defaults.js
@@ -92,85 +92,85 @@ add_task(async function do_test() {
   pm.removeAll();
 
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal3, TEST_PERMISSION));
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal4, TEST_PERMISSION));
-  // make sure principals with userContextId use the same permissions
+  // make sure principals with userContextId or firstPartyDomain use the same permissions
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal6, TEST_PERMISSION));
-  // make sure principals with a firstPartyDomain use different permissions
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION));
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION));
 
   // Asking for this permission to be removed should result in that permission
   // having UNKNOWN_ACTION
   pm.removeFromPrincipal(principal, TEST_PERMISSION);
   Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
                pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
   // make sure principals with userContextId or firstPartyDomain use the same permissions
   Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
                pm.testPermissionFromPrincipal(principal6, TEST_PERMISSION));
+  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+               pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION));
+  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+               pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION));
   // and we should have this UNKNOWN_ACTION reflected in the DB
   await checkCapabilityViaDB(Ci.nsIPermissionManager.UNKNOWN_ACTION);
   // but the permission should *not* appear in the enumerator.
   Assert.equal(null, findCapabilityViaEnum());
 
   // and a subsequent RemoveAll should restore the default
   pm.removeAll();
 
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
-  // make sure principals with userContextId use the same permissions
+  // make sure principals with userContextId or firstPartyDomain use the same permissions
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal6, TEST_PERMISSION));
-  // make sure principals with firstPartyDomain use different permissions
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION));
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION,
                pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION));
   // and allow it to again be seen in the enumerator.
   Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION, findCapabilityViaEnum());
 
   // now explicitly add a permission - this too should override the default.
   pm.addFromPrincipal(principal, TEST_PERMISSION, Ci.nsIPermissionManager.DENY_ACTION);
 
   // it should be reflected in a permission check, in the enumerator and the DB
   Assert.equal(Ci.nsIPermissionManager.DENY_ACTION,
                pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
-  // make sure principals with userContextId use the same permissions
+  // make sure principals with userContextId or firstPartyDomain use the same permissions
   Assert.equal(Ci.nsIPermissionManager.DENY_ACTION,
                pm.testPermissionFromPrincipal(principal6, TEST_PERMISSION));
-  // make sure principals with firstPartyDomain use different permissions
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.DENY_ACTION,
                pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION));
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.DENY_ACTION,
                pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION));
   Assert.equal(Ci.nsIPermissionManager.DENY_ACTION, findCapabilityViaEnum());
   await checkCapabilityViaDB(Ci.nsIPermissionManager.DENY_ACTION);
 
   // explicitly add a different permission - in this case we are no longer
   // replacing the default, but instead replacing the replacement!
   pm.addFromPrincipal(principal, TEST_PERMISSION, Ci.nsIPermissionManager.PROMPT_ACTION);
 
   // it should be reflected in a permission check, in the enumerator and the DB
   Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION,
                pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
-  // make sure principals with userContextId use the same permissions
+  // make sure principals with userContextId or firstPartyDomain use the same permissions
   Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION,
                pm.testPermissionFromPrincipal(principal6, TEST_PERMISSION));
-  // make sure principals with firstPartyDomain use different permissions
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION,
                pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION));
-  Assert.equal(Ci.nsIPermissionManager.UNKNOWN_ACTION,
+  Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION,
                pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION));
   Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION, findCapabilityViaEnum());
   await checkCapabilityViaDB(Ci.nsIPermissionManager.PROMPT_ACTION);
 
   // --------------------------------------------------------------
   // check default permissions and removeAllSince work as expected.
   pm.removeAll(); // ensure only defaults are there.
 
--- a/extensions/permissions/test/unit/test_permmanager_matches.js
+++ b/extensions/permissions/test/unit/test_permmanager_matches.js
@@ -73,39 +73,39 @@ function run_test() {
   let perm_n = pm.getPermissionObject(uri0_n, "test/matches", true);
   pm.addFromPrincipal(uri0_y_, "test/matches", pm.ALLOW_ACTION);
   let perm_y_ = pm.getPermissionObject(uri0_y_, "test/matches", true);
   pm.addFromPrincipal(uri0_1, "test/matches", pm.ALLOW_ACTION);
   let perm_1 = pm.getPermissionObject(uri0_n, "test/matches", true);
   pm.addFromPrincipal(uri0_cnn, "test/matches", pm.ALLOW_ACTION);
   let perm_cnn = pm.getPermissionObject(uri0_n, "test/matches", true);
 
-  matches_always(perm_n, [uri0_n, uri0_1]);
-  matches_weak(perm_n, [uri1_n, uri1_1]);
+  matches_always(perm_n, [uri0_n, uri0_1, uri0_cnn]);
+  matches_weak(perm_n, [uri1_n, uri1_1, uri1_cnn]);
   matches_never(perm_n, [uri2_n, uri3_n, uri4_n, uri5_n,
                            uri0_y_, uri1_y_, uri2_y_, uri3_y_, uri4_y_, uri5_y_,
                            uri2_1, uri3_1, uri4_1, uri5_1,
-                           uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
+                           uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
 
   matches_always(perm_y_, [uri0_y_]);
   matches_weak(perm_y_, [uri1_y_]);
   matches_never(perm_y_, [uri2_y_, uri3_y_, uri4_y_, uri5_y_,
                               uri0_n, uri1_n, uri2_n, uri3_n, uri4_n, uri5_n,
                               uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1,
                               uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
 
-  matches_always(perm_1, [uri0_n, uri0_1]);
-  matches_weak(perm_1, [uri1_n, uri1_1]);
+  matches_always(perm_1, [uri0_n, uri0_1, uri0_cnn]);
+  matches_weak(perm_1, [uri1_n, uri1_1, uri1_cnn]);
   matches_never(perm_1, [uri2_n, uri3_n, uri4_n, uri5_n,
                          uri0_y_, uri1_y_, uri2_y_, uri3_y_, uri4_y_, uri5_y_,
                          uri2_1, uri3_1, uri4_1, uri5_1,
-                         uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
+                         uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
 
-  matches_always(perm_cnn, [uri0_n, uri0_1]);
-  matches_weak(perm_cnn, [uri1_n, uri1_1]);
+  matches_always(perm_cnn, [uri0_n, uri0_1, uri0_cnn]);
+  matches_weak(perm_cnn, [uri1_n, uri1_1, uri1_cnn]);
   matches_never(perm_cnn, [uri2_n, uri3_n, uri4_n, uri5_n,
                            uri0_y_, uri1_y_, uri2_y_, uri3_y_, uri4_y_, uri5_y_,
                            uri2_1, uri3_1, uri4_1, uri5_1,
-                           uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
+                           uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]);
 
   // Clean up!
   pm.removeAll();
 }
--- a/mobile/android/chrome/content/OfflineApps.js
+++ b/mobile/android/chrome/content/OfflineApps.js
@@ -4,21 +4,20 @@
 "use strict";
 
 var OfflineApps = {
   offlineAppRequested: function(aContentWindow) {
     if (!Services.prefs.getBoolPref("browser.offline-apps.notify"))
       return;
 
     let tab = BrowserApp.getTabForWindow(aContentWindow);
-    let principal = aContentWindow.document.nodePrincipal;
     let currentURI = aContentWindow.document.documentURIObject;
 
     // Don't bother showing UI if the user has already made a decision
-    if (Services.perms.testExactPermissionFromPrincipal(principal, "offline-app") != Services.perms.UNKNOWN_ACTION)
+    if (Services.perms.testExactPermission(currentURI, "offline-app") != Services.perms.UNKNOWN_ACTION)
       return;
 
     try {
       if (Services.prefs.getBoolPref("offline-apps.allow_by_default")) {
         // All pages can use offline capabilities, no need to ask the user
         return;
       }
     } catch (e) {
@@ -46,26 +45,26 @@ var OfflineApps = {
 
     let requestor = BrowserApp.manifest ? "'" + BrowserApp.manifest.name + "'" : host;
     let message = strings.formatStringFromName("offlineApps.ask", [requestor], 1);
     let options = { checkbox: Strings.browser.GetStringFromName("offlineApps.dontAskAgain") };
     NativeWindow.doorhanger.show(message, notificationID, buttons, tab.id, options);
   },
 
   allowSite: function(aDocument) {
-    Services.perms.addFromPrincipal(aDocument.nodePrincipal, "offline-app", Services.perms.ALLOW_ACTION);
+    Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.ALLOW_ACTION);
 
     // When a site is enabled while loading, manifest resources will
     // start fetching immediately.  This one time we need to do it
     // ourselves.
     this._startFetching(aDocument);
   },
 
   disallowSite: function(aDocument) {
-    Services.perms.addFromPrincipal(aDocument.nodePrincipal, "offline-app", Services.perms.DENY_ACTION);
+    Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.DENY_ACTION);
   },
 
   _startFetching: function(aDocument) {
     if (!aDocument.documentElement)
       return;
 
     let manifest = aDocument.documentElement.getAttribute("manifest");
     if (!manifest)
--- a/mobile/android/chrome/content/PermissionsHelper.js
+++ b/mobile/android/chrome/content/PermissionsHelper.js
@@ -45,29 +45,29 @@ var PermissionsHelper = {
     "native-intent": {
       label: "helperapps.openWithList2",
       allowed: "helperapps.always",
       denied: "helperapps.never",
     },
   },
 
   onEvent: function onEvent(event, data, callback) {
-    let principal = BrowserApp.selectedBrowser.contentPrincipal;
+    let uri = BrowserApp.selectedBrowser.currentURI;
     let check = false;
 
     switch (event) {
       case "Permissions:Check":
         check = true;
         // fall-through
 
       case "Permissions:Get":
         let permissions = [];
         for (let i = 0; i < this._permissonTypes.length; i++) {
           let type = this._permissonTypes[i];
-          let value = this.getPermission(principal, type);
+          let value = this.getPermission(uri, type);
 
           // Only add the permission if it was set by the user
           if (value == Services.perms.UNKNOWN_ACTION)
             continue;
 
           if (check) {
             GlobalEventDispatcher.sendRequest({
               type: "Permissions:CheckResult",
@@ -127,58 +127,58 @@ var PermissionsHelper = {
    * Gets the permission value stored for a specified permission type.
    *
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "geolocation", "indexedDB", "popup"
    *
    * @return A permission value defined in nsIPermissionManager.
    */
-  getPermission: function getPermission(aPrincipal, aType) {
+  getPermission: function getPermission(aURI, aType) {
     // Password saving isn't a nsIPermissionManager permission type, so handle
     // it seperately.
     if (aType == "password") {
       // By default, login saving is enabled, so if it is disabled, the
       // user selected the never remember option
       if (!Services.logins.getLoginSavingEnabled(aURI.displayPrePath))
         return Services.perms.DENY_ACTION;
 
       // Check to see if the user ever actually saved a login
       if (Services.logins.countLogins(aURI.displayPrePath, "", ""))
         return Services.perms.ALLOW_ACTION;
 
       return Services.perms.UNKNOWN_ACTION;
     }
 
-    // Geolocation consumers use testExactPermissionForPrincipal
+    // Geolocation consumers use testExactPermission
     if (aType == "geolocation")
-      return Services.perms.testExactPermissionForPrincipal(aPrincipal, aType);
+      return Services.perms.testExactPermission(aURI, aType);
 
-    return Services.perms.testPermissionForPrincipal(aPrincipal, aType);
+    return Services.perms.testPermission(aURI, aType);
   },
 
   /**
    * Clears a user-set permission value for the site given a permission type.
    *
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "geolocation", "indexedDB", "popup"
    */
-  clearPermission: function clearPermission(aPrincipal, aType, aContext) {
+  clearPermission: function clearPermission(aURI, aType, aContext) {
     // Password saving isn't a nsIPermissionManager permission type, so handle
     // it seperately.
     if (aType == "password") {
       // Get rid of exisiting stored logings
       let logins = Services.logins.findLogins(aURI.displayPrePath, "", "");
       for (let i = 0; i < logins.length; i++) {
         Services.logins.removeLogin(logins[i]);
       }
       // Re-set login saving to enabled
       Services.logins.setLoginSavingEnabled(aURI.displayPrePath, true);
     } else {
-      Services.perms.removeFromPrincipal(aPrincipal, aType);
+      Services.perms.remove(aURI, aType);
       // Clear content prefs set in ContentPermissionPrompt.js
       Cc["@mozilla.org/content-pref/service;1"]
         .getService(Ci.nsIContentPrefService2)
         .removeByDomainAndName(aURI.spec, aType + ".request.remember", aContext);
     }
   },
 };
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1893,28 +1893,28 @@ var BrowserApp = {
             let normalizedUrl = Services.io.newURI("https://" + browser.currentURI.hostPort);
             if (data.allowContent) {
               // Add the current host in the 'trackingprotection' consumer of
               // the permission manager using a normalized URI. This effectively
               // places this host on the tracking protection white list.
               if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
                 PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
               } else {
-                Services.perms.addFromPrincipal(browser.contentPrincipal, "trackingprotection", Services.perms.ALLOW_ACTION);
+                Services.perms.add(normalizedUrl, "trackingprotection", Services.perms.ALLOW_ACTION);
                 Telemetry.addData("TRACKING_PROTECTION_EVENTS", 1);
               }
             } else {
               // Remove the current host from the 'trackingprotection' consumer
               // of the permission manager. This effectively removes this host
               // from the tracking protection white list (any list actually).
               // eslint-disable-next-line no-lonely-if
               if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
                 PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
               } else {
-                Services.perms.removeFromPrincipal(browser.contentPrincipal, "trackingprotection");
+                Services.perms.remove(normalizedUrl, "trackingprotection");
                 Telemetry.addData("TRACKING_PROTECTION_EVENTS", 2);
               }
             }
           }
         }
 
         // Try to use the session history to reload so that framesets are
         // handled properly. If the window has no session history, fall back
@@ -5342,17 +5342,17 @@ var PopupBlockerObserver = {
   onUpdateBlockedPopups: function onUpdateBlockedPopups(aEvent) {
     let browser = BrowserApp.selectedBrowser;
     if (aEvent.originalTarget != browser)
       return;
 
     if (!browser.blockedPopups)
       return;
 
-    let result = Services.perms.testExactPermissionFromPrincipal(BrowserApp.selectedBrowser.contentPrincipal, "popup");
+    let result = Services.perms.testExactPermission(BrowserApp.selectedBrowser.currentURI, "popup");
     if (result == Ci.nsIPermissionManager.DENY_ACTION)
       return;
 
     // Only show the notification again if we've not already shown it. Since
     // notifications are per-browser, we don't need to worry about re-adding
     // it.
     if (!browser.blockedPopups.reported) {
       if (Services.prefs.getBoolPref("privacy.popups.showBrowserMessage")) {
@@ -5390,18 +5390,18 @@ var PopupBlockerObserver = {
       }
       // Record the fact that we've reported this blocked popup, so we don't
       // show it again.
       browser.blockedPopups.reported = true;
     }
   },
 
   allowPopupsForSite: function allowPopupsForSite(aAllow) {
-    let principal = BrowserApp.selectedBrowser.contentPrincipal;
-    Services.perms.addFromPrincipal(principal, "popup", aAllow
+    let currentURI = BrowserApp.selectedBrowser.currentURI;
+    Services.perms.add(currentURI, "popup", aAllow
                        ? Ci.nsIPermissionManager.ALLOW_ACTION
                        : Ci.nsIPermissionManager.DENY_ACTION);
     dump("Allowing popups for: " + currentURI);
   },
 
   showPopupsForSite: function showPopupsForSite() {
     let uri = BrowserApp.selectedBrowser.currentURI;
     let {blockedPopups} = BrowserApp.selectedBrowser;
--- a/mobile/android/components/geckoview/GeckoViewPermission.js
+++ b/mobile/android/components/geckoview/GeckoViewPermission.js
@@ -44,29 +44,28 @@ GeckoViewPermission.prototype = {
         break;
       }
     }
   },
 
   receiveMessage(aMsg) {
     switch (aMsg.name) {
       case "GeckoView:AddCameraPermission": {
-        let principal;
+        let uri;
         try {
           // This fails for principals that serialize to "null", e.g. file URIs.
-          principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aMsg.data.origin);
+          uri = Services.io.newURI(aMsg.data.origin);
         } catch (e) {
-          principal = Services.scriptSecurityManager.createCodebasePrincipal(
-            Services.io.newURI(aMsg.data.documentURI), {});
+          uri = Services.io.newURI(aMsg.data.documentURI);
         }
         // Although the lifetime is "session" it will be removed upon
         // use so it's more of a one-shot.
-        Services.perms.addFromPrincipal(principal, "MediaManagerVideo",
-                                        Services.perms.ALLOW_ACTION,
-                                        Services.perms.EXPIRE_SESSION);
+        Services.perms.add(uri, "MediaManagerVideo",
+                           Services.perms.ALLOW_ACTION,
+                           Services.perms.EXPIRE_SESSION);
         break;
       }
     }
   },
 
   handleMediaAskDevicePermission: function(aType, aCallback) {
     let perms = [];
     if (aType === "video" || aType === "all") {
--- a/mobile/android/modules/WebrtcUI.jsm
+++ b/mobile/android/modules/WebrtcUI.jsm
@@ -156,17 +156,17 @@ var WebrtcUI = {
       },
       function(error) {
         Cu.reportError(error);
       },
       aSubject.innerWindowID,
       aSubject.callID);
   },
 
-  getDeviceButtons: function(audioDevices, videoDevices, aCallID, aPrincipal) {
+  getDeviceButtons: function(audioDevices, videoDevices, aCallID, aUri) {
     return [{
       label: Strings.browser.GetStringFromName("getUserMedia.denyRequest.label"),
       callback: function() {
         Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID);
       },
     },
     {
       label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"),
@@ -182,17 +182,17 @@ var WebrtcUI = {
         let videoId = 0;
         if (inputs && inputs.videoSource != undefined)
           videoId = inputs.videoSource;
         if (videoDevices[videoId]) {
           allowedDevices.appendElement(videoDevices[videoId]);
           let perms = Services.perms;
           // Although the lifetime is "session" it will be removed upon
           // use so it's more of a one-shot.
-          perms.addFromPrincipal(aPrincipal, "MediaManagerVideo", perms.ALLOW_ACTION, perms.EXPIRE_SESSION);
+          perms.add(aUri, "MediaManagerVideo", perms.ALLOW_ACTION, perms.EXPIRE_SESSION);
         }
 
         Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
       },
       positive: true,
     }];
   },
 
@@ -310,29 +310,29 @@ var WebrtcUI = {
     else if (audioDevices.length)
       requestType = "Microphone";
     else if (videoDevices.length)
       requestType = "Camera";
     else
       return;
 
     let chromeWin = this.getChromeWindow(aContentWindow);
-    let principal = aContentWindow.document.nodePrincipal;
-    let host = principal.URI.host;
+    let uri = aContentWindow.document.documentURIObject;
+    let host = uri.host;
     let requestor = (chromeWin.BrowserApp && chromeWin.BrowserApp.manifest) ?
           "'" + chromeWin.BrowserApp.manifest.name + "'" : host;
     let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1);
 
     let options = { inputs: [] };
     if (videoDevices.length > 1 || audioDevices.length > 0) {
       // videoSource is both the string used for l10n lookup and the object that will be returned
       this._addDevicesToOptions(videoDevices, "videoSource", options);
     }
 
     if (audioDevices.length > 1 || videoDevices.length > 0) {
       this._addDevicesToOptions(audioDevices, "audioDevice", options);
     }
 
-    let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID, principal);
+    let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID, uri);
 
     DoorHanger.show(aContentWindow, message, "webrtc-request", buttons, options, "WEBRTC");
   },
 };