Backed out 4 changesets (bug 1596843) for XPCShellTestsTests build bustage ona CLOSED TREE.
authorGurzau Raul <rgurzau@mozilla.com>
Sun, 17 Nov 2019 11:07:15 +0200
changeset 502339 de185bb7bdd5c8347c41560dc830da32895c4234
parent 502338 f1c44a2eb6041bc202b27d9d3a65254de00285af
child 502340 8b55cc4b13369229e7cf0b81310eef1f79e9ed93
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1596843
milestone72.0a1
backs out69ee727d5b4588e9f666bd99e89ae230b8fcb8e6
a9827fae8655ff42f431f8073ad54a29b1def620
8b2220bc47afa4a203e32530f73fd34e1fd9b687
b10aec041377e78814a6e6073cdead9e817bef00
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 4 changesets (bug 1596843) for XPCShellTestsTests build bustage ona CLOSED TREE. Backed out changeset 69ee727d5b45 (bug 1596843) Backed out changeset a9827fae8655 (bug 1596843) Backed out changeset 8b2220bc47af (bug 1596843) Backed out changeset b10aec041377 (bug 1596843)
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/serviceworkers/ServiceWorkerManager.cpp
dom/workers/remoteworkers/RemoteWorkerChild.cpp
dom/workers/remoteworkers/moz.build
extensions/permissions/nsContentBlocker.cpp
extensions/permissions/nsPermissionManager.cpp
extensions/permissions/nsPermissionManager.h
extensions/permissions/test/unit/test_permmanager_expiration.js
netwerk/base/nsIPermissionManager.idl
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3565,21 +3565,19 @@ nsresult ContentChild::AsyncOpenAnonymou
   // Remember the association with the callback.
   MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID));
   mPendingAnonymousTemporaryFiles.LookupOrAdd(newID, aCallback);
   return NS_OK;
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvSetPermissionsWithKey(
     const nsCString& aPermissionKey, nsTArray<IPC::Permission>&& aPerms) {
-  RefPtr<nsPermissionManager> permManager = nsPermissionManager::GetInstance();
-  if (permManager) {
-    permManager->SetPermissionsWithKey(aPermissionKey, aPerms);
-  }
-
+  nsCOMPtr<nsIPermissionManager> permissionManager =
+      services::GetPermissionManager();
+  permissionManager->SetPermissionsWithKey(aPermissionKey, aPerms);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvRefreshScreens(
     nsTArray<ScreenDetails>&& aScreens) {
   ScreenManager& screenManager = ScreenManager::GetSingleton();
   screenManager.Refresh(std::move(aScreens));
   return IPC_OK();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5500,28 +5500,28 @@ nsresult ContentParent::TransmitPermissi
 }
 
 void ContentParent::EnsurePermissionsByKey(const nsCString& aKey) {
   // NOTE: Make sure to initialize the permission manager before updating the
   // mActivePermissionKeys list. If the permission manager is being initialized
   // by this call to GetPermissionManager, and we've added the key to
   // mActivePermissionKeys, then the permission manager will send down a
   // SendAddPermission before receiving the SendSetPermissionsWithKey message.
-  RefPtr<nsPermissionManager> permManager = nsPermissionManager::GetInstance();
-  if (!permManager) {
-    return;
-  }
+  nsCOMPtr<nsIPermissionManager> permManager = services::GetPermissionManager();
 
   if (mActivePermissionKeys.Contains(aKey)) {
     return;
   }
   mActivePermissionKeys.PutEntry(aKey);
 
   nsTArray<IPC::Permission> perms;
-  permManager->GetPermissionsWithKey(aKey, perms);
+  nsresult rv = permManager->GetPermissionsWithKey(aKey, perms);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
 
   Unused << SendSetPermissionsWithKey(aKey, perms);
 }
 
 bool ContentParent::NeedsPermissionsUpdate(
     const nsACString& aPermissionKey) const {
   return mActivePermissionKeys.Contains(aPermissionKey);
 }
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -58,17 +58,16 @@
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/Unused.h"
 #include "mozilla/EnumSet.h"
 
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
-#include "nsPermissionManager.h"
 #include "nsProxyRelease.h"
 #include "nsQueryObject.h"
 #include "nsTArray.h"
 
 #include "ServiceWorker.h"
 #include "ServiceWorkerContainer.h"
 #include "ServiceWorkerInfo.h"
 #include "ServiceWorkerJobQueue.h"
@@ -2127,34 +2126,30 @@ void ServiceWorkerManager::DispatchFetch
     // ClientSource to be updated immediately after the nsIChannel starts.
     // This is necessary to have the correct controller in place for immediate
     // follow-on requests.
     loadInfo->SetController(serviceWorker->Descriptor());
   }
 
   MOZ_DIAGNOSTIC_ASSERT(serviceWorker);
 
