Bug 796293 - [camera] Picking camera after long press causes app crash and phone reboot. r=fabrice
authorGene Lian <clian@mozilla.com>
Thu, 18 Oct 2012 18:56:28 +0800
changeset 110857 c5cf236799f7ff1bb3492f9119ffea804077f5d5
parent 110856 0bdbca5347f553a74abf65e0c17d4f2120cb93f1
child 110858 db6173f6dd091939e4563d47cb5f2cb5d83e46e9
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersfabrice
bugs796293
milestone19.0a1
Bug 796293 - [camera] Picking camera after long press causes app crash and phone reboot. r=fabrice
dom/messages/SystemMessageInternal.js
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -85,22 +85,32 @@ SystemMessageInternal.prototype = {
                                    { type: aType,
                                      msg: aMessage,
                                      manifest: aManifestURI.spec,
                                      uri: aPageURI.spec,
                                      msgID: messageID })
       });
     }
 
+    let pagesToOpen = {};
     this._pages.forEach(function(aPage) {
       if (!this._isPageMatched(aPage, aType, aPageURI.spec, aManifestURI.spec)) {
         return;
       }
 
-      this._openAppPage(aPage, aMessage, messageID);
+      // Queue this message in the corresponding pages.
+      this._queueMessage(aPage, aMessage, messageID);
+
+      // Open app pages to handle their pending messages.
+      // Note that we only need to open each app page once.
+      let key = this._createKeyForPage(aPage);
+      if (!pagesToOpen.hasOwnProperty(key)) {
+        this._openAppPage(aPage, aMessage);
+        pagesToOpen[key] = true;
+      }
     }, this);
   },
 
   broadcastMessage: function broadcastMessage(aType, aMessage) {
     // Buffer system messages until the webapps' registration is ready,
     // so that we can know the correct pages registered to be broadcasted.
     if (!this._webappsRegistryReady) {
       this._bufferedSysMsgs.push({ how: "broadcast",
@@ -110,29 +120,39 @@ SystemMessageInternal.prototype = {
     }
 
     // Give this message an ID so that we can identify the message and
     // clean it up from the pending message queue when apps receive it.
     let messageID = gUUIDGenerator.generateUUID().toString();
 
     debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
     // Find pages that registered an handler for this type.
+    let pagesToOpen = {};
     this._pages.forEach(function(aPage) {
       if (aPage.type == aType) {
         if (this._listeners[aPage.manifest]) {
           this._listeners[aPage.manifest].forEach(function sendMsg(aListener) {
             aListener.sendAsyncMessage("SystemMessageManager:Message",
                                        { type: aType,
                                          msg: aMessage,
                                          manifest: aPage.manifest,
                                          uri: aPage.uri,
                                          msgID: messageID })
           });
         }
-        this._openAppPage(aPage, aMessage, messageID);
+        // Queue this message in the corresponding pages.
+        this._queueMessage(aPage, aMessage, messageID);
+
+        // Open app pages to handle their pending messages.
+        // Note that we only need to open each app page once.
+        let key = this._createKeyForPage(aPage);
+        if (!pagesToOpen.hasOwnProperty(key)) {
+          this._openAppPage(aPage, aMessage);
+          pagesToOpen[key] = true;
+        }
       }
     }, this);
   },
 
   registerPage: function registerPage(aType, aPageURI, aManifestURI) {
     if (!aPageURI || !aManifestURI) {
       throw Cr.NS_ERROR_INVALID_ARG;
     }
@@ -261,37 +281,57 @@ SystemMessageInternal.prototype = {
               break;
           }
         }, this);
         this._bufferedSysMsgs.length = 0;
         break;
     }
   },
 
-  _openAppPage: function _openAppPage(aPage, aMessage, aMessageID) {
+  _queueMessage: function _queueMessage(aPage, aMessage, aMessageID) {
     // Queue the message for this page because we've never known if an app is
     // opened or not. We'll clean it up when the app has already received it.
     aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
     if (aPage.pendingMessages.length > kMaxPendingMessages) {
       aPage.pendingMessages.splice(0, 1);
     }
+  },
 
+  _openAppPage: function _openAppPage(aPage, aMessage) {
     // We don't need to send the full object to observers.
     let page = { uri: aPage.uri,
                  manifest: aPage.manifest,
                  type: aPage.type,
                  target: aMessage.target };
     debug("Asking to open " + JSON.stringify(page));
     Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
   },
 
   _isPageMatched: function _isPageMatched(aPage, aType, aUri, aManifest) {
     return (aPage.type === aType &&
             aPage.manifest === aManifest &&
             aPage.uri === aUri)
   },
 
+  _createKeyForPage: function _createKeyForPage(aPage) {
+    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+                      .createInstance(Ci.nsIScriptableUnicodeConverter);
+    converter.charset = "UTF-8";
+
+    let hasher = Cc["@mozilla.org/security/hash;1"]
+                   .createInstance(Ci.nsICryptoHash);
+    hasher.init(hasher.SHA1);
+
+    // add uri and action to the hash
+    ["type", "manifest", "uri"].forEach(function(aProp) {
+      let data = converter.convertToByteArray(aPage[aProp], {});
+      hasher.update(data, data.length);
+    });
+
+    return hasher.finish(true);
+  },
+
   classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
 }
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]);