Bug 1018320 - RequestSync API - patch 2 - Wifi Only, r=ehsan
☠☠ backed out by 636498d041b5 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 04 Jan 2015 10:36:53 +0100
changeset 221954 c6fcdd1c681f960d875496b6bef09b7c7eab507c
parent 221953 5e26604cc6e03a3e0bfd49efddeffffc4b7dc442
child 221955 edf5737d6e0e7ead604d0b0cc7b15a33f3828150
push id53474
push useramarchesini@mozilla.com
push dateSun, 04 Jan 2015 09:38:35 +0000
treeherdermozilla-inbound@2ef1c26d77d3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1018320
milestone37.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 1018320 - RequestSync API - patch 2 - Wifi Only, r=ehsan
dom/requestsync/RequestSyncService.jsm
dom/requestsync/RequestSyncWifiService.cpp
dom/requestsync/RequestSyncWifiService.h
dom/requestsync/moz.build
layout/build/nsLayoutStatics.cpp
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -1,18 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict'
 
-/* TODO:
- - wifi
-*/
-
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 function debug(s) {
   //dump('DEBUG RequestSyncService: ' + s + '\n');
 }
 
 const RSYNCDB_VERSION = 1;
 const RSYNCDB_NAME = "requestSync";
@@ -53,26 +49,29 @@ this.RequestSyncService = {
                "RequestSync:Registrations", "RequestSync:Registration",
                "RequestSyncManager:Registrations" ],
 
   _pendingOperation: false,
   _pendingMessages: [],
 
   _registrations: {},
 
+  _wifi: false,
+
   // Initialization of the RequestSyncService.
   init: function() {
     debug("init");
 
     this._messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.addObserver(this, 'xpcom-shutdown', false);
     Services.obs.addObserver(this, 'webapps-clear-data', false);
+    Services.obs.addObserver(this, 'wifi-state-changed', false);
 
     this.initDBHelper("requestSync", RSYNCDB_VERSION, [RSYNCDB_NAME]);
 
     // Loading all the data from the database into the _registrations map.
     // Any incoming message will be stored and processed when the async
     // operation is completed.
 
     let self = this;
@@ -98,38 +97,43 @@ this.RequestSyncService = {
     debug("shutdown");
 
     this._messages.forEach((function(msgName) {
       ppmm.removeMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.removeObserver(this, 'xpcom-shutdown');
     Services.obs.removeObserver(this, 'webapps-clear-data');
+    Services.obs.removeObserver(this, 'wifi-state-changed');
 
     this.close();
 
     // Removing all the registrations will delete the pending timers.
-    for (let key  in this._registrations) {
-      for (let task in this._registrations[key]) {
-        this.removeRegistrationInternal(task, key);
-      }
-    }
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      let key = self.principalToKey(aObj.principal);
+      self.removeRegistrationInternal(aObj.data.task, key);
+    });
   },
 
   observe: function(aSubject, aTopic, aData) {
     debug("observe");
 
     switch (aTopic) {
       case 'xpcom-shutdown':
         this.shutdown();
         break;
 
       case 'webapps-clear-data':
-       this.clearData(aSubject);
-       break;
+        this.clearData(aSubject);
+        break;
+
+      case 'wifi-state-changed':
+        this.wifiStateChanged(aSubject == 'enabled');
+        break;
 
       default:
         debug("Wrong observer topic: " + aTopic);
         break;
     }
   },
 
   // When an app is uninstalled, we have to clean all its tasks.
@@ -439,22 +443,20 @@ this.RequestSyncService = {
                                results: results });
   },
 
   // Get the list of the registered tasks.
   managerRegistrations: function(aTarget, aData, aPrincipal) {
     debug("managerRegistrations");
 
     let results = [];
-    for (var key in this._registrations) {
-      for (var task in this._registrations[key]) {
-        results.push(
-          this.createFullTaskObject(this._registrations[key][task].data));
-      }
-    }
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      results.push(self.createFullTaskObject(aObj.data));
+    });
 
     aTarget.sendAsyncMessage("RequestSyncManager:Registrations:Return",
                              { requestID: aData.requestID,
                                results: results });
   },
 
   // We cannot expose the full internal object to content but just a subset.
   // This method creates this subset.