-  RefPtr<ContinueDispatchFetchEventRunnable> continueRunnable =
+  nsCOMPtr<nsIRunnable> continueRunnable =
       new ContinueDispatchFetchEventRunnable(serviceWorker->WorkerPrivate(),
                                              aChannel, loadGroup,
                                              loadInfo->GetIsDocshellReload());
 
   // When this service worker was registered, we also sent down the permissions
   // for the runnable. They should have arrived by now, but we still need to
   // wait for them if they have not.
   nsCOMPtr<nsIRunnable> permissionsRunnable = NS_NewRunnableFunction(
       "dom::ServiceWorkerManager::DispatchFetchEvent", [=]() {
-        RefPtr<nsPermissionManager> permMgr =
-            nsPermissionManager::GetInstance();
-        if (permMgr) {
-          permMgr->WhenPermissionsAvailable(serviceWorker->Principal(),
-                                            continueRunnable);
-        } else {
-          continueRunnable->HandleError();
-        }
+        nsCOMPtr<nsIPermissionManager> permMgr =
+            services::GetPermissionManager();
+        MOZ_ALWAYS_SUCCEEDS(permMgr->WhenPermissionsAvailable(
+            serviceWorker->Principal(), continueRunnable));
       });
 
   nsCOMPtr<nsIUploadChannel2> uploadChannel =
       do_QueryInterface(internalChannel);
 
   // If there is no upload stream, then continue immediately
   if (!uploadChannel) {
     MOZ_ALWAYS_SUCCEEDS(permissionsRunnable->Run());
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -9,18 +9,18 @@
 #include <utility>
 
 #include "MainThreadUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsIConsoleReportCollector.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIPrincipal.h"
+#include "nsIPermissionManager.h"
 #include "nsNetUtil.h"
-#include "nsPermissionManager.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 #include "RemoteWorkerService.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasePrincipal.h"
@@ -469,22 +469,20 @@ nsresult RemoteWorkerChild::ExecWorkerOn
         __func__, [initializeWorkerRunnable = std::move(runnable),
                    self = std::move(self)] {
           if (NS_WARN_IF(!initializeWorkerRunnable->Dispatch())) {
             self->TransitionStateToTerminated();
             self->CreationFailedOnAnyThread();
           }
         });
 
-    RefPtr<nsPermissionManager> permissionManager =
-        nsPermissionManager::GetInstance();
-    if (!permissionManager) {
-      return NS_ERROR_FAILURE;
-    }
-    permissionManager->WhenPermissionsAvailable(principal, r);
+    nsCOMPtr<nsIPermissionManager> permissionManager =
+        services::GetPermissionManager();
+    MOZ_ALWAYS_SUCCEEDS(
+        permissionManager->WhenPermissionsAvailable(principal, r));
   } else {
     if (NS_WARN_IF(!runnable->Dispatch())) {
       rv = NS_ERROR_FAILURE;
       return rv;
     }
   }
 
   scopeExit.release();
