Bug 912612 - Add a timer dedicated to apps update when system updates are disabled. r=etienne,vingtetun
authorFabrice Desré <fabrice@mozilla.com>
Wed, 11 Sep 2013 05:00:48 -0700
changeset 146615 564f0718eefe0f22949bcb28df74eec588a6eb9a
parent 146614 2ba79e21c3ca8d5ba1824298804e3aa62358cef2
child 146616 cccdb7f084a40ce98d927e40a2560569378148ff
push id25267
push userryanvm@gmail.com
push dateThu, 12 Sep 2013 00:58:25 +0000
treeherdermozilla-central@2f11fad2f307 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersetienne, vingtetun
bugs912612
milestone26.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 912612 - Add a timer dedicated to apps update when system updates are disabled. r=etienne,vingtetun
b2g/app/b2g.js
b2g/chrome/content/settings.js
b2g/chrome/content/shell.js
b2g/components/B2GComponents.manifest
b2g/components/UpdatePrompt.js
b2g/components/WebappsUpdateTimer.js
b2g/components/WebappsUpdater.jsm
b2g/components/moz.build
b2g/installer/package-manifest.in
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -518,16 +518,19 @@ pref("app.update.socket.maxErrors", 20);
 // field.
 pref("app.update.log", true);
 #else
 // Explicitly disable the shutdown watchdog.  It's enabled by default.
 // When the updater is disabled, we want to know about shutdown hangs.
 pref("shutdown.watchdog.timeoutSecs", -1);
 #endif
 
+// Check daily for apps updates.
+pref("webapps.update.interval", 86400);
+
 // Extensions preferences
 pref("extensions.update.enabled", false);
 pref("extensions.getAddons.cache.enabled", false);
 
 // Context Menu
 pref("ui.click_hold_context_menus", true);
 pref("ui.click_hold_context_menus.delay", 750);
 
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -313,17 +313,17 @@ let AdbController = {
         this.debug("updateState: Waiting for all vars to be initialized");
       }
       return;
     }
 
     // Check if we have a remote debugging session going on. If so, we won't
     // disable adb even if the screen is locked.
     let isDebugging = Object.keys(DebuggerServer._connections).length > 0;
