runtest: introduce --user parameter

Currently runtest script installs and then runs test apks with default
"adb install" and "adb shell am instrument" behavior.  They are actually
different,  "adb install" uses USER_ALL, "am instrument" uses
USER_CURRENT.  This cl introduces a way to specify exactly which user a
test should run with in a multiple user environment.  This also provides
a work around for b/22976637 for now.

Bug: 19913735
Bug: 22976637
Change-Id: I65e2b2c79768734a8bc9261f8c4693c9f89016b1
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index cd39480..7dd8f4c 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -176,7 +176,7 @@
 
   def StartInstrumentationForPackage(
       self, package_name, runner_name, timeout_time=60*10,
-      no_window_animation=False, instrumentation_args={}):
+      no_window_animation=False, instrumentation_args={}, user=None):
     """Run instrumentation test for given package and runner.
 
     Equivalent to StartInstrumentation, except instrumentation path is
@@ -185,11 +185,12 @@
     instrumentation_path = "%s/%s" % (package_name, runner_name)
     return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
                                      no_window_animation=no_window_animation,
-                                     instrumentation_args=instrumentation_args)
+                                     instrumentation_args=instrumentation_args,
+                                     user=user)
 
   def StartInstrumentation(
       self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
-      profile=False, instrumentation_args={}):
+      profile=False, instrumentation_args={}, user=None):
 
     """Runs an instrumentation class on the target.
 
@@ -208,6 +209,7 @@
       profile: If True, profiling will be turned on for the instrumentation.
       instrumentation_args: Dictionary of key value bundle arguments to pass to
       instrumentation.
+      user: The user id to start the instrumentation with.
 
     Returns:
       (test_results, inst_finished_bundle)
@@ -229,7 +231,8 @@
     command_string = self._BuildInstrumentationCommandPath(
         instrumentation_path, no_window_animation=no_window_animation,
         profile=profile, raw_mode=True,
-        instrumentation_args=instrumentation_args)
+        instrumentation_args=instrumentation_args,
+        user=user)
     logger.Log(command_string)
     (test_results, inst_finished_bundle) = (
         am_instrument_parser.ParseAmInstrumentOutput(
@@ -255,7 +258,7 @@
 
   def StartInstrumentationNoResults(
       self, package_name, runner_name, no_window_animation=False,
-      raw_mode=False, instrumentation_args={}):
+      raw_mode=False, instrumentation_args={}, user=None):
     """Runs instrumentation and dumps output to stdout.
 
     Equivalent to StartInstrumentation, but will dump instrumentation
@@ -264,17 +267,19 @@
     """
     adb_command_string = self.PreviewInstrumentationCommand(
         package_name, runner_name, no_window_animation=no_window_animation,
-        raw_mode=raw_mode, instrumentation_args=instrumentation_args)
+        raw_mode=raw_mode, instrumentation_args=instrumentation_args,
+        user=user)
     logger.Log(adb_command_string)
     run_command.RunCommand(adb_command_string, return_output=False)
 
   def PreviewInstrumentationCommand(
       self, package_name, runner_name, no_window_animation=False,
-      raw_mode=False, instrumentation_args={}):
+      raw_mode=False, instrumentation_args={}, user=None):
     """Returns a string of adb command that will be executed."""
     inst_command_string = self._BuildInstrumentationCommand(
         package_name, runner_name, no_window_animation=no_window_animation,
-        raw_mode=raw_mode, instrumentation_args=instrumentation_args)
+        raw_mode=raw_mode, instrumentation_args=instrumentation_args,
+        user=user)
     return self.PreviewShellCommand(inst_command_string)
 
   def PreviewShellCommand(self, cmd):
@@ -282,18 +287,20 @@
 
   def _BuildInstrumentationCommand(
       self, package, runner_name, no_window_animation=False, profile=False,
-      raw_mode=True, instrumentation_args={}):
+      raw_mode=True, instrumentation_args={}, user=None):
     instrumentation_path = "%s/%s" % (package, runner_name)
 
     return self._BuildInstrumentationCommandPath(
         instrumentation_path, no_window_animation=no_window_animation,
         profile=profile, raw_mode=raw_mode,
-        instrumentation_args=instrumentation_args)
+        instrumentation_args=instrumentation_args, user=user)
 
   def _BuildInstrumentationCommandPath(
       self, instrumentation_path, no_window_animation=False, profile=False,
-      raw_mode=True, instrumentation_args={}):
+      raw_mode=True, instrumentation_args={}, user=None):
     command_string = "am instrument"
+    if user:
+      command_string += " --user %s" % user
     if no_window_animation:
       command_string += " --no_window_animation"
     if profile:
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index 9b011a6..37b6198 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -172,6 +172,11 @@
     parser.add_option("--suite", dest="suite",
                       help="Run all tests defined as part of the "
                       "the given test suite")
+    parser.add_option("--user", dest="user",
+                      help="The user that test apks are installing to."
+                      " This is the integer user id, e.g. 0 or 10."
+                      " If no user is specified, apk will be installed with"
+                      " adb's default behavior, which is currently all users.")
     group = optparse.OptionGroup(
         parser, "Targets", "Use these options to direct tests to a specific "
         "Android target")
@@ -338,6 +343,8 @@
             extra_flags = ""
             if test_requires_permissions and not self._options.skip_permissions:
               extra_flags = "-g"
+            if self._options.user:
+              extra_flags += " --user " + self._options.user
             logger.Log("adb install -r %s %s" % (extra_flags, abs_install_path))
             logger.Log(self._adb.Install(abs_install_path, extra_flags))
           else:
diff --git a/testrunner/test_defs/instrumentation_test.py b/testrunner/test_defs/instrumentation_test.py
index 1bbedee..2a0d88d 100644
--- a/testrunner/test_defs/instrumentation_test.py
+++ b/testrunner/test_defs/instrumentation_test.py
@@ -154,7 +154,8 @@
             package_name=self.GetPackageName(),
             runner_name=self.GetRunnerName(),
             timeout_time=60*60,
-            instrumentation_args=instrumentation_args)
+            instrumentation_args=instrumentation_args,
+            user=options.user)
       except errors.InstrumentationError, errors.DeviceUnresponsiveError:
         return
       self._PrintTestResults(test_results)
@@ -175,7 +176,8 @@
                                         runner_name=self.GetRunnerName(),
                                         raw_mode=options.raw_mode,
                                         instrumentation_args=
-                                        instrumentation_args)
+                                        instrumentation_args,
+                                        user=options.user)
 
   def _CheckInstrumentationInstalled(self, adb):
     if not adb.IsInstrumentationInstalled(self.GetPackageName(),