--- a/dom/workers/remoteworkers/moz.build
+++ b/dom/workers/remoteworkers/moz.build
@@ -24,17 +24,16 @@ UNIFIED_SOURCES += [
     'RemoteWorkerParent.cpp',
     'RemoteWorkerService.cpp',
     'RemoteWorkerServiceChild.cpp',
     'RemoteWorkerServiceParent.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/serviceworkers',
-    '/extensions/permissions',
     '/xpcom/build',
 ]
 
 IPDL_SOURCES += [
     'PRemoteWorker.ipdl',
     'PRemoteWorkerController.ipdl',
     'PRemoteWorkerService.ipdl',
     'RemoteWorkerTypes.ipdlh',
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -288,17 +288,17 @@ nsresult nsContentBlocker::TestPermissio
   // check the permission list first; if we find an entry, it overrides
   // default prefs.
   // Don't forget the aContentType ranges from 1..8, while the
   // array is indexed 0..7
   // All permissions tested by this method are preload permissions, so don't
   // bother actually checking with the permission manager unless we have a
   // preload permission.
   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
-  if (mPermissionManager->HasPreloadPermissions()) {
+  if (mPermissionManager->GetHasPreloadPermissions()) {
     rv = mPermissionManager->LegacyTestPermissionFromURI(
         aCurrentURI, nullptr, kTypeString[aContentType - 1], &permission);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // If there is nothing on the list, use the default.
   if (!permission) {
     permission = mBehaviorPref[aContentType - 1];
--- a/extensions/permissions/nsPermissionManager.cpp
+++ b/extensions/permissions/nsPermissionManager.cpp
@@ -2274,16 +2274,31 @@ nsresult nsPermissionManager::LegacyTest
     nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes,
     const nsACString& aType, uint32_t* aPermission) {
   return CommonTestPermission(aURI, aOriginAttributes, -1, aType, aPermission,
                               nsIPermissionManager::UNKNOWN_ACTION, false,
                               false, true);
 }
 
 NS_IMETHODIMP
+nsPermissionManager::TestPermissionFromWindow(mozIDOMWindow* aWindow,
+                                              const nsACString& aType,
+                                              uint32_t* aPermission) {
+  NS_ENSURE_ARG(aWindow);
+  nsCOMPtr<nsPIDOMWindowInner> window = nsPIDOMWindowInner::From(aWindow);
+
+  // Get the document for security check
+  RefPtr<Document> document = window->GetExtantDoc();
+  NS_ENSURE_TRUE(document, NS_NOINTERFACE);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+  return TestPermissionFromPrincipal(principal, aType, aPermission);
+}
+
+NS_IMETHODIMP
 nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                  const nsACString& aType,
                                                  uint32_t* aPermission) {
   return CommonTestPermission(aPrincipal, -1, aType, aPermission,
                               nsIPermissionManager::UNKNOWN_ACTION, false,
                               false, true);
 }
 
@@ -2646,17 +2661,18 @@ nsresult nsPermissionManager::RemoveAllM
   ENSURE_NOT_CHILD_PROCESS;
 
   return RemovePermissionEntries(
       [aModificationTime](const PermissionEntry& aPermEntry) {
         return aModificationTime <= aPermEntry.mModificationTime;
       });
 }
 
-nsresult nsPermissionManager::RemovePermissionsWithAttributes(
+NS_IMETHODIMP
+nsPermissionManager::RemovePermissionsWithAttributes(
     const nsAString& aPattern) {
   ENSURE_NOT_CHILD_PROCESS;
   mozilla::OriginAttributesPattern pattern;
   if (!pattern.Init(aPattern)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   return RemovePermissionsWithAttributes(pattern);
@@ -3021,20 +3037,72 @@ void nsPermissionManager::UpdateDB(
     return;
   }
 
   nsCOMPtr<mozIStoragePendingStatement> pending;
   rv = aStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
-void nsPermissionManager::GetPermissionsWithKey(
-    const nsACString& aPermissionKey, nsTArray<IPC::Permission>& aPerms) {
+NS_IMETHODIMP
+nsPermissionManager::UpdateExpireTime(nsIPrincipal* aPrincipal,
+                                      const nsACString& aType,
+                                      bool aExactHostMatch,
+                                      uint64_t aSessionExpireTime,
+                                      uint64_t aPersistentExpireTime) {
+  NS_ENSURE_ARG_POINTER(aPrincipal);
+
+  uint64_t nowms = PR_Now() / 1000;
+  if (aSessionExpireTime < nowms || aPersistentExpireTime < nowms) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return NS_OK;
+  }
+
+  // Setting the expire time of an nsEP is non-sensical.
+  if (IsExpandedPrincipal(aPrincipal)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  MOZ_ASSERT(PermissionAvailable(aPrincipal, aType));
+
+  int32_t typeIndex = GetTypeIndex(aType, false);
+  // If type == -1, the type isn't known,
+  // so just return NS_OK
+  if (typeIndex == -1) return NS_OK;
+
+  PermissionHashKey* entry =
+      GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch);
+  if (!entry) {
+    return NS_OK;
+  }
+
+  int32_t idx = entry->GetPermissionIndex(typeIndex);
+  if (-1 == idx) {
+    return NS_OK;
+  }
+
+  PermissionEntry& perm = entry->GetPermissions()[idx];
+  if (perm.mExpireType == EXPIRE_TIME) {
+    perm.mExpireTime = aPersistentExpireTime;
+  } else if (perm.mExpireType == EXPIRE_SESSION && perm.mExpireTime != 0) {
+    perm.mExpireTime = aSessionExpireTime;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPermissionManager::GetPermissionsWithKey(const nsACString& aPermissionKey,
+                                           nsTArray<IPC::Permission>& aPerms) {
   aPerms.Clear();
-  MOZ_ASSERT(XRE_IsParentProcess());
+  if (NS_WARN_IF(XRE_IsContentProcess())) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
     PermissionHashKey* entry = iter.Get();
 
     nsAutoCString permissionKey;
     GetKeyForOrigin(entry->GetKey()->mOrigin, permissionKey);
 
     // If the keys don't match, and we aren't getting the default "" key, then
@@ -3057,35 +3125,40 @@ void nsPermissionManager::GetPermissions
           (!isPreload && aPermissionKey == permissionKey)) {
         aPerms.AppendElement(
             IPC::Permission(entry->GetKey()->mOrigin,
                             mTypeArray[permEntry.mType], permEntry.mPermission,
                             permEntry.mExpireType, permEntry.mExpireTime));
       }
     }
   }
+
+  return NS_OK;
 }
 
-void nsPermissionManager::SetPermissionsWithKey(
-    const nsACString& aPermissionKey, nsTArray<IPC::Permission>& aPerms) {
-  MOZ_ASSERT(XRE_IsParentProcess());
+NS_IMETHODIMP
+nsPermissionManager::SetPermissionsWithKey(const nsACString& aPermissionKey,
+                                           nsTArray<IPC::Permission>& aPerms) {
+  if (NS_WARN_IF(XRE_IsParentProcess())) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   RefPtr<GenericNonExclusivePromise::Private> promise;
   bool foundKey =
       mPermissionKeyPromiseMap.Get(aPermissionKey, getter_AddRefs(promise));
   if (promise) {
     MOZ_ASSERT(foundKey);
     // NOTE: This will resolve asynchronously, so we can mark it as resolved
     // now, and be confident that we will have filled in the database before any
     // callbacks run.
     promise->Resolve(true, __func__);
   } else if (foundKey) {
     // NOTE: We shouldn't be sent two InitializePermissionsWithKey for the same
     // key, but it's possible.
-    return;
+    return NS_OK;
   }
   mPermissionKeyPromiseMap.Put(aPermissionKey, nullptr);
 
   // Add the permissions locally to our process
   for (IPC::Permission& perm : aPerms) {
     nsCOMPtr<nsIPrincipal> principal;
     nsresult rv =
         GetPrincipalFromOrigin(perm.origin, getter_AddRefs(principal));
@@ -3103,16 +3176,17 @@ void nsPermissionManager::SetPermissions
     // The child process doesn't care about modification times - it neither
     // reads nor writes, nor removes them based on the date - so 0 (which
     // will end up as now()) is fine.
     uint64_t modificationTime = 0;
     AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
                 perm.expireTime, modificationTime, eNotify, eNoDBOperation,
                 true /* ignoreSessionPermissions */);
   }
+  return NS_OK;
 }
 
 /* static */
 void nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin,
                                           nsACString& aKey) {
   aKey.Truncate();
 
   // We only key origins for http, https, and ftp URIs. All origins begin with
@@ -3232,23 +3306,24 @@ bool nsPermissionManager::PermissionAvai
                                  permissionKey.get())
                      .get());
       return false;
     }
   }
   return true;
 }
 
