conman: use monotime.

Establishing connectivity enables clock synchronization. This is likely
to occur in the middle of provisioning, breaking timeout logic in conman
and leading to false provisioning failures.

Change-Id: I8921b4d16f858c7fd99a9d7ac53c719e1db77cc1
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index 11da31c..f43ee8d 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -26,6 +26,15 @@
 import ratchet
 import status
 
+try:
+  import monotime  # pylint: disable=unused-import,g-import-not-at-top
+except ImportError:
+  pass
+try:
+  _gettime = time.monotonic
+except AttributeError:
+  _gettime = time.time
+
 
 HOSTNAME = socket.gethostname()
 TMP_HOSTS = '/tmp/hosts'
@@ -446,7 +455,7 @@
        to join the WLAN again.
     7. Sleep for the rest of the duration of _run_duration_s.
     """
-    start_time = time.time()
+    start_time = _gettime()
     self.notifier.process_events()
     while self.notifier.check_events():
       self.notifier.read_events()
@@ -507,7 +516,7 @@
       # routes to the ACS for provisioning.
       if ((not self.acs() or provisioning_failed) and
           not getattr(wifi, 'last_successful_bss_info', None) and
-          time.time() > wifi.last_wifi_scan_time + self._wifi_scan_period_s):
+          _gettime() > wifi.last_wifi_scan_time + self._wifi_scan_period_s):
         logging.debug('Performing scan on %s.', wifi.name)
         self._wifi_scan(wifi)
 
@@ -518,7 +527,7 @@
       # case 5 is unavailable for some reason.
       for band in wifi.bands:
         wlan_configuration = self._wlan_configuration.get(band, None)
-        if wlan_configuration and time.time() >= self._try_wlan_after[band]:
+        if wlan_configuration and _gettime() >= self._try_wlan_after[band]:
           logging.info('Trying to join WLAN on %s.', wifi.name)
           wlan_configuration.start_client()
           if self._connected_to_wlan(wifi):
@@ -529,7 +538,7 @@
           else:
             logging.error('Failed to connect to WLAN on %s.', wifi.name)
             wifi.status.connected_to_wlan = False
-            self._try_wlan_after[band] = time.time() + self._wlan_retry_s
+            self._try_wlan_after[band] = _gettime() + self._wlan_retry_s
       else:
         # If we are aren't on the WLAN, can ping the ACS, and haven't gotten a
         # new WLAN configuration yet, there are two possibilities:
@@ -552,7 +561,7 @@
             if provisioning_failed:
               wifi.last_successful_bss_info = None
 
-          now = time.time()
+          now = _gettime()
           if self._wlan_configuration:
             logging.info('ACS has not updated WLAN configuration; will retry '
                          ' with old config.')
@@ -571,7 +580,7 @@
         # If we didn't manage to join the WLAN, and we don't have an ACS
         # connection or the ACS session failed, we should try another open AP.
         if not self.acs() or provisioning_failed:
-          now = time.time()
+          now = _gettime()
           if self._connected_to_open(wifi) and not provisioning_failed:
             logging.debug('Waiting for provisioning for %ds.',
                           now - self.provisioning_since(wifi))
@@ -579,7 +588,7 @@
             logging.debug('Not connected to ACS or provisioning failed')
             self._try_next_bssid(wifi)
 
-    time.sleep(max(0, self._run_duration_s - (time.time() - start_time)))
+    time.sleep(max(0, self._run_duration_s - (_gettime() - start_time)))
 
   def acs(self):
     result = False
@@ -784,7 +793,7 @@
   def _wifi_scan(self, wifi):
     """Perform a wifi scan and update wifi.cycler."""
     logging.info('Scanning on %s...', wifi.name)
-    wifi.last_wifi_scan_time = time.time()
+    wifi.last_wifi_scan_time = _gettime()
     subprocess.call(self.IFUP + [wifi.name])
     # /bin/wifi takes a --band option but then finds the right interface for it,
     # so it's okay to just pick the first band here.
@@ -825,7 +834,7 @@
         wifi.attach_wpa_control(self._wpa_control_interface)
         wifi.handle_wpa_events()
         wifi.status.connected_to_open = True
-        now = time.time()
+        now = _gettime()
         wifi.complain_about_acs_at = now + 5
         logging.info('Attempting to provision via SSID %s', bss_info.ssid)
         self._try_to_upload_logs = True
diff --git a/conman/cycler.py b/conman/cycler.py
index 23f2ce4..7795368 100755
--- a/conman/cycler.py
+++ b/conman/cycler.py
@@ -4,6 +4,15 @@
 
 import time
 
+try:
+  import monotime  # pylint: disable=unused-import,g-import-not-at-top
+except ImportError:
+  pass
+try:
+  _gettime = time.monotonic
+except AttributeError:
+  _gettime = time.time
+
 
 class AgingPriorityCycler(object):
   """A modified priority queue.
@@ -40,7 +49,7 @@
     try:
       self._items[item][0] = priority
     except KeyError:
-      self._items[item] = [priority, time.time()]
+      self._items[item] = [priority, _gettime()]
 
   def remove(self, item):
     if item in self._items:
@@ -65,7 +74,7 @@
     if self.empty():
       return
 
-    now = time.time()
+    now = _gettime()
 
     def aged_priority(key_value):
       _, (priority, birth) = key_value
@@ -86,7 +95,7 @@
     Args:
       items:  An iterable of (item, priority).
     """
-    now = time.time()
+    now = _gettime()
     new_items = {}
     for item, priority in items:
       t = now
diff --git a/conman/ratchet.py b/conman/ratchet.py
index 350ed47..07e61a8 100644
--- a/conman/ratchet.py
+++ b/conman/ratchet.py
@@ -6,6 +6,15 @@
 import os
 import time
 
+try:
+  import monotime  # pylint: disable=unused-import,g-import-not-at-top
+except ImportError:
+  pass
+try:
+  _gettime = time.monotonic
+except AttributeError:
+  _gettime = time.time
+
 # This has to be called before another module calls it with a higher log level.
 # pylint: disable=g-import-not-at-top
 logging.basicConfig(level=logging.DEBUG)
@@ -37,8 +46,8 @@
       t0:  The timestamp after which to evaluate the condition.
       start_at:  The timestamp from which to compute the timeout.
     """
-    self.t0 = t0 or time.time()
-    self.start_at = start_at or time.time()
+    self.t0 = t0 or _gettime()
+    self.start_at = start_at or _gettime()
     self.done_after = None
     self.done_by = None
     self.timed_out = False
@@ -56,21 +65,21 @@
       self.mark_done()
       return True
 
-    now = time.time()
+    now = _gettime()
     if now > self.start_at + self.timeout:
       self.timed_out = True
       self.logger.info('%s timed out after %.2f seconds',
                        self.name, now - self.t0)
       raise TimeoutException()
 
-    self.not_done_before = time.time()
+    self.not_done_before = _gettime()
     return False
 
   def mark_done(self):
     # In general, we don't know when a condition finished, but we know it was
     # *after* whenever it was most recently not done.
     self.done_after = self.not_done_before
-    self.done_by = time.time()
+    self.done_by = _gettime()
     self.logger.info('%s completed after %.2f seconds',
                      self.name, self.done_by - self.t0)