deploy_chrome: Don't try to disable rootfs verification if target is writable

If the target dir is writable we don't need to disable rootfs verification and reboot.

BUG=chromium:436971
TEST=Steps in bug.

Change-Id: I0ab53242d0b737442b2279b925cd28d33df6f30c
Reviewed-on: https://chromium-review.googlesource.com/232004
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Tested-by: Robert Flack <flackr@chromium.org>
Reviewed-by: Daniel Erat <derat@chromium.org>
Commit-Queue: Robert Flack <flackr@chromium.org>
diff --git a/scripts/deploy_chrome.py b/scripts/deploy_chrome.py
index 95c8a4e..0ba0ac3 100644
--- a/scripts/deploy_chrome.py
+++ b/scripts/deploy_chrome.py
@@ -97,14 +97,15 @@
     self.tempdir = tempdir
     self.options = options
     self.staging_dir = staging_dir
-    self.host = remote.RemoteAccess(options.to, tempdir, port=options.port)
-    self._rootfs_is_still_readonly = multiprocessing.Event()
+    if not self.options.staging_only:
+      self.device = remote.RemoteDevice(options.to, port=options.port)
+    self._target_dir_is_still_readonly = multiprocessing.Event()
 
     self.copy_paths = chrome_util.GetCopyPaths('chrome')
     self.chrome_dir = _CHROME_DIR
 
   def _GetRemoteMountFree(self, remote_dir):
