dom/messages/SystemMessageInternal.js

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 const Cc = Components.classes;
     8 const Ci = Components.interfaces;
     9 const Cu = Components.utils;
    10 const Cr = Components.results;
    12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    13 Cu.import("resource://gre/modules/Services.jsm");
    14 Cu.import("resource://gre/modules/SystemMessagePermissionsChecker.jsm");
    16 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
    17                                    "@mozilla.org/parentprocessmessagemanager;1",
    18                                    "nsIMessageBroadcaster");
    20 XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
    21                                    "@mozilla.org/uuid-generator;1",
    22                                    "nsIUUIDGenerator");
    24 XPCOMUtils.defineLazyServiceGetter(this, "powerManagerService",
    25                                    "@mozilla.org/power/powermanagerservice;1",
    26                                    "nsIPowerManagerService");
    28 // Limit the number of pending messages for a given page.
    29 let kMaxPendingMessages;
    30 try {
    31   kMaxPendingMessages =
    32     Services.prefs.getIntPref("dom.messages.maxPendingMessages");
    33 } catch(e) {
    34   // getIntPref throws when the pref is not set.
    35   kMaxPendingMessages = 5;
    36 }
    38 const kMessages =["SystemMessageManager:GetPendingMessages",
    39                   "SystemMessageManager:HasPendingMessages",
    40                   "SystemMessageManager:Register",
    41                   "SystemMessageManager:Unregister",
    42                   "SystemMessageManager:Message:Return:OK",
    43                   "SystemMessageManager:AskReadyToRegister",
    44                   "SystemMessageManager:HandleMessagesDone",
    45                   "child-process-shutdown"]
    47 function debug(aMsg) {
    48   // dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
    49 }
    52 let defaultMessageConfigurator = {
    53   get mustShowRunningApp() {
    54     return false;
    55   }
    56 };
    58 const MSG_SENT_SUCCESS = 0;
    59 const MSG_SENT_FAILURE_PERM_DENIED = 1;
    60 const MSG_SENT_FAILURE_APP_NOT_RUNNING = 2;
    62 // Implementation of the component used by internal users.
    64 function SystemMessageInternal() {
    65   // The set of pages registered by installed apps. We keep the
    66   // list of pending messages for each page here also.
    67   this._pages = [];
    69   // The set of listeners. This is a multi-dimensional object. The _listeners
    70   // object itself is a map from manifest URL -> an array mapping proccesses to
    71   // windows. We do this so that we can track both what processes we have to
    72   // send system messages to as well as supporting the single-process case
    73   // where we track windows instead.
    74   this._listeners = {};
    76   this._webappsRegistryReady = false;
    77   this._bufferedSysMsgs = [];
    79   this._cpuWakeLocks = {};
    81   this._configurators = {};
    83   Services.obs.addObserver(this, "xpcom-shutdown", false);
    84   Services.obs.addObserver(this, "webapps-registry-start", false);
    85   Services.obs.addObserver(this, "webapps-registry-ready", false);
    86   kMessages.forEach(function(aMsg) {
    87     ppmm.addMessageListener(aMsg, this);
    88   }, this);
    90   Services.obs.notifyObservers(this, "system-message-internal-ready", null);
    91 }
    93 SystemMessageInternal.prototype = {
    95   _getMessageConfigurator: function(aType) {
    96     debug("_getMessageConfigurator for type: " + aType);
    97     if (this._configurators[aType] === undefined) {
    98       let contractID =
    99         "@mozilla.org/dom/system-messages/configurator/" + aType + ";1";
   100       if (contractID in Cc) {
   101         debug(contractID + " is registered, creating an instance");
   102         this._configurators[aType] =
   103           Cc[contractID].createInstance(Ci.nsISystemMessagesConfigurator);
   104       } else {
   105         debug(contractID + "is not registered, caching the answer");
   106         this._configurators[aType] = null;
   107       }
   108     }
   109     return this._configurators[aType] || defaultMessageConfigurator;
   110   },
   112   _cancelCpuWakeLock: function(aPageKey) {
   113     let cpuWakeLock = this._cpuWakeLocks[aPageKey];
   114     if (cpuWakeLock) {
   115       debug("Releasing the CPU wake lock for page key = " + aPageKey);
   116       cpuWakeLock.wakeLock.unlock();
   117       cpuWakeLock.timer.cancel();
   118       delete this._cpuWakeLocks[aPageKey];
   119     }
   120   },
   122   _acquireCpuWakeLock: function(aPageKey) {
   123     let cpuWakeLock = this._cpuWakeLocks[aPageKey];
   124     if (!cpuWakeLock) {
   125       // We have to ensure the CPU doesn't sleep during the process of the page
   126       // handling the system messages, so that they can be handled on time.
   127       debug("Acquiring a CPU wake lock for page key = " + aPageKey);
   128       cpuWakeLock = this._cpuWakeLocks[aPageKey] = {
   129         wakeLock: powerManagerService.newWakeLock("cpu"),
   130         timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
   131         lockCount: 1
   132       };
   133     } else {
   134       // We've already acquired the CPU wake lock for this page,
   135       // so just add to the lock count and extend the timeout.
   136       cpuWakeLock.lockCount++;
   137     }
   139     // Set a watchdog to avoid locking the CPU wake lock too long,
   140     // because it'd exhaust the battery quickly which is very bad.
   141     // This could probably happen if the app failed to launch or
   142     // handle the system messages due to any unexpected reasons.
   143     cpuWakeLock.timer.initWithCallback(function timerCb() {
   144       debug("Releasing the CPU wake lock because the system messages " +
   145             "were not handled by its registered page before time out.");
   146       this._cancelCpuWakeLock(aPageKey);
   147     }.bind(this), 30000, Ci.nsITimer.TYPE_ONE_SHOT);
   148   },
   150   _releaseCpuWakeLock: function _releaseCpuWakeLock(aPageKey, aHandledCount) {
   151     let cpuWakeLock = this._cpuWakeLocks[aPageKey];
   152     if (cpuWakeLock) {
   153       cpuWakeLock.lockCount -= aHandledCount;
   154       if (cpuWakeLock.lockCount <= 0) {
   155         debug("Unlocking the CPU wake lock now that the system messages " +
   156               "have been successfully handled by its registered page.");
   157         this._cancelCpuWakeLock(aPageKey);
   158       }
   159     }
   160   },
   162   _findPage: function(aType, aPageURL, aManifestURL) {
   163     let page = null;
   164     this._pages.some(function(aPage) {
   165       if (this._isPageMatched(aPage, aType, aPageURL, aManifestURL)) {
   166         page = aPage;
   167       }
   168       return page !== null;
   169     }, this);
   170     return page;
   171   },
   173   sendMessage: function(aType, aMessage, aPageURI, aManifestURI, aExtra) {
   174     // Buffer system messages until the webapps' registration is ready,
   175     // so that we can know the correct pages registered to be sent.
   176     if (!this._webappsRegistryReady) {
   177       this._bufferedSysMsgs.push({ how: "send",
   178                                    type: aType,
   179                                    msg: aMessage,
   180                                    pageURI: aPageURI,
   181                                    manifestURI: aManifestURI,
   182                                    extra: aExtra });
   183       return;
   184     }
   186     // Give this message an ID so that we can identify the message and
   187     // clean it up from the pending message queue when apps receive it.
   188     let messageID = gUUIDGenerator.generateUUID().toString();
   190     debug("Sending " + aType + " " + JSON.stringify(aMessage) +
   191       " for " + aPageURI.spec + " @ " + aManifestURI.spec +
   192       '; extra: ' + JSON.stringify(aExtra));
   194     let result = this._sendMessageCommon(aType,
   195                                          aMessage,
   196                                          messageID,
   197                                          aPageURI.spec,
   198                                          aManifestURI.spec,
   199                                          aExtra);
   200     debug("Returned status of sending message: " + result);
   202     // Don't need to open the pages and queue the system message
   203     // which was not allowed to be sent.
   204     if (result === MSG_SENT_FAILURE_PERM_DENIED) {
   205       return;
   206     }
   208     let page = this._findPage(aType, aPageURI.spec, aManifestURI.spec);
   209     if (page) {
   210       // Queue this message in the corresponding pages.
   211       this._queueMessage(page, aMessage, messageID);
   213       this._openAppPage(page, aMessage, aExtra, result);
   214     }
   215   },
   217   broadcastMessage: function(aType, aMessage, aExtra) {
   218     // Buffer system messages until the webapps' registration is ready,
   219     // so that we can know the correct pages registered to be broadcasted.
   220     if (!this._webappsRegistryReady) {
   221       this._bufferedSysMsgs.push({ how: "broadcast",
   222                                    type: aType,
   223                                    msg: aMessage,
   224                                    extra: aExtra });
   225       return;
   226     }
   228     // Give this message an ID so that we can identify the message and
   229     // clean it up from the pending message queue when apps receive it.
   230     let messageID = gUUIDGenerator.generateUUID().toString();
   232     debug("Broadcasting " + aType + " " + JSON.stringify(aMessage) +
   233       '; extra = ' + JSON.stringify(aExtra));
   234     // Find pages that registered an handler for this type.
   235     this._pages.forEach(function(aPage) {
   236       if (aPage.type == aType) {
   237         let result = this._sendMessageCommon(aType,
   238                                              aMessage,
   239                                              messageID,
   240                                              aPage.pageURL,
   241                                              aPage.manifestURL,
   242                                              aExtra);
   243         debug("Returned status of sending message: " + result);
   246         // Don't need to open the pages and queue the system message
   247         // which was not allowed to be sent.
   248         if (result === MSG_SENT_FAILURE_PERM_DENIED) {
   249           return;
   250         }
   252         // Queue this message in the corresponding pages.
   253         this._queueMessage(aPage, aMessage, messageID);
   255         this._openAppPage(aPage, aMessage, aExtra, result);
   256       }
   257     }, this);
   258   },
   260   registerPage: function(aType, aPageURI, aManifestURI) {
   261     if (!aPageURI || !aManifestURI) {
   262       throw Cr.NS_ERROR_INVALID_ARG;
   263     }
   265     let pageURL = aPageURI.spec;
   266     let manifestURL = aManifestURI.spec;
   268     // Don't register duplicates for this tuple.
   269     let page = this._findPage(aType, pageURL, manifestURL);
   270     if (page) {
   271       debug("Ignoring duplicate registration of " +
   272             [aType, pageURL, manifestURL]);
   273       return;
   274     }
   276     this._pages.push({ type: aType,
   277                        pageURL: pageURL,
   278                        manifestURL: manifestURL,
   279                        pendingMessages: [] });
   280   },
   282   _findTargetIndex: function(aTargets, aTarget) {
   283     if (!aTargets || !aTarget) {
   284       return -1;
   285     }
   286     for (let index = 0; index < aTargets.length; ++index) {
   287       let target = aTargets[index];
   288       if (target.target === aTarget) {
   289         return index;
   290       }
   291     }
   292     return -1;
   293   },
   295   _isEmptyObject: function(aObj) {
   296     for (let name in aObj) {
   297       return false;
   298     }
   299     return true;
   300   },
   302   _removeTargetFromListener: function(aTarget,
   303                                       aManifestURL,
   304                                       aRemoveListener,
   305                                       aPageURL) {
   306     let targets = this._listeners[aManifestURL];
   307     if (!targets) {
   308       return false;
   309     }
   311     let index = this._findTargetIndex(targets, aTarget);
   312     if (index === -1) {
   313       return false;
   314     }
   316     if (aRemoveListener) {
   317       debug("remove the listener for " + aManifestURL);
   318       delete this._listeners[aManifestURL];
   319       return true;
   320     }
   322     let target = targets[index];
   323     if (aPageURL && target.winCounts[aPageURL] !== undefined &&
   324         --target.winCounts[aPageURL] === 0) {
   325       delete target.winCounts[aPageURL];
   326     }
   328     if (this._isEmptyObject(target.winCounts)) {
   329       if (targets.length === 1) {
   330         // If it's the only one, get rid of the entry of manifest URL entirely.
   331         debug("remove the listener for " + aManifestURL);
   332         delete this._listeners[aManifestURL];
   333       } else {
   334         // If more than one left, remove this one and leave the rest.
   335         targets.splice(index, 1);
   336       }
   337     }
   338     return true;
   339   },
   341   receiveMessage: function(aMessage) {
   342     let msg = aMessage.json;
   344     // To prevent the hacked child process from sending commands to parent
   345     // to manage system messages, we need to check its manifest URL.
   346     if (["SystemMessageManager:Register",
   347          // TODO: fix bug 988142 to re-enable.
   348          // "SystemMessageManager:Unregister",
   349          "SystemMessageManager:GetPendingMessages",
   350          "SystemMessageManager:HasPendingMessages",
   351          "SystemMessageManager:Message:Return:OK",
   352          "SystemMessageManager:HandleMessagesDone"].indexOf(aMessage.name) != -1) {
   353       if (!aMessage.target.assertContainApp(msg.manifestURL)) {
   354         debug("Got message from a child process containing illegal manifest URL.");
   355         return null;
   356       }
   357     }
   359     switch(aMessage.name) {
   360       case "SystemMessageManager:AskReadyToRegister":
   361         return true;
   362         break;
   363       case "SystemMessageManager:Register":
   364       {
   365         debug("Got Register from " + msg.pageURL + " @ " + msg.manifestURL);
   366         let pageURL = msg.pageURL;
   367         let targets, index;
   368         if (!(targets = this._listeners[msg.manifestURL])) {
   369           let winCounts = {};
   370           winCounts[pageURL] = 1;
   371           this._listeners[msg.manifestURL] = [{ target: aMessage.target,
   372                                                 winCounts: winCounts }];
   373         } else if ((index = this._findTargetIndex(targets,
   374                                                   aMessage.target)) === -1) {
   375           let winCounts = {};
   376           winCounts[pageURL] = 1;
   377           targets.push({ target: aMessage.target,
   378                          winCounts: winCounts });
   379         } else {
   380           let winCounts = targets[index].winCounts;
   381           if (winCounts[pageURL] === undefined) {
   382             winCounts[pageURL] = 1;
   383           } else {
   384             winCounts[pageURL]++;
   385           }
   386         }
   388         debug("listeners for " + msg.manifestURL +
   389               " innerWinID " + msg.innerWindowID);
   390         break;
   391       }
   392       case "child-process-shutdown":
   393       {
   394         debug("Got child-process-shutdown from " + aMessage.target);
   395         for (let manifestURL in this._listeners) {
   396           // See if any processes in this manifest URL have this target.
   397           this._removeTargetFromListener(aMessage.target,
   398                                          manifestURL,
   399                                          true,
   400                                          null);
   401         }
   402         break;
   403       }
   404       case "SystemMessageManager:Unregister":
   405       {
   406         debug("Got Unregister from " + aMessage.target +
   407               " innerWinID " + msg.innerWindowID);
   408         this._removeTargetFromListener(aMessage.target,
   409                                        msg.manifestURL,
   410                                        false,
   411                                        msg.pageURL);
   412         break;
   413       }
   414       case "SystemMessageManager:GetPendingMessages":
   415       {
   416         debug("received SystemMessageManager:GetPendingMessages " + msg.type +
   417           " for " + msg.pageURL + " @ " + msg.manifestURL);
   419         // This is a sync call used to return the pending messages for a page.
   420         // Find the right page to get its corresponding pending messages.
   421         let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
   422         if (!page) {
   423           return;
   424         }
   426         // Return the |msg| of each pending message (drop the |msgID|).
   427         let pendingMessages = [];
   428         page.pendingMessages.forEach(function(aMessage) {
   429           pendingMessages.push(aMessage.msg);
   430         });
   432         // Clear the pending queue for this page. This is OK since we'll store
   433         // pending messages in the content process (|SystemMessageManager|).
   434         page.pendingMessages.length = 0;
   436         // Send the array of pending messages.
   437         aMessage.target
   438                 .sendAsyncMessage("SystemMessageManager:GetPendingMessages:Return",
   439                                   { type: msg.type,
   440                                     manifestURL: msg.manifestURL,
   441                                     pageURL: msg.pageURL,
   442                                     msgQueue: pendingMessages });
   443         break;
   444       }
   445       case "SystemMessageManager:HasPendingMessages":
   446       {
   447         debug("received SystemMessageManager:HasPendingMessages " + msg.type +
   448           " for " + msg.pageURL + " @ " + msg.manifestURL);
   450         // This is a sync call used to return if a page has pending messages.
   451         // Find the right page to get its corresponding pending messages.
   452         let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
   453         if (!page) {
   454           return false;
   455         }
   457         return page.pendingMessages.length != 0;
   458         break;
   459       }
   460       case "SystemMessageManager:Message:Return:OK":
   461       {
   462         debug("received SystemMessageManager:Message:Return:OK " + msg.type +
   463           " for " + msg.pageURL + " @ " + msg.manifestURL);
   465         // We need to clean up the pending message since the app has already
   466         // received it, thus avoiding the re-lanunched app handling it again.
   467         let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
   468         if (page) {
   469           let pendingMessages = page.pendingMessages;
   470           for (let i = 0; i < pendingMessages.length; i++) {
   471             if (pendingMessages[i].msgID === msg.msgID) {
   472               pendingMessages.splice(i, 1);
   473               break;
   474             }
   475           }
   476         }
   477         break;
   478       }
   479       case "SystemMessageManager:HandleMessagesDone":
   480       {
   481         debug("received SystemMessageManager:HandleMessagesDone " + msg.type +
   482           " with " + msg.handledCount + " for " + msg.pageURL +
   483           " @ " + msg.manifestURL);
   485         // A page has finished handling some of its system messages, so we try
   486         // to release the CPU wake lock we acquired on behalf of that page.
   487         this._releaseCpuWakeLock(this._createKeyForPage(msg), msg.handledCount);
   488         break;
   489       }
   490     }
   491   },
   493   observe: function(aSubject, aTopic, aData) {
   494     switch (aTopic) {
   495       case "xpcom-shutdown":
   496         kMessages.forEach(function(aMsg) {
   497           ppmm.removeMessageListener(aMsg, this);
   498         }, this);
   499         Services.obs.removeObserver(this, "xpcom-shutdown");
   500         Services.obs.removeObserver(this, "webapps-registry-start");
   501         Services.obs.removeObserver(this, "webapps-registry-ready");
   502         ppmm = null;
   503         this._pages = null;
   504         this._bufferedSysMsgs = null;
   505         break;
   506       case "webapps-registry-start":
   507         this._webappsRegistryReady = false;
   508         break;
   509       case "webapps-registry-ready":
   510         // After the webapps' registration has been done for sure,
   511         // re-fire the buffered system messages if there is any.
   512         this._webappsRegistryReady = true;
   513         this._bufferedSysMsgs.forEach(function(aSysMsg) {
   514           switch (aSysMsg.how) {
   515             case "send":
   516               this.sendMessage(
   517                 aSysMsg.type, aSysMsg.msg,
   518                 aSysMsg.pageURI, aSysMsg.manifestURI, aSysMsg.extra);
   519               break;
   520             case "broadcast":
   521               this.broadcastMessage(aSysMsg.type, aSysMsg.msg, aSysMsg.extra);
   522               break;
   523           }
   524         }, this);
   525         this._bufferedSysMsgs.length = 0;
   526         break;
   527     }
   528   },
   530   _queueMessage: function(aPage, aMessage, aMessageID) {
   531     // Queue the message for this page because we've never known if an app is
   532     // opened or not. We'll clean it up when the app has already received it.
   533     aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
   534     if (aPage.pendingMessages.length > kMaxPendingMessages) {
   535       aPage.pendingMessages.splice(0, 1);
   536     }
   537   },
   539   _openAppPage: function(aPage, aMessage, aExtra, aMsgSentStatus) {
   540     // This means the app must be brought to the foreground.
   541     let showApp = this._getMessageConfigurator(aPage.type).mustShowRunningApp;
   543     // We should send the open-app message if the system message was
   544     // not sent, or if it was sent but we should show the app anyway.
   545     if ((aMsgSentStatus === MSG_SENT_SUCCESS) && !showApp) {
   546       return;
   547     }
   549     // This flag means the app must *only* be brought to the foreground
   550     // and we don't need to load the app to handle messages.
   551     let onlyShowApp = (aMsgSentStatus === MSG_SENT_SUCCESS) && showApp;
   553     // We don't need to send the full object to observers.
   554     let page = { pageURL: aPage.pageURL,
   555                  manifestURL: aPage.manifestURL,
   556                  type: aPage.type,
   557                  extra: aExtra,
   558                  target: aMessage.target,
   559                  onlyShowApp: onlyShowApp,
   560                  showApp: showApp };
   561     debug("Asking to open " + JSON.stringify(page));
   562     Services.obs.notifyObservers(this,
   563                                  "system-messages-open-app",
   564                                  JSON.stringify(page));
   565   },
   567   _isPageMatched: function(aPage, aType, aPageURL, aManifestURL) {
   568     return (aPage.type === aType &&
   569             aPage.manifestURL === aManifestURL &&
   570             aPage.pageURL === aPageURL)
   571   },
   573   _createKeyForPage: function _createKeyForPage(aPage) {
   574     let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
   575                       .createInstance(Ci.nsIScriptableUnicodeConverter);
   576     converter.charset = "UTF-8";
   578     let hasher = Cc["@mozilla.org/security/hash;1"]
   579                    .createInstance(Ci.nsICryptoHash);
   580     hasher.init(hasher.SHA1);
   582     // add manifest/page URL and action to the hash
   583     ["type", "manifestURL", "pageURL"].forEach(function(aProp) {
   584       let data = converter.convertToByteArray(aPage[aProp], {});
   585       hasher.update(data, data.length);
   586     });
   588     return hasher.finish(true);
   589   },
   591   _sendMessageCommon: function(aType, aMessage, aMessageID,
   592                                aPageURL, aManifestURL, aExtra) {
   593     // Don't send the system message not granted by the app's permissions.
   594     if (!SystemMessagePermissionsChecker
   595           .isSystemMessagePermittedToSend(aType,
   596                                           aPageURL,
   597                                           aManifestURL)) {
   598       return MSG_SENT_FAILURE_PERM_DENIED;
   599     }
   601     let appPageIsRunning = false;
   602     let pageKey = this._createKeyForPage({ type: aType,
   603                                            manifestURL: aManifestURL,
   604                                            pageURL: aPageURL });
   606     let targets = this._listeners[aManifestURL];
   607     if (targets) {
   608       for (let index = 0; index < targets.length; ++index) {
   609         let target = targets[index];
   610         // We only need to send the system message to the targets (processes)
   611         // which contain the window page that matches the manifest/page URL of
   612         // the destination of system message.
   613         if (target.winCounts[aPageURL] === undefined) {
   614           continue;
   615         }
   617         appPageIsRunning = true;
   618         // We need to acquire a CPU wake lock for that page and expect that
   619         // we'll receive a "SystemMessageManager:HandleMessagesDone" message
   620         // when the page finishes handling the system message. At that point,
   621         // we'll release the lock we acquired.
   622         this._acquireCpuWakeLock(pageKey);
   624         // Multiple windows can share the same target (process), the content
   625         // window needs to check if the manifest/page URL is matched. Only
   626         // *one* window should handle the system message.
   627         let manager = target.target;
   628         manager.sendAsyncMessage("SystemMessageManager:Message",
   629                                  { type: aType,
   630                                    msg: aMessage,
   631                                    manifestURL: aManifestURL,
   632                                    pageURL: aPageURL,
   633                                    msgID: aMessageID });
   634       }
   635     }
   637     if (!appPageIsRunning) {
   638       // The app page isn't running and relies on the 'open-app' chrome event to
   639       // wake it up. We still need to acquire a CPU wake lock for that page and
   640       // expect that we will receive a "SystemMessageManager:HandleMessagesDone"
   641       // message when the page finishes handling the system message with other
   642       // pending messages. At that point, we'll release the lock we acquired.
   643       this._acquireCpuWakeLock(pageKey);
   644       return MSG_SENT_FAILURE_APP_NOT_RUNNING;
   645     } else {
   646       return MSG_SENT_SUCCESS;
   647     }
   649   },
   651   classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
   653   QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal,
   654                                          Ci.nsIObserver])
   655 }
   657 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]);

mercurial