1#!/bin/bash
2
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18set -e
19
20# Run ART APEX tests.
21
22SCRIPT_DIR=$(dirname $0)
23
24# Status of whole test script.
25exit_status=0
26# Status of current test suite.
27test_status=0
28
29function say {
30  echo "$0: $*"
31}
32
33function die {
34  echo "$0: $*"
35  exit 1
36}
37
38if [[ -z "$ANDROID_BUILD_TOP" ]]; then
39  export ANDROID_BUILD_TOP=$(pwd)
40  if [[ ! -x "$ANDROID_BUILD_TOP/build/soong/soong_ui.bash" ]]; then
41    die "Run from the root of the Android tree, or run lunch/banchan/tapas first."
42  fi
43fi
44
45query_build_vars=(
46  HOST_OUT
47  PRODUCT_COMPRESSED_APEX
48  PRODUCT_OUT
49)
50vars="$($ANDROID_BUILD_TOP/build/soong/soong_ui.bash \
51        --dumpvars-mode --vars="${query_build_vars[*]}")"
52# Assign to a variable and eval that, since bash ignores any error status from
53# the command substitution if it's directly on the eval line.
54eval $vars
55
56# Switch the build system to unbundled mode in the reduced manifest branch.
57if [ ! -d $ANDROID_BUILD_TOP/frameworks/base ]; then
58  export TARGET_BUILD_UNBUNDLED=true
59fi
60
61deapex_binaries=(
62  deapexer
63  debugfs_static
64  fsck.erofs
65)
66
67have_deapex_binaries=true
68for f in ${deapex_binaries[@]}; do
69  if [ ! -e "$HOST_OUT/bin/$f" ]; then
70    have_deapex_binaries=false
71  fi
72done
73if $have_deapex_binaries; then :; else
74  deapex_targets=( ${deapex_binaries[@]/%/-host} )
75  say "Building host binaries for deapexer: ${deapex_targets[*]}"
76  build/soong/soong_ui.bash --make-mode ${deapex_targets[@]} || \
77    die "Failed to build: ${deapex_targets[*]}"
78fi
79
80# Fail early.
81set -e
82
83build_apex_p=true
84list_image_files_p=false
85print_image_tree_p=false
86print_file_sizes_p=false
87
88function usage {
89  cat <<EOF
90Usage: $0 [OPTION] [apexes...]
91Build (optional) and run tests on ART APEX package (on host). Defaults to all
92applicable APEXes if none is given on the command line.
93
94  -B, --skip-build    skip the build step
95  -l, --list-files    list the contents of the ext4 image (\`find\`-like style)
96  -t, --print-tree    list the contents of the ext4 image (\`tree\`-like style)
97  -s, --print-sizes   print the size in bytes of each file when listing contents
98  --bitness=32|64|multilib|auto  passed on to art_apex_test.py
99  -h, --help          display this help and exit
100
101EOF
102  exit
103}
104
105device_bitness_arg=""
106apex_modules=()
107
108while [[ $# -gt 0 ]]; do
109  case "$1" in
110    (-B|--skip-build)  build_apex_p=false;;
111    (-l|--list-files)  list_image_files_p=true;;
112    (-t|--print-tree)  print_image_tree_p=true;;
113    (-s|--print-sizes) print_file_sizes_p=true;;
114    (--bitness=*)      device_bitness_arg=$1;;
115    (-h|--help) usage;;
116    (-*) die "Unknown option: '$1'
117Try '$0 --help' for more information.";;
118    (*) apex_modules+=($1);;
119  esac
120  shift
121done
122
123# build_apex APEX_MODULES
124# -----------------------
125# Build APEX packages APEX_MODULES.
126function build_apex {
127  if $build_apex_p; then
128    say "Building $@" && build/soong/soong_ui.bash --make-mode "$@" || die "Cannot build $@"
129  fi
130}
131
132# maybe_list_apex_contents_apex APEX TMPDIR [other]
133function maybe_list_apex_contents_apex {
134  local print_options=()
135  if $print_file_sizes_p; then
136    print_options+=(--size)
137  fi
138
139  # List the contents of the apex in list form.
140  if $list_image_files_p; then
141    say "Listing image files"
142    $SCRIPT_DIR/art_apex_test.py --list ${print_options[@]} $@
143  fi
144
145  # List the contents of the apex in tree form.
146  if $print_image_tree_p; then
147    say "Printing image tree"
148    $SCRIPT_DIR/art_apex_test.py --tree ${print_options[@]} $@
149  fi
150}
151
152function fail_check {
153  echo "$0: FAILED: $*"
154  test_status=1
155  exit_status=1
156}
157
158if [ ${#apex_modules[@]} -eq 0 ]; then
159  # Test as many modules as possible.
160  apex_modules=(
161    "com.android.art"
162    "com.android.art.debug"
163    "com.android.art.testing"
164  )
165fi
166
167# Build the APEX packages (optional).
168build_apex ${apex_modules[@]}
169
170# Clean-up.
171function cleanup {
172  rm -rf "$work_dir"
173}
174
175# Garbage collection.
176function finish {
177  # Don't fail early during cleanup.
178  set +e
179  cleanup
180}
181
182for apex_module in ${apex_modules[@]}; do
183  test_status=0
184  say "Checking APEX package $apex_module"
185  work_dir=$(mktemp -d)
186  trap finish EXIT
187
188  art_apex_test_args="--tmpdir $work_dir"
189  test_only_args=""
190  art_apex_test_args="$art_apex_test_args $device_bitness_arg"
191  # Note: The Testing ART APEX is never built as a Compressed APEX.
192  if [[ "$PRODUCT_COMPRESSED_APEX" = true && $apex_module != *.testing ]]; then
193    apex_path="$PRODUCT_OUT/system/apex/${apex_module}.capex"
194  else
195    apex_path="$PRODUCT_OUT/system/apex/${apex_module}.apex"
196  fi
197  if $have_deapex_binaries; then
198    art_apex_test_args="$art_apex_test_args --deapexer $HOST_OUT/bin/deapexer"
199    art_apex_test_args="$art_apex_test_args --debugfs $HOST_OUT/bin/debugfs_static"
200    art_apex_test_args="$art_apex_test_args --fsckerofs $HOST_OUT/bin/fsck.erofs"
201  fi
202  case $apex_module in
203    (*.debug)   test_only_args="--flavor debug";;
204    (*.testing) test_only_args="--flavor testing";;
205    (*)         test_only_args="--flavor release";;
206  esac
207  say "APEX package path: $apex_path"
208
209  # List the contents of the APEX image (optional).
210  maybe_list_apex_contents_apex $art_apex_test_args $apex_path
211
212  # Run tests on APEX package.
213  $SCRIPT_DIR/art_apex_test.py $art_apex_test_args $test_only_args $apex_path \
214    || fail_check "Checks failed on $apex_module"
215
216  # Clean up.
217  trap - EXIT
218  cleanup
219
220  [[ "$test_status" = 0 ]] && say "$apex_module tests passed"
221  echo
222done
223
224[[ "$exit_status" = 0 ]] && say "All ART APEX tests passed"
225
226exit $exit_status
227