-void nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal,
-                                                   nsIRunnable* aRunnable) {
+NS_IMETHODIMP
+nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal,
+                                              nsIRunnable* aRunnable) {
   MOZ_ASSERT(aRunnable);
 
   if (!XRE_IsContentProcess()) {
     aRunnable->Run();
-    return;
+    return NS_OK;
   }
 
   nsTArray<RefPtr<GenericNonExclusivePromise>> promises;
   for (auto& key : GetAllKeysForPrincipal(aPrincipal)) {
     RefPtr<GenericNonExclusivePromise::Private> promise;
     if (!mPermissionKeyPromiseMap.Get(key, getter_AddRefs(promise))) {
       // In this case we have found a permission which isn't available in the
       // content process and hasn't been requested yet. We need to create a new
@@ -3264,27 +3339,30 @@ void nsPermissionManager::WhenPermission
     }
   }
 
   // If all of our permissions are available, immediately run the runnable. This
   // avoids any extra overhead during fetch interception which is performance
   // sensitive.
   if (promises.IsEmpty()) {
     aRunnable->Run();
-    return;
+    return NS_OK;
   }
 
   auto* thread = SystemGroup::AbstractMainThreadFor(TaskCategory::Other);
 
   RefPtr<nsIRunnable> runnable = aRunnable;
   GenericNonExclusivePromise::All(thread, promises)
       ->Then(
           thread, __func__, [runnable]() { runnable->Run(); },
           []() {
             NS_WARNING(
                 "nsPermissionManager permission promise rejected. We're "
                 "probably shutting down.");
           });
+  return NS_OK;
 }
 
