Bug 1536454 - Part 1 - Add userHadInteractedWithDocument and documentDOMContentLoadedTimestamp attributes to nsIContentPermissionPrompt. r=Ehsan
authorJohann Hofmann <jhofmann@mozilla.com>
Thu, 18 Apr 2019 13:43:05 +0000
changeset 470077 565279f288410f563f7871360a1d53d8e3f60dd9
parent 470076 ee03e8a4f6cd04cfc183a4ed2012c872cb021df0
child 470078 c4beb7256d16cf3f18739fd20dad8411f4a99092
push id112843
push useraiakab@mozilla.com
push dateFri, 19 Apr 2019 09:50:22 +0000
treeherdermozilla-inbound@c06f27cbfe40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1536454
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1536454 - Part 1 - Add userHadInteractedWithDocument and documentDOMContentLoadedTimestamp attributes to nsIContentPermissionPrompt. r=Ehsan Differential Revision: https://phabricator.services.mozilla.com/D26942
browser/actors/WebRTCChild.jsm
browser/modules/test/browser/head.js
dom/base/nsContentPermissionHelper.cpp
dom/base/nsContentPermissionHelper.h
dom/interfaces/base/nsIContentPermissionPrompt.idl
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/push/Push.jsm
--- a/browser/actors/WebRTCChild.jsm
+++ b/browser/actors/WebRTCChild.jsm
@@ -215,16 +215,25 @@ function prompt(aContentWindow, aWindowI
     setupPendingListsInitially(aContentWindow);
   }
   aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
 
   // Record third party origins for telemetry.
   let isThirdPartyOrigin =
     aContentWindow.document.location.origin != aContentWindow.top.document.location.origin;
 
