AI 143713: am: CL 143688 am: CL 143562 Usability fixes for runtest.py
  Original author: brettchabot
  Merged from: //branches/cupcake/...
  Original author: android-build
  Merged from: //branches/donutburger/...

Automated import of CL 143713
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index fb304df..ad1b2c9 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -297,8 +297,7 @@
       WaitForResponseTimedOutError if wait_time elapses and pm still does not
       respond.
     """
-    logger.Log("Waiting for device package manager for %s seconds..."
-               % wait_time)
+    logger.Log("Waiting for device package manager...")
     self.SendCommand("wait-for-device")
     # Now the device is there, but may not be running.
     # Query the package manager with a basic command
@@ -315,7 +314,8 @@
         time.sleep(wait_period)
         attempts += 1
     if not pm_found:
-      raise errors.WaitForResponseTimedOutError
+      raise errors.WaitForResponseTimedOutError(
+          "Package manager did not respond after %s seconds" % wait_time)
     
   def Sync(self, retry_count=3):
     """Perform a adb sync.
@@ -331,13 +331,12 @@
     output = self.SendCommand("sync", retry_count=retry_count)
     if "Read-only file system" in output:
       logger.SilentLog(output) 
-      logger.Log("adb sync failed due to read only fs, retrying")
+      logger.Log("Remounting read-only filesystem")
       self.SendCommand("remount")
       output = self.SendCommand("sync", retry_count=retry_count)
     if "No space left on device" in output:
       logger.SilentLog(output) 
-      logger.Log("adb sync failed due to no space on device, trying shell" + 
-                 " start/stop")
+      logger.Log("Restarting device runtime")
       self.SendShellCommand("stop", retry_count=retry_count)
       output = self.SendCommand("sync", retry_count=retry_count)
       self.SendShellCommand("start", retry_count=retry_count)
@@ -345,3 +344,15 @@
     logger.SilentLog(output)
     self.WaitForDevicePm()
     return output
+  
+  def IsDevicePresent(self):
+    """Check if targeted device is present.
+
+    Returns:
+      True if device is present, False otherwise.
+    """
+    output = self.SendShellCommand("ls", retry_count=0)
+    if output.startswith("error:"):
+      return False
+    else:
+      return True
diff --git a/testrunner/coverage.py b/testrunner/coverage.py
index 507c5c7..39a2ceb 100755
--- a/testrunner/coverage.py
+++ b/testrunner/coverage.py
@@ -70,6 +70,27 @@
   def EnableCoverageBuild(self):
     """Enable building an Android target with code coverage instrumentation."""
     os.environ[self._EMMA_BUILD_FLAG] = "true"
+    #TODO: can emma.jar automagically be added to bootclasspath here?
+
+  def TestDeviceCoverageSupport(self):
+    """Check if device has support for generating code coverage metrics.
+
+    Currently this will check if the emma.jar file is on the device's boot
+    classpath.
+
+    Returns:
+      True if device can support code coverage. False otherwise.
+    """
+    output = self._adb.SendShellCommand("cat init.rc | grep BOOTCLASSPATH | "
+                                        "grep emma.jar")
+    if len(output) > 0:
+      return True
+    else:
+      logger.Log("Error: Targeted device does not have emma.jar on its "
+                 "BOOTCLASSPATH.")
+      logger.Log("Modify the BOOTCLASSPATH entry in system/core/rootdir/init.rc"
+                 " to add emma.jar")
+      return False
 
   def ExtractReport(self, test_suite,
                     device_coverage_path=_DEVICE_COVERAGE_PATH,
diff --git a/testrunner/logger.py b/testrunner/logger.py
index 762c893..61463a1 100755
--- a/testrunner/logger.py
+++ b/testrunner/logger.py
@@ -25,6 +25,7 @@
 
 _LOG_FILE = None
 _verbose = False
+_log_time = True
 
 def Init(log_file_path):
   """Set the path to the log file"""
@@ -57,8 +58,13 @@
 
 def _PrependTimeStamp(log_string):
   """Returns the log_string prepended with current timestamp """
-  return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"),
-      log_string)
+  global _log_time
+  if _log_time:
+    return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"),
+        log_string)
+  else:
+    # timestamp logging disabled
+    return log_string  
 
 def SilentLog(new_str):
   """Silently log new_str. Unless verbose mode is enabled, will log new_str
@@ -77,7 +83,12 @@
   """ Enable or disable verbose logging"""
   global _verbose
   _verbose = new_verbose
-
+  
+def SetTimestampLogging(new_timestamp=True):
+  """ Enable or disable outputting a timestamp with each log entry"""
+  global _log_time
+  _log_time = new_timestamp
+    
 def main():
   pass
 
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index bf5bb22..a4df950 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -53,6 +53,10 @@
       "The runtest script works in two ways.  You can query it "
       "for a list of tests, or you can launch one or more tests.")
 
+  def __init__(self):
+    # disable logging of timestamp
+    logger.SetTimestampLogging(False)  
+
   def _ProcessOptions(self):
     """Processes command-line options."""
     # TODO error messages on once-only or mutually-exclusive options.
@@ -178,10 +182,14 @@
         self._coverage_gen.EnableCoverageBuild()
         self._AddBuildTarget(self._coverage_gen.GetEmmaBuildPath(), target_set)
       target_build_string = " ".join(list(target_set))
-      logger.Log("Building %s" % target_build_string)
+      logger.Log("mmm %s" % target_build_string)
       cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files' %  (target_build_string,
                                                             self._root_path)
-      if not self._options.preview:
+      if self._options.preview:
+        # in preview mode, just display to the user what command would have been
+        # run
+        logger.Log("adb sync")
+      else:
         run_command.RunCommand(cmd, return_output=False)
         logger.Log("Syncing to device...")
         self._adb.Sync()
@@ -259,6 +267,10 @@
         self._DumpTests()
         return
 
+      if not self._adb.IsDevicePresent():
+        logger.Log("Error: specified device cannot be found")
+        return
+
       if not self._options.skip_build:
         self._DoBuild()