Bumping manifests a=b2g-bump
[gecko.git] / dom / alarm / AlarmsManager.js
blob2550ea092254aae31fb2454931755003ec7d3894
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 /* static functions */
8 const DEBUG = false;
9 const REQUEST_CPU_LOCK_TIMEOUT = 10 * 1000; // 10 seconds.
11 function debug(aStr) {
12   if (DEBUG)
13     dump("AlarmsManager: " + aStr + "\n");
16 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
18 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
19 Cu.import("resource://gre/modules/Services.jsm");
20 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
22 XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
23                                    "@mozilla.org/power/powermanagerservice;1",
24                                    "nsIPowerManagerService");
26 function AlarmsManager() {
27   debug("Constructor");
29   // A <requestId, {cpuLock, timer}> map.
30   this._cpuLockDict = new Map();
33 AlarmsManager.prototype = {
34   __proto__: DOMRequestIpcHelper.prototype,
36   contractID : "@mozilla.org/alarmsManager;1",
38   classID : Components.ID("{fea1e884-9b05-11e1-9b64-87a7016c3860}"),
40   QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
41                                           Ci.nsISupportsWeakReference,
42                                           Ci.nsIObserver]),
44   add: function add(aDate, aRespectTimezone, aData) {
45     debug("add()");
47     if (!this._manifestURL) {
48       debug("Cannot add alarms for non-installed apps.");
49       throw Components.results.NS_ERROR_FAILURE;
50     }
52     if (!aDate) {
53       throw Components.results.NS_ERROR_INVALID_ARG;
54     }
56     let isIgnoreTimezone = true;
58     switch (aRespectTimezone) {
59       case "honorTimezone":
60         isIgnoreTimezone = false;
61         break;
63       case "ignoreTimezone":
64         isIgnoreTimezone = true;
65         break;
67       default:
68         throw Components.results.NS_ERROR_INVALID_ARG;
69         break;
70     }
72     let data = aData;
73     if (aData) {
74       // Run JSON.stringify() in the sand box with the principal of the calling
75       // web page to ensure no cross-origin object is involved. A "Permission
76       // Denied" error will be thrown in case of privilege violation.
77       let sandbox = new Cu.Sandbox(Cu.getWebIDLCallerPrincipal());
78       sandbox.data = aData;
79       data = JSON.parse(Cu.evalInSandbox("JSON.stringify(data)", sandbox));
80     }
81     let request = this.createRequest();
82     let requestId = this.getRequestId(request);
83     this._lockCpuForRequest(requestId);
84     this._cpmm.sendAsyncMessage("AlarmsManager:Add",
85                                 { requestId: requestId,
86                                   date: aDate,
87                                   ignoreTimezone: isIgnoreTimezone,
88                                   data: data,
89                                   pageURL: this._pageURL,
90                                   manifestURL: this._manifestURL });
91     return request;
92   },
94   remove: function remove(aId) {
95     debug("remove()");
97     this._cpmm.sendAsyncMessage("AlarmsManager:Remove",
98                                 { id: aId, manifestURL: this._manifestURL });
99   },
101   getAll: function getAll() {
102     debug("getAll()");
104     let request = this.createRequest();
105     this._cpmm.sendAsyncMessage("AlarmsManager:GetAll",
106                                 { requestId: this.getRequestId(request),
107                                   manifestURL: this._manifestURL });
108     return request;
109   },
111   receiveMessage: function receiveMessage(aMessage) {
112     debug("receiveMessage(): " + aMessage.name);
114     let json = aMessage.json;
115     let request = this.getRequest(json.requestId);
117     if (!request) {
118       debug("No request stored! " + json.requestId);
119       return;
120     }
122     switch (aMessage.name) {
123       case "AlarmsManager:Add:Return:OK":
124         this._unlockCpuForRequest(json.requestId);
125         Services.DOMRequest.fireSuccess(request, json.id);
126         break;
128       case "AlarmsManager:GetAll:Return:OK":
129         // We don't need to expose everything to the web content.
130         let alarms = [];
131         json.alarms.forEach(function trimAlarmInfo(aAlarm) {
132           let alarm = { "id": aAlarm.id,
133                         "date": aAlarm.date,
134                         "respectTimezone": aAlarm.ignoreTimezone ?
135                                              "ignoreTimezone" : "honorTimezone",
136                         "data": aAlarm.data };
137           alarms.push(alarm);
138         });
140         Services.DOMRequest.fireSuccess(request,
141                                         Cu.cloneInto(alarms, this._window));
142         break;
144       case "AlarmsManager:Add:Return:KO":
145         this._unlockCpuForRequest(json.requestId);
146         Services.DOMRequest.fireError(request, json.errorMsg);
147         break;
149       case "AlarmsManager:GetAll:Return:KO":
150         Services.DOMRequest.fireError(request, json.errorMsg);
151         break;
153       default:
154         debug("Wrong message: " + aMessage.name);
155         break;
156     }
158     this.removeRequest(json.requestId);
159    },
161   // nsIDOMGlobalPropertyInitializer implementation
162   init: function init(aWindow) {
163     debug("init()");
165     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
166                    .getService(Ci.nsISyncMessageSender);
168     // Add the valid messages to be listened.
169     this.initDOMRequestHelper(aWindow, ["AlarmsManager:Add:Return:OK",
170                                         "AlarmsManager:Add:Return:KO",
171                                         "AlarmsManager:GetAll:Return:OK",
172                                         "AlarmsManager:GetAll:Return:KO"]);
174     // Get the manifest URL if this is an installed app
175     let appsService = Cc["@mozilla.org/AppsService;1"]
176                         .getService(Ci.nsIAppsService);
177     let principal = aWindow.document.nodePrincipal;
178     this._pageURL = principal.URI.spec;
179     this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
180     this._window = aWindow;
181   },
183   // Called from DOMRequestIpcHelper.
184   uninit: function uninit() {
185     debug("uninit()");
186   },
188   _lockCpuForRequest: function (aRequestId) {
189     if (this._cpuLockDict.has(aRequestId)) {
190       debug('Cpu wakelock for request ' + aRequestId + ' has been acquired. ' +
191             'You may call this function repeatedly or requestId is collision.');
192       return;
193     }
195     // Acquire a lock for given request and save for lookup lately.
196     debug('Acquire cpu lock for request ' + aRequestId);
197     let cpuLockInfo = {
198       cpuLock: gPowerManagerService.newWakeLock("cpu"),
199       timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
200     };
201     this._cpuLockDict.set(aRequestId, cpuLockInfo);
203     // Start a timer to prevent from non-responding request.
204     cpuLockInfo.timer.initWithCallback(() => {
205       debug('Request timeout! Release the cpu lock');
206       this._unlockCpuForRequest(aRequestId);
207     }, REQUEST_CPU_LOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
208   },
210   _unlockCpuForRequest: function(aRequestId) {
211     let cpuLockInfo = this._cpuLockDict.get(aRequestId);
212     if (!cpuLockInfo) {
213       debug('The cpu lock for requestId ' + aRequestId + ' is either invalid ' +
214             'or has been released.');
215       return;
216     }
218     // Release the cpu lock and cancel the timer.
219     debug('Release the cpu lock for ' + aRequestId);
220     cpuLockInfo.cpuLock.unlock();
221     cpuLockInfo.timer.cancel();
222     this._cpuLockDict.delete(aRequestId);
223   },
227 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlarmsManager])