autotest: Reboot servo_v3 every 4 days.

BUG=chromium:1105595
TEST=run local

./server/autoserv -s --host-info-subdir host_info_store -m      chromeos1-row4-rack1-host5 --lab True --local-only-host-info True -R -r /tr/

also on dead servo-host
./server/autoserv -s --host-info-subdir host_info_store -m     chromeos4-row6-rack5-host3 --lab True --local-only-host-info True -R -r /tr/

Change-Id: I3100a0bb09322d555e1c13dea2f4e9a06ebbf265
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2297807
Tested-by: Otabek Kasimov <otabek@google.com>
Commit-Queue: Otabek Kasimov <otabek@google.com>
Reviewed-by: Garry Wang <xianuowang@chromium.org>
diff --git a/server/hosts/servo_host.py b/server/hosts/servo_host.py
index b3e4868..35d37b0 100644
--- a/server/hosts/servo_host.py
+++ b/server/hosts/servo_host.py
@@ -639,6 +639,39 @@
             return ''
         return resp.stdout.strip()
 
+    def reboot_servo_v3_with_long_uptime(self):
+        """Check and reboot servo_v3 if uptime more than 4 days/96 hours."""
+        try:
+            if self.get_board() != 'beaglebone_servo':
+                logging.info('Servo reboot is only applicable for servo V3.')
+                return
+        except Exception as e:
+            logging.error('(Non-critical) Fail to detect servo_host '
+                          'board: %s', e)
+            logging.info('Servo-host board not detected! Skipping reboot.')
+            return
+
+        try:
+            uptime_hours = float(self.check_uptime())/3600
+            if uptime_hours < 96:
+                logging.info('Uptime of servo_v3: %s hour(s)', uptime_hours)
+                return
+        except Exception as e:
+            logging.debug('(Non-critical)Failed to get uptime; %s', e)
+            return
+
+        self.record('INFO', None, None,
+                    'Starting reboot servo_v3 since it has been up for more '
+                    'than 96 hours')
+        try:
+            self.reboot()
+            message = 'Servo_v3 reboot completed successfully.'
+        except Exception as e:
+            logging.debug("Fail to reboot servo_v3; %s", e)
+            message = ('Servo_v3 reboot failed, please check debug log '
+                       'for details.')
+        logging.info(message)
+        self.record('INFO', None, None, message)
 
     def _reset_servo(self):
         logging.info('Resetting servo through smart usbhub.')
@@ -1440,12 +1473,16 @@
 
     newhost = ServoHost(**servo_args)
 
-    # Reset servo if the servo is locked, as we check if the servohost is up,
-    # if the servohost is labstation and if the servohost is in lab inside the
-    # locking logic. Also check try_servo_repair to make sure we only do this
-    # in AdminRepair tasks.
-    if newhost._is_locked and try_servo_repair:
-        newhost.reset_servo()
+    # Reset or reboot servo device only during AdminRepair tasks.
+    if try_servo_repair:
+        if newhost._is_locked:
+            # Reset servo if the servo is locked, as we check if the servohost
+            # is up, if the servohost is labstation and if the servohost is in
+            # lab inside the locking logic.
+            newhost.reset_servo()
+        else:
+            newhost.reboot_servo_v3_with_long_uptime()
+
     if dut:
         newhost.set_dut_hostname(dut.hostname)