Bug 1080752 - Hold wakelock when attempting to connect to push server. r=dougt
authorNikhil Marathe <nsm.nikhil@gmail.com>
Mon, 09 Mar 2015 15:40:04 -0700
changeset 263866 3fb5364095bfeaedb7c3689aa6c3b9b80e7045a4
parent 263865 f63a2cf3fa11b5ee08b84e5d24dcfab51f56c90c
child 263867 0166341c3da78bfcf299e94f5961c83ac47ee055
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt
bugs1080752
milestone39.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 1080752 - Hold wakelock when attempting to connect to push server. r=dougt
dom/push/PushService.jsm
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -28,16 +28,20 @@ Cu.importGlobalProperties(["indexedDB"])
 
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
                                   "resource://gre/modules/AlarmService.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
+                                   "@mozilla.org/power/powermanagerservice;1",
+                                   "nsIPowerManagerService");
+
 var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
 
 this.EXPORTED_SYMBOLS = ["PushService"];
 
 const prefs = new Preferences("services.push.");
 // Set debug first so that all debugging actually works.
 gDebuggingEnabled = prefs.get("debug");
 
@@ -868,18 +872,28 @@ this.PushService = {
     else {
       debug("Unsupported websocket scheme " + uri.scheme);
       return;
     }
 
     debug("serverURL: " + uri.spec);
     this._wsListener = new PushWebSocketListener(this);
     this._ws.protocol = "push-notification";
-    this._ws.asyncOpen(uri, serverURL, this._wsListener, null);
-    this._currentState = STATE_WAITING_FOR_WS_START;
+
+    try {
+      // Grab a wakelock before we open the socket to ensure we don't go to sleep
+      // before connection the is opened.
+      this._ws.asyncOpen(uri, serverURL, this._wsListener, null);
+      this._acquireWakeLock();
+      this._currentState = STATE_WAITING_FOR_WS_START;
+    } catch(e) {
+      debug("Error opening websocket. asyncOpen failed!");
+      this._shutdownWS();
+      this._reconnectAfterBackoff();
+    }
   },
 
   _startListeningIfChannelsPresent: function() {
     // Check to see if we need to do anything.
     this._db.getAllChannelIDs(function(channelIDs) {
       if (channelIDs.length > 0) {
         this._beginWSSetup();
       }
@@ -992,16 +1006,48 @@ this.PushService = {
       // called between _reconnectAfterBackoff() setting the alarm and the
       // alarm firing.
 
       // Websocket is shut down. Backoff interval expired, try to connect.
       this._beginWSSetup();
     }
   },
 
+  _acquireWakeLock: function() {
+    if (!this._socketWakeLock) {
+      debug("Acquiring Socket Wakelock");
+      this._socketWakeLock = gPowerManagerService.newWakeLock("cpu");
+    }
+    if (!this._socketWakeLockTimer) {
+      debug("Creating Socket WakeLock Timer");
+      this._socketWakeLockTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    }
+
+    debug("Setting Socket WakeLock Timer");
+    this._socketWakeLockTimer
+      .initWithCallback(this._releaseWakeLock.bind(this),
+                        // Allow the same time for socket setup as we do for
+                        // requests after the setup. Fudge it a bit since
+                        // timers can be a little off and we don't want to go
+                        // to sleep just as the socket connected.
+                        this._requestTimeout + 1000,
+                        Ci.nsITimer.ONE_SHOT);
+  },
+
+  _releaseWakeLock: function() {
+    debug("Releasing Socket WakeLock");
+    if (this._socketWakeLockTimer) {
+      this._socketWakeLockTimer.cancel();
+    }
+    if (this._socketWakeLock) {
+      this._socketWakeLock.unlock();
+      this._socketWakeLock = null;
+    }
+  },
+
   /**
    * Protocol handler invoked by server message.
    */
   _handleHelloReply: function(reply) {
     debug("handleHelloReply()");
     if (this._currentState != STATE_WAITING_FOR_HELLO) {
       debug("Unexpected state " + this._currentState +
             "(expected STATE_WAITING_FOR_HELLO)");
@@ -1507,16 +1553,18 @@ this.PushService = {
       requestID: aPageRecord.requestID,
       error: "Database error"
     });
   },
 
   // begin Push protocol handshake
   _wsOnStart: function(context) {
     debug("wsOnStart()");
+    this._releaseWakeLock();
+
     if (this._currentState != STATE_WAITING_FOR_WS_START) {
       debug("NOT in STATE_WAITING_FOR_WS_START. Current state " +
             this._currentState + ". Skipping");
       return;
     }
 
     // Since we've had a successful connection reset the retry fail count.
     this._retryFailCount = 0;
@@ -1563,16 +1611,17 @@ this.PushService = {
    * This statusCode is not the websocket protocol status code, but the TCP
    * connection close status code.
    *
    * If we do not explicitly call ws.close() then statusCode is always
    * NS_BASE_STREAM_CLOSED, even on a successful close.
    */
   _wsOnStop: function(context, statusCode) {
     debug("wsOnStop()");
+    this._releaseWakeLock();
 
     if (statusCode != Cr.NS_OK &&
         !(statusCode == Cr.NS_BASE_STREAM_CLOSED && this._willBeWokenUpByUDP)) {
       debug("Socket error " + statusCode);
       this._reconnectAfterBackoff();
     }
 
     // Bug 896919. We always shutdown the WebSocket, even if we need to