+  // WebRTC prompts have a bunch of special requirements, such as being able to
+  // grant two permissions (microphone and camera), selecting devices and showing
+  // a screen sharing preview. All this could have probably been baked into
+  // nsIContentPermissionRequest prompts, but the team that implemented this back
+  // then chose to just build their own prompting mechanism instead.
+  //
+  // So, what you are looking at here is not a real nsIContentPermissionRequest, but
+  // something that looks really similar and will be transmitted to webrtcUI.jsm
+  // for showing the prompt.
   let request = {
     callID: aCallID,
     windowID: aWindowID,
     origin: aContentWindow.origin,
     documentURI: aContentWindow.document.documentURI,
     secure: aSecure,
     isHandlingUserInput: aIsHandlingUserInput,
     isThirdPartyOrigin,
--- a/browser/modules/test/browser/head.js
+++ b/browser/modules/test/browser/head.js
@@ -70,16 +70,19 @@ function makeMockPermissionRequest(brows
   let type = {
     options: Cc["@mozilla.org/array;1"].createInstance(Ci.nsIArray),
     QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionType]),
   };
   let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
   types.appendElement(type);
   let result = {
     types,
+    documentDOMContentLoadedTimestamp: 0,
+    isHandlingUserInput: false,
+    userHadInteractedWithDocument: false,
     principal: browser.contentPrincipal,
     topLevelPrincipal: browser.contentPrincipal,
     requester: null,
     _cancelled: false,
     cancel() {
       this._cancelled = true;
     },
     _allowed: false,
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -7,16 +7,17 @@
 #include <map>
 #include "nsCOMPtr.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/PContentPermission.h"
+#include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/Preferences.h"
@@ -114,53 +115,59 @@ VisibilityChangeListener::GetCallback() 
   return callback.forget();
 }
 
 namespace mozilla {
 namespace dom {
 
 class ContentPermissionRequestParent : public PContentPermissionRequestParent {
  public:
-  ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
-                                 Element* aElement,
-                                 const IPC::Principal& aPrincipal,
-                                 const IPC::Principal& aTopLevelPrincipal,
-                                 const bool aIsHandlingUserInput);
+  ContentPermissionRequestParent(
+      const nsTArray<PermissionRequest>& aRequests, Element* aElement,
+      const IPC::Principal& aPrincipal,
+      const IPC::Principal& aTopLevelPrincipal, const bool aIsHandlingUserInput,
+      const bool aUserHadInteractedWithDocument,
+      const DOMTimeStamp aDocumentDOMContentLoadedTimestamp);
   virtual ~ContentPermissionRequestParent();
 
   bool IsBeingDestroyed();
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<Element> mElement;
   bool mIsHandlingUserInput;
+  bool mUserHadInteractedWithDocument;
+  DOMTimeStamp mDocumentDOMContentLoadedTimestamp;
   RefPtr<nsContentPermissionRequestProxy> mProxy;
   nsTArray<PermissionRequest> mRequests;
 
  private:
   // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual mozilla::ipc::IPCResult Recvprompt() override;
   virtual mozilla::ipc::IPCResult RecvNotifyVisibility(
       const bool& aIsVisible) override;
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
   virtual void ActorDestroy(ActorDestroyReason why) override;
 };
 
 ContentPermissionRequestParent::ContentPermissionRequestParent(
     const nsTArray<PermissionRequest>& aRequests, Element* aElement,
     const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
-    const bool aIsHandlingUserInput) {
+    const bool aIsHandlingUserInput, const bool aUserHadInteractedWithDocument,
+    const DOMTimeStamp aDocumentDOMContentLoadedTimestamp) {
   MOZ_COUNT_CTOR(ContentPermissionRequestParent);
 
   mPrincipal = aPrincipal;
   mTopLevelPrincipal = aTopLevelPrincipal;
   mElement = aElement;
   mRequests = aRequests;
   mIsHandlingUserInput = aIsHandlingUserInput;
+  mUserHadInteractedWithDocument = aUserHadInteractedWithDocument;
+  mDocumentDOMContentLoadedTimestamp = aDocumentDOMContentLoadedTimestamp;
 }
 
 ContentPermissionRequestParent::~ContentPermissionRequestParent() {
   MOZ_COUNT_DTOR(ContentPermissionRequestParent);
 }
 
 mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
   mProxy = new nsContentPermissionRequestProxy(this);
@@ -317,20 +324,22 @@ nsresult nsContentPermissionUtils::Creat
   return NS_OK;
 }
 
 /* static */
 PContentPermissionRequestParent*
 nsContentPermissionUtils::CreateContentPermissionRequestParent(
     const nsTArray<PermissionRequest>& aRequests, Element* aElement,
     const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
-    const bool aIsHandlingUserInput, const TabId& aTabId) {
+    const bool aIsHandlingUserInput, const bool aUserHadInteractedWithDocument,
+    const DOMTimeStamp aDocumentDOMContentLoadedTimestamp,
+    const TabId& aTabId) {
   PContentPermissionRequestParent* parent = new ContentPermissionRequestParent(
-      aRequests, aElement, aPrincipal, aTopLevelPrincipal,
-      aIsHandlingUserInput);
+      aRequests, aElement, aPrincipal, aTopLevelPrincipal, aIsHandlingUserInput,
+      aUserHadInteractedWithDocument, aDocumentDOMContentLoadedTimestamp);
   ContentPermissionRequestParentMap()[parent] = aTabId;
 
   return parent;
 }
 
 /* static */
 nsresult nsContentPermissionUtils::AskPermission(
     nsIContentPermissionRequest* aRequest, nsPIDOMWindowInner* aWindow) {
@@ -360,23 +369,34 @@ nsresult nsContentPermissionUtils::AskPe
     nsCOMPtr<nsIPrincipal> topLevelPrincipal;
     rv = aRequest->GetTopLevelPrincipal(getter_AddRefs(topLevelPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool isHandlingUserInput;
     rv = aRequest->GetIsHandlingUserInput(&isHandlingUserInput);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    bool userHadInteractedWithDocument;
+    rv = aRequest->GetUserHadInteractedWithDocument(
+        &userHadInteractedWithDocument);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    DOMTimeStamp documentDOMContentLoadedTimestamp;
+    rv = aRequest->GetDocumentDOMContentLoadedTimestamp(
+        &documentDOMContentLoadedTimestamp);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     ContentChild::GetSingleton()->SetEventTargetForActor(
         req, aWindow->EventTargetFor(TaskCategory::Other));
 
     req->IPDLAddRef();
     ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
         req, permArray, IPC::Principal(principal),
         IPC::Principal(topLevelPrincipal), isHandlingUserInput,
+        userHadInteractedWithDocument, documentDOMContentLoadedTimestamp,
         child->GetTabId());
     ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();
 
     req->Sendprompt();
     return NS_OK;
   }
 
   // for chrome process
@@ -523,17 +543,36 @@ ContentPermissionRequestBase::ContentPer
     nsIPrincipal* aPrincipal, nsPIDOMWindowInner* aWindow,
     const nsACString& aPrefName, const nsACString& aType)
     : mPrincipal(aPrincipal),
       mTopLevelPrincipal(aWindow ? ::GetTopLevelPrincipal(aWindow) : nullptr),
       mWindow(aWindow),
       mRequester(aWindow ? new nsContentPermissionRequester(aWindow) : nullptr),
       mPrefName(aPrefName),
       mType(aType),