-    result = self.host.RemoteSh(DF_COMMAND % remote_dir, capture_output=True)
+    result = self.device.RunCommand(DF_COMMAND % remote_dir)
     line = result.output.splitlines()[1]
     value = line.split()[3]
     multipliers = {
@@ -115,7 +116,8 @@
     return int(value.rstrip('GMK')) * multipliers.get(value[-1], 1)
 
   def _GetRemoteDirSize(self, remote_dir):
-    result = self.host.RemoteSh('du -ks %s' % remote_dir, capture_output=True)
+    result = self.device.RunCommand('du -ks %s' % remote_dir,
+                                    capture_output=True)
     return int(result.output.split()[0])
 
   def _GetStagingDirSize(self):
@@ -125,8 +127,8 @@
     return int(result.output.split()[0])
 
   def _ChromeFileInUse(self):
-    result = self.host.RemoteSh(LSOF_COMMAND % (self.options.target_dir,),
-                                error_code_ok=True, capture_output=True)
+    result = self.device.RunCommand(LSOF_COMMAND % (self.options.target_dir,),
+                                    error_code_ok=True, capture_output=True)
     return result.returncode == 0
 
   def _DisableRootfsVerification(self):
@@ -140,7 +142,7 @@
         # Since we stopped Chrome earlier, it's good form to start it up again.
         if self.options.startui:
           logging.info('Starting Chrome...')
-          self.host.RemoteSh('start ui')
+          self.device.RunCommand('start ui')
         raise DeployFailure('Need rootfs verification to be disabled. '
                             'Aborting.')
 
@@ -150,12 +152,12 @@
     cmd = ('/usr/share/vboot/bin/make_dev_ssd.sh --partitions %d '
            '--remove_rootfs_verification --force')
     for partition in (KERNEL_A_PARTITION, KERNEL_B_PARTITION):
-      self.host.RemoteSh(cmd % partition, error_code_ok=True)
+      self.device.RunCommand(cmd % partition, error_code_ok=True)
 
     # A reboot in developer mode takes a while (and has delays), so the user
     # will have time to read and act on the USB boot instructions below.
     logging.info('Please remember to press Ctrl-U if you are booting from USB.')
-    self.host.RemoteReboot()
+    self.device.Reboot()
 
     # Now that the machine has been rebooted, we need to kill Chrome again.
     self._KillProcsIfNeeded()
@@ -168,7 +170,7 @@
     # <job_name> <status> ['process' <pid>].
     # <status> is in the format <goal>/<state>.
     try:
-      result = self.host.RemoteSh('status ui', capture_output=True)
+      result = self.device.RunCommand('status ui', capture_output=True)
     except cros_build_lib.RunCommandError as e:
       if 'Unknown job' in e.result.error:
         return False
@@ -180,7 +182,7 @@
   def _KillProcsIfNeeded(self):
     if self._CheckUiJobStarted():
       logging.info('Shutting down Chrome...')
-      self.host.RemoteSh('stop ui')
+      self.device.RunCommand('stop ui')
 
     # Developers sometimes run session_manager manually, in which case we'll
     # need to help shut the chrome processes down.
@@ -190,7 +192,7 @@
           logging.warning('The chrome binary on the device is in use.')
           logging.warning('Killing chrome and session_manager processes...\n')
 
-          self.host.RemoteSh("pkill 'chrome|session_manager'",
+          self.device.RunCommand("pkill 'chrome|session_manager'",
                              error_code_ok=True)
           # Wait for processes to actually terminate
           time.sleep(POST_KILL_WAIT)
@@ -203,18 +205,19 @@
   def _MountRootfsAsWritable(self, error_code_ok=True):
     """Mount the rootfs as writable.
 
-    If the command fails, and error_code_ok is True, then this function sets
-    self._rootfs_is_still_readonly.
+    If the command fails, and error_code_ok is True, and the target dir is not
+    writable then this function sets self._target_dir_is_still_readonly.
 
     Args:
       error_code_ok: See remote.RemoteAccess.RemoteSh for details.
     """
     # TODO: Should migrate to use the remount functions in remote_access.
-    result = self.host.RemoteSh(MOUNT_RW_COMMAND,
-                                error_code_ok=error_code_ok,
-                                capture_output=True)
-    if result.returncode:
-      self._rootfs_is_still_readonly.set()
+    result = self.device.RunCommand(MOUNT_RW_COMMAND,
+                                    error_code_ok=error_code_ok,
+                                    capture_output=True)
+    if (result.returncode and
+        not self.device.IsPathWritable(self.options.target_dir)):
+      self._target_dir_is_still_readonly.set()
 
   def _GetDeviceInfo(self):
     steps = [
@@ -244,26 +247,26 @@
     logging.info('Copying Chrome to %s on device...', self.options.target_dir)
     # Show the output (status) for this command.
     dest_path = _CHROME_DIR
-    self.host.Rsync('%s/' % os.path.abspath(self.staging_dir),
-                    self.options.target_dir,
-                    inplace=True, debug_level=logging.INFO,
-                    verbose=self.options.verbose)
+    self.device.CopyToDevice('%s/' % os.path.abspath(self.staging_dir),
+                             self.options.target_dir,
+                             inplace=True, debug_level=logging.INFO,
+                             verbose=self.options.verbose)
 
     for p in self.copy_paths:
       if p.mode:
         # Set mode if necessary.
-        self.host.RemoteSh('chmod %o %s/%s' % (p.mode, dest_path,
-                                               p.src if not p.dest else p.dest))
+        self.device.RunCommand('chmod %o %s/%s' % (
+            p.mode, dest_path, p.src if not p.dest else p.dest))
 
 
     if self.options.startui:
       logging.info('Starting UI...')
-      self.host.RemoteSh('start ui')
+      self.device.RunCommand('start ui')
 
   def _CheckConnection(self):
     try:
       logging.info('Testing connection to the device...')
-      self.host.RemoteSh('true')
+      self.device.RunCommand('true')
     except cros_build_lib.RunCommandError as ex:
       logging.error('Error connecting to the test device.')
       raise DeployFailure(ex)
@@ -293,11 +296,17 @@
     logging.info('Mounting Chrome...')
 
     # Create directory if does not exist
-    self.host.RemoteSh('mkdir -p --mode 0775 %s' % (self.options.mount_dir,))
-    self.host.RemoteSh(_BIND_TO_FINAL_DIR_CMD % (self.options.target_dir,
-                                                 self.options.mount_dir))
+    self.device.RunCommand('mkdir -p --mode 0775 %s' % (
+                               self.options.mount_dir,))
+    self.device.RunCommand(_BIND_TO_FINAL_DIR_CMD % (self.options.target_dir,
+                                                     self.options.mount_dir))
     # Chrome needs partition to have exec and suid flags set
-    self.host.RemoteSh(_SET_MOUNT_FLAGS_CMD % (self.options.mount_dir,))
+    self.device.RunCommand(_SET_MOUNT_FLAGS_CMD % (self.options.mount_dir,))
+
+  def Cleanup(self):
+    """Clean up RemoteDevice."""
+    if not self.options.staging_only:
+      self.device.Cleanup()
 
   def Perform(self):
     self._CheckDeployType()
@@ -316,9 +325,9 @@
                                     return_values=True)
     self._CheckDeviceFreeSpace(ret[0])
 
-    # If we failed to mark the rootfs as writable, try disabling rootfs
-    # verification.
-    if self._rootfs_is_still_readonly.is_set():
+    # If we're trying to deploy to a dir which is not writable and we failed
+    # to mark the rootfs as writable, try disabling rootfs verification.
+    if self._target_dir_is_still_readonly.is_set():
       self._DisableRootfsVerification()
 
     if self.options.mount_dir is not None:
@@ -625,3 +634,4 @@
         deploy.Perform()
       except failures_lib.StepFailure as ex:
         raise SystemExit(str(ex).strip())
+      deploy.Cleanup()