-    debug("isDebugging=" + isDebugging);
+    this.debug("isDebugging=" + isDebugging);
 
     let enableAdb = this.remoteDebuggerEnabled &&
       (!(this.lockEnabled && this.locked) || isDebugging);
 
     let useDisableAdbTimer = true;
     try {
       if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
         // Marionette is enabled. Marionette requires that adb be on (and also
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1130,16 +1130,19 @@ window.addEventListener('ContentStart', 
     } else if (e.detail.type == "delete-crash" && e.detail.crashID) {
       debugCrashReport("deleting crash at user request ", e.detail.crashID);
       shell.deleteCrash(e.detail.crashID);
     }
   });
 });
 
 window.addEventListener('ContentStart', function update_onContentStart() {
+  Cu.import('resource://gre/modules/WebappsUpdater.jsm');
+  WebappsUpdater.handleContentStart(shell);
+
   let promptCc = Cc["@mozilla.org/updates/update-prompt;1"];
   if (!promptCc) {
     return;
   }
 
   let updatePrompt = promptCc.createInstance(Ci.nsIUpdatePrompt);
   if (!updatePrompt) {
     return;
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -68,8 +68,13 @@ contract @mozilla.org/recovery-service;1
 
 # B2GAboutRedirector
 component {920400b1-cf8f-4760-a9c4-441417b15134} B2GAboutRedirector.js
 contract @mozilla.org/network/protocol/about;1?what=certerror {920400b1-cf8f-4760-a9c4-441417b15134}
 
 # FilePicker.js
 component {436ff8f9-0acc-4b11-8ec7-e293efba3141} FilePicker.js
 contract @mozilla.org/filepicker;1 {436ff8f9-0acc-4b11-8ec7-e293efba3141}
+
+# WebappsUpdateTimer.js
+component {637b0f77-2429-49a0-915f-abf5d0db8b9a} WebappsUpdateTimer.js
+contract @mozilla.org/b2g/webapps-update-timer;1 {637b0f77-2429-49a0-915f-abf5d0db8b9a}
+category update-timer WebappsUpdateTimer @mozilla.org/b2g/webapps-update-timer;1,getService,background-update-timer,webapps.update.interval,86400
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -7,16 +7,17 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/WebappsUpdater.jsm");
 
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   function log_noop(msg) { };
 
 const PREF_APPLY_PROMPT_TIMEOUT          = "b2g.update.apply-prompt-timeout";
@@ -444,85 +445,30 @@ UpdatePrompt.prototype = {
         this.handleDownloadCancel();
         break;
       case "update-prompt-apply-result":
         this.handleApplyPromptResult(detail);
         break;
     }
   },
 
-  appsUpdated: function UP_appsUpdated(aApps) {
-    log("appsUpdated: " + aApps.length + " apps to update");
-    let lock = Services.settings.createLock();
-    lock.set("apps.updateStatus", "check-complete", null);
-    this.sendChromeEvent("apps-update-check", { apps: aApps });
-    this._checkingApps = false;
-  },
-
-  // Trigger apps update check and wait for all to be done before
-  // notifying gaia.
-  onUpdateCheckStart: function UP_onUpdateCheckStart() {
-    log("onUpdateCheckStart (" + this._checkingApps + ")");
-    // Don't start twice.
-    if (this._checkingApps) {
-      return;
-    }
-
-    this._checkingApps = true;
-
-    let self = this;
-
-    let window = Services.wm.getMostRecentWindow("navigator:browser");
-    let all = window.navigator.mozApps.mgmt.getAll();
-
-    all.onsuccess = function() {
-      let appsCount = this.result.length;
-      let appsChecked = 0;
-      let appsToUpdate = [];
-      this.result.forEach(function updateApp(aApp) {
-        let update = aApp.checkForUpdate();
-        update.onsuccess = function() {
-          if (aApp.downloadAvailable) {
-            appsToUpdate.push(aApp.manifestURL);
-          }
-
-          appsChecked += 1;
-          if (appsChecked == appsCount) {
-            self.appsUpdated(appsToUpdate);
-          }
-        }
-        update.onerror = function() {
-          appsChecked += 1;
-          if (appsChecked == appsCount) {
-            self.appsUpdated(appsToUpdate);
-          }
-        }
-      });
-    }
-
-    all.onerror = function() {
-      // Could not get the app list, just notify to update nothing.
-      self.appsUpdated([]);
-    }
-  },
-
   // nsIObserver
 
   observe: function UP_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "idle":
         this._waitingForIdle = false;
         this.showApplyPrompt(this._update);
         // Fall through
       case "quit-application":
         Services.idle.removeIdleObserver(this, this.applyIdleTimeout / 1000);
         Services.obs.removeObserver(this, "quit-application");
         break;
       case "update-check-start":
-        this.onUpdateCheckStart();
+        WebappsUpdater.updateApps();
         break;
     }
   },
 
   // nsITimerCallback
 
   notify: function UP_notify(aTimer) {
     if (aTimer == this._applyPromptTimer) {
new file mode 100644
--- /dev/null
+++ b/b2g/components/WebappsUpdateTimer.js
@@ -0,0 +1,67 @@
+/* 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/. */
+
+/**
+ * This component triggers an app update check even when system updates are
+ * disabled to make sure we always check for app updates.
+ */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/WebappsUpdater.jsm");
+
+function debug(aStr) {
+  //dump("--*-- WebappsUpdateTimer: " + aStr);
+}
+
+function WebappsUpdateTimer() {
+}
+
+WebappsUpdateTimer.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]),
+  classID: Components.ID("{637b0f77-2429-49a0-915f-abf5d0db8b9a}"),
+
+  notify: function(aTimer) {
+    try {
+      // We want to check app updates if system updates are disabled or
+      // if they update frecency is not daily.
+      if (Services.prefs.getBoolPref("app.update.enabled") === true &&
+          Services.prefs.getIntPref("app.update.interval") === 86400) {
+        return;
+      }
+    } catch(e) {
+      // That should never happen..
+    }
+
+    // If we are offline, wait to be online to start the update check.
+    if (Services.io.offline) {
+      debug("Network is offline. Setting up an offline status observer.");
+      Services.obs.addObserver(this, "network:offline-status-changed", false);
+      return;
+    }
+
+    // This will trigger app updates in b2g/components/WebappsUpdater.jsm
+    // that also takes care of notifying gaia.
+    WebappsUpdater.updateApps();
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic !== "network:offline-status-changed" ||
+        aData !== "online") {
+      return;
+    }
+
+    debug("Network is online. Checking updates.");
+    Services.obs.removeObserver(this, "network:offline-status-changed");
+    WebappsUpdater.updateApps();
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsUpdateTimer]);
new file mode 100644
--- /dev/null
+++ b/b2g/components/WebappsUpdater.jsm
@@ -0,0 +1,95 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = ["WebappsUpdater"];
+
+const Cc = Components.classes;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.WebappsUpdater = {
+  _checkingApps: false,
+  _pendingEvents: [],
+
+  handleContentStart: function(aShell) {
+    let content = aShell.contentBrowser.contentWindow;
+    this._pendingEvents.forEach(aShell.sendChromeEvent);
+
+    this._pendingEvents.length = 0;
+  },
+
+  sendChromeEvent: function(aType, aDetail) {
+    let detail = aDetail || {};
+    detail.type = aType;
+
+    let browser = Services.wm.getMostRecentWindow("navigator:browser");
+    if (!browser) {
+      this._pendingEvents.push(detail);
+      dump("Warning: Couldn't send update event " + aType +
+          ": no content browser. Will send again when content becomes available.");
+      return false;
+    }
+
+    browser.shell.sendChromeEvent(detail);
+    return true;
+  },
+
+  _appsUpdated: function(aApps) {
+    dump("appsUpdated: " + aApps.length + " apps to update");
+    let lock = Services.settings.createLock();
+    lock.set("apps.updateStatus", "check-complete", null);
+    this.sendChromeEvent("apps-update-check", { apps: aApps });
+    this._checkingApps = false;
+  },
+
+  // Trigger apps update check and wait for all to be done before
+  // notifying gaia.
+  updateApps: function() {
+    dump("updateApps (" + this._checkingApps + ")");
+    // Don't start twice.
+    if (this._checkingApps) {
+      return;
+    }
+
+    this._checkingApps = true;
+
+    let self = this;
+
+    let window = Services.wm.getMostRecentWindow("navigator:browser");
+    let all = window.navigator.mozApps.mgmt.getAll();
+
+    all.onsuccess = function() {
+      let appsCount = this.result.length;
+      let appsChecked = 0;
+      let appsToUpdate = [];
+      this.result.forEach(function updateApp(aApp) {
+        let update = aApp.checkForUpdate();
+        update.onsuccess = function() {
+          if (aApp.downloadAvailable) {
+            appsToUpdate.push(aApp.manifestURL);
+          }
+
+          appsChecked += 1;
+          if (appsChecked == appsCount) {
+            self._appsUpdated(appsToUpdate);
+          }
+        }
+        update.onerror = function() {
+          appsChecked += 1;
+          if (appsChecked == appsCount) {
+            self._appsUpdated(appsToUpdate);
+          }
+        }
+      });
+    }
+
+    all.onerror = function() {
+      // Could not get the app list, just notify to update nothing.
+      self._appsUpdated([]);
+    }
+  }
+};
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -20,16 +20,17 @@ EXTRA_COMPONENTS += [
     'ContentPermissionPrompt.js',
     'FilePicker.js',
     'MailtoProtocolHandler.js',
     'MozKeyboard.js',
     'PaymentGlue.js',
     'ProcessGlobal.js',
     'SmsProtocolHandler.js',
     'TelProtocolHandler.js',
+    'WebappsUpdateTimer.js',
     'YoutubeProtocolHandler.js',
 ]
 
 EXTRA_PP_COMPONENTS += [
     'B2GComponents.manifest',
     'DirectoryProvider.js',
     'RecoveryService.js',
 ]
@@ -39,9 +40,10 @@ if CONFIG['MOZ_UPDATER']:
         'UpdatePrompt.js',
     ]
 
 EXTRA_JS_MODULES += [
     'ErrorPage.jsm',
     'Keyboard.jsm',
     'SignInToWebsite.jsm',
     'TelURIParser.jsm',
+    'WebappsUpdater.jsm',
 ]
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -728,16 +728,17 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/components/MarionetteComponents.manifest
 @BINPATH@/components/marionettecomponent.js
 #endif
 @BINPATH@/components/AlertsService.js
 @BINPATH@/components/ContentPermissionPrompt.js
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
+@BINPATH@/components/WebappsUpdateTimer.js
 @BINPATH@/components/MozKeyboard.js
 @BINPATH@/components/DirectoryProvider.js
 @BINPATH@/components/ActivitiesGlue.js
 @BINPATH@/components/ProcessGlobal.js
 @BINPATH@/components/ContentHandler.js
 @BINPATH@/components/PaymentGlue.js
 @BINPATH@/components/YoutubeProtocolHandler.js
 @BINPATH@/components/RecoveryService.js