-bool nsPermissionManager::HasPreloadPermissions() {
-  return sPreloadPermissionCount > 0;
+NS_IMETHODIMP
+nsPermissionManager::GetHasPreloadPermissions(bool* aResult) {
+  *aResult = sPreloadPermissionCount > 0;
+  return NS_OK;
 }
--- a/extensions/permissions/nsPermissionManager.h
+++ b/extensions/permissions/nsPermissionManager.h
@@ -24,20 +24,16 @@
 #include "nsRefPtrHashtable.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ExpandedPrincipal.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Variant.h"
 #include "mozilla/Vector.h"
 
-namespace IPC {
-struct Permission;
-}
-
 namespace mozilla {
 class OriginAttributesPattern;
 }
 
 class nsIPermission;
 class mozIStorageConnection;
 class mozIStorageAsyncStatement;
 
@@ -205,16 +201,19 @@ class nsPermissionManager final : public
    * Initialize the permission-manager service.
    * The permission manager is always initialized at startup because when it
    * was lazy-initialized on demand, it was possible for it to be created
    * once shutdown had begun, resulting in the manager failing to correctly
    * shutdown because it missed its shutdown observer notification.
    */
   static void Startup();
 
+  nsresult RemovePermissionsWithAttributes(
+      mozilla::OriginAttributesPattern& aAttrs);
+
   /**
    * See `nsIPermissionManager::GetPermissionsWithKey` for more info on
    * permission keys.
    *
    * Get the permission key corresponding to the given Principal. This method is
    * intentionally infallible, as we want to provide an permission key to every
    * principal. Principals which don't have meaningful URIs with http://,
    * https://, or ftp:// schemes are given the default "" Permission Key.
@@ -289,78 +288,16 @@ class nsPermissionManager final : public
    * Returns false if this permission manager wouldn't have the permission
    * requested available.
    *
    * If aType is empty, checks that the permission manager would have all
    * permissions available for the given principal.
    */
   bool PermissionAvailable(nsIPrincipal* aPrincipal, const nsACString& aType);
 
-  /**
-   * The content process doesn't have access to every permission. Instead, when
-   * LOAD_DOCUMENT_URI channels for http://, https://, and ftp:// URIs are
-   * opened, the permissions for those channels are sent down to the content
-   * process before the OnStartRequest message. Permissions for principals with
-   * other schemes are sent down at process startup.
-   *
-   * Permissions are keyed and grouped by "Permission Key"s.
-   * `nsPermissionManager::GetKeyForPrincipal` provides the mechanism for
-   * determining the permission key for a given principal.
-   *
-   * This method may only be called in the parent process. It fills the nsTArray
-   * argument with the IPC::Permission objects which have a matching permission
-   * key.
-   *
-   * @param permissionKey  The key to use to find the permissions of interest.
-   * @param perms  An array which will be filled with the permissions which
-   *               match the given permission key.
-   */
-  void GetPermissionsWithKey(const nsACString& aPermissionKey,
-                             nsTArray<IPC::Permission>& aPerms);
-
-  /**
-   * See `nsPermissionManager::GetPermissionsWithKey` for more info on
-   * Permission keys.
-   *
-   * `SetPermissionsWithKey` may only be called in the Child process, and
-   * initializes the permission manager with the permissions for a given
-   * Permission key. marking permissions with that key as available.
-   *
-   * @param permissionKey  The key for the permissions which have been sent
-   * over.
-   * @param perms  An array with the permissions which match the given key.
-   */
-  void SetPermissionsWithKey(const nsACString& aPermissionKey,
-                             nsTArray<IPC::Permission>& aPerms);
-
-  /**
-   * Add a callback which should be run when all permissions are available for
-   * the given nsIPrincipal. This method invokes the callback runnable
-   * synchronously when the permissions are already available. Otherwise the
-   * callback will be run asynchronously in SystemGroup when all permissions
-   * are available in the future.
-   *
-   * NOTE: This method will not request the permissions be sent by the parent
-   * process. This should only be used to wait for permissions which may not
-   * have arrived yet in order to ensure they are present.
-   *
-   * @param aPrincipal The principal to wait for permissions to be available
-   * for.
-   * @param aRunnable  The runnable to run when permissions are available for
-   * the given principal.
-   */
-  void WhenPermissionsAvailable(nsIPrincipal* aPrincipal,
-                                nsIRunnable* aRunnable);
-
-  /**
-   * True if any "preload" permissions are present. This is used to avoid making
-   * potentially expensive permissions checks in nsContentBlocker.
-   */
-  bool HasPreloadPermissions();
-
  private:
   virtual ~nsPermissionManager();
 
   // NOTE: nullptr can be passed as aType - if it is this function will return
   // "false" unconditionally.
   static bool HasDefaultPref(const nsACString& aType) {
     // A list of permissions that can have a fallback default permission
     // set under the permissions.default.* pref.
@@ -585,20 +522,16 @@ class nsPermissionManager final : public
   /**
    * This method removes all permissions modified after the specified time.
    */
   nsresult RemoveAllModifiedSince(int64_t aModificationTime);
 
   template <class T>
   nsresult RemovePermissionEntries(T aCondition);
 
-  nsresult RemovePermissionsWithAttributes(const nsAString& aPattern);
-  nsresult RemovePermissionsWithAttributes(
-      mozilla::OriginAttributesPattern& aAttrs);
-
   nsRefPtrHashtable<nsCStringHashKey,
                     mozilla::GenericNonExclusivePromise::Private>
       mPermissionKeyPromiseMap;
 
   nsCOMPtr<mozIStorageConnection> mDBConn;
   nsCOMPtr<mozIStorageAsyncStatement> mStmtInsert;
   nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete;
   nsCOMPtr<mozIStorageAsyncStatement> mStmtUpdate;
--- a/extensions/permissions/test/unit/test_permmanager_expiration.js
+++ b/extensions/permissions/test/unit/test_permmanager_expiration.js
@@ -79,29 +79,72 @@ function* do_run_test() {
   pm.addFromPrincipal(
     principal,
     "test/expiration-perm-nexp",
     1,
     pm.EXPIRE_NEVER,
     0
   );
 
+  // add a permission for renewal
+  pm.addFromPrincipal(
+    principal,
+    "test/expiration-perm-renewable",
+    1,
+    pm.EXPIRE_TIME,
+    now + 100
+  );
+  pm.addFromPrincipal(
+    principal,
+    "test/expiration-session-renewable",
+    1,
+    pm.EXPIRE_SESSION,
+    now + 100
+  );
+
+  // And immediately renew them with longer timeouts
+  pm.updateExpireTime(
+    principal,
+    "test/expiration-perm-renewable",
+    true,
+    now + 100,
+    now + 1e6
+  );
+  pm.updateExpireTime(
+    principal,
+    "test/expiration-session-renewable",
+    true,
+    now + 1e6,
+    now + 100
+  );
+
   // check that the second two haven't expired yet
   Assert.equal(
     1,
     pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp3")
   );
   Assert.equal(
     1,
     pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp3")
   );
   Assert.equal(
     1,
     pm.testPermissionFromPrincipal(principal, "test/expiration-perm-nexp")
   );
+  Assert.equal(
+    1,
+    pm.testPermissionFromPrincipal(principal, "test/expiration-perm-renewable")
+  );
+  Assert.equal(
+    1,
+    pm.testPermissionFromPrincipal(
+      principal,
+      "test/expiration-session-renewable"
+    )
+  );
 
   // ... and the first one has
   do_timeout(10, continue_test);
   yield;
   Assert.equal(
     0,
     pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp")
   );
@@ -135,10 +178,23 @@ function* do_run_test() {
     null,
     pm.getPermissionObject(principal, "test/expiration-perm-exp2", false)
   );
   Assert.equal(
     null,
     pm.getPermissionObject(principal, "test/expiration-session-exp2", false)
   );
 
+  // Check that the renewable permissions actually got renewed
+  Assert.equal(
+    1,
+    pm.testPermissionFromPrincipal(principal, "test/expiration-perm-renewable")
+  );
+  Assert.equal(
+    1,
+    pm.testPermissionFromPrincipal(
+      principal,
+      "test/expiration-session-renewable"
+    )
+  );
+
   do_finish_generator_test(test_generator);
 }
--- a/netwerk/base/nsIPermissionManager.idl
+++ b/netwerk/base/nsIPermissionManager.idl
@@ -25,18 +25,29 @@
  *          "changed"
  *          a permission was changed. the subject is the new permission.
  *          "cleared"
  *          the entire permission list was cleared. the subject is null.
  */
 
 #include "nsISupports.idl"
 
+interface nsIObserver;
 interface nsIPrincipal;
+interface mozIDOMWindow;
 interface nsIPermission;
+interface nsIRunnable;
+
+%{ C++
+namespace IPC {
+struct Permission;
+}
+#include "nsTArrayForwardDeclare.h"
+%}
+[ref] native IPCPermissionArrayRef(nsTArray<IPC::Permission>);
 
 [scriptable, builtinclass, uuid(4dcb3851-eba2-4e42-b236-82d2596fca22)]
 interface nsIPermissionManager : nsISupports
 {
   /**
    * Predefined return values for the testPermission method and for
    * the permission param of the add method
    * NOTE: UNKNOWN_ACTION (0) is reserved to represent the
@@ -137,16 +148,26 @@ interface nsIPermissionManager : nsISupp
    * System principals will always have permissions granted.
    * This function will perform a pref lookup to permissions.default.<type>
    * if the specific permission type is part of the whitelist for that functionality.
    */
   uint32_t testPermissionFromPrincipal(in nsIPrincipal principal,
                                        in ACString type);
 
   /**
+   * Test whether the principal associated with the window's document has the
+   * permission to perform a given action.  System principals will always
+   * have permissions granted.
+   * This function will perform a pref lookup to permissions.default.<type>
+   * if the specific permission type is part of the whitelist for that functionality.
+   */
+  uint32_t testPermissionFromWindow(in mozIDOMWindow window,
+                                    in ACString type);
+
+  /**
    * See testExactPermission() above.
    * System principals will always have permissions granted.
    * This function will perform a pref lookup to permissions.default.<type>
    * if the specific permission type is part of the whitelist for that functionality.
    */
   uint32_t testExactPermissionFromPrincipal(in nsIPrincipal principal,
                                             in ACString type);
 
@@ -184,24 +205,107 @@ interface nsIPermissionManager : nsISupp
 
   /**
    * Returns all stored permissions.
    * @return an array of nsIPermission objects
    */
   readonly attribute Array<nsIPermission> all;
 
   /**
+   * Remove all permissions that will match the origin pattern.
+   */
+  void removePermissionsWithAttributes(in AString patternAsJSON);
+
+  /**
+   * If the current permission is set to expire, reset the expiration time. If
+   * there is no permission or the current permission does not expire, this
+   * method will silently return.
+   *
+   * @param sessionExpiretime  an integer representation of when this permission
+   *                           should be forgotten (milliseconds since
+   *                           Jan 1 1970 0:00:00), if it is currently
+   *                           EXPIRE_SESSION.
+   * @param sessionExpiretime  an integer representation of when this permission
+   *                           should be forgotten (milliseconds since
+   *                           Jan 1 1970 0:00:00), if it is currently
+   *                           EXPIRE_TIME.
+   */
+  void updateExpireTime(in nsIPrincipal principal,
+                        in ACString type,
+                        in boolean exactHost,
+                        in uint64_t sessionExpireTime,
+                        in uint64_t persistentExpireTime);
+
+  /**
+   * The content process doesn't have access to every permission. Instead, when
+   * LOAD_DOCUMENT_URI channels for http://, https://, and ftp:// URIs are
+   * opened, the permissions for those channels are sent down to the content
+   * process before the OnStartRequest message. Permissions for principals with
+   * other schemes are sent down at process startup.
+   *
+   * Permissions are keyed and grouped by "Permission Key"s.
+   * `nsPermissionManager::GetKeyForPrincipal` provides the mechanism for
+   * determining the permission key for a given principal.
+   *
+   * This method may only be called in the parent process. It fills the nsTArray
+   * argument with the IPC::Permission objects which have a matching permission
+   * key.
+   *
+   * @param permissionKey  The key to use to find the permissions of interest.
+   * @param perms  An array which will be filled with the permissions which
+   *               match the given permission key.
+   */
+  void getPermissionsWithKey(in ACString permissionKey, out IPCPermissionArrayRef perms);
+
+  /**
+   * See `nsIPermissionManager::GetPermissionsWithKey` for more info on
+   * Permission keys.
+   *
+   * `SetPermissionsWithKey` may only be called in the Child process, and
+   * initializes the permission manager with the permissions for a given
+   * Permission key. marking permissions with that key as available.
+   *
+   * @param permissionKey  The key for the permissions which have been sent over.
+   * @param perms  An array with the permissions which match the given key.
+   */
+  void setPermissionsWithKey(in ACString permissionKey, in IPCPermissionArrayRef perms);
+
+  /**
    * Broadcasts permissions for the given principal to all content processes.
    *
    * DO NOT USE THIS METHOD if you can avoid it. It was added in bug XXX to
    * handle the current temporary implementation of ServiceWorker debugging. It
    * will be removed when service worker debugging is fixed.
    *
    * @param aPrincipal The principal to broadcast permissions for.
    */
   void broadcastPermissionsForPrincipalToAllContentProcesses(in nsIPrincipal aPrincipal);
+
+  /**
+   * Add a callback which should be run when all permissions are available for
+   * the given nsIPrincipal. This method invokes the callback runnable
+   * synchronously when the permissions are already available. Otherwise the
+   * callback will be run asynchronously in SystemGroup when all permissions
+   * are available in the future.
+   *
+   * NOTE: This method will not request the permissions be sent by the parent
+   * process. This should only be used to wait for permissions which may not
+   * have arrived yet in order to ensure they are present.
+   *
+   * @param aPrincipal The principal to wait for permissions to be available for.
+   * @param aRunnable  The runnable to run when permissions are available for the
+   *                   given principal.
+   */
+  void whenPermissionsAvailable(in nsIPrincipal aPrincipal,
+                                in nsIRunnable aRunnable);
+
+  /**
+   * True if any "preload" permissions are present. This is used to avoid making
+   * potentially expensive permissions checks in nsContentBlocker.
+   */
+  [infallible] readonly attribute boolean hasPreloadPermissions;
 };
 
 %{ C++
 #define NS_PERMISSIONMANAGER_CONTRACTID "@mozilla.org/permissionmanager;1"
 
 #define PERM_CHANGE_NOTIFICATION "perm-changed"
 %}