blob: aebf5a67781c04df2096d3c8d185650fcc973899 [file] [log] [blame]
Elliott Hughes40ef99e2011-08-11 17:44:34 -07001# Copyright (C) 2011 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Nicolas Geoffray70a998c2014-12-04 17:05:22 +000015# This script is used on host and device. It uses a common subset
16# shell dialect that should work on the host (e.g. bash), and
17# Android (e.g. mksh).
18
Orion Hodson9763f2e2017-03-28 08:27:23 +010019# Globals
Orion Hodson9763f2e2017-03-28 08:27:23 +010020ART_BINARY=dalvikvm
21DELETE_ANDROID_DATA="no"
22LAUNCH_WRAPPER=
23LIBART=libart.so
24JIT_PROFILE="no"
Alex Lighta4817fb2018-06-12 10:56:35 -070025ALLOW_DEFAULT_JDWP="no"
Orion Hodson9763f2e2017-03-28 08:27:23 +010026VERBOSE="no"
Nicolas Geoffrayc0c07852017-08-08 09:44:15 +010027CLEAN_OAT_FILES="yes"
Vladimir Markoafd44ea2017-07-14 13:52:02 +010028EXTRA_OPTIONS=()
Orion Hodson9763f2e2017-03-28 08:27:23 +010029
Calin Juravle64f45cb2017-03-16 19:58:26 -070030# Follow all sym links to get the program name.
31if [ z"$BASH_SOURCE" != z ]; then
32 PROG_NAME="$BASH_SOURCE"
33else
34 PROG_NAME="$0"
35fi
36while [ -h "$PROG_NAME" ]; do
37 # On Mac OS, readlink -f doesn't work.
38 PROG_NAME="$(readlink "$PROG_NAME")"
39done
Nicolas Geoffray9583fbc2014-02-28 15:21:07 +000040
Nicolas Geoffrayfc3c67a2014-07-02 14:57:53 +010041function find_libdir() {
Orion Hodson9763f2e2017-03-28 08:27:23 +010042 # Get the actual file, $1 is the ART_BINARY_PATH and may be a symbolic link.
Nicolas Geoffray70a998c2014-12-04 17:05:22 +000043 # Use realpath instead of readlink because Android does not have a readlink.
Orion Hodson9763f2e2017-03-28 08:27:23 +010044 if [[ "$(realpath "$1")" == *dalvikvm64 ]]; then
Nicolas Geoffrayfc3c67a2014-07-02 14:57:53 +010045 echo "lib64"
46 else
47 echo "lib"
48 fi
49}
50
Nicolas Geoffray49cda062017-04-21 13:08:25 +010051function replace_compiler_filter_with_quicken() {
52 ARGS_WITH_QUICKEN=("$@")
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +000053
54 found="false"
55 ((index=0))
56 while ((index <= $#)); do
Nicolas Geoffray49cda062017-04-21 13:08:25 +010057 what="${ARGS_WITH_QUICKEN[$index]}"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +000058
59 case "$what" in
60 --compiler-filter=*)
Nicolas Geoffray49cda062017-04-21 13:08:25 +010061 ARGS_WITH_QUICKEN[$index]="--compiler-filter=quicken"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +000062 found="true"
63 ;;
64 esac
65
66 ((index++))
67 shift
68 done
69 if [ "$found" != "true" ]; then
Nicolas Geoffray49cda062017-04-21 13:08:25 +010070 ARGS_WITH_QUICKEN=(-Xcompiler-option --compiler-filter=quicken "${ARGS_WITH_QUICKEN[@]}")
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +000071 fi
72}
73
Orion Hodson9763f2e2017-03-28 08:27:23 +010074function usage() {
75 cat 1>&2 <<EOF
76Usage: art [OPTIONS] [--] [ART_OPTIONS] CLASS
Nicolas Geoffrayf63a0a52014-09-02 15:24:25 +010077
Orion Hodson9763f2e2017-03-28 08:27:23 +010078Supported OPTIONS include:
79 --32 Use the 32-bit Android Runtime.
80 --64 Use the 64-bit Android Runtime.
Orion Hodson9763f2e2017-03-28 08:27:23 +010081 -d Use the debug ART library (libartd.so).
82 --debug Equivalent to -d.
83 --gdb Launch the Android Runtime in gdb.
Alex Light84b92e02017-09-29 13:46:14 -070084 --gdbserver <comms> Launch the Android Runtime in gdbserver using the
85 supplied communication channel.
Orion Hodson9763f2e2017-03-28 08:27:23 +010086 --help Display usage message.
87 --invoke-with <program> Launch the Android Runtime in <program>.
88 --perf Launch the Android Runtime with perf recording.
89 --perf-report Launch the Android Runtime with perf recording with
90 report upon completion.
91 --profile Run with profiling, then run using profile data.
92 --verbose Run script verbosely.
Nicolas Geoffrayc0c07852017-08-08 09:44:15 +010093 --no-clean Don't cleanup oat directories.
Alex Lighta4817fb2018-06-12 10:56:35 -070094 --allow-default-jdwp Don't automatically put in -XjdwpProvider:none.
95 You probably do not want this.
Orion Hodson9763f2e2017-03-28 08:27:23 +010096
97The ART_OPTIONS are passed directly to the Android Runtime.
98
99Example:
100 art --32 -cp my_classes.dex MainClass
101
102Common errors:
103 1) Not having core.art available (see $ANDROID_BUILD_TOP/art/Android.mk).
104 eg m -j32 build-art-host
105 2) Not having boot.art available (see $ANDROID_BUILD_TOP/build/make/core/dex_preopt_libart_boot.mk)
106 eg m -j32 out/target/product/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art
107EOF
108}
109
110function clean_android_data() {
111 if [ "$DELETE_ANDROID_DATA" = "yes" ]; then
112 rm -rf $ANDROID_DATA
Nicolas Geoffrayf63a0a52014-09-02 15:24:25 +0100113 fi
Orion Hodson9763f2e2017-03-28 08:27:23 +0100114}
115
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100116# Given 'VAR1=VAL VAR2=VAL2 ... cmd arg1 arg2 ... argN' run the 'cmd' with the args
117# with the modified environment {VAR1=VAL,VAL2=,...}.
118#
119# Also prints the command to be run if verbose mode is enabled.
Orion Hodson9763f2e2017-03-28 08:27:23 +0100120function verbose_run() {
121 if [ "$VERBOSE" = "yes" ]; then
122 echo "$@"
123 fi
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100124
125 env "$@"
Orion Hodson9763f2e2017-03-28 08:27:23 +0100126}
127
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000128# Parse a colon-separated list into an array (e.g. "foo.dex:bar.dex" -> (foo.dex bar.dex))
129PARSE_CLASSPATH_RESULT=() # Return value will be here due to shell limitations.
130parse_classpath() {
131 local cp="$1"
132 local oldifs=$IFS
133
134 local cp_array
135 cp_array=()
136
137 IFS=":"
138 for part in $cp; do
139 cp_array+=("$part")
140 done
141 IFS=$oldifs
142
143 PARSE_CLASSPATH_RESULT=("${cp_array[@]}")
144}
145
146# Sets 'PARSE_CLASSPATH_RESULT' to an array of class path dex files.
147# e.g. (-cp foo/classes.dex:bar/classes.dex) -> (foo/classes.dex bar/classes.dex)
148find_cp_in_args() {
149 local found="false"
150 local index=0
151 local what
152
153 while [[ $# -gt 0 ]]; do
154 case "$1" in
155 -cp|-classpath)
156 parse_classpath "$2"
157 # Sets 'PARSE_CLASSPATH_RESULT' to an array of class path dex files.
158 # Subsequent parses will overwrite the preceding.
159 shift
160 ;;
161 esac
162 shift
163 done
164}
165
166# Delete the 'oat' directories relative to the classpath's dex files.
167# e.g. (foo/classes.dex bar/classes.dex) would delete (foo/oat bar/oat) directories.
168cleanup_oat_directory() {
169 local classpath
170 classpath=("$@")
171
172 local dirpath
173
174 for path in "${classpath[@]}"; do
175 dirpath="$(dirname "$path")"
176 [[ -d "$dirpath" ]] && verbose_run rm -rf "$dirpath/oat"
177 done
178}
179
180# Parse -cp <CP>, -classpath <CP>, and $CLASSPATH to find the dex files.
181# Each dex file's directory will have an 'oat' file directory, delete it.
182# Input: Command line arguments to the art script.
183# e.g. -cp foo/classes.dex:bar/classes.dex would delete (foo/oat bar/oat) directories.
184cleanup_oat_directory_for_classpath() {
Nicolas Geoffrayc0c07852017-08-08 09:44:15 +0100185 if [ "$CLEAN_OAT_FILES" = "yes" ]; then
186 # First try: Use $CLASSPATH environment variable.
187 parse_classpath "$CLASSPATH"
188 # Second try: Look for latest -cp or -classpath arg which will take precedence.
189 find_cp_in_args "$@"
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000190
Nicolas Geoffrayc0c07852017-08-08 09:44:15 +0100191 cleanup_oat_directory "${PARSE_CLASSPATH_RESULT[@]}"
192 fi
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000193}
194
Igor Murashkind54ac262017-07-26 11:16:23 -0700195# Attempt to find $ANDROID_ROOT/framework/<isa>/core.art' without knowing what <isa> is.
196function check_if_boot_image_file_exists() {
197 local image_location_dir="$1"
198 local image_location_name="$2"
199
200 # Expand image_files to a list of existing image files on the disk.
201 # If no such files exist, it expands to single element 'dir/*/file' with a literal '*'.
202 local image_files
203 image_files=("$image_location_dir"/*/"$image_location_name") # avoid treating "*" as literal.
204
205 # Array always has at least 1 element. Test explicitly whether the file exists.
206 [[ -e "${image_files[0]}" ]]
207}
208
Igor Murashkin7fef4eb2017-07-14 15:45:47 -0700209# Automatically find the boot image location. It uses core.art by default.
210# On a real device, it might only have a boot.art, so use that instead when core.art does not exist.
211function detect_boot_image_location() {
212 local image_location_dir="$ANDROID_ROOT/framework"
213 local image_location_name="core.art"
214
Igor Murashkind54ac262017-07-26 11:16:23 -0700215 # If there are no existing core.art, try to find boot.art.
216 # If there is no boot.art then leave it as-is, assumes -Ximage is explicitly used.
217 # Otherwise let dalvikvm give the error message about an invalid image file.
218 if ! check_if_boot_image_file_exists "$image_location_dir" "core.art" && \
219 check_if_boot_image_file_exists "$image_location_dir" "boot.art"; then
Igor Murashkin7fef4eb2017-07-14 15:45:47 -0700220 image_location_name="boot.art"
221 fi
222
223 local image_location="$image_location_dir/$image_location_name"
224 echo "$image_location"
225}
226
Nicolas Geoffrayffda8b82017-10-06 13:48:08 +0100227# If android logging is not explicitly set, only print warnings and errors.
228if [ -z "$ANDROID_LOG_TAGS" ]; then
229 ANDROID_LOG_TAGS='*:w'
230fi
231
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000232# Runs dalvikvm, returns its exit code.
233# (Oat directories are cleaned up in between runs)
Orion Hodson9763f2e2017-03-28 08:27:23 +0100234function run_art() {
Igor Murashkin7fef4eb2017-07-14 15:45:47 -0700235 local image_location="$(detect_boot_image_location)"
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000236 local ret
Igor Murashkin7fef4eb2017-07-14 15:45:47 -0700237
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000238 # First cleanup any left-over 'oat' files from the last time dalvikvm was run.
239 cleanup_oat_directory_for_classpath "$@"
240 # Run dalvikvm.
Nicolas Geoffrayffda8b82017-10-06 13:48:08 +0100241 verbose_run ANDROID_DATA="$ANDROID_DATA" \
242 ANDROID_ROOT="$ANDROID_ROOT" \
243 LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
244 PATH="$ANDROID_ROOT/bin:$PATH" \
245 LD_USE_LOAD_BIAS=1 \
246 ANDROID_LOG_TAGS="$ANDROID_LOG_TAGS" \
247 $LAUNCH_WRAPPER $ART_BINARY_PATH $lib \
248 -XXlib:"$LIBART" \
249 -Xnorelocate \
250 -Ximage:"$image_location" \
Orion Hodson9763f2e2017-03-28 08:27:23 +0100251 "$@"
Nicolas Geoffray162a5702017-08-04 09:28:32 +0000252 ret=$?
253
254 # Avoid polluting disk with 'oat' files after dalvikvm has finished.
255 cleanup_oat_directory_for_classpath "$@"
256
257 # Forward exit code of dalvikvm.
258 return $ret
Orion Hodson9763f2e2017-03-28 08:27:23 +0100259}
260
261while [[ "$1" = "-"* ]]; do
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100262 case "$1" in
Orion Hodson9763f2e2017-03-28 08:27:23 +0100263 --)
264 # No more arguments for this script.
265 shift
266 break
267 ;;
268 --32)
269 ART_BINARY=dalvikvm32
270 ;;
271 --64)
272 ART_BINARY=dalvikvm64
273 ;;
Orion Hodson9763f2e2017-03-28 08:27:23 +0100274 -d)
275 ;& # Fallthrough
276 --debug)
277 LIBART="libartd.so"
Andreas Gampe1c5b42f2017-06-15 18:20:45 -0700278 # Expect that debug mode wants all checks.
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100279 EXTRA_OPTIONS+=(-XX:SlowDebug=true)
Orion Hodson9763f2e2017-03-28 08:27:23 +0100280 ;;
Alex Light84b92e02017-09-29 13:46:14 -0700281 --gdbserver)
282 LAUNCH_WRAPPER="gdbserver $2"
283 shift
284 ;;
Orion Hodson9763f2e2017-03-28 08:27:23 +0100285 --gdb)
286 LIBART="libartd.so"
287 LAUNCH_WRAPPER="gdb --args"
288 ;;
289 --help)
290 usage
291 exit 0
292 ;;
293 --invoke-with)
294 LAUNCH_WRAPPER=$2
295 shift
296 ;;
297 --perf)
298 PERF="record"
299 ;;
300 --perf-report)
301 PERF="report"
302 ;;
303 --profile)
304 JIT_PROFILE="yes"
305 ;;
306 --verbose)
307 VERBOSE="yes"
308 ;;
Nicolas Geoffrayc0c07852017-08-08 09:44:15 +0100309 --no-clean)
310 CLEAN_OAT_FILES="no"
311 ;;
Alex Lighta4817fb2018-06-12 10:56:35 -0700312 --allow-default-jdwp)
313 ALLOW_DEFAULT_JDWP="yes"
314 ;;
Orion Hodson9763f2e2017-03-28 08:27:23 +0100315 --*)
316 echo "unknown option: $1" 1>&2
317 usage
318 exit 1
319 ;;
320 *)
321 break
322 ;;
323 esac
324 shift
Nicolas Geoffrayf63a0a52014-09-02 15:24:25 +0100325done
326
Orion Hodson9763f2e2017-03-28 08:27:23 +0100327if [ $# -eq 0 ]; then
328 usage
329 exit 1
330fi
331
Brian Carlstrom87bb26f2014-09-08 11:13:47 -0700332PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
333ANDROID_ROOT=$PROG_DIR/..
Orion Hodson9763f2e2017-03-28 08:27:23 +0100334ART_BINARY_PATH=$ANDROID_ROOT/bin/$ART_BINARY
Brian Carlstrom87bb26f2014-09-08 11:13:47 -0700335
Orion Hodson9763f2e2017-03-28 08:27:23 +0100336if [ ! -x "$ART_BINARY_PATH" ]; then
337 cat 1>&2 <<EOF
338Android Runtime not found: $ART_BINARY_PATH
339This script should be in the same directory as the Android Runtime ($ART_BINARY).
340EOF
341 exit 1
342fi
343
344LIBDIR="$(find_libdir $ART_BINARY_PATH)"
345LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
Orion Hodson9763f2e2017-03-28 08:27:23 +0100346
Nicolas Geoffray70a998c2014-12-04 17:05:22 +0000347# If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own,
348# and ensure we delete it at the end.
349if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then
Igor Murashkin7fef4eb2017-07-14 15:45:47 -0700350 if [[ $PWD != / ]]; then
351 ANDROID_DATA="$PWD/android-data$$"
352 else
353 # Use /data/local/tmp when running this from adb shell, since it starts out in /
354 # by default.
355 ANDROID_DATA="$ANDROID_DATA/local/tmp/android-data$$"
356 fi
Igor Murashkind54ac262017-07-26 11:16:23 -0700357 mkdir -p "$ANDROID_DATA"
Orion Hodson9763f2e2017-03-28 08:27:23 +0100358 DELETE_ANDROID_DATA="yes"
Nicolas Geoffray70a998c2014-12-04 17:05:22 +0000359fi
360
Orion Hodson9763f2e2017-03-28 08:27:23 +0100361if [ "$PERF" != "" ]; then
David Srbecky0dcb17f2018-08-13 12:41:47 +0100362 LAUNCH_WRAPPER="perf record -g --call-graph dwarf -F 10000 -o $ANDROID_DATA/perf.data -e cycles:u $LAUNCH_WRAPPER"
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100363 EXTRA_OPTIONS+=(-Xcompiler-option --generate-debug-info)
Nicolas Geoffraye099a612014-12-12 13:52:00 +0000364fi
365
Alex Lighta4817fb2018-06-12 10:56:35 -0700366if [ "$ALLOW_DEFAULT_JDWP" = "no" ]; then
367 EXTRA_OPTIONS+=(-XjdwpProvider:none)
368fi
369
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000370if [ "$JIT_PROFILE" = "yes" ]; then
371 # Create the profile. The runtime expects profiles to be created before
372 # execution.
373 PROFILE_PATH="$ANDROID_DATA/primary.prof"
Igor Murashkind54ac262017-07-26 11:16:23 -0700374 touch "$PROFILE_PATH"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000375
Nicolas Geoffray49cda062017-04-21 13:08:25 +0100376 # Replace the compiler filter with quicken so that we
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000377 # can capture the profile.
Nicolas Geoffray49cda062017-04-21 13:08:25 +0100378 ARGS_WITH_QUICKEN=
379 replace_compiler_filter_with_quicken "$@"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000380
381 run_art -Xjitsaveprofilinginfo \
382 -Xps-min-methods-to-save:1 \
383 -Xps-min-classes-to-save:1 \
384 -Xps-min-notification-before-wake:10 \
385 -Xps-profile-path:$PROFILE_PATH \
386 -Xusejit:true \
Nicolas Geoffray49cda062017-04-21 13:08:25 +0100387 "${ARGS_WITH_QUICKEN[@]}" \
Igor Murashkin11942442017-07-20 11:08:34 -0700388 &> "$ANDROID_DATA/profile_gen.log"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000389 EXIT_STATUS=$?
390
391 if [ $EXIT_STATUS != 0 ]; then
Igor Murashkind54ac262017-07-26 11:16:23 -0700392 echo "Profile run failed: " >&2
393 cat "$ANDROID_DATA/profile_gen.log" >&2
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000394 clean_android_data
395 exit $EXIT_STATUS
396 fi
397
Igor Murashkind54ac262017-07-26 11:16:23 -0700398 # Wipe dalvik-cache so that a subsequent run_art must regenerate it.
399 # Leave $ANDROID_DATA intact since it contains our profile file.
400 rm -rf "$ANDROID_DATA/dalvik-cache"
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000401
402 # Append arguments so next invocation of run_art uses the profile.
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100403 EXTRA_OPTIONS+=(-Xcompiler-option --profile-file="$PROFILE_PATH")
Nicolas Geoffray9d7baf42017-04-19 09:01:29 +0000404fi
405
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100406# Protect additional arguments in quotes to preserve whitespaces (used by
407# run-jdwp-test.sh when running on device), '$' (may be used as part of
408# classpath) and other special characters when evaluated.
409EXTRA_OPTIONS+=("$@")
Calin Juravle64f45cb2017-03-16 19:58:26 -0700410
Vladimir Markoafd44ea2017-07-14 13:52:02 +0100411run_art "${EXTRA_OPTIONS[@]}"
Orion Hodson9763f2e2017-03-28 08:27:23 +0100412EXIT_STATUS=$?
Calin Juravleaa980612014-10-20 15:58:57 +0100413
Orion Hodson9763f2e2017-03-28 08:27:23 +0100414if [ "$PERF" != "" ]; then
415 if [ "$PERF" = report ]; then
Calin Juravleaa980612014-10-20 15:58:57 +0100416 perf report -i $ANDROID_DATA/perf.data
417 fi
418 echo "Perf data saved in: $ANDROID_DATA/perf.data"
419else
Orion Hodson9763f2e2017-03-28 08:27:23 +0100420 # Perf output is placed under $ANDROID_DATA so not cleaned when perf options used.
421 clean_android_data
Calin Juravleaa980612014-10-20 15:58:57 +0100422fi
423
Nicolas Geoffray89c4e282014-03-24 09:33:30 +0000424exit $EXIT_STATUS