Bug 1007520 - Part 2: Avoid leaking Activities.callers in ActivitiesService.jsm. r=fabrice, a=lmandel
authorTing-Yu Chou <janus926@gmail.com>
Thu, 29 May 2014 17:16:58 +0800
changeset 188197 ae02c86181e6ef15939846b95b41420ba5087dfb
parent 188196 6f8b310d40e2d179e11b4405226df3ecc769b625
child 188198 7b479856388272dbcc4b979b433c91145512ea8a
push id452
push userryanvm@gmail.com
push dateMon, 30 Jun 2014 21:10:14 +0000
treeherdermozilla-b2g30_v1_4@7b4798563882 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice, lmandel
bugs1007520
milestone30.0
Bug 1007520 - Part 2: Avoid leaking Activities.callers in ActivitiesService.jsm. r=fabrice, a=lmandel
dom/activities/src/ActivitiesService.jsm
--- a/dom/activities/src/ActivitiesService.jsm
+++ b/dom/activities/src/ActivitiesService.jsm
@@ -196,72 +196,70 @@ let Activities = {
     * - finds a list of matching activities.
     * - calls the UI glue to get the user choice.
     * - fire an system message of type "activity" to this app, sending the
     *   activity data as a payload.
     */
   startActivity: function activities_startActivity(aMsg) {
     debug("StartActivity: " + JSON.stringify(aMsg));
 
+    let self = this;
     let successCb = function successCb(aResults) {
       debug(JSON.stringify(aResults));
 
       // We have no matching activity registered, let's fire an error.
       if (aResults.options.length === 0) {
-        Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+        self.trySendAndCleanup(aMsg.id, "Activity:FireError", {
           "id": aMsg.id,
           "error": "NO_PROVIDER"
         });
-        delete Activities.callers[aMsg.id];
         return;
       }
 
       function getActivityChoice(aChoice) {
         debug("Activity choice: " + aChoice);
 
         // The user has cancelled the choice, fire an error.
         if (aChoice === -1) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireError", {
+          self.trySendAndCleanup(aMsg.id, "Activity:FireError", {
             "id": aMsg.id,
             "error": "ActivityCanceled"
           });
-          delete Activities.callers[aMsg.id];
           return;
         }
 
         let sysmm = Cc["@mozilla.org/system-message-internal;1"]
                       .getService(Ci.nsISystemMessagesInternal);
         if (!sysmm) {
           // System message is not present, what should we do?
-          delete Activities.callers[aMsg.id];
+          delete self.callers[aMsg.id];
           return;
         }
 
         debug("Sending system message...");
         let result = aResults.options[aChoice];
         sysmm.sendMessage("activity", {
             "id": aMsg.id,
             "payload": aMsg.options,
             "target": result.description
           },
           Services.io.newURI(result.description.href, null, null),
           Services.io.newURI(result.manifest, null, null),
           {
-            "manifestURL": Activities.callers[aMsg.id].manifestURL,
-            "pageURL": Activities.callers[aMsg.id].pageURL
+            "manifestURL": self.callers[aMsg.id].manifestURL,
+            "pageURL": self.callers[aMsg.id].pageURL
           });
 
         if (!result.description.returnValue) {
-          Activities.callers[aMsg.id].mm.sendAsyncMessage("Activity:FireSuccess", {
+          // No need to notify observers, since we don't want the caller
+          // to be raised on the foreground that quick.
+          self.trySendAndCleanup(aMsg.id, "Activity:FireSuccess", {
             "id": aMsg.id,
             "result": null
           });
-          // No need to notify observers, since we don't want the caller
-          // to be raised on the foreground that quick.
-          delete Activities.callers[aMsg.id];
         }
       };
 
       let glue = Cc["@mozilla.org/dom/activities/ui-glue;1"]
                    .createInstance(Ci.nsIActivityUIGlue);
       glue.chooseActivity(aResults.name, aResults.options, getActivityChoice);
     };
 
@@ -273,16 +271,24 @@ let Activities = {
     let matchFunc = function matchFunc(aResult) {
       return ActivitiesServiceFilter.match(aMsg.options.data,
                                            aResult.description.filters);
     };
 
     this.db.find(aMsg, successCb, errorCb, matchFunc);
   },
 
+  trySendAndCleanup: function activities_trySendAndCleanup(aId, aName, aPayload) {
+    try {
+      this.callers[aId].mm.sendAsyncMessage(aName, aPayload);
+    } finally {
+      delete this.callers[aId];
+    }
+  },
+
   receiveMessage: function activities_receiveMessage(aMessage) {
     let mm = aMessage.target;
     let msg = aMessage.json;
 
     let caller;
     let obsData;
 
     if (aMessage.name == "Activity:PostResult" ||
@@ -306,22 +312,20 @@ let Activities = {
         this.startActivity(msg);
         break;
 
       case "Activity:Ready":
         caller.childMM = mm;
         break;
 
       case "Activity:PostResult":
-        caller.mm.sendAsyncMessage("Activity:FireSuccess", msg);
-        delete this.callers[msg.id];
+        this.trySendAndCleanup(msg.id, "Activity:FireSuccess", msg);
         break;
       case "Activity:PostError":
-        caller.mm.sendAsyncMessage("Activity:FireError", msg);
-        delete this.callers[msg.id];
+        this.trySendAndCleanup(msg.id, "Activity:FireError", msg);
         break;
 
       case "Activities:Register":
         let self = this;
         this.db.add(msg,
           function onSuccess(aEvent) {
             mm.sendAsyncMessage("Activities:Register:OK", null);
             let res = [];
@@ -350,21 +354,20 @@ let Activities = {
         }
         break;
       case "Activities:GetContentTypes":
         this.sendContentTypes(mm);
         break;
       case "child-process-shutdown":
         for (let id in this.callers) {
           if (this.callers[id].childMM == mm) {
-            this.callers[id].mm.sendAsyncMessage("Activity:FireError", {
+            this.trySendAndCleanup(id, "Activity:FireError", {
               "id": id,
               "error": "ActivityCanceled"
             });
-            delete this.callers[id];
             break;
           }
         }
         break;
     }
   },
 
   updateContentTypeList: function updateContentTypeList(aActivity, aResult) {