1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2016 The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker"""Module containing common logic from python testing tools.""" 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Workerimport abc 20*795d594fSAndroid Build Coastguard Workerimport os 21*795d594fSAndroid Build Coastguard Workerimport signal 22*795d594fSAndroid Build Coastguard Workerimport shlex 23*795d594fSAndroid Build Coastguard Workerimport shutil 24*795d594fSAndroid Build Coastguard Workerimport time 25*795d594fSAndroid Build Coastguard Worker 26*795d594fSAndroid Build Coastguard Workerfrom enum import Enum 27*795d594fSAndroid Build Coastguard Workerfrom enum import unique 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Workerfrom subprocess import DEVNULL 30*795d594fSAndroid Build Coastguard Workerfrom subprocess import check_call 31*795d594fSAndroid Build Coastguard Workerfrom subprocess import PIPE 32*795d594fSAndroid Build Coastguard Workerfrom subprocess import Popen 33*795d594fSAndroid Build Coastguard Workerfrom subprocess import STDOUT 34*795d594fSAndroid Build Coastguard Workerfrom subprocess import TimeoutExpired 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Workerfrom tempfile import mkdtemp 37*795d594fSAndroid Build Coastguard Workerfrom tempfile import NamedTemporaryFile 38*795d594fSAndroid Build Coastguard Worker 39*795d594fSAndroid Build Coastguard Worker# Temporary directory path on device. 40*795d594fSAndroid Build Coastguard WorkerDEVICE_TMP_PATH = '/data/local/tmp' 41*795d594fSAndroid Build Coastguard Worker 42*795d594fSAndroid Build Coastguard Worker# Architectures supported in dalvik cache. 43*795d594fSAndroid Build Coastguard WorkerDALVIK_CACHE_ARCHS = ['arm', 'arm64', 'x86', 'x86_64'] 44*795d594fSAndroid Build Coastguard Worker 45*795d594fSAndroid Build Coastguard Worker 46*795d594fSAndroid Build Coastguard Worker@unique 47*795d594fSAndroid Build Coastguard Workerclass RetCode(Enum): 48*795d594fSAndroid Build Coastguard Worker """Enum representing normalized return codes.""" 49*795d594fSAndroid Build Coastguard Worker SUCCESS = 0 50*795d594fSAndroid Build Coastguard Worker TIMEOUT = 1 51*795d594fSAndroid Build Coastguard Worker ERROR = 2 52*795d594fSAndroid Build Coastguard Worker NOTCOMPILED = 3 53*795d594fSAndroid Build Coastguard Worker NOTRUN = 4 54*795d594fSAndroid Build Coastguard Worker 55*795d594fSAndroid Build Coastguard Worker 56*795d594fSAndroid Build Coastguard Worker@unique 57*795d594fSAndroid Build Coastguard Workerclass LogSeverity(Enum): 58*795d594fSAndroid Build Coastguard Worker VERBOSE = 0 59*795d594fSAndroid Build Coastguard Worker DEBUG = 1 60*795d594fSAndroid Build Coastguard Worker INFO = 2 61*795d594fSAndroid Build Coastguard Worker WARNING = 3 62*795d594fSAndroid Build Coastguard Worker ERROR = 4 63*795d594fSAndroid Build Coastguard Worker FATAL = 5 64*795d594fSAndroid Build Coastguard Worker SILENT = 6 65*795d594fSAndroid Build Coastguard Worker 66*795d594fSAndroid Build Coastguard Worker @property 67*795d594fSAndroid Build Coastguard Worker def symbol(self): 68*795d594fSAndroid Build Coastguard Worker return self.name[0] 69*795d594fSAndroid Build Coastguard Worker 70*795d594fSAndroid Build Coastguard Worker @classmethod 71*795d594fSAndroid Build Coastguard Worker def FromSymbol(cls, s): 72*795d594fSAndroid Build Coastguard Worker for log_severity in LogSeverity: 73*795d594fSAndroid Build Coastguard Worker if log_severity.symbol == s: 74*795d594fSAndroid Build Coastguard Worker return log_severity 75*795d594fSAndroid Build Coastguard Worker raise ValueError("{0} is not a valid log severity symbol".format(s)) 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker def __ge__(self, other): 78*795d594fSAndroid Build Coastguard Worker if self.__class__ is other.__class__: 79*795d594fSAndroid Build Coastguard Worker return self.value >= other.value 80*795d594fSAndroid Build Coastguard Worker return NotImplemented 81*795d594fSAndroid Build Coastguard Worker 82*795d594fSAndroid Build Coastguard Worker def __gt__(self, other): 83*795d594fSAndroid Build Coastguard Worker if self.__class__ is other.__class__: 84*795d594fSAndroid Build Coastguard Worker return self.value > other.value 85*795d594fSAndroid Build Coastguard Worker return NotImplemented 86*795d594fSAndroid Build Coastguard Worker 87*795d594fSAndroid Build Coastguard Worker def __le__(self, other): 88*795d594fSAndroid Build Coastguard Worker if self.__class__ is other.__class__: 89*795d594fSAndroid Build Coastguard Worker return self.value <= other.value 90*795d594fSAndroid Build Coastguard Worker return NotImplemented 91*795d594fSAndroid Build Coastguard Worker 92*795d594fSAndroid Build Coastguard Worker def __lt__(self, other): 93*795d594fSAndroid Build Coastguard Worker if self.__class__ is other.__class__: 94*795d594fSAndroid Build Coastguard Worker return self.value < other.value 95*795d594fSAndroid Build Coastguard Worker return NotImplemented 96*795d594fSAndroid Build Coastguard Worker 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Workerdef GetEnvVariableOrError(variable_name): 99*795d594fSAndroid Build Coastguard Worker """Gets value of an environmental variable. 100*795d594fSAndroid Build Coastguard Worker 101*795d594fSAndroid Build Coastguard Worker If the variable is not set raises FatalError. 102*795d594fSAndroid Build Coastguard Worker 103*795d594fSAndroid Build Coastguard Worker Args: 104*795d594fSAndroid Build Coastguard Worker variable_name: string, name of variable to get. 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker Returns: 107*795d594fSAndroid Build Coastguard Worker string, value of requested variable. 108*795d594fSAndroid Build Coastguard Worker 109*795d594fSAndroid Build Coastguard Worker Raises: 110*795d594fSAndroid Build Coastguard Worker FatalError: Requested variable is not set. 111*795d594fSAndroid Build Coastguard Worker """ 112*795d594fSAndroid Build Coastguard Worker top = os.environ.get(variable_name) 113*795d594fSAndroid Build Coastguard Worker if top is None: 114*795d594fSAndroid Build Coastguard Worker raise FatalError('{0} environmental variable not set.'.format( 115*795d594fSAndroid Build Coastguard Worker variable_name)) 116*795d594fSAndroid Build Coastguard Worker return top 117*795d594fSAndroid Build Coastguard Worker 118*795d594fSAndroid Build Coastguard Worker 119*795d594fSAndroid Build Coastguard Workerdef _DexArchCachePaths(android_data_path): 120*795d594fSAndroid Build Coastguard Worker """Returns paths to architecture specific caches. 121*795d594fSAndroid Build Coastguard Worker 122*795d594fSAndroid Build Coastguard Worker Args: 123*795d594fSAndroid Build Coastguard Worker android_data_path: string, path dalvik-cache resides in. 124*795d594fSAndroid Build Coastguard Worker 125*795d594fSAndroid Build Coastguard Worker Returns: 126*795d594fSAndroid Build Coastguard Worker Iterable paths to architecture specific caches. 127*795d594fSAndroid Build Coastguard Worker """ 128*795d594fSAndroid Build Coastguard Worker return ('{0}/dalvik-cache/{1}'.format(android_data_path, arch) 129*795d594fSAndroid Build Coastguard Worker for arch in DALVIK_CACHE_ARCHS) 130*795d594fSAndroid Build Coastguard Worker 131*795d594fSAndroid Build Coastguard Worker 132*795d594fSAndroid Build Coastguard Workerdef RunCommandForOutput(cmd, env, stdout, stderr, timeout=60): 133*795d594fSAndroid Build Coastguard Worker """Runs command piping output to files, stderr or stdout. 134*795d594fSAndroid Build Coastguard Worker 135*795d594fSAndroid Build Coastguard Worker Args: 136*795d594fSAndroid Build Coastguard Worker cmd: list of strings, command to run. 137*795d594fSAndroid Build Coastguard Worker env: shell environment to run the command with. 138*795d594fSAndroid Build Coastguard Worker stdout: file handle or one of Subprocess.PIPE, Subprocess.STDOUT, 139*795d594fSAndroid Build Coastguard Worker Subprocess.DEVNULL, see Popen. 140*795d594fSAndroid Build Coastguard Worker stderr: file handle or one of Subprocess.PIPE, Subprocess.STDOUT, 141*795d594fSAndroid Build Coastguard Worker Subprocess.DEVNULL, see Popen. 142*795d594fSAndroid Build Coastguard Worker timeout: int, timeout in seconds. 143*795d594fSAndroid Build Coastguard Worker 144*795d594fSAndroid Build Coastguard Worker Returns: 145*795d594fSAndroid Build Coastguard Worker tuple (string, string, RetCode) stdout output, stderr output, normalized 146*795d594fSAndroid Build Coastguard Worker return code. 147*795d594fSAndroid Build Coastguard Worker """ 148*795d594fSAndroid Build Coastguard Worker proc = Popen(cmd, stdout=stdout, stderr=stderr, env=env, 149*795d594fSAndroid Build Coastguard Worker universal_newlines=True, start_new_session=True) 150*795d594fSAndroid Build Coastguard Worker try: 151*795d594fSAndroid Build Coastguard Worker (output, stderr_output) = proc.communicate(timeout=timeout) 152*795d594fSAndroid Build Coastguard Worker if proc.returncode == 0: 153*795d594fSAndroid Build Coastguard Worker retcode = RetCode.SUCCESS 154*795d594fSAndroid Build Coastguard Worker else: 155*795d594fSAndroid Build Coastguard Worker retcode = RetCode.ERROR 156*795d594fSAndroid Build Coastguard Worker except TimeoutExpired: 157*795d594fSAndroid Build Coastguard Worker os.killpg(os.getpgid(proc.pid), signal.SIGTERM) 158*795d594fSAndroid Build Coastguard Worker (output, stderr_output) = proc.communicate() 159*795d594fSAndroid Build Coastguard Worker retcode = RetCode.TIMEOUT 160*795d594fSAndroid Build Coastguard Worker return (output, stderr_output, retcode) 161*795d594fSAndroid Build Coastguard Worker 162*795d594fSAndroid Build Coastguard Worker 163*795d594fSAndroid Build Coastguard Workerdef _LogCmdOutput(logfile, cmd, output, retcode): 164*795d594fSAndroid Build Coastguard Worker """Logs output of a command. 165*795d594fSAndroid Build Coastguard Worker 166*795d594fSAndroid Build Coastguard Worker Args: 167*795d594fSAndroid Build Coastguard Worker logfile: file handle to logfile. 168*795d594fSAndroid Build Coastguard Worker cmd: list of strings, command. 169*795d594fSAndroid Build Coastguard Worker output: command output. 170*795d594fSAndroid Build Coastguard Worker retcode: RetCode, normalized retcode. 171*795d594fSAndroid Build Coastguard Worker """ 172*795d594fSAndroid Build Coastguard Worker logfile.write('Command:\n{0}\n{1}\nReturn code: {2}\n'.format( 173*795d594fSAndroid Build Coastguard Worker CommandListToCommandString(cmd), output, retcode)) 174*795d594fSAndroid Build Coastguard Worker 175*795d594fSAndroid Build Coastguard Worker 176*795d594fSAndroid Build Coastguard Workerdef RunCommand(cmd, out, err, timeout=5): 177*795d594fSAndroid Build Coastguard Worker """Executes a command, and returns its return code. 178*795d594fSAndroid Build Coastguard Worker 179*795d594fSAndroid Build Coastguard Worker Args: 180*795d594fSAndroid Build Coastguard Worker cmd: list of strings, a command to execute 181*795d594fSAndroid Build Coastguard Worker out: string, file name to open for stdout (or None) 182*795d594fSAndroid Build Coastguard Worker err: string, file name to open for stderr (or None) 183*795d594fSAndroid Build Coastguard Worker timeout: int, time out in seconds 184*795d594fSAndroid Build Coastguard Worker Returns: 185*795d594fSAndroid Build Coastguard Worker RetCode, return code of running command (forced RetCode.TIMEOUT 186*795d594fSAndroid Build Coastguard Worker on timeout) 187*795d594fSAndroid Build Coastguard Worker """ 188*795d594fSAndroid Build Coastguard Worker devnull = DEVNULL 189*795d594fSAndroid Build Coastguard Worker outf = devnull 190*795d594fSAndroid Build Coastguard Worker if out is not None: 191*795d594fSAndroid Build Coastguard Worker outf = open(out, mode='w') 192*795d594fSAndroid Build Coastguard Worker errf = devnull 193*795d594fSAndroid Build Coastguard Worker if err is not None: 194*795d594fSAndroid Build Coastguard Worker errf = open(err, mode='w') 195*795d594fSAndroid Build Coastguard Worker (_, _, retcode) = RunCommandForOutput(cmd, None, outf, errf, timeout) 196*795d594fSAndroid Build Coastguard Worker if outf != devnull: 197*795d594fSAndroid Build Coastguard Worker outf.close() 198*795d594fSAndroid Build Coastguard Worker if errf != devnull: 199*795d594fSAndroid Build Coastguard Worker errf.close() 200*795d594fSAndroid Build Coastguard Worker return retcode 201*795d594fSAndroid Build Coastguard Worker 202*795d594fSAndroid Build Coastguard Worker 203*795d594fSAndroid Build Coastguard Workerdef CommandListToCommandString(cmd): 204*795d594fSAndroid Build Coastguard Worker """Converts shell command represented as list of strings to a single string. 205*795d594fSAndroid Build Coastguard Worker 206*795d594fSAndroid Build Coastguard Worker Each element of the list is wrapped in double quotes. 207*795d594fSAndroid Build Coastguard Worker 208*795d594fSAndroid Build Coastguard Worker Args: 209*795d594fSAndroid Build Coastguard Worker cmd: list of strings, shell command. 210*795d594fSAndroid Build Coastguard Worker 211*795d594fSAndroid Build Coastguard Worker Returns: 212*795d594fSAndroid Build Coastguard Worker string, shell command. 213*795d594fSAndroid Build Coastguard Worker """ 214*795d594fSAndroid Build Coastguard Worker return ' '.join([shlex.quote(segment) for segment in cmd]) 215*795d594fSAndroid Build Coastguard Worker 216*795d594fSAndroid Build Coastguard Worker 217*795d594fSAndroid Build Coastguard Workerclass FatalError(Exception): 218*795d594fSAndroid Build Coastguard Worker """Fatal error in script.""" 219*795d594fSAndroid Build Coastguard Worker 220*795d594fSAndroid Build Coastguard Worker 221*795d594fSAndroid Build Coastguard Workerclass ITestEnv(object): 222*795d594fSAndroid Build Coastguard Worker """Test environment abstraction. 223*795d594fSAndroid Build Coastguard Worker 224*795d594fSAndroid Build Coastguard Worker Provides unified interface for interacting with host and device test 225*795d594fSAndroid Build Coastguard Worker environments. Creates a test directory and expose methods to modify test files 226*795d594fSAndroid Build Coastguard Worker and run commands. 227*795d594fSAndroid Build Coastguard Worker """ 228*795d594fSAndroid Build Coastguard Worker __meta_class__ = abc.ABCMeta 229*795d594fSAndroid Build Coastguard Worker 230*795d594fSAndroid Build Coastguard Worker @abc.abstractmethod 231*795d594fSAndroid Build Coastguard Worker def CreateFile(self, name=None): 232*795d594fSAndroid Build Coastguard Worker """Creates a file in test directory. 233*795d594fSAndroid Build Coastguard Worker 234*795d594fSAndroid Build Coastguard Worker Returned path to file can be used in commands run in the environment. 235*795d594fSAndroid Build Coastguard Worker 236*795d594fSAndroid Build Coastguard Worker Args: 237*795d594fSAndroid Build Coastguard Worker name: string, file name. If None file is named arbitrarily. 238*795d594fSAndroid Build Coastguard Worker 239*795d594fSAndroid Build Coastguard Worker Returns: 240*795d594fSAndroid Build Coastguard Worker string, environment specific path to file. 241*795d594fSAndroid Build Coastguard Worker """ 242*795d594fSAndroid Build Coastguard Worker 243*795d594fSAndroid Build Coastguard Worker @abc.abstractmethod 244*795d594fSAndroid Build Coastguard Worker def WriteLines(self, file_path, lines): 245*795d594fSAndroid Build Coastguard Worker """Writes lines to a file in test directory. 246*795d594fSAndroid Build Coastguard Worker 247*795d594fSAndroid Build Coastguard Worker If file exists it gets overwritten. If file doest not exist it is created. 248*795d594fSAndroid Build Coastguard Worker 249*795d594fSAndroid Build Coastguard Worker Args: 250*795d594fSAndroid Build Coastguard Worker file_path: string, environment specific path to file. 251*795d594fSAndroid Build Coastguard Worker lines: list of strings to write. 252*795d594fSAndroid Build Coastguard Worker """ 253*795d594fSAndroid Build Coastguard Worker 254*795d594fSAndroid Build Coastguard Worker @abc.abstractmethod 255*795d594fSAndroid Build Coastguard Worker def RunCommand(self, cmd, log_severity=LogSeverity.ERROR): 256*795d594fSAndroid Build Coastguard Worker """Runs command in environment. 257*795d594fSAndroid Build Coastguard Worker 258*795d594fSAndroid Build Coastguard Worker Args: 259*795d594fSAndroid Build Coastguard Worker cmd: list of strings, command to run. 260*795d594fSAndroid Build Coastguard Worker log_severity: LogSeverity, minimum severity of logs included in output. 261*795d594fSAndroid Build Coastguard Worker Returns: 262*795d594fSAndroid Build Coastguard Worker tuple (string, int) output, return code. 263*795d594fSAndroid Build Coastguard Worker """ 264*795d594fSAndroid Build Coastguard Worker 265*795d594fSAndroid Build Coastguard Worker @abc.abstractproperty 266*795d594fSAndroid Build Coastguard Worker def logfile(self): 267*795d594fSAndroid Build Coastguard Worker """Gets file handle to logfile residing on host.""" 268*795d594fSAndroid Build Coastguard Worker 269*795d594fSAndroid Build Coastguard Worker 270*795d594fSAndroid Build Coastguard Workerclass HostTestEnv(ITestEnv): 271*795d594fSAndroid Build Coastguard Worker """Host test environment. Concrete implementation of ITestEnv. 272*795d594fSAndroid Build Coastguard Worker 273*795d594fSAndroid Build Coastguard Worker Maintains a test directory in /tmp/. Runs commands on the host in modified 274*795d594fSAndroid Build Coastguard Worker shell environment. Mimics art script behavior. 275*795d594fSAndroid Build Coastguard Worker 276*795d594fSAndroid Build Coastguard Worker For methods documentation see base class. 277*795d594fSAndroid Build Coastguard Worker """ 278*795d594fSAndroid Build Coastguard Worker 279*795d594fSAndroid Build Coastguard Worker def __init__(self, directory_prefix, cleanup=True, logfile_path=None, 280*795d594fSAndroid Build Coastguard Worker timeout=60, x64=False): 281*795d594fSAndroid Build Coastguard Worker """Constructor. 282*795d594fSAndroid Build Coastguard Worker 283*795d594fSAndroid Build Coastguard Worker Args: 284*795d594fSAndroid Build Coastguard Worker directory_prefix: string, prefix for environment directory name. 285*795d594fSAndroid Build Coastguard Worker cleanup: boolean, if True remove test directory in destructor. 286*795d594fSAndroid Build Coastguard Worker logfile_path: string, can be used to specify custom logfile location. 287*795d594fSAndroid Build Coastguard Worker timeout: int, seconds, time to wait for single test run to finish. 288*795d594fSAndroid Build Coastguard Worker x64: boolean, whether to setup in x64 mode. 289*795d594fSAndroid Build Coastguard Worker """ 290*795d594fSAndroid Build Coastguard Worker self._cleanup = cleanup 291*795d594fSAndroid Build Coastguard Worker self._timeout = timeout 292*795d594fSAndroid Build Coastguard Worker self._env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix) 293*795d594fSAndroid Build Coastguard Worker if logfile_path is None: 294*795d594fSAndroid Build Coastguard Worker self._logfile = open('{0}/log'.format(self._env_path), 'w+') 295*795d594fSAndroid Build Coastguard Worker else: 296*795d594fSAndroid Build Coastguard Worker self._logfile = open(logfile_path, 'w+') 297*795d594fSAndroid Build Coastguard Worker os.mkdir('{0}/dalvik-cache'.format(self._env_path)) 298*795d594fSAndroid Build Coastguard Worker for arch_cache_path in _DexArchCachePaths(self._env_path): 299*795d594fSAndroid Build Coastguard Worker os.mkdir(arch_cache_path) 300*795d594fSAndroid Build Coastguard Worker lib = 'lib64' if x64 else 'lib' 301*795d594fSAndroid Build Coastguard Worker android_root = GetEnvVariableOrError('ANDROID_HOST_OUT') 302*795d594fSAndroid Build Coastguard Worker android_i18n_root = android_root + '/com.android.i18n' 303*795d594fSAndroid Build Coastguard Worker android_art_root = android_root + '/com.android.art' 304*795d594fSAndroid Build Coastguard Worker android_tzdata_root = android_root + '/com.android.tzdata' 305*795d594fSAndroid Build Coastguard Worker library_path = android_root + '/' + lib 306*795d594fSAndroid Build Coastguard Worker path = android_root + '/bin' 307*795d594fSAndroid Build Coastguard Worker self._shell_env = os.environ.copy() 308*795d594fSAndroid Build Coastguard Worker self._shell_env['ANDROID_DATA'] = self._env_path 309*795d594fSAndroid Build Coastguard Worker self._shell_env['ANDROID_ROOT'] = android_root 310*795d594fSAndroid Build Coastguard Worker self._shell_env['ANDROID_I18N_ROOT'] = android_i18n_root 311*795d594fSAndroid Build Coastguard Worker self._shell_env['ANDROID_ART_ROOT'] = android_art_root 312*795d594fSAndroid Build Coastguard Worker self._shell_env['ANDROID_TZDATA_ROOT'] = android_tzdata_root 313*795d594fSAndroid Build Coastguard Worker self._shell_env['LD_LIBRARY_PATH'] = library_path 314*795d594fSAndroid Build Coastguard Worker self._shell_env['DYLD_LIBRARY_PATH'] = library_path 315*795d594fSAndroid Build Coastguard Worker self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH']) 316*795d594fSAndroid Build Coastguard Worker # Using dlopen requires load bias on the host. 317*795d594fSAndroid Build Coastguard Worker self._shell_env['LD_USE_LOAD_BIAS'] = '1' 318*795d594fSAndroid Build Coastguard Worker 319*795d594fSAndroid Build Coastguard Worker def __del__(self): 320*795d594fSAndroid Build Coastguard Worker if self._cleanup: 321*795d594fSAndroid Build Coastguard Worker shutil.rmtree(self._env_path) 322*795d594fSAndroid Build Coastguard Worker 323*795d594fSAndroid Build Coastguard Worker def CreateFile(self, name=None): 324*795d594fSAndroid Build Coastguard Worker if name is None: 325*795d594fSAndroid Build Coastguard Worker f = NamedTemporaryFile(dir=self._env_path, delete=False) 326*795d594fSAndroid Build Coastguard Worker else: 327*795d594fSAndroid Build Coastguard Worker f = open('{0}/{1}'.format(self._env_path, name), 'w+') 328*795d594fSAndroid Build Coastguard Worker return f.name 329*795d594fSAndroid Build Coastguard Worker 330*795d594fSAndroid Build Coastguard Worker def WriteLines(self, file_path, lines): 331*795d594fSAndroid Build Coastguard Worker with open(file_path, 'w') as f: 332*795d594fSAndroid Build Coastguard Worker f.writelines('{0}\n'.format(line) for line in lines) 333*795d594fSAndroid Build Coastguard Worker return 334*795d594fSAndroid Build Coastguard Worker 335*795d594fSAndroid Build Coastguard Worker def RunCommand(self, cmd, log_severity=LogSeverity.ERROR): 336*795d594fSAndroid Build Coastguard Worker self._EmptyDexCache() 337*795d594fSAndroid Build Coastguard Worker env = self._shell_env.copy() 338*795d594fSAndroid Build Coastguard Worker env.update({'ANDROID_LOG_TAGS':'*:' + log_severity.symbol.lower()}) 339*795d594fSAndroid Build Coastguard Worker (output, err_output, retcode) = RunCommandForOutput( 340*795d594fSAndroid Build Coastguard Worker cmd, env, PIPE, PIPE, self._timeout) 341*795d594fSAndroid Build Coastguard Worker # We append err_output to output to stay consistent with DeviceTestEnv 342*795d594fSAndroid Build Coastguard Worker # implementation. 343*795d594fSAndroid Build Coastguard Worker output += err_output 344*795d594fSAndroid Build Coastguard Worker _LogCmdOutput(self._logfile, cmd, output, retcode) 345*795d594fSAndroid Build Coastguard Worker return (output, retcode) 346*795d594fSAndroid Build Coastguard Worker 347*795d594fSAndroid Build Coastguard Worker @property 348*795d594fSAndroid Build Coastguard Worker def logfile(self): 349*795d594fSAndroid Build Coastguard Worker return self._logfile 350*795d594fSAndroid Build Coastguard Worker 351*795d594fSAndroid Build Coastguard Worker def _EmptyDexCache(self): 352*795d594fSAndroid Build Coastguard Worker """Empties dex cache. 353*795d594fSAndroid Build Coastguard Worker 354*795d594fSAndroid Build Coastguard Worker Iterate over files in architecture specific cache directories and remove 355*795d594fSAndroid Build Coastguard Worker them. 356*795d594fSAndroid Build Coastguard Worker """ 357*795d594fSAndroid Build Coastguard Worker for arch_cache_path in _DexArchCachePaths(self._env_path): 358*795d594fSAndroid Build Coastguard Worker for file_path in os.listdir(arch_cache_path): 359*795d594fSAndroid Build Coastguard Worker file_path = '{0}/{1}'.format(arch_cache_path, file_path) 360*795d594fSAndroid Build Coastguard Worker if os.path.isfile(file_path): 361*795d594fSAndroid Build Coastguard Worker os.unlink(file_path) 362*795d594fSAndroid Build Coastguard Worker 363*795d594fSAndroid Build Coastguard Worker 364*795d594fSAndroid Build Coastguard Workerclass DeviceTestEnv(ITestEnv): 365*795d594fSAndroid Build Coastguard Worker """Device test environment. Concrete implementation of ITestEnv. 366*795d594fSAndroid Build Coastguard Worker 367*795d594fSAndroid Build Coastguard Worker For methods documentation see base class. 368*795d594fSAndroid Build Coastguard Worker """ 369*795d594fSAndroid Build Coastguard Worker 370*795d594fSAndroid Build Coastguard Worker def __init__(self, directory_prefix, cleanup=True, logfile_path=None, 371*795d594fSAndroid Build Coastguard Worker timeout=60, specific_device=None): 372*795d594fSAndroid Build Coastguard Worker """Constructor. 373*795d594fSAndroid Build Coastguard Worker 374*795d594fSAndroid Build Coastguard Worker Args: 375*795d594fSAndroid Build Coastguard Worker directory_prefix: string, prefix for environment directory name. 376*795d594fSAndroid Build Coastguard Worker cleanup: boolean, if True remove test directory in destructor. 377*795d594fSAndroid Build Coastguard Worker logfile_path: string, can be used to specify custom logfile location. 378*795d594fSAndroid Build Coastguard Worker timeout: int, seconds, time to wait for single test run to finish. 379*795d594fSAndroid Build Coastguard Worker specific_device: string, serial number of device to use. 380*795d594fSAndroid Build Coastguard Worker """ 381*795d594fSAndroid Build Coastguard Worker self._cleanup = cleanup 382*795d594fSAndroid Build Coastguard Worker self._timeout = timeout 383*795d594fSAndroid Build Coastguard Worker self._specific_device = specific_device 384*795d594fSAndroid Build Coastguard Worker self._host_env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix) 385*795d594fSAndroid Build Coastguard Worker if logfile_path is None: 386*795d594fSAndroid Build Coastguard Worker self._logfile = open('{0}/log'.format(self._host_env_path), 'w+') 387*795d594fSAndroid Build Coastguard Worker else: 388*795d594fSAndroid Build Coastguard Worker self._logfile = open(logfile_path, 'w+') 389*795d594fSAndroid Build Coastguard Worker self._device_env_path = '{0}/{1}'.format( 390*795d594fSAndroid Build Coastguard Worker DEVICE_TMP_PATH, os.path.basename(self._host_env_path)) 391*795d594fSAndroid Build Coastguard Worker self._shell_env = os.environ.copy() 392*795d594fSAndroid Build Coastguard Worker 393*795d594fSAndroid Build Coastguard Worker self._AdbMkdir('{0}/dalvik-cache'.format(self._device_env_path)) 394*795d594fSAndroid Build Coastguard Worker for arch_cache_path in _DexArchCachePaths(self._device_env_path): 395*795d594fSAndroid Build Coastguard Worker self._AdbMkdir(arch_cache_path) 396*795d594fSAndroid Build Coastguard Worker 397*795d594fSAndroid Build Coastguard Worker def __del__(self): 398*795d594fSAndroid Build Coastguard Worker if self._cleanup: 399*795d594fSAndroid Build Coastguard Worker shutil.rmtree(self._host_env_path) 400*795d594fSAndroid Build Coastguard Worker check_call(shlex.split( 401*795d594fSAndroid Build Coastguard Worker 'adb shell if [ -d "{0}" ]; then rm -rf "{0}"; fi' 402*795d594fSAndroid Build Coastguard Worker .format(self._device_env_path))) 403*795d594fSAndroid Build Coastguard Worker 404*795d594fSAndroid Build Coastguard Worker def CreateFile(self, name=None): 405*795d594fSAndroid Build Coastguard Worker with NamedTemporaryFile(mode='w') as temp_file: 406*795d594fSAndroid Build Coastguard Worker self._AdbPush(temp_file.name, self._device_env_path) 407*795d594fSAndroid Build Coastguard Worker if name is None: 408*795d594fSAndroid Build Coastguard Worker name = os.path.basename(temp_file.name) 409*795d594fSAndroid Build Coastguard Worker return '{0}/{1}'.format(self._device_env_path, name) 410*795d594fSAndroid Build Coastguard Worker 411*795d594fSAndroid Build Coastguard Worker def WriteLines(self, file_path, lines): 412*795d594fSAndroid Build Coastguard Worker with NamedTemporaryFile(mode='w') as temp_file: 413*795d594fSAndroid Build Coastguard Worker temp_file.writelines('{0}\n'.format(line) for line in lines) 414*795d594fSAndroid Build Coastguard Worker temp_file.flush() 415*795d594fSAndroid Build Coastguard Worker self._AdbPush(temp_file.name, file_path) 416*795d594fSAndroid Build Coastguard Worker return 417*795d594fSAndroid Build Coastguard Worker 418*795d594fSAndroid Build Coastguard Worker def _ExtractPid(self, brief_log_line): 419*795d594fSAndroid Build Coastguard Worker """Extracts PID from a single logcat line in brief format.""" 420*795d594fSAndroid Build Coastguard Worker pid_start_idx = brief_log_line.find('(') + 2 421*795d594fSAndroid Build Coastguard Worker if pid_start_idx == -1: 422*795d594fSAndroid Build Coastguard Worker return None 423*795d594fSAndroid Build Coastguard Worker pid_end_idx = brief_log_line.find(')', pid_start_idx) 424*795d594fSAndroid Build Coastguard Worker if pid_end_idx == -1: 425*795d594fSAndroid Build Coastguard Worker return None 426*795d594fSAndroid Build Coastguard Worker return brief_log_line[pid_start_idx:pid_end_idx] 427*795d594fSAndroid Build Coastguard Worker 428*795d594fSAndroid Build Coastguard Worker def _ExtractSeverity(self, brief_log_line): 429*795d594fSAndroid Build Coastguard Worker """Extracts LogSeverity from a single logcat line in brief format.""" 430*795d594fSAndroid Build Coastguard Worker if not brief_log_line: 431*795d594fSAndroid Build Coastguard Worker return None 432*795d594fSAndroid Build Coastguard Worker return LogSeverity.FromSymbol(brief_log_line[0]) 433*795d594fSAndroid Build Coastguard Worker 434*795d594fSAndroid Build Coastguard Worker def RunCommand(self, cmd, log_severity=LogSeverity.ERROR): 435*795d594fSAndroid Build Coastguard Worker self._EmptyDexCache() 436*795d594fSAndroid Build Coastguard Worker env_vars_cmd = 'ANDROID_DATA={0} ANDROID_LOG_TAGS=*:i'.format( 437*795d594fSAndroid Build Coastguard Worker self._device_env_path) 438*795d594fSAndroid Build Coastguard Worker adb_cmd = ['adb'] 439*795d594fSAndroid Build Coastguard Worker if self._specific_device: 440*795d594fSAndroid Build Coastguard Worker adb_cmd += ['-s', self._specific_device] 441*795d594fSAndroid Build Coastguard Worker logcat_cmd = adb_cmd + ['logcat', '-v', 'brief', '-s', '-b', 'main', 442*795d594fSAndroid Build Coastguard Worker '-T', '1', 'dex2oat:*', 'dex2oatd:*'] 443*795d594fSAndroid Build Coastguard Worker logcat_proc = Popen(logcat_cmd, stdout=PIPE, stderr=STDOUT, 444*795d594fSAndroid Build Coastguard Worker universal_newlines=True) 445*795d594fSAndroid Build Coastguard Worker cmd_str = CommandListToCommandString(cmd) 446*795d594fSAndroid Build Coastguard Worker # Print PID of the shell and exec command. We later retrieve this PID and 447*795d594fSAndroid Build Coastguard Worker # use it to filter dex2oat logs, keeping those with matching parent PID. 448*795d594fSAndroid Build Coastguard Worker device_cmd = ('echo $$ && ' + env_vars_cmd + ' exec ' + cmd_str) 449*795d594fSAndroid Build Coastguard Worker cmd = adb_cmd + ['shell', device_cmd] 450*795d594fSAndroid Build Coastguard Worker (output, _, retcode) = RunCommandForOutput(cmd, self._shell_env, PIPE, 451*795d594fSAndroid Build Coastguard Worker STDOUT, self._timeout) 452*795d594fSAndroid Build Coastguard Worker # We need to make sure to only kill logcat once all relevant logs arrive. 453*795d594fSAndroid Build Coastguard Worker # Sleep is used for simplicity. 454*795d594fSAndroid Build Coastguard Worker time.sleep(0.5) 455*795d594fSAndroid Build Coastguard Worker logcat_proc.kill() 456*795d594fSAndroid Build Coastguard Worker end_of_first_line = output.find('\n') 457*795d594fSAndroid Build Coastguard Worker if end_of_first_line != -1: 458*795d594fSAndroid Build Coastguard Worker parent_pid = output[:end_of_first_line] 459*795d594fSAndroid Build Coastguard Worker output = output[end_of_first_line + 1:] 460*795d594fSAndroid Build Coastguard Worker logcat_output, _ = logcat_proc.communicate() 461*795d594fSAndroid Build Coastguard Worker logcat_lines = logcat_output.splitlines(keepends=True) 462*795d594fSAndroid Build Coastguard Worker dex2oat_pids = [] 463*795d594fSAndroid Build Coastguard Worker for line in logcat_lines: 464*795d594fSAndroid Build Coastguard Worker # Dex2oat was started by our runtime instance. 465*795d594fSAndroid Build Coastguard Worker if 'Running dex2oat (parent PID = ' + parent_pid in line: 466*795d594fSAndroid Build Coastguard Worker dex2oat_pids.append(self._ExtractPid(line)) 467*795d594fSAndroid Build Coastguard Worker break 468*795d594fSAndroid Build Coastguard Worker if dex2oat_pids: 469*795d594fSAndroid Build Coastguard Worker for line in logcat_lines: 470*795d594fSAndroid Build Coastguard Worker if (self._ExtractPid(line) in dex2oat_pids and 471*795d594fSAndroid Build Coastguard Worker self._ExtractSeverity(line) >= log_severity): 472*795d594fSAndroid Build Coastguard Worker output += line 473*795d594fSAndroid Build Coastguard Worker _LogCmdOutput(self._logfile, cmd, output, retcode) 474*795d594fSAndroid Build Coastguard Worker return (output, retcode) 475*795d594fSAndroid Build Coastguard Worker 476*795d594fSAndroid Build Coastguard Worker @property 477*795d594fSAndroid Build Coastguard Worker def logfile(self): 478*795d594fSAndroid Build Coastguard Worker return self._logfile 479*795d594fSAndroid Build Coastguard Worker 480*795d594fSAndroid Build Coastguard Worker def PushClasspath(self, classpath): 481*795d594fSAndroid Build Coastguard Worker """Push classpath to on-device test directory. 482*795d594fSAndroid Build Coastguard Worker 483*795d594fSAndroid Build Coastguard Worker Classpath can contain multiple colon separated file paths, each file is 484*795d594fSAndroid Build Coastguard Worker pushed. Returns analogous classpath with paths valid on device. 485*795d594fSAndroid Build Coastguard Worker 486*795d594fSAndroid Build Coastguard Worker Args: 487*795d594fSAndroid Build Coastguard Worker classpath: string, classpath in format 'a/b/c:d/e/f'. 488*795d594fSAndroid Build Coastguard Worker Returns: 489*795d594fSAndroid Build Coastguard Worker string, classpath valid on device. 490*795d594fSAndroid Build Coastguard Worker """ 491*795d594fSAndroid Build Coastguard Worker paths = classpath.split(':') 492*795d594fSAndroid Build Coastguard Worker device_paths = [] 493*795d594fSAndroid Build Coastguard Worker for path in paths: 494*795d594fSAndroid Build Coastguard Worker device_paths.append('{0}/{1}'.format( 495*795d594fSAndroid Build Coastguard Worker self._device_env_path, os.path.basename(path))) 496*795d594fSAndroid Build Coastguard Worker self._AdbPush(path, self._device_env_path) 497*795d594fSAndroid Build Coastguard Worker return ':'.join(device_paths) 498*795d594fSAndroid Build Coastguard Worker 499*795d594fSAndroid Build Coastguard Worker def _AdbPush(self, what, where): 500*795d594fSAndroid Build Coastguard Worker check_call(shlex.split('adb push "{0}" "{1}"'.format(what, where)), 501*795d594fSAndroid Build Coastguard Worker stdout=self._logfile, stderr=self._logfile) 502*795d594fSAndroid Build Coastguard Worker 503*795d594fSAndroid Build Coastguard Worker def _AdbMkdir(self, path): 504*795d594fSAndroid Build Coastguard Worker check_call(shlex.split('adb shell mkdir "{0}" -p'.format(path)), 505*795d594fSAndroid Build Coastguard Worker stdout=self._logfile, stderr=self._logfile) 506*795d594fSAndroid Build Coastguard Worker 507*795d594fSAndroid Build Coastguard Worker def _EmptyDexCache(self): 508*795d594fSAndroid Build Coastguard Worker """Empties dex cache.""" 509*795d594fSAndroid Build Coastguard Worker for arch_cache_path in _DexArchCachePaths(self._device_env_path): 510*795d594fSAndroid Build Coastguard Worker cmd = 'adb shell if [ -d "{0}" ]; then rm -f "{0}"/*; fi'.format( 511*795d594fSAndroid Build Coastguard Worker arch_cache_path) 512*795d594fSAndroid Build Coastguard Worker check_call(shlex.split(cmd), stdout=self._logfile, stderr=self._logfile) 513