Bug 777224 - Alarm API - .getAll() and .remove() can only interact with alarms scheduled by the same app. r=vivien
authorGene Lian <clian@mozilla.com>
Wed, 01 Aug 2012 13:58:49 +0800
changeset 106701 5e80ccb26f3d441112eae6c3bb08ca1dd2ecf816
parent 106700 111ee5107308c375a79269698c5ccff407911516
child 106702 719b1d10b55480524fc13d02ba7c53227c37f277
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvivien
bugs777224
milestone17.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 777224 - Alarm API - .getAll() and .remove() can only interact with alarms scheduled by the same app. r=vivien
dom/alarm/AlarmDB.jsm
dom/alarm/AlarmService.jsm
dom/alarm/AlarmsManager.js
--- a/dom/alarm/AlarmDB.jsm
+++ b/dom/alarm/AlarmDB.jsm
@@ -74,52 +74,81 @@ AlarmDB.prototype = {
       aSuccessCb, 
       aErrorCb
     );
   },
 
   /**
    * @param aId
    *        The ID of record to be removed.
+   * @param aManifestURL
+   *        The manifest URL of the app that alarm belongs to.
+   *        If null, directly remove the ID record; otherwise,
+   *        need to check if the alarm belongs to this app.
    * @param aSuccessCb
    *        Callback function to invoke with result.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
-  remove: function remove(aId, aSuccessCb, aErrorCb) {
+  remove: function remove(aId, aManifestURL, aSuccessCb, aErrorCb) {
     debug("remove()");
 
     this.newTxn(
       "readwrite", 
       function txnCb(aTxn, aStore) {
         debug("Going to remove " + aId);
-        aStore.delete(aId);
+
+        // Look up the existing record and compare the manifestURL
+        // to see if the alarm to be removed belongs to this app.
+        aStore.get(aId).onsuccess = function doRemove(aEvent) {
+          let alarm = aEvent.target.result;
+
+          if (!alarm) {
+            debug("Alarm doesn't exist. No need to remove it.");
+            return;
+          }
+
+          if (aManifestURL && aManifestURL != alarm.manifestURL) {
+            debug("Cannot remove the alarm added by other apps.");
+            return;
+          }
+
+          aStore.delete(aId);
+        };
       }, 
       aSuccessCb, 
       aErrorCb
     );
   },
 
   /**
+   * @param aManifestURL
+   *        The manifest URL of the app that alarms belong to.
+   *        If null, directly return all alarms; otherwise,
+   *        only return the alarms that belong to this app.
    * @param aSuccessCb
    *        Callback function to invoke with result array.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
-  getAll: function getAll(aSuccessCb, aErrorCb) {
+  getAll: function getAll(aManifestURL, aSuccessCb, aErrorCb) {
     debug("getAll()");
 
     this.newTxn(
       "readonly", 
       function txnCb(aTxn, aStore) {
         if (!aTxn.result)
-          aTxn.result = {};
+          aTxn.result = [];
 
         aStore.mozGetAll().onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
+          aEvent.target.result.forEach(function addAlarm(aAlarm) {
+            if (!aManifestURL || aManifestURL == aAlarm.manifestURL)
+              aTxn.result.push(aAlarm);
+          });
+
           debug("Request successful. Record count: " + aTxn.result.length);
         };
       }, 
       aSuccessCb, 
       aErrorCb
     );
   }
 };
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -75,16 +75,17 @@ let AlarmService = {
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let mm = aMessage.target.QueryInterface(Ci.nsIFrameMessageManager);
     let json = aMessage.json;
     switch (aMessage.name) {
       case "AlarmsManager:GetAll":
         this._db.getAll(
+          json.manifestURL,
           function getAllSuccessCb(aAlarms) {
             debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms));
             this._sendAsyncMessage(mm, "GetAll", true, json.requestId, aAlarms);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
             this._sendAsyncMessage(mm, "GetAll", false, json.requestId, aErrorMsg);
           }.bind(this)
         );
@@ -145,30 +146,34 @@ let AlarmService = {
             this._sendAsyncMessage(mm, "Add", false, json.requestId, aErrorMsg);
           }.bind(this)
         );
         break;
 
       case "AlarmsManager:Remove":
         this._removeAlarmFromDb(
           json.id,
+          json.manifestURL,
           function removeSuccessCb() {
             debug("Callback after removing alarm from database.");
 
             // if there is no alarm being set
             if (!this._currentAlarm) {
               this._debugCurrentAlarm();
               return;
             }
 
             // check if the alarm to be removed is in the queue
+            // by ID and whether it belongs to the requesting app
             let alarmQueue = this._alarmQueue;
-            if (this._currentAlarm.id != json.id) {
+            if (this._currentAlarm.id != json.id || 
+                this._currentAlarm.manifestURL != json.manifestURL) {
               for (let i = 0; i < alarmQueue.length; i++) {
-                if (alarmQueue[i].id == json.id) {
+                if (alarmQueue[i].id == json.id && 
+                    alarmQueue[i].manifestURL == json.manifestURL) {
                   alarmQueue.splice(i, 1);
                   break;
                 }
               }
               this._debugCurrentAlarm();
               return;
             }
 
@@ -219,29 +224,30 @@ let AlarmService = {
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
 
     aMessageManager.sendAsyncMessage("AlarmsManager:" + aMessageName + ":Return:" + (aSuccess ? "OK" : "KO"), json);
   },
 
-  _removeAlarmFromDb: function _removeAlarmFromDb(aId, aRemoveSuccessCb) {
+  _removeAlarmFromDb: function _removeAlarmFromDb(aId, aManifestURL, aRemoveSuccessCb) {
     debug("_removeAlarmFromDb()");
 
     // If the aRemoveSuccessCb is undefined or null, set a 
     // dummy callback for it which is needed for _db.remove()
     if (!aRemoveSuccessCb) {
       aRemoveSuccessCb = function removeSuccessCb() {
         debug("Remove alarm from DB successfully.");
       };
     }
 
     this._db.remove(
       aId,
+      aManifestURL,
       aRemoveSuccessCb,
       function removeErrorCb(aErrorMsg) {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
       }
     );
   },
 
   _fireSystemMessage: function _fireSystemMessage(aAlarm) {
@@ -250,31 +256,31 @@ let AlarmService = {
     messenger.sendMessage("alarm", aAlarm, manifestURI);
   },
 
   _onAlarmFired: function _onAlarmFired() {
     debug("_onAlarmFired()");
 
     if (this._currentAlarm) {
       this._fireSystemMessage(this._currentAlarm);
-      this._removeAlarmFromDb(this._currentAlarm.id);
+      this._removeAlarmFromDb(this._currentAlarm.id, null);
       this._currentAlarm = null;
     }
 
     // Reset the next alarm from the queue.
     let alarmQueue = this._alarmQueue;
     while (alarmQueue.length > 0) {
       let nextAlarm = alarmQueue.shift();
       let nextAlarmTime = this._getAlarmTime(nextAlarm);
 
       // If the next alarm has been expired, directly 
       // fire system message for it instead of setting it.
       if (nextAlarmTime <= Date.now()) {
         this._fireSystemMessage(nextAlarm);
-        this._removeAlarmFromDb(nextAlarm.id);
+        this._removeAlarmFromDb(nextAlarm.id, null);
       } else {
         this._currentAlarm = nextAlarm;
         break;
       }
     }
     this._debugCurrentAlarm();
   },
 
@@ -284,16 +290,17 @@ let AlarmService = {
     this._currentTimezoneOffset = aTimezoneOffset;
     this._restoreAlarmsFromDb();
   },
 
   _restoreAlarmsFromDb: function _restoreAlarmsFromDb() {
     debug("_restoreAlarmsFromDb()");
 
     this._db.getAll(
+      null,
       function getAllSuccessCb(aAlarms) {
         debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms));
 
         // clear any alarms set or queued in the cache
         let alarmQueue = this._alarmQueue;
         alarmQueue.length = 0;
         this._currentAlarm = null;
         
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -73,27 +73,27 @@ AlarmsManager.prototype = {
     return request;
   },
 
   remove: function remove(aId) {
     debug("remove()");
 
     return this._cpmm.sendSyncMessage(
       "AlarmsManager:Remove", 
-      { id: aId }
+      { id: aId, manifestURL: this._manifestURL }
     );
   },
 
   getAll: function getAll() {
     debug("getAll()");
 
     let request = this.createRequest();
     this._cpmm.sendAsyncMessage(
       "AlarmsManager:GetAll", 
-      { requestId: this.getRequestId(request) }
+      { requestId: this.getRequestId(request), manifestURL: this._manifestURL }
     );
     return request;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let json = aMessage.json;