1#
2# Copyright (C) 2022 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import sys, os, shutil, shlex, re, subprocess, glob
17from argparse import ArgumentParser, BooleanOptionalAction, Namespace
18from os import path
19from os.path import isfile, isdir, basename
20from subprocess import check_output, DEVNULL, PIPE, STDOUT
21from tempfile import NamedTemporaryFile
22from testrunner import env
23from typing import List
24
25COLOR = (os.environ.get("LUCI_CONTEXT") == None)  # Disable colors on LUCI.
26COLOR_BLUE = '\033[94m' if COLOR else ''
27COLOR_GREEN = '\033[92m' if COLOR else ''
28COLOR_NORMAL = '\033[0m' if COLOR else ''
29COLOR_RED = '\033[91m' if COLOR else ''
30
31def parse_args(argv):
32  argp, opt_bool = ArgumentParser(), BooleanOptionalAction
33  argp.add_argument("--64", dest="is64", action="store_true")
34  argp.add_argument("--O", action="store_true")
35  argp.add_argument("--Xcompiler-option", default=[], action="append")
36  argp.add_argument("--add-libdir-argument", action="store_true")
37  argp.add_argument("--android-art-root", default="/apex/com.android.art")
38  argp.add_argument("--android-i18n-root", default="/apex/com.android.i18n")
39  argp.add_argument("--android-log-tags", default="*:i")
40  argp.add_argument("--android-root", default="/system")
41  argp.add_argument("--android-runtime-option", default=[], action="append")
42  argp.add_argument("--android-tzdata-root", default="/apex/com.android.tzdata")
43  argp.add_argument("--app-image", default=True, action=opt_bool)
44  argp.add_argument("--baseline", action="store_true")
45  argp.add_argument("--bionic", action="store_true")
46  argp.add_argument("--boot", default="")
47  argp.add_argument("--chroot", default="")
48  argp.add_argument("--compiler-only-option", default=[], action="append")
49  argp.add_argument("--create-runner", action="store_true")
50  argp.add_argument("--diff-min-log-tag", default="E")
51  argp.add_argument("--debug", action="store_true")
52  argp.add_argument("--debug-agent")
53  argp.add_argument("--debug-wrap-agent", action="store_true")
54  argp.add_argument("--dex2oat-dm", action="store_true")
55  argp.add_argument(
56      "--dex2oat-rt-timeout", type=int,
57      default=360)  # The *hard* timeout.  6 min.
58  argp.add_argument(
59      "--dex2oat-timeout", type=int, default=300)  # The "soft" timeout.  5 min.
60  argp.add_argument("--dry-run", action="store_true")
61  argp.add_argument("--experimental", default=[], action="append")
62  argp.add_argument("--external-log-tags", action="store_true")
63  argp.add_argument("--gc-stress", action="store_true")
64  argp.add_argument("--gdb", action="store_true")
65  argp.add_argument("--gdb-arg", default=[], action="append")
66  argp.add_argument("--gdb-dex2oat", action="store_true")
67  argp.add_argument("--gdb-dex2oat-args")
68  argp.add_argument("--gdbserver", action="store_true")
69  argp.add_argument("--gdbserver-bin")
70  argp.add_argument("--gdbserver-port", default=":5039")
71  argp.add_argument("--host", action="store_true")
72  argp.add_argument("--image", default=True, action=opt_bool)
73  argp.add_argument("--instruction-set-features", default="")
74  argp.add_argument("--interpreter", action="store_true")
75  argp.add_argument("--switch-interpreter", action="store_true")
76  argp.add_argument("--invoke-with", default=[], action="append")
77  argp.add_argument("--jit", action="store_true")
78  argp.add_argument("--jvm", action="store_true")
79  argp.add_argument("--jvmti", action="store_true")
80  argp.add_argument("--jvmti-field-stress", action="store_true")
81  argp.add_argument("--jvmti-redefine-stress", action="store_true")
82  argp.add_argument("--jvmti-step-stress", action="store_true")
83  argp.add_argument("--jvmti-trace-stress", action="store_true")
84  argp.add_argument("--lib", default="")
85  argp.add_argument("--optimize", default=True, action=opt_bool)
86  argp.add_argument("--prebuild", default=True, action=opt_bool)
87  argp.add_argument("--profile", action="store_true")
88  argp.add_argument("--random-profile", action="store_true")
89  argp.add_argument("--relocate", default=False, action=opt_bool)
90  argp.add_argument("--runtime-dm", action="store_true")
91  argp.add_argument("--runtime-option", default=[], action="append")
92  argp.add_argument("--secondary", action="store_true")
93  argp.add_argument("--secondary-app-image", default=True, action=opt_bool)
94  argp.add_argument("--secondary-class-loader-context", default="")
95  argp.add_argument("--secondary-compilation", default=True, action=opt_bool)
96  argp.add_argument("--simpleperf", action="store_true")
97  argp.add_argument("--sync", action="store_true")
98  argp.add_argument("--testlib", default=[], action="append")
99  argp.add_argument("--timeout", default=0, type=int)
100  argp.add_argument("--vdex", action="store_true")
101  argp.add_argument("--vdex-arg", default=[], action="append")
102  argp.add_argument("--vdex-filter", default="")
103  argp.add_argument("--verify", default=True, action=opt_bool)
104  argp.add_argument("--verify-soft-fail", action="store_true")
105  argp.add_argument("--with-agent", default=[], action="append")
106  argp.add_argument("--zygote", action="store_true")
107  argp.add_argument("--test_args", default=[], action="append")
108  argp.add_argument("--stdout_file", default="")
109  argp.add_argument("--stderr_file", default="")
110  argp.add_argument("--main", default="Main")
111  argp.add_argument("--expected_exit_code", default=0)
112
113  # Python parser requires the format --key=--value, since without the equals symbol
114  # it looks like the required value has been omitted and there is just another flag.
115  # For example, '--args --foo --host --64' will become '--arg=--foo --host --64'
116  # because otherwise the --args is missing its value and --foo is unknown argument.
117  for i, arg in reversed(list(enumerate(argv))):
118    if arg in [
119        "--args", "--runtime-option", "--android-runtime-option",
120        "-Xcompiler-option", "--compiler-only-option"
121    ]:
122      argv[i] += "=" + argv.pop(i + 1)
123
124  # Accept single-dash arguments as if they were double-dash arguments.
125  # For exmpample, '-Xcompiler-option' becomes '--Xcompiler-option'
126  # became single-dash can be used only with single-letter arguments.
127  for i, arg in list(enumerate(argv)):
128    if arg.startswith("-") and not arg.startswith("--"):
129      argv[i] = "-" + arg
130    if arg == "--":
131      break
132
133  return argp.parse_args(argv)
134
135def get_target_arch(is64: bool) -> str:
136  # We may build for two arches. Get the one with the expected bitness.
137  arches = [a for a in [env.TARGET_ARCH, env.TARGET_2ND_ARCH] if a]
138  assert len(arches) > 0, "TARGET_ARCH/TARGET_2ND_ARCH not set"
139  if is64:
140    arches = [a for a in arches if a.endswith("64")]
141    assert len(arches) == 1, f"Can not find (unique) 64-bit arch in {arches}"
142  else:
143    arches = [a for a in arches if not a.endswith("64")]
144    assert len(arches) == 1, f"Can not find (unique) 32-bit arch in {arches}"
145  return arches[0]
146
147# Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
148# because that's what we use for compiling the boot.art image.
149# It may contain additional modules from TEST_CORE_JARS.
150bpath_modules = ("core-oj core-libart okhttp bouncycastle apache-xml core-icu4j"
151                 " conscrypt")
152
153
154# Helper function to construct paths for apex modules (for both -Xbootclasspath and
155# -Xbootclasspath-location).
156def get_apex_bootclasspath_impl(bpath_prefix: str):
157  bpath_separator = ""
158  bpath = ""
159  bpath_jar = ""
160  for bpath_module in bpath_modules.split(" "):
161    apex_module = "com.android.art"
162    if bpath_module == "conscrypt":
163      apex_module = "com.android.conscrypt"
164    if bpath_module == "core-icu4j":
165      apex_module = "com.android.i18n"
166    bpath_jar = f"/apex/{apex_module}/javalib/{bpath_module}.jar"
167    bpath += f"{bpath_separator}{bpath_prefix}{bpath_jar}"
168    bpath_separator = ":"
169  return bpath
170
171
172# Gets a -Xbootclasspath paths with the apex modules.
173def get_apex_bootclasspath(host: bool):
174  bpath_prefix = ""
175
176  if host:
177    bpath_prefix = os.environ["ANDROID_HOST_OUT"]
178
179  return get_apex_bootclasspath_impl(bpath_prefix)
180
181
182# Gets a -Xbootclasspath-location paths with the apex modules.
183def get_apex_bootclasspath_locations(host: bool):
184  bpath_location_prefix = ""
185
186  if host:
187    ANDROID_BUILD_TOP=os.environ["ANDROID_BUILD_TOP"]
188    ANDROID_HOST_OUT=os.environ["ANDROID_HOST_OUT"]
189    if ANDROID_HOST_OUT[0:len(ANDROID_BUILD_TOP)+1] == f"{ANDROID_BUILD_TOP}/":
190      bpath_location_prefix=ANDROID_HOST_OUT[len(ANDROID_BUILD_TOP)+1:]
191    else:
192      print(f"ANDROID_BUILD_TOP/ is not a prefix of ANDROID_HOST_OUT"\
193            "\nANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"\
194            "\nANDROID_HOST_OUT={ANDROID_HOST_OUT}")
195      sys.exit(1)
196
197  return get_apex_bootclasspath_impl(bpath_location_prefix)
198
199
200def default_run(ctx, args, **kwargs):
201  # Clone the args so we can modify them without affecting args in the caller.
202  args = Namespace(**vars(args))
203
204  # Overwrite args based on the named parameters.
205  # E.g. the caller can do `default_run(args, jvmti=True)` to modify args.jvmti.
206  for name, new_value in kwargs.items():
207    old_value = getattr(args, name)
208    assert isinstance(new_value, old_value.__class__), name + " should have type " + str(old_value.__class__)
209    if isinstance(old_value, list):
210      setattr(args, name, old_value + new_value)  # Lists get merged.
211    else:
212      setattr(args, name, new_value)
213
214  ON_VM = os.environ.get("ART_TEST_ON_VM")
215
216  # Store copy of stdout&stderr of command in files so that we can diff them later.
217  # This may run under 'adb shell' so we are limited only to 'sh' shell feature set.
218  def tee(cmd: str):
219    # 'tee' works on stdout only, so we need to temporarily swap stdout and stderr.
220    cmd = f"({cmd} | tee -a {DEX_LOCATION}/{basename(args.stdout_file)}) 3>&1 1>&2 2>&3"
221    cmd = f"({cmd} | tee -a {DEX_LOCATION}/{basename(args.stderr_file)}) 3>&1 1>&2 2>&3"
222    return f"set -o pipefail; {cmd}"  # Use exit code of first failure in piped command.
223
224  local_path = os.path.dirname(__file__)
225
226  ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
227  ANDROID_DATA = os.environ.get("ANDROID_DATA")
228  ANDROID_HOST_OUT = os.environ["ANDROID_HOST_OUT"]
229  ANDROID_LOG_TAGS = os.environ.get("ANDROID_LOG_TAGS", "")
230  ART_TIME_OUT_MULTIPLIER = int(os.environ.get("ART_TIME_OUT_MULTIPLIER", 1))
231  DEX2OAT = os.environ.get("DEX2OAT", "")
232  DEX_LOCATION = os.environ["DEX_LOCATION"]
233  JAVA = os.environ.get("JAVA")
234  OUT_DIR = os.environ.get("OUT_DIR")
235  PATH = os.environ.get("PATH", "")
236  SANITIZE_HOST = os.environ.get("SANITIZE_HOST", "")
237  TEST_NAME = os.environ["TEST_NAME"]
238
239  assert ANDROID_BUILD_TOP, "Did you forget to run `lunch`?"
240
241  ANDROID_ROOT = args.android_root
242  ANDROID_ART_ROOT = args.android_art_root
243  ANDROID_I18N_ROOT = args.android_i18n_root
244  ANDROID_TZDATA_ROOT = args.android_tzdata_root
245  ARCHITECTURES_32 = "(arm|x86|none)"
246  ARCHITECTURES_64 = "(arm64|x86_64|riscv64|none)"
247  ARCHITECTURES_PATTERN = ARCHITECTURES_32
248  GET_DEVICE_ISA_BITNESS_FLAG = "--32"
249  BOOT_IMAGE = args.boot
250  CHROOT = args.chroot
251  COMPILE_FLAGS = ""
252  DALVIKVM = "dalvikvm32"
253  DEBUGGER = "n"
254  WITH_AGENT = args.with_agent
255  DEBUGGER_AGENT = args.debug_agent
256  WRAP_DEBUGGER_AGENT = args.debug_wrap_agent
257  DEX2OAT_NDEBUG_BINARY = "dex2oat32"
258  DEX2OAT_DEBUG_BINARY = "dex2oatd32"
259  EXPERIMENTAL = args.experimental
260  FALSE_BIN = "false"
261  FLAGS = ""
262  ANDROID_FLAGS = ""
263  GDB = ""
264  GDB_ARGS = ""
265  GDB_DEX2OAT_EXTRA_ARGS = ""
266  GDBSERVER_DEVICE = "gdbserver"
267  GDBSERVER_HOST = "gdbserver"
268  HAVE_IMAGE = args.image
269  HOST = args.host
270  BIONIC = args.bionic
271  CREATE_ANDROID_ROOT = False
272  INTERPRETER = args.interpreter
273  SWITCH_INTERPRETER = args.switch_interpreter
274  JIT = args.jit
275  INVOKE_WITH = " ".join(args.invoke_with)
276  USE_JVMTI = args.jvmti
277  IS_JVMTI_TEST = False
278  ADD_LIBDIR_ARGUMENTS = args.add_libdir_argument
279  SUFFIX64 = ""
280  ISA = "x86"
281  LIBRARY_DIRECTORY = "lib"
282  TEST_DIRECTORY = "nativetest"
283  MAIN = args.main
284  OPTIMIZE = args.optimize
285  PREBUILD = args.prebuild
286  RELOCATE = args.relocate
287  SECONDARY_DEX = ""
288  TIME_OUT = "timeout"  # "n" (disabled), "timeout" (use timeout), "gdb" (use gdb)
289  TIMEOUT_DUMPER = "signal_dumper"
290  # Values in seconds.
291  TIME_OUT_EXTRA = 0
292  TIME_OUT_VALUE = args.timeout
293  USE_GDB = args.gdb
294  USE_GDBSERVER = args.gdbserver
295  GDBSERVER_PORT = args.gdbserver_port
296  USE_GDB_DEX2OAT = args.gdb_dex2oat
297  USE_JVM = args.jvm
298  VERIFY = "y" if args.verify else "n"  # y=yes,n=no,s=softfail
299  ZYGOTE = ""
300  DEX_VERIFY = ""
301  INSTRUCTION_SET_FEATURES = args.instruction_set_features
302  ARGS = ""
303  VDEX_ARGS = ""
304  DRY_RUN = args.dry_run
305  TEST_VDEX = args.vdex
306  TEST_DEX2OAT_DM = args.dex2oat_dm
307  TEST_RUNTIME_DM = args.runtime_dm
308  TEST_IS_NDEBUG = args.O
309  APP_IMAGE = args.app_image
310  SECONDARY_APP_IMAGE = args.secondary_app_image
311  SECONDARY_CLASS_LOADER_CONTEXT = args.secondary_class_loader_context
312  SECONDARY_COMPILATION = args.secondary_compilation
313  JVMTI_STRESS = False
314  JVMTI_REDEFINE_STRESS = args.jvmti_redefine_stress
315  JVMTI_STEP_STRESS = args.jvmti_step_stress
316  JVMTI_FIELD_STRESS = args.jvmti_field_stress
317  JVMTI_TRACE_STRESS = args.jvmti_trace_stress
318  PROFILE = args.profile
319  RANDOM_PROFILE = args.random_profile
320  DEX2OAT_TIMEOUT = args.dex2oat_timeout
321  DEX2OAT_RT_TIMEOUT = args.dex2oat_rt_timeout
322  CREATE_RUNNER = args.create_runner
323  INT_OPTS = ""
324  SIMPLEPERF = args.simpleperf
325  DEBUGGER_OPTS = ""
326  JVM_VERIFY_ARG = ""
327  LIB = args.lib
328
329  # if True, run 'sync' before dalvikvm to make sure all files from
330  # build step (e.g. dex2oat) were finished writing.
331  SYNC_BEFORE_RUN = args.sync
332
333  # When running a debug build, we want to run with all checks.
334  ANDROID_FLAGS += " -XX:SlowDebug=true"
335  # The same for dex2oatd, both prebuild and runtime-driven.
336  ANDROID_FLAGS += (" -Xcompiler-option --runtime-arg -Xcompiler-option "
337                    "-XX:SlowDebug=true")
338  COMPILER_FLAGS = "  --runtime-arg -XX:SlowDebug=true"
339
340  # Let the compiler and runtime know that we are running tests.
341  COMPILE_FLAGS += " --compile-art-test"
342  ANDROID_FLAGS += " -Xcompiler-option --compile-art-test"
343
344  if USE_JVMTI:
345    IS_JVMTI_TEST = True
346    # Secondary images block some tested behavior.
347    SECONDARY_APP_IMAGE = False
348  if args.gc_stress:
349    # Give an extra 20 mins if we are gc-stress.
350    TIME_OUT_EXTRA += 1200
351  for arg in args.testlib:
352    ARGS += f" {arg}"
353  for arg in args.test_args:
354    ARGS += f" {arg}"
355  for arg in args.compiler_only_option:
356    COMPILE_FLAGS += f" {arg}"
357  for arg in args.Xcompiler_option:
358    FLAGS += f" -Xcompiler-option {arg}"
359    COMPILE_FLAGS += f" {arg}"
360  if args.secondary:
361    SECONDARY_DEX = f":{DEX_LOCATION}/{TEST_NAME}-ex.jar"
362    # Enable cfg-append to make sure we get the dump for both dex files.
363    # (otherwise the runtime compilation of the secondary dex will overwrite
364    # the dump of the first one).
365    FLAGS += " -Xcompiler-option --dump-cfg-append"
366    COMPILE_FLAGS += " --dump-cfg-append"
367  for arg in args.android_runtime_option:
368    ANDROID_FLAGS += f" {arg}"
369  for arg in args.runtime_option:
370    FLAGS += f" {arg}"
371    if arg == "-Xmethod-trace":
372      # Method tracing can slow some tests down a lot.
373      TIME_OUT_EXTRA += 1200
374  if JVMTI_REDEFINE_STRESS:
375    # APP_IMAGE doesn't really work with jvmti redefine stress
376    SECONDARY_APP_IMAGE = False
377    JVMTI_STRESS = True
378  if JVMTI_REDEFINE_STRESS or JVMTI_STEP_STRESS or JVMTI_FIELD_STRESS or JVMTI_TRACE_STRESS:
379    USE_JVMTI = True
380    JVMTI_STRESS = True
381  if HOST:
382    ANDROID_ROOT = ANDROID_HOST_OUT
383    ANDROID_ART_ROOT = f"{ANDROID_HOST_OUT}/com.android.art"
384    ANDROID_I18N_ROOT = f"{ANDROID_HOST_OUT}/com.android.i18n"
385    ANDROID_TZDATA_ROOT = f"{ANDROID_HOST_OUT}/com.android.tzdata"
386    # On host, we default to using the symlink, as the PREFER_32BIT
387    # configuration is the only configuration building a 32bit version of
388    # dex2oat.
389    DEX2OAT_DEBUG_BINARY = "dex2oatd"
390    DEX2OAT_NDEBUG_BINARY = "dex2oat"
391  if BIONIC:
392    # We need to create an ANDROID_ROOT because currently we cannot create
393    # the frameworks/libcore with linux_bionic so we need to use the normal
394    # host ones which are in a different location.
395    CREATE_ANDROID_ROOT = True
396  if WITH_AGENT:
397    USE_JVMTI = True
398  if DEBUGGER_AGENT:
399    DEBUGGER = "agent"
400    USE_JVMTI = True
401    TIME_OUT = "n"
402  if args.debug:
403    USE_JVMTI = True
404    DEBUGGER = "y"
405    TIME_OUT = "n"
406  if args.gdbserver_bin:
407    arg = args.gdbserver_bin
408    GDBSERVER_HOST = arg
409    GDBSERVER_DEVICE = arg
410  if args.gdbserver or args.gdb or USE_GDB_DEX2OAT:
411    TIME_OUT = "n"
412  for arg in args.gdb_arg:
413    GDB_ARGS += f" {arg}"
414  if args.gdb_dex2oat_args:
415    for arg in args.gdb_dex2oat_args.split(";"):
416      GDB_DEX2OAT_EXTRA_ARGS += f'"{arg}" '
417  if args.zygote:
418    ZYGOTE = "-Xzygote"
419    print("Spawning from zygote")
420  if args.baseline:
421    FLAGS += " -Xcompiler-option --baseline"
422    COMPILE_FLAGS += " --baseline"
423  if args.verify_soft_fail:
424    VERIFY = "s"
425  if args.is64:
426    SUFFIX64 = "64"
427    ISA = "x86_64"
428    GDBSERVER_DEVICE = "gdbserver64"
429    DALVIKVM = "dalvikvm64"
430    LIBRARY_DIRECTORY = "lib64"
431    TEST_DIRECTORY = "nativetest64"
432    ARCHITECTURES_PATTERN = ARCHITECTURES_64
433    GET_DEVICE_ISA_BITNESS_FLAG = "--64"
434    DEX2OAT_NDEBUG_BINARY = "dex2oat64"
435    DEX2OAT_DEBUG_BINARY = "dex2oatd64"
436  if args.vdex_filter:
437    option = args.vdex_filter
438    VDEX_ARGS += f" --compiler-filter={option}"
439  if args.vdex_arg:
440    arg = args.vdex_arg
441    VDEX_ARGS += f" {arg}"
442
443# HACK: Force the use of `signal_dumper` on host.
444  if HOST or ON_VM:
445    TIME_OUT = "timeout"
446
447# If you change this, update the timeout in testrunner.py as well.
448  if not TIME_OUT_VALUE:
449    # 10 minutes is the default.
450    TIME_OUT_VALUE = 600
451
452    # For sanitized builds use a larger base.
453    # TODO: Consider sanitized target builds?
454    if SANITIZE_HOST != "":
455      TIME_OUT_VALUE = 1500  # 25 minutes.
456
457    TIME_OUT_VALUE += TIME_OUT_EXTRA
458
459# Escape hatch for slow hosts or devices. Accept an environment variable as a timeout factor.
460  if ART_TIME_OUT_MULTIPLIER:
461    TIME_OUT_VALUE *= ART_TIME_OUT_MULTIPLIER
462
463# The DEX_LOCATION with the chroot prefix, if any.
464  CHROOT_DEX_LOCATION = f"{CHROOT}{DEX_LOCATION}"
465
466  # If running on device, determine the ISA of the device.
467  if not HOST and not USE_JVM:
468    ISA = get_target_arch(args.is64)
469
470  if not USE_JVM:
471    FLAGS += f" {ANDROID_FLAGS}"
472    # we don't want to be trying to get adbconnections since the plugin might
473    # not have been built.
474    FLAGS += " -XjdwpProvider:none"
475    for feature in EXPERIMENTAL:
476      FLAGS += f" -Xexperimental:{feature} -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:{feature}"
477      COMPILE_FLAGS = f"{COMPILE_FLAGS} --runtime-arg -Xexperimental:{feature}"
478
479  if CREATE_ANDROID_ROOT:
480    ANDROID_ROOT = f"{DEX_LOCATION}/android-root"
481
482  if ZYGOTE == "":
483    if OPTIMIZE:
484      if VERIFY == "y":
485        DEX_OPTIMIZE = "-Xdexopt:verified"
486      else:
487        DEX_OPTIMIZE = "-Xdexopt:all"
488    else:
489      DEX_OPTIMIZE = "-Xdexopt:none"
490
491    if VERIFY == "y":
492      JVM_VERIFY_ARG = "-Xverify:all"
493    elif VERIFY == "s":
494      JVM_VERIFY_ARG = "Xverify:all"
495      DEX_VERIFY = "-Xverify:softfail"
496    else:  # VERIFY == "n"
497      DEX_VERIFY = "-Xverify:none"
498      JVM_VERIFY_ARG = "-Xverify:none"
499
500  if DEBUGGER == "y":
501    # Use this instead for ddms and connect by running 'ddms':
502    # DEBUGGER_OPTS="-XjdwpOptions=server=y,suspend=y -XjdwpProvider:adbconnection"
503    # TODO: add a separate --ddms option?
504
505    PORT = 12345
506    print("Waiting for jdb to connect:")
507    if not HOST:
508      print(f"    adb forward tcp:{PORT} tcp:{PORT}")
509    print(f"    jdb -attach localhost:{PORT}")
510    if not USE_JVM:
511      # Use the default libjdwp agent. Use --debug-agent to use a custom one.
512      DEBUGGER_OPTS = f"-agentpath:libjdwp.so=transport=dt_socket,address={PORT},server=y,suspend=y -XjdwpProvider:internal"
513    else:
514      DEBUGGER_OPTS = f"-agentlib:jdwp=transport=dt_socket,address={PORT},server=y,suspend=y"
515  elif DEBUGGER == "agent":
516    PORT = 12345
517    # TODO Support ddms connection and support target.
518    assert HOST, "--debug-agent not supported yet for target!"
519    AGENTPATH = DEBUGGER_AGENT
520    if WRAP_DEBUGGER_AGENT:
521      WRAPPROPS = f"{ANDROID_ROOT}/{LIBRARY_DIRECTORY}/libwrapagentpropertiesd.so"
522      if TEST_IS_NDEBUG:
523        WRAPPROPS = f"{ANDROID_ROOT}/{LIBRARY_DIRECTORY}/libwrapagentproperties.so"
524      AGENTPATH = f"{WRAPPROPS}={ANDROID_BUILD_TOP}/art/tools/libjdwp-compat.props,{AGENTPATH}"
525    print(f"Connect to localhost:{PORT}")
526    DEBUGGER_OPTS = f"-agentpath:{AGENTPATH}=transport=dt_socket,address={PORT},server=y,suspend=y"
527
528  for agent in WITH_AGENT:
529    FLAGS += f" -agentpath:{agent}"
530
531  if USE_JVMTI:
532    if not USE_JVM:
533      plugin = "libopenjdkjvmtid.so"
534      if TEST_IS_NDEBUG:
535        plugin = "libopenjdkjvmti.so"
536      # We used to add flags here that made the runtime debuggable but that is not
537      # needed anymore since the plugin can do it for us now.
538      FLAGS += f" -Xplugin:{plugin}"
539
540      # For jvmti tests, set the threshold of compilation to 1, so we jit early to
541      # provide better test coverage for jvmti + jit. This means we won't run
542      # the default --jit configuration but it is not too important test scenario for
543      # jvmti tests. This is art specific flag, so don't use it with jvm.
544      FLAGS += " -Xjitthreshold:1"
545
546# Add the libdir to the argv passed to the main function.
547  if ADD_LIBDIR_ARGUMENTS:
548    if HOST:
549      ARGS += f" {ANDROID_HOST_OUT}/{TEST_DIRECTORY}/"
550    else:
551      ARGS += f" /data/{TEST_DIRECTORY}/art/{ISA}/"
552  if IS_JVMTI_TEST:
553    agent = "libtiagentd.so"
554    lib = "tiagentd"
555    if TEST_IS_NDEBUG:
556      agent = "libtiagent.so"
557      lib = "tiagent"
558
559    ARGS += f" {lib}"
560    if USE_JVM:
561      FLAGS += f" -agentpath:{ANDROID_HOST_OUT}/nativetest64/{agent}={TEST_NAME},jvm"
562    else:
563      FLAGS += f" -agentpath:{agent}={TEST_NAME},art"
564
565  if JVMTI_STRESS:
566    agent = "libtistressd.so"
567    if TEST_IS_NDEBUG:
568      agent = "libtistress.so"
569
570    # Just give it a default start so we can always add ',' to it.
571    agent_args = "jvmti-stress"
572    if JVMTI_REDEFINE_STRESS:
573      # We really cannot do this on RI so don't both passing it in that case.
574      if not USE_JVM:
575        agent_args = f"{agent_args},redefine"
576    if JVMTI_FIELD_STRESS:
577      agent_args = f"{agent_args},field"
578    if JVMTI_STEP_STRESS:
579      agent_args = f"{agent_args},step"
580    if JVMTI_TRACE_STRESS:
581      agent_args = f"{agent_args},trace"
582    # In the future add onto this;
583    if USE_JVM:
584      FLAGS += f" -agentpath:{ANDROID_HOST_OUT}/nativetest64/{agent}={agent_args}"
585    else:
586      FLAGS += f" -agentpath:{agent}={agent_args}"
587
588  if USE_JVM:
589    ctx.export(
590      ANDROID_I18N_ROOT = ANDROID_I18N_ROOT,
591      DEX_LOCATION = DEX_LOCATION,
592      JAVA_HOME = os.environ["JAVA_HOME"],
593      LANG = "en_US.UTF-8",  # Needed to enable unicode and make the output is deterministic.
594      LD_LIBRARY_PATH = f"{ANDROID_HOST_OUT}/lib64",
595    )
596    # Some jvmti tests are flaky without -Xint on the RI.
597    if IS_JVMTI_TEST:
598      FLAGS += " -Xint"
599    # Xmx is necessary since we don't pass down the ART flags to JVM.
600    # We pass the classes2 path whether it's used (src-multidex) or not.
601    cmdline = f"{JAVA} {DEBUGGER_OPTS} {JVM_VERIFY_ARG} -Xmx256m -classpath classes:classes2 {FLAGS} {MAIN} {ARGS}"
602    ctx.run(tee(cmdline), expected_exit_code=args.expected_exit_code)
603    return
604
605  b_path = get_apex_bootclasspath(HOST)
606  b_path_locations = get_apex_bootclasspath_locations(HOST)
607
608  BCPEX = ""
609  if isfile(f"{TEST_NAME}-bcpex.jar"):
610    BCPEX = f":{DEX_LOCATION}/{TEST_NAME}-bcpex.jar"
611
612  # Pass down the bootclasspath
613  FLAGS += f" -Xbootclasspath:{b_path}{BCPEX}"
614  FLAGS += f" -Xbootclasspath-locations:{b_path_locations}{BCPEX}"
615  COMPILE_FLAGS += f" --runtime-arg -Xbootclasspath:{b_path}"
616  COMPILE_FLAGS += f" --runtime-arg -Xbootclasspath-locations:{b_path_locations}"
617
618  if not HAVE_IMAGE:
619    # Disable image dex2oat - this will forbid the runtime to patch or compile an image.
620    FLAGS += " -Xnoimage-dex2oat"
621
622    # We'll abuse a second flag here to test different behavior. If --relocate, use the
623    # existing image - relocation will fail as patching is disallowed. If --no-relocate,
624    # pass a non-existent image - compilation will fail as dex2oat is disallowed.
625    if not RELOCATE:
626      BOOT_IMAGE = "/system/non-existent/boot.art"
627    # App images cannot be generated without a boot image.
628    APP_IMAGE = False
629  DALVIKVM_BOOT_OPT = f"-Ximage:{BOOT_IMAGE}"
630
631  if USE_GDB_DEX2OAT:
632    assert HOST, "The --gdb-dex2oat option is not yet implemented for target."
633
634  assert not USE_GDBSERVER, "Not supported"
635  if USE_GDB:
636    if not HOST:
637      # We might not have any hostname resolution if we are using a chroot.
638      GDB = f"{GDBSERVER_DEVICE} --no-startup-with-shell 127.0.0.1{GDBSERVER_PORT}"
639    else:
640      GDB = "gdb"
641      GDB_ARGS += f" -d '{ANDROID_BUILD_TOP}' --args {DALVIKVM}"
642
643  if SWITCH_INTERPRETER:
644    # run on the slow switch-interpreter enabled with -Xint
645    INT_OPTS += " -Xint"
646
647  if INTERPRETER:
648    # run on Nterp the fast interpreter, not the slow switch-interpreter enabled with -Xint
649    INT_OPTS += " -Xusejit:false"
650
651  if JIT:
652    INT_OPTS += " -Xusejit:true"
653  else:
654    INT_OPTS += " -Xusejit:false"
655
656  if INTERPRETER or SWITCH_INTERPRETER or JIT:
657    if VERIFY == "y":
658      INT_OPTS += " -Xcompiler-option --compiler-filter=verify"
659      COMPILE_FLAGS += " --compiler-filter=verify"
660    elif VERIFY == "s":
661      INT_OPTS += " -Xcompiler-option --compiler-filter=verify"
662      COMPILE_FLAGS += " --compiler-filter=verify"
663      DEX_VERIFY = f"{DEX_VERIFY} -Xverify:softfail"
664    else:  # VERIFY == "n"
665      INT_OPTS += " -Xcompiler-option --compiler-filter=assume-verified"
666      COMPILE_FLAGS += " --compiler-filter=assume-verified"
667      DEX_VERIFY = f"{DEX_VERIFY} -Xverify:none"
668
669  JNI_OPTS = "-Xjnigreflimit:512 -Xcheck:jni"
670
671  COMPILE_FLAGS += " --runtime-arg -Xnorelocate"
672  if RELOCATE:
673    FLAGS += " -Xrelocate"
674  else:
675    FLAGS += " -Xnorelocate"
676
677  if BIONIC and not ON_VM:
678    # This is the location that soong drops linux_bionic builds. Despite being
679    # called linux_bionic-x86 the build is actually amd64 (x86_64) only.
680    assert path.exists(f"{OUT_DIR}/soong/host/linux_bionic-x86"), (
681        "linux_bionic-x86 target doesn't seem to have been built!")
682    # Set TIMEOUT_DUMPER manually so it works even with apex's
683    TIMEOUT_DUMPER = f"{OUT_DIR}/soong/host/linux_bionic-x86/bin/signal_dumper"
684
685  # Prevent test from silently falling back to interpreter in no-prebuild mode. This happens
686  # when DEX_LOCATION path is too long, because vdex/odex filename is constructed by taking
687  # full path to dex, stripping leading '/', appending '@classes.vdex' and changing every
688  # remaining '/' into '@'.
689  if HOST:
690    max_filename_size = int(check_output(f"getconf NAME_MAX {DEX_LOCATION}", shell=True))
691  else:
692    # There is no getconf on device, fallback to standard value.
693    # See NAME_MAX in kernel <linux/limits.h>
694    max_filename_size = 255
695  # Compute VDEX_NAME.
696  DEX_LOCATION_STRIPPED = DEX_LOCATION.lstrip("/")
697  VDEX_NAME = f"{DEX_LOCATION_STRIPPED}@{TEST_NAME}.jar@classes.vdex".replace(
698      "/", "@")
699  assert len(VDEX_NAME) <= max_filename_size, "Dex location path too long"
700
701  if HOST:
702    # On host, run binaries (`dex2oat(d)`, `dalvikvm`, `profman`) from the `bin`
703    # directory under the "Android Root" (usually `out/host/linux-x86`).
704    #
705    # TODO(b/130295968): Adjust this if/when ART host artifacts are installed
706    # under the ART root (usually `out/host/linux-x86/com.android.art`).
707    ANDROID_ART_BIN_DIR = f"{ANDROID_ROOT}/bin"
708  else:
709    # On target, run binaries (`dex2oat(d)`, `dalvikvm`, `profman`) from the ART
710    # APEX's `bin` directory. This means the linker will observe the ART APEX
711    # linker configuration file (`/apex/com.android.art/etc/ld.config.txt`) for
712    # these binaries.
713    ANDROID_ART_BIN_DIR = f"{ANDROID_ART_ROOT}/bin"
714
715  profman_cmdline = "true"
716  dex2oat_cmdline = "true"
717  vdex_cmdline = "true"
718  dm_cmdline = "true"
719  mkdir_locations = f"{DEX_LOCATION}/dalvik-cache/{ISA}"
720  strip_cmdline = "true"
721  sync_cmdline = "true"
722  linkroot_cmdline = "true"
723  linkroot_overlay_cmdline = "true"
724
725  def linkdirs(host_out: str, root: str):
726    dirs = list(filter(os.path.isdir, glob.glob(os.path.join(host_out, "*"))))
727    # Also create a link for the boot image.
728    dirs.append(f"{ANDROID_HOST_OUT}/apex/art_boot_images")
729    return " && ".join(f"ln -sf {dir} {root}" for dir in dirs)
730
731  if CREATE_ANDROID_ROOT:
732    mkdir_locations += f" {ANDROID_ROOT}"
733    linkroot_cmdline = linkdirs(ANDROID_HOST_OUT, ANDROID_ROOT)
734    if BIONIC:
735      # TODO Make this overlay more generic.
736      linkroot_overlay_cmdline = linkdirs(
737          f"{OUT_DIR}/soong/host/linux_bionic-x86", ANDROID_ROOT)
738    # Replace the boot image to a location expected by the runtime.
739    DALVIKVM_BOOT_OPT = f"-Ximage:{ANDROID_ROOT}/art_boot_images/javalib/boot.art"
740
741  # PROFILE takes precedence over RANDOM_PROFILE, since PROFILE tests require a
742  # specific profile to run properly.
743  if PROFILE or RANDOM_PROFILE:
744    profman_cmdline = f"{ANDROID_ART_BIN_DIR}/profman  \
745      --apk={DEX_LOCATION}/{TEST_NAME}.jar \
746      --dex-location={DEX_LOCATION}/{TEST_NAME}.jar"
747
748    if isfile(f"{TEST_NAME}-ex.jar") and SECONDARY_COMPILATION:
749      profman_cmdline = f"{profman_cmdline} \
750        --apk={DEX_LOCATION}/{TEST_NAME}-ex.jar \
751        --dex-location={DEX_LOCATION}/{TEST_NAME}-ex.jar"
752
753    COMPILE_FLAGS = f"{COMPILE_FLAGS} --profile-file={DEX_LOCATION}/{TEST_NAME}.prof"
754    FLAGS = f"{FLAGS} -Xcompiler-option --profile-file={DEX_LOCATION}/{TEST_NAME}.prof"
755    if PROFILE:
756      profman_cmdline = f"{profman_cmdline} --create-profile-from={DEX_LOCATION}/profile \
757          --reference-profile-file={DEX_LOCATION}/{TEST_NAME}.prof"
758
759    else:
760      profman_cmdline = f"{profman_cmdline} --generate-test-profile={DEX_LOCATION}/{TEST_NAME}.prof \
761          --generate-test-profile-seed=0"
762
763  def write_dex2oat_cmdlines(name: str):
764    nonlocal dex2oat_cmdline, dm_cmdline, vdex_cmdline
765
766    class_loader_context = ""
767    enable_app_image = False
768    if APP_IMAGE:
769      enable_app_image = True
770
771    # If the name ends in -ex then this is a secondary dex file
772    if name.endswith("-ex"):
773      # Lazily realize the default value in case DEX_LOCATION/TEST_NAME change
774      nonlocal SECONDARY_CLASS_LOADER_CONTEXT
775      if SECONDARY_CLASS_LOADER_CONTEXT == "":
776        if SECONDARY_DEX == "":
777          # Tests without `--secondary` load the "-ex" jar in a separate PathClassLoader
778          # that is a child of the main PathClassLoader. If the class loader is constructed
779          # in any other way, the test needs to specify the secondary CLC explicitly.
780          SECONDARY_CLASS_LOADER_CONTEXT = f"PCL[];PCL[{DEX_LOCATION}/{TEST_NAME}.jar]"
781        else:
782          # Tests with `--secondary` load the `-ex` jar a part of the main PathClassLoader.
783          SECONDARY_CLASS_LOADER_CONTEXT = f"PCL[{DEX_LOCATION}/{TEST_NAME}.jar]"
784      class_loader_context = f"'--class-loader-context={SECONDARY_CLASS_LOADER_CONTEXT}'"
785      enable_app_image = enable_app_image and SECONDARY_APP_IMAGE
786
787    app_image = ""
788    if enable_app_image:
789      app_image = f"--app-image-file={DEX_LOCATION}/oat/{ISA}/{name}.art --resolve-startup-const-strings=true"
790
791    dex2oat_binary = DEX2OAT_DEBUG_BINARY
792    if TEST_IS_NDEBUG:
793      dex2oat_binary = DEX2OAT_NDEBUG_BINARY
794
795    dex2oat_cmdline = f"{INVOKE_WITH} "
796
797    if USE_GDB_DEX2OAT:
798      nonlocal GDB_DEX2OAT_EXTRA_ARGS
799      dex2oat_cmdline += f"gdb {GDB_DEX2OAT_EXTRA_ARGS} \
800                          -d '{ANDROID_BUILD_TOP}' --args "
801
802    dex2oat_cmdline += f"'{ANDROID_ART_BIN_DIR}/{dex2oat_binary}' \
803                        {COMPILE_FLAGS} \
804                        --boot-image={BOOT_IMAGE} \
805                        --dex-file={DEX_LOCATION}/{name}.jar \
806                        --oat-file={DEX_LOCATION}/oat/{ISA}/{name}.odex \
807                        {app_image} \
808                        --generate-mini-debug-info \
809                        --instruction-set={ISA} \
810                        {class_loader_context}"
811
812    if INSTRUCTION_SET_FEATURES != "":
813      dex2oat_cmdline += f" --instruction-set-features={INSTRUCTION_SET_FEATURES}"
814
815    # Add in a timeout. This is important for testing the compilation/verification time of
816    # pathological cases. We do not append a timeout when debugging dex2oat because we
817    # do not want it to exit while debugging.
818    # Note: as we don't know how decent targets are (e.g., emulator), only do this on the host for
819    #       now. We should try to improve this.
820    #       The current value is rather arbitrary. run-tests should compile quickly.
821    # Watchdog timeout is in milliseconds so add 3 '0's to the dex2oat timeout.
822    if HOST and not USE_GDB_DEX2OAT:
823      # Use SIGRTMIN+2 to try to dump threads.
824      # Use -k 1m to SIGKILL it a minute later if it hasn't ended.
825      dex2oat_cmdline = f"timeout -k {DEX2OAT_TIMEOUT}s -s SIGRTMIN+2 {DEX2OAT_RT_TIMEOUT}s {dex2oat_cmdline} --watchdog-timeout={DEX2OAT_TIMEOUT}000"
826    if PROFILE or RANDOM_PROFILE:
827      vdex_cmdline = f"{dex2oat_cmdline} {VDEX_ARGS} --input-vdex={DEX_LOCATION}/oat/{ISA}/{name}.vdex --output-vdex={DEX_LOCATION}/oat/{ISA}/{name}.vdex"
828    elif TEST_VDEX:
829      if VDEX_ARGS == "":
830        # If no arguments need to be passed, just delete the odex file so that the runtime only picks up the vdex file.
831        vdex_cmdline = f"rm {DEX_LOCATION}/oat/{ISA}/{name}.odex"
832      else:
833        vdex_cmdline = f"{dex2oat_cmdline} {VDEX_ARGS} --input-vdex={DEX_LOCATION}/oat/{ISA}/{name}.vdex"
834    elif TEST_DEX2OAT_DM:
835      vdex_cmdline = f"{dex2oat_cmdline} {VDEX_ARGS} --dump-timings --dm-file={DEX_LOCATION}/oat/{ISA}/{name}.dm"
836      dex2oat_cmdline = f"{dex2oat_cmdline} --copy-dex-files=false --output-vdex={DEX_LOCATION}/oat/{ISA}/primary.vdex"
837      dm_cmdline = f"zip -qj {DEX_LOCATION}/oat/{ISA}/{name}.dm {DEX_LOCATION}/oat/{ISA}/primary.vdex"
838    elif TEST_RUNTIME_DM:
839      dex2oat_cmdline = f"{dex2oat_cmdline} --copy-dex-files=false --output-vdex={DEX_LOCATION}/oat/{ISA}/primary.vdex"
840      dm_cmdline = f"zip -qj {DEX_LOCATION}/{name}.dm {DEX_LOCATION}/oat/{ISA}/primary.vdex"
841
842# Enable mini-debug-info for JIT (if JIT is used).
843
844  FLAGS += " -Xcompiler-option --generate-mini-debug-info"
845
846  if PREBUILD:
847    mkdir_locations += f" {DEX_LOCATION}/oat/{ISA}"
848
849    # "Primary".
850    write_dex2oat_cmdlines(TEST_NAME)
851    dex2oat_cmdline = re.sub(" +", " ", dex2oat_cmdline)
852    dm_cmdline = re.sub(" +", " ", dm_cmdline)
853    vdex_cmdline = re.sub(" +", " ", vdex_cmdline)
854
855    # Enable mini-debug-info for JIT (if JIT is used).
856    FLAGS += " -Xcompiler-option --generate-mini-debug-info"
857
858    if isfile(f"{TEST_NAME}-ex.jar") and SECONDARY_COMPILATION:
859      # "Secondary" for test coverage.
860
861      # Store primary values.
862      base_dex2oat_cmdline = dex2oat_cmdline
863      base_dm_cmdline = dm_cmdline
864      base_vdex_cmdline = vdex_cmdline
865
866      write_dex2oat_cmdlines(f"{TEST_NAME}-ex")
867      dex2oat_cmdline = re.sub(" +", " ", dex2oat_cmdline)
868      dm_cmdline = re.sub(" +", " ", dm_cmdline)
869      vdex_cmdline = re.sub(" +", " ", vdex_cmdline)
870
871      # Concatenate.
872      dex2oat_cmdline = f"{base_dex2oat_cmdline} && {dex2oat_cmdline}"
873      dm_cmdline = base_dm_cmdline  # Only use primary dm.
874      vdex_cmdline = f"{base_vdex_cmdline} && {vdex_cmdline}"
875
876  if SYNC_BEFORE_RUN:
877    sync_cmdline = "sync"
878
879  DALVIKVM_ISA_FEATURES_ARGS = ""
880  if INSTRUCTION_SET_FEATURES != "":
881    DALVIKVM_ISA_FEATURES_ARGS = f"-Xcompiler-option --instruction-set-features={INSTRUCTION_SET_FEATURES}"
882
883# java.io.tmpdir can only be set at launch time.
884  TMP_DIR_OPTION = ""
885  if not HOST:
886    TMP_DIR_OPTION = "-Djava.io.tmpdir=/data/local/tmp"
887
888# The build servers have an ancient version of bash so we cannot use @Q.
889  QUOTED_DALVIKVM_BOOT_OPT = shlex.quote(DALVIKVM_BOOT_OPT)
890
891  DALVIKVM_CLASSPATH = f"{DEX_LOCATION}/{TEST_NAME}.jar"
892  if isfile(f"{TEST_NAME}-aotex.jar"):
893    DALVIKVM_CLASSPATH = f"{DALVIKVM_CLASSPATH}:{DEX_LOCATION}/{TEST_NAME}-aotex.jar"
894  DALVIKVM_CLASSPATH = f"{DALVIKVM_CLASSPATH}{SECONDARY_DEX}"
895
896  # We set DumpNativeStackOnSigQuit to false to avoid stressing libunwind.
897  # b/27185632
898  # b/24664297
899
900  dalvikvm_logger = ""
901  if ON_VM:
902    dalvikvm_logger = "-Xuse-stderr-logger"
903
904  dalvikvm_cmdline = f"{INVOKE_WITH} {GDB} {ANDROID_ART_BIN_DIR}/{DALVIKVM} \
905                       {GDB_ARGS} \
906                       {FLAGS} \
907                       {DEX_VERIFY} \
908                       -XXlib:{LIB} \
909                       {DEX2OAT} \
910                       {DALVIKVM_ISA_FEATURES_ARGS} \
911                       {ZYGOTE} \
912                       {JNI_OPTS} \
913                       {INT_OPTS} \
914                       {DEBUGGER_OPTS} \
915                       {QUOTED_DALVIKVM_BOOT_OPT} \
916                       {TMP_DIR_OPTION} \
917                       {dalvikvm_logger} \
918                       -XX:DumpNativeStackOnSigQuit:false \
919                       -cp {DALVIKVM_CLASSPATH} {MAIN} {ARGS}"
920
921  if SIMPLEPERF:
922    dalvikvm_cmdline = f"simpleperf record {dalvikvm_cmdline} && simpleperf report"
923
924  def sanitize_dex2oat_cmdline(cmdline: str) -> str:
925    args = []
926    for arg in cmdline.split(" "):
927      if arg == "--class-loader-context=&":
928        arg = "--class-loader-context=\&"
929      args.append(arg)
930    return " ".join(args)
931
932  # Remove whitespace.
933  dex2oat_cmdline = sanitize_dex2oat_cmdline(dex2oat_cmdline)
934  dalvikvm_cmdline = re.sub(" +", " ", dalvikvm_cmdline)
935  dm_cmdline = re.sub(" +", " ", dm_cmdline)
936  vdex_cmdline = sanitize_dex2oat_cmdline(vdex_cmdline)
937  profman_cmdline = re.sub(" +", " ", profman_cmdline)
938
939  # Use an empty ASAN_OPTIONS to enable defaults.
940  # Note: this is required as envsetup right now exports detect_leaks=0.
941  RUN_TEST_ASAN_OPTIONS = ""
942
943  # Multiple shutdown leaks. b/38341789
944  if RUN_TEST_ASAN_OPTIONS != "":
945    RUN_TEST_ASAN_OPTIONS = f"{RUN_TEST_ASAN_OPTIONS}:"
946  RUN_TEST_ASAN_OPTIONS = f"{RUN_TEST_ASAN_OPTIONS}detect_leaks=0"
947
948  assert not args.external_log_tags, "Deprecated: use --android-log-tags=*:v"
949
950  ANDROID_LOG_TAGS = args.android_log_tags
951
952  def filter_output():
953    # Remove unwanted log messages from stderr before diffing with the expected output.
954    # NB: The unwanted log line can be interleaved in the middle of wanted stderr printf.
955    #     In particular, unhandled exception is printed using several unterminated printfs.
956    ALL_LOG_TAGS = ["V", "D", "I", "W", "E", "F", "S"]
957    skip_tag_set = "|".join(ALL_LOG_TAGS[:ALL_LOG_TAGS.index(args.diff_min_log_tag.upper())])
958    skip_reg_exp = fr'#-# #:#:# # # ({skip_tag_set}) [^\n]*\n'
959    skip_reg_exp = skip_reg_exp.replace('#', '[0-9.]+').replace(' ', ' +')
960    ctx.run(fr"sed -i -z -E 's/{skip_reg_exp}//g' '{args.stderr_file}'")
961    if not HAVE_IMAGE:
962      message = "(Unable to open file|Could not create image space)"
963      ctx.run(fr"sed -i -E '/^.* E dalvikvm(|32|64): .* {message}/d' '{args.stderr_file}'")
964    if ANDROID_LOG_TAGS != "*:i" and "D" in skip_tag_set:
965      ctx.run(fr"sed -i -E '/^(Time zone|I18n) APEX ICU file found/d' '{args.stderr_file}'")
966    if ON_VM:
967      messages = "|".join([
968        "failed to connect to tombstoned",
969        "Failed to write stack traces to tombstoned",
970        "Failed to setpriority to :0"])
971      ctx.run(fr"sed -i -E '/({messages})/d' '{args.stderr_file}'")
972
973  if not HOST:
974    # Populate LD_LIBRARY_PATH.
975    LD_LIBRARY_PATH = ""
976    if ANDROID_ROOT != "/system":
977      # Current default installation is dalvikvm 64bits and dex2oat 32bits,
978      # so we can only use LD_LIBRARY_PATH when testing on a local
979      # installation.
980      LD_LIBRARY_PATH = f"{ANDROID_ROOT}/{LIBRARY_DIRECTORY}"
981
982    # This adds libarttest(d).so to the default linker namespace when dalvikvm
983    # is run from /apex/com.android.art/bin. Since that namespace is essentially
984    # an alias for the com_android_art namespace, that gives libarttest(d).so
985    # full access to the internal ART libraries.
986    LD_LIBRARY_PATH = f"/data/{TEST_DIRECTORY}/com.android.art/lib{SUFFIX64}:{LD_LIBRARY_PATH}"
987    dlib = ("" if TEST_IS_NDEBUG else "d")
988    art_test_internal_libraries = [
989        f"libartagent{dlib}.so",
990        f"libarttest{dlib}.so",
991        f"libtiagent{dlib}.so",
992        f"libtistress{dlib}.so",
993    ]
994    NATIVELOADER_DEFAULT_NAMESPACE_LIBS = ":".join(art_test_internal_libraries)
995    dlib = ""
996    art_test_internal_libraries = []
997
998    if not ON_VM:
999      # Needed to access the test's Odex files.
1000      LD_LIBRARY_PATH = f"{DEX_LOCATION}/oat/{ISA}:{LD_LIBRARY_PATH}"
1001    # Needed to access the test's native libraries (see e.g. 674-hiddenapi,
1002    # which generates `libhiddenapitest_*.so` libraries in `{DEX_LOCATION}`).
1003    LD_LIBRARY_PATH = f"{DEX_LOCATION}:{LD_LIBRARY_PATH}"
1004
1005    # Prepend directories to the path on device.
1006    PREPEND_TARGET_PATH = ANDROID_ART_BIN_DIR
1007    if ANDROID_ROOT != "/system":
1008      PREPEND_TARGET_PATH = f"{PREPEND_TARGET_PATH}:{ANDROID_ROOT}/bin"
1009
1010    timeout_dumper_cmd = ""
1011
1012    if TIMEOUT_DUMPER:
1013      # Use "-l" to dump to logcat. That is convenience for the build bot crash symbolization.
1014      # Use exit code 124 for toybox timeout (b/141007616).
1015      timeout_dumper_cmd = f"{TIMEOUT_DUMPER} -l -s 15 -e 124"
1016
1017    timeout_prefix = ""
1018    if TIME_OUT == "timeout":
1019      # Add timeout command if time out is desired.
1020      #
1021      # Note: We first send SIGTERM (the timeout default, signal 15) to the signal dumper, which
1022      #       will induce a full thread dump before killing the process. To ensure any issues in
1023      #       dumping do not lead to a deadlock, we also use the "-k" option to definitely kill the
1024      #       child.
1025      # Note: Using "--foreground" to not propagate the signal to children, i.e., the runtime.
1026      if ON_VM:
1027        timeout_prefix = f"timeout -k 120s {TIME_OUT_VALUE}s"
1028      else:
1029        timeout_prefix = f"timeout --foreground -k 120s {TIME_OUT_VALUE}s {timeout_dumper_cmd}"
1030
1031    ctx.export(
1032      ASAN_OPTIONS = RUN_TEST_ASAN_OPTIONS,
1033      ANDROID_DATA = DEX_LOCATION,
1034      DEX_LOCATION = DEX_LOCATION,
1035      ANDROID_ROOT = ANDROID_ROOT,
1036      ANDROID_I18N_ROOT = ANDROID_I18N_ROOT,
1037      ANDROID_ART_ROOT = ANDROID_ART_ROOT,
1038      ANDROID_TZDATA_ROOT = ANDROID_TZDATA_ROOT,
1039      ANDROID_LOG_TAGS = ANDROID_LOG_TAGS,
1040      LD_LIBRARY_PATH = LD_LIBRARY_PATH,
1041      NATIVELOADER_DEFAULT_NAMESPACE_LIBS = NATIVELOADER_DEFAULT_NAMESPACE_LIBS,
1042      PATH = f"{PREPEND_TARGET_PATH}:$PATH",
1043    )
1044
1045    if USE_GDB or USE_GDBSERVER:
1046      print(f"Forward {GDBSERVER_PORT} to local port and connect GDB")
1047
1048    ctx.run(f"rm -rf {DEX_LOCATION}/{{oat,dalvik-cache}}/ && mkdir -p {mkdir_locations}")
1049    ctx.run(f"{profman_cmdline}")
1050    ctx.run(f"{dex2oat_cmdline}", desc="Dex2oat")
1051    ctx.run(f"{dm_cmdline}")
1052    ctx.run(f"{vdex_cmdline}")
1053    ctx.run(f"{strip_cmdline}")
1054    ctx.run(f"{sync_cmdline}")
1055    ctx.run(tee(f"{timeout_prefix} {dalvikvm_cmdline}"),
1056            expected_exit_code=args.expected_exit_code, desc="DalvikVM")
1057
1058    if ON_VM:
1059      filter_output()
1060
1061  else:
1062    # Host run.
1063    LD_LIBRARY_PATH = f"{ANDROID_ROOT}/{LIBRARY_DIRECTORY}:{ANDROID_ROOT}/{TEST_DIRECTORY}"
1064
1065    ctx.export(
1066      ANDROID_PRINTF_LOG = "brief",
1067      ASAN_OPTIONS = RUN_TEST_ASAN_OPTIONS,
1068      ANDROID_DATA = DEX_LOCATION,
1069      DEX_LOCATION = DEX_LOCATION,
1070      ANDROID_ROOT = ANDROID_ROOT,
1071      ANDROID_I18N_ROOT = ANDROID_I18N_ROOT,
1072      ANDROID_ART_ROOT = ANDROID_ART_ROOT,
1073      ANDROID_TZDATA_ROOT = ANDROID_TZDATA_ROOT,
1074      ANDROID_LOG_TAGS = ANDROID_LOG_TAGS,
1075      LD_LIBRARY_PATH = LD_LIBRARY_PATH,
1076      PATH = f"{PATH}:{ANDROID_ART_BIN_DIR}",
1077      # Temporarily disable address space layout randomization (ASLR).
1078      # This is needed on the host so that the linker loads core.oat at the necessary address.
1079      LD_USE_LOAD_BIAS = "1",
1080      TERM = os.environ.get("TERM", ""),  # Needed for GDB
1081    )
1082
1083    cmdline = dalvikvm_cmdline
1084
1085    if TIME_OUT == "gdb":
1086      if run("uname").stdout.strip() == "Darwin":
1087        # Fall back to timeout on Mac.
1088        TIME_OUT = "timeout"
1089      elif ISA == "x86":
1090        # prctl call may fail in 32-bit on an older (3.2) 64-bit Linux kernel. Fall back to timeout.
1091        TIME_OUT = "timeout"
1092      else:
1093        # Check if gdb is available.
1094        proc = run('gdb --eval-command="quit"', check=False, save_cmd=False)
1095        if proc.returncode != 0:
1096          # gdb isn't available. Fall back to timeout.
1097          TIME_OUT = "timeout"
1098
1099    if TIME_OUT == "timeout":
1100      # Add timeout command if time out is desired.
1101      #
1102      # Note: We first send SIGTERM (the timeout default, signal 15) to the signal dumper, which
1103      #       will induce a full thread dump before killing the process. To ensure any issues in
1104      #       dumping do not lead to a deadlock, we also use the "-k" option to definitely kill the
1105      #       child.
1106      # Note: Using "--foreground" to not propagate the signal to children, i.e., the runtime.
1107      cmdline = f"timeout --foreground -k 120s {TIME_OUT_VALUE}s {TIMEOUT_DUMPER} -s 15 {cmdline}"
1108
1109    os.chdir(ANDROID_BUILD_TOP)
1110
1111    # Make sure we delete any existing compiler artifacts.
1112    # This enables tests to call the RUN script multiple times in a row
1113    # without worrying about interference.
1114    ctx.run(f"rm -rf {DEX_LOCATION}/{{oat,dalvik-cache}}/")
1115
1116    ctx.run(f"mkdir -p {mkdir_locations}")
1117    ctx.run(linkroot_cmdline)
1118    ctx.run(linkroot_overlay_cmdline)
1119    ctx.run(profman_cmdline)
1120    ctx.run(dex2oat_cmdline, desc="Dex2oat")
1121    ctx.run(dm_cmdline)
1122    ctx.run(vdex_cmdline)
1123    ctx.run(strip_cmdline)
1124    ctx.run(sync_cmdline)
1125
1126    if DRY_RUN:
1127      return
1128
1129    if USE_GDB:
1130      # When running under gdb, we cannot do piping and grepping...
1131      ctx.run(cmdline)
1132    else:
1133      ctx.run(tee(cmdline), expected_exit_code=args.expected_exit_code, desc="DalvikVM")
1134      filter_output()
1135