Bug 1408234 - Cleanup the PaymentRequests when document close. r=baku
authorEden Chuang <chenyu.chuang@gapp.nthu.edu.tw>
Mon, 13 Aug 2018 11:24:54 +0200
changeset 431381 c7536967b2f9
parent 431380 056806c8edf3
child 431382 19f9ed0f53b9
push id34440
push userapavel@mozilla.com
push dateTue, 14 Aug 2018 16:15:57 +0000
treeherdermozilla-central@48a45df79f32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1408234
milestone63.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 1408234 - Cleanup the PaymentRequests when document close. r=baku Let PaymentRequest inherit from nsIDocumentActivity interface. Calling RegisterActivityObserver() and UnregisterActivityObserver() in constructor and destructor to get activity notifications from document. When receiving the notification, NotifyOwnerDocumentActivityChanged() will check the owner document's activity status. If the status is disabled, calling PaymentRequestManager::CleanupPayment() to cleanup the PaymentRequest in content process and aslo sending the cleanup information to chrome process.
dom/interfaces/payments/nsIPaymentActionRequest.idl
dom/payments/PaymentRequest.cpp
dom/payments/PaymentRequest.h
dom/payments/PaymentRequestManager.cpp
dom/payments/PaymentRequestManager.h
dom/payments/PaymentRequestService.cpp
dom/payments/ipc/PPaymentRequest.ipdl
dom/payments/ipc/PaymentRequestParent.cpp
--- a/dom/interfaces/payments/nsIPaymentActionRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl
@@ -24,16 +24,17 @@ interface nsIPaymentActionRequest : nsIS
 {
   const uint32_t UNKNOWN_ACTION = 0;
   const uint32_t CREATE_ACTION = 1;
   const uint32_t CANMAKE_ACTION = 2;
   const uint32_t SHOW_ACTION = 3;
   const uint32_t ABORT_ACTION = 4;
   const uint32_t COMPLETE_ACTION = 5;
   const uint32_t UPDATE_ACTION = 6;
+  const uint32_t CLEANUP_ACTION = 7;
 
   /*
    *  The payment request identifier.
    */
   readonly attribute AString requestId;
 
   /*
    *  The type of the requested task.
@@ -91,17 +92,17 @@ interface nsIPaymentCreateActionRequest 
    */
   void initRequest(in AString aRequestId,
                    in nsIPaymentActionCallback aCallback,
                    in uint64_t aTabId,
                    in nsIPrincipal aPrincipal,
                    in nsIArray aMethodData,
                    in nsIPaymentDetails aDetails,
                    in nsIPaymentOptions aOptions,
-		   in AString aShippingOption);
+                   in AString aShippingOption);
 };
 
 [builtinclass, uuid(4429697d-1135-47de-a46e-5196d399ec55)]
 interface nsIPaymentCompleteActionRequest : nsIPaymentActionRequest
 {
   /*
    *  The complete status from merchant side.
    */
@@ -129,17 +130,17 @@ interface nsIPaymentUpdateActionRequest 
   readonly attribute AString shippingOption;
 
   /*
    *  Initialize function for this request.
    */
   void initRequest(in AString aRequestId,
                    in nsIPaymentActionCallback aCallback,
                    in nsIPaymentDetails aDetails,
-		   in AString aShippingOption);
+                   in AString aShippingOption);
 };
 
 %{C++
 #define NS_PAYMENT_ACTION_REQUEST_CID \
   { 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } }
 #define NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-action-request;1"
 
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -42,16 +42,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAcceptPromise)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAbortPromise)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponse)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mShippingAddress)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFullShippingAddress)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaymentRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(PaymentRequest, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(PaymentRequest, DOMEventTargetHelper)
 
 bool
 PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
 {
@@ -637,16 +638,17 @@ PaymentRequest::PaymentRequest(nsPIDOMWi
   , mUpdating(false)
   , mRequestShipping(false)
   , mDeferredShow(false)
   , mUpdateError(NS_OK)
   , mState(eCreated)
   , mIPC(nullptr)
 {
   MOZ_ASSERT(aWindow);
+  RegisterActivityObserver();
 }
 
 already_AddRefed<Promise>
 PaymentRequest::CanMakePayment(ErrorResult& aRv)
 {
   if (mState != eCreated) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
@@ -1053,23 +1055,62 @@ void
 PaymentRequest::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
 {
   MOZ_ASSERT(mDeferredShow);
   mUpdating = false;
   AbortUpdate(NS_ERROR_DOM_ABORT_ERR, mDeferredShow);
   mDeferredShow = false;
 }
 
+void
+PaymentRequest::RegisterActivityObserver()
+{
+  if (nsPIDOMWindowInner* window = GetOwner()) {
+    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+    if (doc) {
+      doc->RegisterActivityObserver(
+        NS_ISUPPORTS_CAST(nsIDocumentActivity*, this));
+    }
+  }
+}
+
+void
+PaymentRequest::UnregisterActivityObserver()
+{
+  if (nsPIDOMWindowInner* window = GetOwner()) {
+    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+    if (doc) {
+      doc->UnregisterActivityObserver(
+        NS_ISUPPORTS_CAST(nsIDocumentActivity*, this));
+    }
+  }
+}
+
+void
+PaymentRequest::NotifyOwnerDocumentActivityChanged()
+{
+  nsPIDOMWindowInner* window = GetOwner();
+  NS_ENSURE_TRUE_VOID(window);
+  nsIDocument* doc = window->GetExtantDoc();
+  NS_ENSURE_TRUE_VOID(doc);
+
+  if (!doc->IsCurrentActiveDocument()) {
+    RefPtr<PaymentRequestManager> mgr = PaymentRequestManager::GetSingleton();
+    mgr->CleanupPayment(this);
+  }
+}
+
 PaymentRequest::~PaymentRequest()
 {
   if (mIPC) {
     // If we're being destroyed, the PaymentRequestManager isn't holding any
     // references to us and we can't be waiting for any replies.
     mIPC->MaybeDelete(false);
   }
+  UnregisterActivityObserver();
 }
 
 JSObject*
 PaymentRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return PaymentRequest_Binding::Wrap(aCx, this, aGivenProto);
 }
 
--- a/dom/payments/PaymentRequest.h
+++ b/dom/payments/PaymentRequest.h
@@ -7,34 +7,36 @@
 #ifndef mozilla_dom_PaymentRequest_h
 #define mozilla_dom_PaymentRequest_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/PaymentRequestBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/ErrorResult.h"
+#include "nsIDocumentActivity.h"
 #include "nsWrapperCache.h"
 #include "PaymentRequestUpdateEvent.h"
 
 namespace mozilla {
 namespace dom {
 
 class EventHandlerNonNull;
 class PaymentAddress;
 class PaymentRequestChild;
 class PaymentResponse;
 
 class PaymentRequest final : public DOMEventTargetHelper
                            , public PromiseNativeHandler
+			   , public nsIDocumentActivity
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PaymentRequest, DOMEventTargetHelper)
+  NS_DECL_NSIDOCUMENTACTIVITY
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<PaymentRequest>
   CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv);
 
   static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
@@ -165,16 +167,19 @@ public:
   PaymentRequestChild* GetIPC()
   {
     return mIPC;
   }
 
 protected:
   ~PaymentRequest();
 
+  void RegisterActivityObserver();
+  void UnregisterActivityObserver();
+
   nsresult DispatchUpdateEvent(const nsAString& aType);
 
   PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId);
 
   // Id for internal identification
   nsString mInternalId;
   // Id for communicating with merchant side
   // mId is initialized to details.id if it exists
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -525,16 +525,32 @@ PaymentRequestManager::UpdatePayment(JSC
   IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
 
   // If aDeferredShow is true, then this call serves as the ShowUpdate call for
   // this request.
   return SendRequestPayment(aRequest, action, aDeferredShow);
 }
 
 nsresult
+PaymentRequestManager::CleanupPayment(PaymentRequest* aRequest)
+{
+  // for the case, the payment request is waiting for response from user.
+  if (auto entry = mActivePayments.Lookup(aRequest)) {
+    NotifyRequestDone(aRequest);
+  }
+  if (mShowingRequest == aRequest) {
+    mShowingRequest = nullptr;
+  }
+  nsAutoString requestId;
+  aRequest->GetInternalId(requestId);
+  IPCPaymentCleanupActionRequest action(requestId);
+  return SendRequestPayment(aRequest, action, false);
+}
+
+nsresult
 PaymentRequestManager::RespondPayment(PaymentRequest* aRequest,
                                       const IPCPaymentActionResponse& aResponse)
 {
   switch (aResponse.type()) {
     case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
       const IPCPaymentCanMakeActionResponse& response = aResponse;
       aRequest->RespondCanMakePayment(response.result());
       NotifyRequestDone(aRequest);
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -52,16 +52,17 @@ public:
   nsresult CompletePayment(PaymentRequest* aRequest,
                            const PaymentComplete& aComplete,
                            bool aTimedOut = false);
   nsresult UpdatePayment(JSContext* aCx,
                          PaymentRequest* aRequest,
                          const PaymentDetailsUpdate& aDetails,
                          bool aRequestShipping,
                          bool aDeferredShow);
+  nsresult CleanupPayment(PaymentRequest* aRequest);
 
   nsresult RespondPayment(PaymentRequest* aRequest,
                           const IPCPaymentActionResponse& aResponse);
   nsresult ChangeShippingAddress(PaymentRequest* aRequest,
                                  const IPCPaymentAddress& aAddress);
   nsresult ChangeShippingOption(PaymentRequest* aRequest,
                                 const nsAString& aOption);
 
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -373,16 +373,30 @@ PaymentRequestService::RequestPayment(ns
         mShowingRequest = payment;
         rv = LaunchUIAction(requestId, nsIPaymentActionRequest::SHOW_ACTION);
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_FAILURE;
       }
       break;
     }
+    case nsIPaymentActionRequest::CLEANUP_ACTION: {
+      nsCOMPtr<nsIPaymentRequest> payment;
+      rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      if (mShowingRequest == payment) {
+        // might need to notify the PaymentRequest is cleanup
+        mShowingRequest = nullptr;
+      }
+      mRequestQueue.RemoveElement(payment);
+      //RemoveActionCallback(requestId);
+      break;
+    }
     default: {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/payments/ipc/PPaymentRequest.ipdl
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -103,24 +103,30 @@ struct IPCPaymentCompleteActionRequest
 
 struct IPCPaymentUpdateActionRequest
 {
   nsString requestId;
   IPCPaymentDetails details;
   nsString shippingOption;
 };
 
+struct IPCPaymentCleanupActionRequest
+{
+  nsString requestId;
+};
+
 union IPCPaymentActionRequest
 {
   IPCPaymentCreateActionRequest;
   IPCPaymentCanMakeActionRequest;
   IPCPaymentShowActionRequest;
   IPCPaymentAbortActionRequest;
   IPCPaymentCompleteActionRequest;
   IPCPaymentUpdateActionRequest;
+  IPCPaymentCleanupActionRequest;
 };
 
 struct IPCPaymentCanMakeActionResponse
 {
   nsString requestId;
   bool result;
 };
 
--- a/dom/payments/ipc/PaymentRequestParent.cpp
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -142,16 +142,26 @@ PaymentRequestParent::RecvRequestPayment
       rv = updateAction->InitRequest(request.requestId(),
                                      this,
                                      details,
                                      request.shippingOption());
       action = do_QueryInterface(updateAction);
       MOZ_ASSERT(action);
       break;
     }
+    case IPCPaymentActionRequest::TIPCPaymentCleanupActionRequest: {
+      const IPCPaymentCleanupActionRequest& request = aRequest;
+      rv = CreateActionRequest(request.requestId(),
+                               nsIPaymentActionRequest::CLEANUP_ACTION,
+                               getter_AddRefs(action));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+      break;
+    }
     default: {
       return IPC_FAIL(this, "Unexpected request type");
     }
   }
   nsCOMPtr<nsIPaymentRequestService> service =
     do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
   MOZ_ASSERT(service);
   rv = service->RequestPayment(action);