-      mIsHandlingUserInput(EventStateManager::IsHandlingUserInput()) {}
+      mIsHandlingUserInput(EventStateManager::IsHandlingUserInput()),
+      mUserHadInteractedWithDocument(false),
+      mDocumentDOMContentLoadedTimestamp(0) {
+  if (!aWindow) {
+    return;
+  }
+
+  Document* doc = aWindow->GetExtantDoc();
+  if (!doc) {
+    return;
+  }
+
+  mUserHadInteractedWithDocument = doc->UserHasInteracted();
+
+  nsDOMNavigationTiming* navTiming = doc->GetNavigationTiming();
+  if (navTiming) {
+    mDocumentDOMContentLoadedTimestamp =
+        navTiming->GetDomContentLoadedEventEnd();
+  }
+}
 
 NS_IMETHODIMP
 ContentPermissionRequestBase::GetPrincipal(
     nsIPrincipal** aRequestingPrincipal) {
   NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
   return NS_OK;
 }
 
@@ -560,16 +599,30 @@ ContentPermissionRequestBase::GetElement
 NS_IMETHODIMP
 ContentPermissionRequestBase::GetIsHandlingUserInput(
     bool* aIsHandlingUserInput) {
   *aIsHandlingUserInput = mIsHandlingUserInput;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+ContentPermissionRequestBase::GetUserHadInteractedWithDocument(
+    bool* aUserHadInteractedWithDocument) {
+  *aUserHadInteractedWithDocument = mUserHadInteractedWithDocument;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ContentPermissionRequestBase::GetDocumentDOMContentLoadedTimestamp(
+    DOMTimeStamp* aDocumentDOMContentLoadedTimestamp) {
+  *aDocumentDOMContentLoadedTimestamp = mDocumentDOMContentLoadedTimestamp;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ContentPermissionRequestBase::GetRequester(
     nsIContentPermissionRequester** aRequester) {
   NS_ENSURE_ARG_POINTER(aRequester);
 
   nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
   requester.forget(aRequester);
   return NS_OK;
 }
@@ -859,16 +912,39 @@ nsContentPermissionRequestProxy::GetIsHa
   if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
   }
   *aIsHandlingUserInput = mParent->mIsHandlingUserInput;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsContentPermissionRequestProxy::GetUserHadInteractedWithDocument(
+    bool* aUserHadInteractedWithDocument) {
+  NS_ENSURE_ARG_POINTER(aUserHadInteractedWithDocument);
+  if (mParent == nullptr) {
+    return NS_ERROR_FAILURE;
+  }
+  *aUserHadInteractedWithDocument = mParent->mUserHadInteractedWithDocument;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsContentPermissionRequestProxy::GetDocumentDOMContentLoadedTimestamp(
+    DOMTimeStamp* aDocumentDOMContentLoadedTimestamp) {
+  NS_ENSURE_ARG_POINTER(aDocumentDOMContentLoadedTimestamp);
+  if (mParent == nullptr) {
+    return NS_ERROR_FAILURE;
+  }
+  *aDocumentDOMContentLoadedTimestamp =
+      mParent->mDocumentDOMContentLoadedTimestamp;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsContentPermissionRequestProxy::Cancel() {
   if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
   }
 
   // Don't send out the delete message when the managing protocol (PBrowser) is
   // being destroyed and PContentPermissionRequest will soon be.
   if (mParent->IsBeingDestroyed()) {
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -67,16 +67,18 @@ class nsContentPermissionUtils {
   static nsresult CreatePermissionArray(const nsACString& aType,
                                         const nsTArray<nsString>& aOptions,
                                         nsIArray** aTypesArray);
 
   static PContentPermissionRequestParent* CreateContentPermissionRequestParent(
       const nsTArray<PermissionRequest>& aRequests, Element* aElement,
       const IPC::Principal& aPrincipal,
       const IPC::Principal& aTopLevelPrincipal, const bool aIsHandlingUserInput,
+      const bool aUserHadInteractedWithDocument,
+      const DOMTimeStamp aDocumentDOMContentLoadedTimestamp,
       const TabId& aTabId);
 
   static nsresult AskPermission(nsIContentPermissionRequest* aRequest,
                                 nsPIDOMWindowInner* aWindow);
 
   static nsTArray<PContentPermissionRequestParent*>
   GetContentPermissionRequestParentById(const TabId& aTabId);
 
@@ -116,16 +118,20 @@ class ContentPermissionRequestBase : pub
   NS_DECL_CYCLE_COLLECTION_CLASS(ContentPermissionRequestBase)
 
   NS_IMETHOD GetTypes(nsIArray** aTypes) override;
   NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal) override;
   NS_IMETHOD GetTopLevelPrincipal(nsIPrincipal** aTopLevelPrincipal) override;
   NS_IMETHOD GetWindow(mozIDOMWindow** aWindow) override;
   NS_IMETHOD GetElement(mozilla::dom::Element** aElement) override;
   NS_IMETHOD GetIsHandlingUserInput(bool* aIsHandlingUserInput) override;
+  NS_IMETHOD GetUserHadInteractedWithDocument(
+      bool* aUserHadInteractedWithDocument) override;
+  NS_IMETHOD GetDocumentDOMContentLoadedTimestamp(
+      DOMTimeStamp* aDocumentDOMContentLoadedTimestamp) override;
   NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override;
   // Overrides for Allow() and Cancel() aren't provided by this class.
   // That is the responsibility of the subclasses.
 
   enum class PromptResult {
     Granted,
     Denied,
     Pending,
@@ -150,16 +156,18 @@ class ContentPermissionRequestBase : pub
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIContentPermissionRequester> mRequester;
   nsCString mPrefName;
   nsCString mType;
   bool mIsHandlingUserInput;
+  bool mUserHadInteractedWithDocument;
+  DOMTimeStamp mDocumentDOMContentLoadedTimestamp;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 using mozilla::dom::ContentPermissionRequestParent;
 
 class nsContentPermissionRequestProxy : public nsIContentPermissionRequest {
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -1,13 +1,14 @@
 /* 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/. */
 
 #include "nsISupports.idl"
+#include "domstubs.idl"
 
 interface nsIPrincipal;
 interface mozIDOMWindow;
 interface nsIArray;
 
 webidl Element;
 
 /**
@@ -83,16 +84,18 @@ interface nsIContentPermissionRequest : 
    *  originated in.  Typically the element will be non-null
    *  in when using out of process content.  window or
    *  element can be null but not both.
    */
   readonly attribute mozIDOMWindow window;
   readonly attribute Element element;
 
   readonly attribute boolean isHandlingUserInput;
+  readonly attribute boolean userHadInteractedWithDocument;
+  readonly attribute DOMTimeStamp documentDOMContentLoadedTimestamp;
 
   /**
    *  The requester to get the required information of
    *  the window.
    */
   readonly attribute nsIContentPermissionRequester requester;
 
   /**
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3020,17 +3020,18 @@ mozilla::ipc::IPCResult ContentChild::Re
   return IPC_FAIL_NO_REASON(this);
 #endif
 }
 
 PContentPermissionRequestChild*
 ContentChild::AllocPContentPermissionRequestChild(
     const InfallibleTArray<PermissionRequest>& aRequests,
     const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
-    const bool& aIsHandlingUserInput, const TabId& aTabId) {
+    const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
+    const DOMTimeStamp aPageLoadTimestamp, const TabId& aTabId) {
   MOZ_CRASH("unused");
   return nullptr;
 }
 
 bool ContentChild::DeallocPContentPermissionRequestChild(
     PContentPermissionRequestChild* actor) {
   nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(actor);
   auto child = static_cast<RemotePermissionRequest*>(actor);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -532,17 +532,18 @@ class ContentChild final : public PConte
   PWebrtcGlobalChild* AllocPWebrtcGlobalChild();
 
   bool DeallocPWebrtcGlobalChild(PWebrtcGlobalChild* aActor);
 
   PContentPermissionRequestChild* AllocPContentPermissionRequestChild(
       const InfallibleTArray<PermissionRequest>& aRequests,
       const IPC::Principal& aPrincipal,
       const IPC::Principal& aTopLevelPrincipal,
-      const bool& aIsHandlingUserInput, const TabId& aTabId);
+      const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
+      const DOMTimeStamp aPageLoadTimestamp, const TabId& aTabId);
   bool DeallocPContentPermissionRequestChild(
       PContentPermissionRequestChild* actor);
 
   // Windows specific - set up audio session
   mozilla::ipc::IPCResult RecvSetAudioSessionData(const nsID& aId,
                                                   const nsString& aDisplayName,
                                                   const nsString& aIconPath);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4620,27 +4620,28 @@ mozilla::ipc::IPCResult ContentParent::R
   }
   return IPC_OK();
 }
 
 PContentPermissionRequestParent*
 ContentParent::AllocPContentPermissionRequestParent(
     const InfallibleTArray<PermissionRequest>& aRequests,
     const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
-    const bool& aIsHandlingUserInput, const TabId& aTabId) {
+    const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
+    const DOMTimeStamp& aPageLoadTimestamp, const TabId& aTabId) {
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   RefPtr<TabParent> tp =
       cpm->GetTopLevelTabParentByProcessAndTabId(this->ChildID(), aTabId);
   if (!tp) {
     return nullptr;
   }
 
   return nsContentPermissionUtils::CreateContentPermissionRequestParent(
       aRequests, tp->GetOwnerElement(), aPrincipal, aTopLevelPrincipal,
-      aIsHandlingUserInput, aTabId);
+      aIsHandlingUserInput, aDocumentHasUserInput, aPageLoadTimestamp, aTabId);
 }
 
 bool ContentParent::DeallocPContentPermissionRequestParent(
     PContentPermissionRequestParent* actor) {
   nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
   delete actor;
   return true;
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -495,18 +495,19 @@ class ContentParent final : public PCont
 
   mozilla::ipc::IPCResult RecvFinishShutdown();
 
   void MaybeInvokeDragSession(TabParent* aParent);
 
   PContentPermissionRequestParent* AllocPContentPermissionRequestParent(
       const InfallibleTArray<PermissionRequest>& aRequests,
       const IPC::Principal& aPrincipal,
-      const IPC::Principal& aTopLevelPrincipal, const bool& aIsTrusted,
-      const TabId& aTabId);
+      const IPC::Principal& aTopLevelPrincipal,
+      const bool& aIsHandlingUserInput, const bool& aDocumentHasUserInput,
+      const DOMTimeStamp& aPageLoadTimestamp, const TabId& aTabId);
 
   bool DeallocPContentPermissionRequestParent(
       PContentPermissionRequestParent* actor);
 
   virtual bool HandleWindowsMessages(const Message& aMsg) const override;
 
   void ForkNewProcess(bool aBlocking);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1126,17 +1126,17 @@ parent:
      *   To identify which tab issues this request.
      *
      * NOTE: The principal is untrusted in the parent process. Only
      *       principals that can live in the content process should
      *       provided.
      */
     async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
                                     Principal aTopLevelPrincipal, bool aIsHandlingUserInput,
-                                    TabId tabId);
+                                    bool aDocumentHasUserInput, uint64_t aPageLoadTimestamp, TabId tabId);
 
     async ShutdownProfile(nsCString aProfile);
 
     /**
      * Request graphics initialization information from the parent.
      */
     sync GetGraphicsDeviceInitData()
         returns (ContentDeviceData aData);
--- a/dom/push/Push.jsm
+++ b/dom/push/Push.jsm
@@ -177,21 +177,23 @@ Push.prototype = {
       options: [],
       QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionType]),
     };
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type);
 
     // create a nsIContentPermissionRequest
     let request = {
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
       types: typeArray,
       principal: this._principal,
       isHandlingUserInput,
+      userHadInteractedWithDocument: this._window.document.userHasInteracted,
+      documentDOMContentLoadedTimestamp: this._window.performance.timing.domContentLoadedEventEnd,
       topLevelPrincipal: this._topLevelPrincipal,
-      QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
       allow: allowCallback,
       cancel: cancelCallback,
       window: this._window,
     };
 
     // Using askPermission from nsIDOMWindowUtils that takes care of the
     // remoting if needed.
     let windowUtils = this._window.windowUtils;