Bug 789973 - B2G system time: adjust system clock after receiving NITZ timestamp (part 2). r=philikon
authorGene Lian <clian@mozilla.com>
Fri, 28 Sep 2012 14:02:57 +0800
changeset 114793 dacfa6d8c92ed5299b4be3b23a97dcfb1d258a33
parent 114792 99bf6b597e44406f3973a04b5da84fd01ff8f771
child 114794 4858ec60ad5f0bc6f6bd6a77a524fdcca4e4d97c
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon
bugs789973
milestone18.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 789973 - B2G system time: adjust system clock after receiving NITZ timestamp (part 2). r=philikon
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -35,16 +35,17 @@ const nsIAudioManager = Ci.nsIAudioManag
 const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
 
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsDeliveredObserverTopic         = "sms-delivered";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
 const kSysMsgListenerReadyObserverTopic  = "system-message-listener-ready";
+const kTimeNitzAutomaticUpdateEnabled    = "time.nitz.automatic-update.enabled";
 const DOM_SMS_DELIVERY_RECEIVED          = "received";
 const DOM_SMS_DELIVERY_SENT              = "sent";
 
 const RIL_IPC_TELEPHONY_MSG_NAMES = [
   "RIL:EnumerateCalls",
   "RIL:GetMicrophoneMuted",
   "RIL:SetMicrophoneMuted",
   "RIL:GetSpeakerEnabled",
@@ -97,16 +98,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gTimeService",
+                                   "@mozilla.org/time/timeservice;1",
+                                   "nsITimeService");
+
 XPCOMUtils.defineLazyGetter(this, "WAP", function () {
   let WAP = {};
   Cu.import("resource://gre/modules/WapPushManager.js", WAP);
   return WAP;
 });
 
 function convertRILCallState(state) {
   switch (state) {
@@ -234,16 +239,20 @@ function RadioInterfaceLayer() {
   lock.get("ril.supl.user", this);
   lock.get("ril.supl.passwd", this);
   lock.get("ril.supl.httpProxyHost", this);
   lock.get("ril.supl.httpProxyPort", this);
 
   // Read the desired setting of call waiting from the settings DB.
   lock.get("ril.callwaiting.enabled", this);
 
+  // Read the 'time.nitz.automatic-update.enabled' setting to see if
+  // we need to adjust the system clock time and time zone by NITZ.
+  lock.get(kTimeNitzAutomaticUpdateEnabled, this);
+
   this._messageManagerByRequest = {};
 
   for (let msgname of RIL_IPC_TELEPHONY_MSG_NAMES) {
     ppmm.addMessageListener(msgname, this);
   }
   for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
     ppmm.addMessageListener(msgname, this);
   }
@@ -464,27 +473,17 @@ RadioInterfaceLayer.prototype = {
         return;
       case "datacallstatechange":
         this.handleDataCallState(message);
         break;
       case "datacalllist":
         this.handleDataCallList(message);
         break;
       case "nitzTime":
-        // TODO bug 714349
-        // Send information to time manager to decide what to do with it
-        // Message contains networkTimeInSeconds, networkTimeZoneInMinutes,
-        // dstFlag,localTimeStampInMS
-        // indicating the time, daylight savings flag, and timezone
-        // sent from the network and a timestamp of when the message was received
-        // so an offset can be added if/when the time is actually set.
-        debug("nitzTime networkTime=" + message.networkTimeInSeconds +
-              " timezone=" + message.networkTimeZoneInMinutes +
-              " dst=" + message.dstFlag +
-              " timestamp=" + message.localTimeStampInMS);
+        this.handleNitzTime(message);
         break;
       case "iccinfochange":
         this.handleICCInfoChange(message);
         break;
       case "iccGetCardLock":
       case "iccSetCardLock":
       case "iccUnlockCardLock":
         this.handleICCCardLockResult(message);
@@ -1217,16 +1216,45 @@ RadioInterfaceLayer.prototype = {
   /**
    * Handle data call list.
    */
   handleDataCallList: function handleDataCallList(message) {
     this._deliverDataCallCallback("receiveDataCallList",
                                   [message.datacalls, message.datacalls.length]);
   },
 
+  /**
+   * Handle the NITZ message.
+   */
+  handleNitzTime: function handleNitzTime(message) {
+    if (!this._nitzAutomaticUpdateEnabled) {
+      return;
+    }
+    // To set the system clock time. Note that there could be a time diff
+    // between when the NITZ was received and when the time is actually set.
+    gTimeService.set(
+      message.networkTimeInMS + (Date.now() - message.receiveTimeInMS));
+
+    // To set the sytem timezone. Note that we need to convert the time zone
+    // value to a UTC repesentation string in the format of "UTC(+/-)hh:mm".
+    // Ex, time zone -480 is "UTC-08:00"; time zone 630 is "UTC+10:30".
+    //
+    // We can unapply the DST correction if we want the raw time zone offset:
+    // message.networkTimeZoneInMinutes -= message.networkDSTInMinutes;
+    if (message.networkTimeZoneInMinutes != (new Date()).getTimezoneOffset()) {
+      let absTimeZoneInMinutes = Math.abs(message.networkTimeZoneInMinutes);
+      let timeZoneStr = "UTC";
+      timeZoneStr += (message.networkTimeZoneInMinutes >= 0 ? "+" : "-");
+      timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2);
+      timeZoneStr += ":";
+      timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2);
+      gSettingsService.createLock().set("time.timezone", timeZoneStr, null);
+    }
+  },
+
   handleICCInfoChange: function handleICCInfoChange(message) {
     let oldIcc = this.rilContext.icc;
     this.rilContext.icc = message;
    
     let iccInfoChanged = !oldIcc ||
                          oldIcc.iccid != message.iccid ||
                          oldIcc.mcc != message.mcc || 
                          oldIcc.mnc != message.mnc;
@@ -1313,18 +1341,21 @@ RadioInterfaceLayer.prototype = {
 
   // APN data for making data calls.
   dataCallSettings: {},
   dataCallSettingsMMS: {},
   dataCallSettingsSUPL: {},
   _dataCallSettingsToRead: [],
   _oldRilDataEnabledState: null,
 
+  // Flag to determine whether to use NITZ. It corresponds to the
+  // 'time.nitz.automatic-update.enabled' setting from the UI.
+  _nitzAutomaticUpdateEnabled: null,
+
   // nsISettingsServiceCallback
-
   handle: function handle(aName, aResult) {
     switch(aName) {
       case "ril.radio.disabled":
         debug("'ril.radio.disabled' is now " + aResult);
         this._radioEnabled = !aResult;
         this._ensureRadioState();
         break;
       case "ril.radio.preferredNetworkType":
@@ -1367,16 +1398,19 @@ RadioInterfaceLayer.prototype = {
       case "ril.supl.httpProxyPort":
         key = aName.slice(9);
         this.dataCallSettingsSUPL[key] = aResult;
         break;
       case "ril.callwaiting.enabled":
         this._callWaitingEnabled = aResult;
         this.setCallWaitingEnabled(this._callWaitingEnabled);
         break;
+      case kTimeNitzAutomaticUpdateEnabled:
+        this._nitzAutomaticUpdateEnabled = aResult;
+        break;
     };
   },
 
   handleError: function handleError(aErrorMessage) {
     debug("There was an error while reading RIL settings.");
 
     // Default radio to on.
     this._radioEnabled = true;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -4523,32 +4523,34 @@ RIL[UNSOLICITED_NITZ_TIME_RECEIVED] = fu
   let now = Date.now();
 	
   let year = parseInt(dateString.substr(0, 2), 10);
   let month = parseInt(dateString.substr(3, 2), 10);
   let day = parseInt(dateString.substr(6, 2), 10);
   let hours = parseInt(dateString.substr(9, 2), 10);
   let minutes = parseInt(dateString.substr(12, 2), 10);
   let seconds = parseInt(dateString.substr(15, 2), 10);
-  let tz = parseInt(dateString.substr(17, 3), 10); // TZ is in 15 min. units
-  let dst = parseInt(dateString.substr(21, 2), 10); // DST already is in local time
-
-  let timeInSeconds = Date.UTC(year + PDU_TIMESTAMP_YEAR_OFFSET, month - 1, day,
-                               hours, minutes, seconds) / 1000;
-
-  if (isNaN(timeInSeconds)) {
+  // Note that |tz| is in 15-min units.
+  let tz = parseInt(dateString.substr(17, 3), 10);
+  // Note that |dst| is in 1-hour units and is already applied in |tz|.
+  let dst = parseInt(dateString.substr(21, 2), 10);
+
+  let timeInMS = Date.UTC(year + PDU_TIMESTAMP_YEAR_OFFSET, month - 1, day,
+                          hours, minutes, seconds);
+
+  if (isNaN(timeInMS)) {
     if (DEBUG) debug("NITZ failed to convert date");
     return;
   }
 
   this.sendDOMMessage({rilMessageType: "nitzTime",
-                       networkTimeInSeconds: timeInSeconds,
-                       networkTimeZoneInMinutes: tz * 15,
-                       dstFlag: dst,
-                       localTimeStampInMS: now});
+                       networkTimeInMS: timeInMS,
+                       networkTimeZoneInMinutes: -(tz * 15),
+                       networkDSTInMinutes: -(dst * 60),
+                       receiveTimeInMS: now});
 };
 
 RIL[UNSOLICITED_SIGNAL_STRENGTH] = function UNSOLICITED_SIGNAL_STRENGTH(length) {
   this[REQUEST_SIGNAL_STRENGTH](length, {rilRequestError: ERROR_SUCCESS});
 };
 RIL[UNSOLICITED_DATA_CALL_LIST_CHANGED] = function UNSOLICITED_DATA_CALL_LIST_CHANGED(length) {
   if (RILQUIRKS_V5_LEGACY) {
     this.getDataCallList();