10fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#!/usr/bin/env python3.4
20fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#
30fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# Copyright (C) 2016 The Android Open Source Project
40fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#
50fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# Licensed under the Apache License, Version 2.0 (the "License");
60fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# you may not use this file except in compliance with the License.
70fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# You may obtain a copy of the License at
80fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#
90fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#   http://www.apache.org/licenses/LICENSE-2.0
100fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz#
110fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# Unless required by applicable law or agreed to in writing, software
120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# distributed under the License is distributed on an "AS IS" BASIS,
130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# See the License for the specific language governing permissions and
150fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# limitations under the License.
160fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
170fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz"""Module containing common logic from python testing tools."""
180fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
190fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczimport abc
200fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczimport os
210d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewiczimport signal
220fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczimport shlex
230d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewiczimport shutil
24698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewiczimport time
250fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
26e03474846d69e82677abe2c9b66607d9556f455bAart Bikfrom enum import Enum
27e03474846d69e82677abe2c9b66607d9556f455bAart Bikfrom enum import unique
28e03474846d69e82677abe2c9b66607d9556f455bAart Bik
29e03474846d69e82677abe2c9b66607d9556f455bAart Bikfrom subprocess import DEVNULL
300fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom subprocess import check_call
310fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom subprocess import PIPE
320fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom subprocess import Popen
3386379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewiczfrom subprocess import STDOUT
340fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom subprocess import TimeoutExpired
350fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
360fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom tempfile import mkdtemp
370fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczfrom tempfile import NamedTemporaryFile
380fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
390fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# Temporary directory path on device.
400fa3cbd4286db31c872c7009ff3cca359073c01fWojciech StaszkiewiczDEVICE_TMP_PATH = '/data/local/tmp'
410fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
420fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz# Architectures supported in dalvik cache.
430fa3cbd4286db31c872c7009ff3cca359073c01fWojciech StaszkiewiczDALVIK_CACHE_ARCHS = ['arm', 'arm64', 'x86', 'x86_64']
440fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
450fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
460d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz@unique
470d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewiczclass RetCode(Enum):
480d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  """Enum representing normalized return codes."""
490d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  SUCCESS = 0
500d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  TIMEOUT = 1
510d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  ERROR = 2
520d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  NOTCOMPILED = 3
530d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  NOTRUN = 4
540d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
550d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
56698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz@unique
57698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewiczclass LogSeverity(Enum):
58698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  VERBOSE = 0
59698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  DEBUG = 1
60698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  INFO = 2
61698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  WARNING = 3
62698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  ERROR = 4
63698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  FATAL = 5
64698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  SILENT = 6
65698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
66698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  @property
67698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def symbol(self):
68698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return self.name[0]
69698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
70698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  @classmethod
71698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def FromSymbol(cls, s):
72698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    for log_severity in LogSeverity:
73698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      if log_severity.symbol == s:
74698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        return log_severity
75698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    raise ValueError("{0} is not a valid log severity symbol".format(s))
76698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
77698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def __ge__(self, other):
78698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if self.__class__ is other.__class__:
79698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return self.value >= other.value
80698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return NotImplemented
81698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
82698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def __gt__(self, other):
83698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if self.__class__ is other.__class__:
84698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return self.value > other.value
85698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return NotImplemented
86698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
87698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def __le__(self, other):
88698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if self.__class__ is other.__class__:
89698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return self.value <= other.value
90698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return NotImplemented
91698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
92698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def __lt__(self, other):
93698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if self.__class__ is other.__class__:
94698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return self.value < other.value
95e03474846d69e82677abe2c9b66607d9556f455bAart Bik    return NotImplemented
96698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
97698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
980fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczdef GetEnvVariableOrError(variable_name):
990fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Gets value of an environmental variable.
1000fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1010fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  If the variable is not set raises FatalError.
1020fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1030fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Args:
1040fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    variable_name: string, name of variable to get.
1050fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1060fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Returns:
1070fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    string, value of requested variable.
1080fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1090fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Raises:
1100fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    FatalError: Requested variable is not set.
1110fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
1120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  top = os.environ.get(variable_name)
1130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  if top is None:
1140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    raise FatalError('{0} environmental variable not set.'.format(
1150fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz        variable_name))
1160fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  return top
1170fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1180fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
119e03474846d69e82677abe2c9b66607d9556f455bAart Bikdef GetJackClassPath():
120e03474846d69e82677abe2c9b66607d9556f455bAart Bik  """Returns Jack's classpath."""
121e03474846d69e82677abe2c9b66607d9556f455bAart Bik  top = GetEnvVariableOrError('ANDROID_BUILD_TOP')
122e03474846d69e82677abe2c9b66607d9556f455bAart Bik  libdir = top + '/out/host/common/obj/JAVA_LIBRARIES'
123e03474846d69e82677abe2c9b66607d9556f455bAart Bik  return libdir + '/core-libart-hostdex_intermediates/classes.jack:' \
124e03474846d69e82677abe2c9b66607d9556f455bAart Bik       + libdir + '/core-oj-hostdex_intermediates/classes.jack'
125e03474846d69e82677abe2c9b66607d9556f455bAart Bik
126e03474846d69e82677abe2c9b66607d9556f455bAart Bik
1270fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczdef _DexArchCachePaths(android_data_path):
1280fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Returns paths to architecture specific caches.
1290fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1300fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Args:
1310fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    android_data_path: string, path dalvik-cache resides in.
1320fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1330fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Returns:
1340fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Iterable paths to architecture specific caches.
1350fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
1360fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  return ('{0}/dalvik-cache/{1}'.format(android_data_path, arch)
1370fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz          for arch in DALVIK_CACHE_ARCHS)
1380fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1390fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1400d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewiczdef RunCommandForOutput(cmd, env, stdout, stderr, timeout=60):
1410d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  """Runs command piping output to files, stderr or stdout.
1420d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
1430d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  Args:
1440d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    cmd: list of strings, command to run.
1450d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    env: shell environment to run the command with.
1460d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    stdout: file handle or one of Subprocess.PIPE, Subprocess.STDOUT,
1470d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      Subprocess.DEVNULL, see Popen.
1480d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    stderr: file handle or one of Subprocess.PIPE, Subprocess.STDOUT,
1490d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      Subprocess.DEVNULL, see Popen.
1500d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    timeout: int, timeout in seconds.
1510d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
1520d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  Returns:
1530d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    tuple (string, string, RetCode) stdout output, stderr output, normalized
1540d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      return code.
1550d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  """
1560d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  proc = Popen(cmd, stdout=stdout, stderr=stderr, env=env,
1570d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz               universal_newlines=True, start_new_session=True)
1580d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  try:
1590d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    (output, stderr_output) = proc.communicate(timeout=timeout)
1600d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if proc.returncode == 0:
1610d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      retcode = RetCode.SUCCESS
1620d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    else:
1630d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      retcode = RetCode.ERROR
1640d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  except TimeoutExpired:
1650d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
1660d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    (output, stderr_output) = proc.communicate()
1670d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    retcode = RetCode.TIMEOUT
1680d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  return (output, stderr_output, retcode)
1690d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
1700d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
171698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewiczdef _LogCmdOutput(logfile, cmd, output, retcode):
172698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  """Logs output of a command.
1730fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1740fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Args:
1750fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    logfile: file handle to logfile.
176698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    cmd: list of strings, command.
177698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    output: command output.
178698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    retcode: RetCode, normalized retcode.
1790fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
18086379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz  logfile.write('Command:\n{0}\n{1}\nReturn code: {2}\n'.format(
1810d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      CommandListToCommandString(cmd), output, retcode))
1820fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
1830fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
184e03474846d69e82677abe2c9b66607d9556f455bAart Bikdef RunCommand(cmd, out, err, timeout=5):
185e03474846d69e82677abe2c9b66607d9556f455bAart Bik  """Executes a command, and returns its return code.
186e03474846d69e82677abe2c9b66607d9556f455bAart Bik
187e03474846d69e82677abe2c9b66607d9556f455bAart Bik  Args:
188e03474846d69e82677abe2c9b66607d9556f455bAart Bik    cmd: list of strings, a command to execute
189e03474846d69e82677abe2c9b66607d9556f455bAart Bik    out: string, file name to open for stdout (or None)
190e03474846d69e82677abe2c9b66607d9556f455bAart Bik    err: string, file name to open for stderr (or None)
191e03474846d69e82677abe2c9b66607d9556f455bAart Bik    timeout: int, time out in seconds
192e03474846d69e82677abe2c9b66607d9556f455bAart Bik  Returns:
193e03474846d69e82677abe2c9b66607d9556f455bAart Bik    RetCode, return code of running command (forced RetCode.TIMEOUT
194e03474846d69e82677abe2c9b66607d9556f455bAart Bik    on timeout)
195e03474846d69e82677abe2c9b66607d9556f455bAart Bik  """
196e03474846d69e82677abe2c9b66607d9556f455bAart Bik  devnull = DEVNULL
197e03474846d69e82677abe2c9b66607d9556f455bAart Bik  outf = devnull
198e03474846d69e82677abe2c9b66607d9556f455bAart Bik  if out is not None:
199e03474846d69e82677abe2c9b66607d9556f455bAart Bik    outf = open(out, mode='w')
200e03474846d69e82677abe2c9b66607d9556f455bAart Bik  errf = devnull
201e03474846d69e82677abe2c9b66607d9556f455bAart Bik  if err is not None:
202e03474846d69e82677abe2c9b66607d9556f455bAart Bik    errf = open(err, mode='w')
203e03474846d69e82677abe2c9b66607d9556f455bAart Bik  (_, _, retcode) = RunCommandForOutput(cmd, None, outf, errf, timeout)
204e03474846d69e82677abe2c9b66607d9556f455bAart Bik  if outf != devnull:
205e03474846d69e82677abe2c9b66607d9556f455bAart Bik    outf.close()
206e03474846d69e82677abe2c9b66607d9556f455bAart Bik  if errf != devnull:
207e03474846d69e82677abe2c9b66607d9556f455bAart Bik    errf.close()
208e03474846d69e82677abe2c9b66607d9556f455bAart Bik  return retcode
209e03474846d69e82677abe2c9b66607d9556f455bAart Bik
210e03474846d69e82677abe2c9b66607d9556f455bAart Bik
2110d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewiczdef CommandListToCommandString(cmd):
2120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Converts shell command represented as list of strings to a single string.
2130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Each element of the list is wrapped in double quotes.
2150fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2160fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Args:
2170fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    cmd: list of strings, shell command.
2180fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2190fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Returns:
2200fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    string, shell command.
2210fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
2220d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  return ' '.join([shlex.quote(segment) for segment in cmd])
2230fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2240fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2250fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczclass FatalError(Exception):
2260fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Fatal error in script."""
2270fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2280fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2290fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczclass ITestEnv(object):
2300fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Test environment abstraction.
2310fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2320fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Provides unified interface for interacting with host and device test
2330fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  environments. Creates a test directory and expose methods to modify test files
2340fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  and run commands.
2350fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
2360fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  __meta_class__ = abc.ABCMeta
2370fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2380fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @abc.abstractmethod
2390fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def CreateFile(self, name=None):
2400fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Creates a file in test directory.
2410fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2420fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Returned path to file can be used in commands run in the environment.
2430fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2440fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Args:
2450fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      name: string, file name. If None file is named arbitrarily.
2460fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2470fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Returns:
2480fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      string, environment specific path to file.
2490fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """
2500fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2510fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @abc.abstractmethod
2520fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def WriteLines(self, file_path, lines):
2530fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Writes lines to a file in test directory.
2540fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2550fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    If file exists it gets overwritten. If file doest not exist it is created.
2560fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2570fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Args:
2580fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      file_path: string, environment specific path to file.
2590fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      lines: list of strings to write.
2600fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """
2610fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2620fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @abc.abstractmethod
263698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
264698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    """Runs command in environment.
2650fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2660fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Args:
26786379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      cmd: list of strings, command to run.
268698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      log_severity: LogSeverity, minimum severity of logs included in output.
2690fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Returns:
270698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      tuple (string, int) output, return code.
2710fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """
2720fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2730fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @abc.abstractproperty
2740fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def logfile(self):
2750fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Gets file handle to logfile residing on host."""
2760fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2770fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2780fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczclass HostTestEnv(ITestEnv):
2790fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Host test environment. Concrete implementation of ITestEnv.
2800fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2810fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  Maintains a test directory in /tmp/. Runs commands on the host in modified
2820fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  shell environment. Mimics art script behavior.
2830fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2840fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  For methods documentation see base class.
2850fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
2860fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2870d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  def __init__(self, directory_prefix, cleanup=True, logfile_path=None,
2880d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz               timeout=60, x64=False):
2890fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Constructor.
2900fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
2910fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Args:
2920d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      directory_prefix: string, prefix for environment directory name.
2930d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      cleanup: boolean, if True remove test directory in destructor.
2940d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      logfile_path: string, can be used to specify custom logfile location.
2950d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      timeout: int, seconds, time to wait for single test run to finish.
2960fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      x64: boolean, whether to setup in x64 mode.
2970fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """
2980d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._cleanup = cleanup
2990d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._timeout = timeout
3000d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix)
3010d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if logfile_path is None:
3020d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      self._logfile = open('{0}/log'.format(self._env_path), 'w+')
3030d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    else:
3040d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      self._logfile = open(logfile_path, 'w+')
3050fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    os.mkdir('{0}/dalvik-cache'.format(self._env_path))
3060fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    for arch_cache_path in _DexArchCachePaths(self._env_path):
3070fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      os.mkdir(arch_cache_path)
3080fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    lib = 'lib64' if x64 else 'lib'
3090fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    android_root = GetEnvVariableOrError('ANDROID_HOST_OUT')
3100fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    library_path = android_root + '/' + lib
3110fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    path = android_root + '/bin'
3120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env = os.environ.copy()
3130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env['ANDROID_DATA'] = self._env_path
3140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env['ANDROID_ROOT'] = android_root
3150fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env['LD_LIBRARY_PATH'] = library_path
31686379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    self._shell_env['DYLD_LIBRARY_PATH'] = library_path
3170fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH'])
3180fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    # Using dlopen requires load bias on the host.
3190fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._shell_env['LD_USE_LOAD_BIAS'] = '1'
3200fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3210d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  def __del__(self):
3220d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if self._cleanup:
3230d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      shutil.rmtree(self._env_path)
3240d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
3250fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def CreateFile(self, name=None):
3260fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    if name is None:
3270fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      f = NamedTemporaryFile(dir=self._env_path, delete=False)
3280fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    else:
3290fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      f = open('{0}/{1}'.format(self._env_path, name), 'w+')
3300fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    return f.name
3310fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3320fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def WriteLines(self, file_path, lines):
3330fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    with open(file_path, 'w') as f:
3340fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      f.writelines('{0}\n'.format(line) for line in lines)
3350fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    return
3360fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
337698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
3380fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._EmptyDexCache()
33986379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    env = self._shell_env.copy()
340698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    env.update({'ANDROID_LOG_TAGS':'*:' + log_severity.symbol.lower()})
341698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    (output, err_output, retcode) = RunCommandForOutput(
342698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        cmd, env, PIPE, PIPE, self._timeout)
343698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # We append err_output to output to stay consistent with DeviceTestEnv
344698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # implementation.
345698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    output += err_output
346698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    _LogCmdOutput(self._logfile, cmd, output, retcode)
347698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return (output, retcode)
3480fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3490fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @property
3500fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def logfile(self):
3510fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    return self._logfile
3520fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3530fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def _EmptyDexCache(self):
3540fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Empties dex cache.
3550fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3560fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    Iterate over files in architecture specific cache directories and remove
3570fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    them.
3580fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """
3590fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    for arch_cache_path in _DexArchCachePaths(self._env_path):
3600fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      for file_path in os.listdir(arch_cache_path):
3610fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz        file_path = '{0}/{1}'.format(arch_cache_path, file_path)
3620fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz        if os.path.isfile(file_path):
3630fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz          os.unlink(file_path)
3640fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3650fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3660fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewiczclass DeviceTestEnv(ITestEnv):
3670fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """Device test environment. Concrete implementation of ITestEnv.
3680fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3690fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  For methods documentation see base class.
3700fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  """
3710fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3720d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  def __init__(self, directory_prefix, cleanup=True, logfile_path=None,
3730d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz               timeout=60, specific_device=None):
3740d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    """Constructor.
3750d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
3760d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    Args:
3770d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      directory_prefix: string, prefix for environment directory name.
3780d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      cleanup: boolean, if True remove test directory in destructor.
3790d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      logfile_path: string, can be used to specify custom logfile location.
3800d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      timeout: int, seconds, time to wait for single test run to finish.
3810d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      specific_device: string, serial number of device to use.
3820d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    """
3830d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._cleanup = cleanup
3840d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._timeout = timeout
3850d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._specific_device = specific_device
3860d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    self._host_env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix)
3870d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if logfile_path is None:
3880d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      self._logfile = open('{0}/log'.format(self._host_env_path), 'w+')
3890d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    else:
3900d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      self._logfile = open(logfile_path, 'w+')
3910fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._device_env_path = '{0}/{1}'.format(
3920fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz        DEVICE_TMP_PATH, os.path.basename(self._host_env_path))
39386379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    self._shell_env = os.environ.copy()
3940fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3950fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._AdbMkdir('{0}/dalvik-cache'.format(self._device_env_path))
3960fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    for arch_cache_path in _DexArchCachePaths(self._device_env_path):
3970fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      self._AdbMkdir(arch_cache_path)
3980fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
3990d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz  def __del__(self):
4000d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if self._cleanup:
4010d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      shutil.rmtree(self._host_env_path)
4020d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz      check_call(shlex.split(
4030d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz          'adb shell if [ -d "{0}" ]; then rm -rf "{0}"; fi'
4040d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz          .format(self._device_env_path)))
4050d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz
4060fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def CreateFile(self, name=None):
4070fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    with NamedTemporaryFile(mode='w') as temp_file:
4080fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      self._AdbPush(temp_file.name, self._device_env_path)
4090fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      if name is None:
4100fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz        name = os.path.basename(temp_file.name)
4110fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      return '{0}/{1}'.format(self._device_env_path, name)
4120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
4130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def WriteLines(self, file_path, lines):
4140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    with NamedTemporaryFile(mode='w') as temp_file:
4150fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      temp_file.writelines('{0}\n'.format(line) for line in lines)
41686379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      temp_file.flush()
4170fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      self._AdbPush(temp_file.name, file_path)
4180fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    return
4190fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
420698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def _ExtractPid(self, brief_log_line):
421698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    """Extracts PID from a single logcat line in brief format."""
422698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    pid_start_idx = brief_log_line.find('(') + 2
423698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if pid_start_idx == -1:
424698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return None
425698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    pid_end_idx = brief_log_line.find(')', pid_start_idx)
426698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if pid_end_idx == -1:
427698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return None
428698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return brief_log_line[pid_start_idx:pid_end_idx]
429698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
430698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def _ExtractSeverity(self, brief_log_line):
431698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    """Extracts LogSeverity from a single logcat line in brief format."""
432698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if not brief_log_line:
433698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      return None
434698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return LogSeverity.FromSymbol(brief_log_line[0])
435698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz
436698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz  def RunCommand(self, cmd, log_severity=LogSeverity.ERROR):
4370fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    self._EmptyDexCache()
438698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    env_vars_cmd = 'ANDROID_DATA={0} ANDROID_LOG_TAGS=*:i'.format(
439698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        self._device_env_path)
440698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    adb_cmd = ['adb']
4410d0fd4a6bcf3b1223f1f5ed31d61aadfcfe79bc9Wojciech Staszkiewicz    if self._specific_device:
442698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      adb_cmd += ['-s', self._specific_device]
443698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    logcat_cmd = adb_cmd + ['logcat', '-v', 'brief', '-s', '-b', 'main',
444698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz                            '-T', '1', 'dex2oat:*', 'dex2oatd:*']
445698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    logcat_proc = Popen(logcat_cmd, stdout=PIPE, stderr=STDOUT,
446698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz                        universal_newlines=True)
447698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    cmd_str = CommandListToCommandString(cmd)
448698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # Print PID of the shell and exec command. We later retrieve this PID and
449698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # use it to filter dex2oat logs, keeping those with matching parent PID.
450698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    device_cmd = ('echo $$ && ' + env_vars_cmd + ' exec ' + cmd_str)
451698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    cmd = adb_cmd + ['shell', device_cmd]
452698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    (output, _, retcode) = RunCommandForOutput(cmd, self._shell_env, PIPE,
453698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz                                               STDOUT, self._timeout)
454698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # We need to make sure to only kill logcat once all relevant logs arrive.
455698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    # Sleep is used for simplicity.
456698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    time.sleep(0.5)
457698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    logcat_proc.kill()
458698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    end_of_first_line = output.find('\n')
459698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    if end_of_first_line != -1:
460698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      parent_pid = output[:end_of_first_line]
461698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      output = output[end_of_first_line + 1:]
462698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      logcat_output, _ = logcat_proc.communicate()
463698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      logcat_lines = logcat_output.splitlines(keepends=True)
464698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      dex2oat_pids = []
465698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      for line in logcat_lines:
466698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        # Dex2oat was started by our runtime instance.
467698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        if 'Running dex2oat (parent PID = ' + parent_pid in line:
468698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz          dex2oat_pids.append(self._ExtractPid(line))
469698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz          break
470698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz      if dex2oat_pids:
471698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz        for line in logcat_lines:
472698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz          if (self._ExtractPid(line) in dex2oat_pids and
473698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz              self._ExtractSeverity(line) >= log_severity):
474698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz            output += line
475698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    _LogCmdOutput(self._logfile, cmd, output, retcode)
476698e4b30e6d0e937e34e73a3c5349f67a076e1b5Wojciech Staszkiewicz    return (output, retcode)
4770fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
4780fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  @property
4790fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def logfile(self):
4800fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    return self._logfile
4810fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
48286379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz  def PushClasspath(self, classpath):
48386379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    """Push classpath to on-device test directory.
48486379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz
48586379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    Classpath can contain multiple colon separated file paths, each file is
48686379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    pushed. Returns analogous classpath with paths valid on device.
48786379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz
48886379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    Args:
48986379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      classpath: string, classpath in format 'a/b/c:d/e/f'.
49086379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    Returns:
49186379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      string, classpath valid on device.
49286379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    """
49386379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    paths = classpath.split(':')
49486379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    device_paths = []
49586379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    for path in paths:
49686379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      device_paths.append('{0}/{1}'.format(
49786379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz          self._device_env_path, os.path.basename(path)))
49886379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz      self._AdbPush(path, self._device_env_path)
49986379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz    return ':'.join(device_paths)
50086379941f33ce651fc4cbc62ce7d95a15bbce8f8Wojciech Staszkiewicz
5010fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def _AdbPush(self, what, where):
5020fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    check_call(shlex.split('adb push "{0}" "{1}"'.format(what, where)),
5030fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz               stdout=self._logfile, stderr=self._logfile)
5040fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
5050fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def _AdbMkdir(self, path):
5060fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    check_call(shlex.split('adb shell mkdir "{0}" -p'.format(path)),
5070fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz               stdout=self._logfile, stderr=self._logfile)
5080fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz
5090fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz  def _EmptyDexCache(self):
5100fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    """Empties dex cache."""
5110fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz    for arch_cache_path in _DexArchCachePaths(self._device_env_path):
5120fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      cmd = 'adb shell if [ -d "{0}" ]; then rm -f "{0}"/*; fi'.format(
5130fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz          arch_cache_path)
5140fa3cbd4286db31c872c7009ff3cca359073c01fWojciech Staszkiewicz      check_call(shlex.split(cmd), stdout=self._logfile, stderr=self._logfile)
515