@@ -483,24 +485,31 @@ this.RequestSyncService = {
     return obj;
   },
 
   // Creation of the timer for a particular task object.
   scheduleTimer: function(aObj) {
     debug("scheduleTimer");
 
     // A  registration can be already inactive if it was 1 shot.
-    if (aObj.active) {
-      aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    if (!aObj.active) {
+      return;
+    }
 
-      let self = this;
-      aObj.timer.initWithCallback(function() { self.timeout(aObj); },
-                                  aObj.data.minInterval * 1000,
-                                  Ci.nsITimer.TYPE_ONE_SHOT);
+    // WifiOnly check.
+    if (aObj.data.wifiOnly && !this._wifi) {
+      return;
     }
+
+    aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+    let self = this;
+    aObj.timer.initWithCallback(function() { self.timeout(aObj); },
+                                aObj.data.minInterval * 1000,
+                                Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   timeout: function(aObj) {
     debug("timeout");
 
     let app = appsService.getAppByLocalId(aObj.principal.appId);
     if (!app) {
       dump("ERROR!! RequestSyncService - Failed to retrieve app data from a principal.\n");
@@ -612,14 +621,57 @@ this.RequestSyncService = {
     function() {
       self.pendingOperationDone();
       aSuccessCb();
     },
     function() {
       self.pendingOperationDone();
       aErrorCb();
     });
+  },
+
+  forEachRegistration: function(aCb) {
+    // This method is used also to remove registations from the map, so we have
+    // to make a new list and let _registations free to be used.
+    let list = [];
+    for (var key in this._registrations) {
+      for (var task in this._registrations[key]) {
+        list.push(this._registrations[key][task]);
+      }
+    }
+
+    for (var i = 0; i < list.length; ++i) {
+      aCb(list[i]);
+    }
+  },
+
+  wifiStateChanged: function(aEnabled) {
+    debug("onWifiStateChanged");
+    this._wifi = aEnabled;
+
+    if (!this._wifi) {
+      // Disable all the wifiOnly tasks.
+      this.forEachRegistration(function(aObj) {
+        if (aObj.data.wifiOnly && aObj.timer) {
+          aObj.timer.cancel();
+          aObj.timer = null;
+        }
+      });
+      return;
+    }
+
+    // Enable all the tasks.
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      if (aObj.active && !aObj.timer) {
+        if (!aObj.data.wifiOnly) {
+          dump("ERROR - Found a disabled task that is not wifiOnly.");
+        }
+
+        self.scheduleTimer(aObj);
+      }
+    });
   }
 }
 
 RequestSyncService.init();
 
 this.EXPORTED_SYMBOLS = [""];
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncWifiService.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RequestSyncWifiService.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIObserverService.h"
+
+namespace mozilla {
+namespace dom {
+
+using namespace hal;
+
+NS_IMPL_ISUPPORTS0(RequestSyncWifiService)
+
+namespace {
+
+StaticRefPtr<RequestSyncWifiService> sService;
+
+} // anonymous namespace
+
+/* static */ void
+RequestSyncWifiService::Init()
+{
+  nsRefPtr<RequestSyncWifiService> service = GetInstance();
+  if (!service) {
+    NS_WARNING("Failed to initialize RequestSyncWifiService.");
+  }
+}
+
+/* static */ already_AddRefed<RequestSyncWifiService>
+RequestSyncWifiService::GetInstance()
+{
+  if (!sService) {
+    sService = new RequestSyncWifiService();
+    hal::RegisterNetworkObserver(sService);
+    ClearOnShutdown(&sService);
+  }
+
+  nsRefPtr<RequestSyncWifiService> service = sService.get();
+  return service.forget();
+}
+
+void
+RequestSyncWifiService::Notify(const hal::NetworkInformation& aNetworkInfo)
+{
+  bool isWifi = aNetworkInfo.isWifi();
+  if (isWifi == mIsWifi) {
+    return;
+  }
+
+  mIsWifi = isWifi;
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr, "wifi-state-changed",
+                         mIsWifi ? MOZ_UTF16("enabled") :
+                                   MOZ_UTF16("disabled"));
+  }
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncWifiService.h
@@ -0,0 +1,43 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_RequestSyncWifiService_h
+#define mozilla_dom_RequestSyncWifiService_h
+
+#include "mozilla/dom/network/Types.h"
+#include "mozilla/Hal.h"
+#include "nsIObserver.h"
+
+namespace mozilla {
+namespace dom {
+
+class RequestSyncWifiService MOZ_FINAL : public nsISupports
+                                       , public NetworkObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  static void Init();
+
+  static already_AddRefed<RequestSyncWifiService> GetInstance();
+
+  void Notify(const hal::NetworkInformation& aNetworkInfo);
+
+private:
+  RequestSyncWifiService()
+    : mIsWifi(false)
+  {}
+
+  ~RequestSyncWifiService()
+  {}
+
+  bool mIsWifi;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RequestSyncWifiService_h
--- a/dom/requestsync/moz.build
+++ b/dom/requestsync/moz.build
@@ -1,17 +1,30 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
+EXPORTS.mozilla.dom += [
+    'RequestSyncWifiService.h',
+]
+
 EXTRA_COMPONENTS += [
     'RequestSync.manifest',
     'RequestSyncManager.js',
     'RequestSyncScheduler.js',
 ]
 
 EXTRA_JS_MODULES += [
     'RequestSyncService.jsm',
 ]
+
+SOURCES += [
+    'RequestSyncWifiService.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FAIL_ON_WARNINGS = True
+FINAL_LIBRARY = 'xul'
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -59,16 +59,17 @@
 #include "nsMathMLOperators.h"
 #include "Navigator.h"
 #include "DOMStorageObserver.h"
 #include "CacheObserver.h"
 #include "DisplayItemClip.h"
 #include "ActiveLayerTracker.h"
 #include "CounterStyleManager.h"
 #include "FrameLayerBuilder.h"
+#include "mozilla/dom/RequestSyncWifiService.h"
 
 #include "AudioChannelService.h"
 #include "mozilla/dom/DataStoreService.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsXULContentUtils.h"
 #include "nsXULPrototypeCache.h"
@@ -295,16 +296,20 @@ nsLayoutStatics::Initialize()
   CacheObserver::Init();
 
   CounterStyleManager::InitializeBuiltinCounterStyles();
 
   CameraPreferences::Initialize();
 
   IMEStateManager::Init();
 
+#ifdef MOZ_B2G
+  RequestSyncWifiService::Init();
+#endif
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
   // memory reporter manager.