1#!/bin/bash
2
3# Copyright (C) 2019 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
18# Test Android Runtime (Boot) device configuration flags (living in namespace
19# `runtime_native_boot`).
20
21me=$(basename $0)
22
23# Namespace containing the tested flag.
24namespace=runtime_native_boot
25# Default set of checked zygote processes.
26zygotes=
27
28# Status of whole test script.
29exit_status=0
30
31function say {
32  echo "$me: $*"
33}
34
35function banner {
36  local separator=$(echo "$@" | sed s/./=/g )
37  say "$separator"
38  say "$@"
39  say "$separator"
40}
41
42function fail {
43  say "FAILED: $@"
44  exit_status=1
45}
46
47function reboot_and_wait_for_device {
48  say "Rebooting device..."
49  adb reboot
50  adb wait-for-device >/dev/null
51  # Wait until the device has finished booting. Give the device 60 iterations
52  # (~60 seconds) to try and finish booting before declaring defeat.
53  local niters=60
54  for i in $(seq $niters); do
55    [[ $(adb shell getprop sys.boot_completed) -eq 1 ]] && return 0
56    sleep 1
57  done
58  fail "Device did not finish booting before timeout (~$niters seconds)"
59}
60
61# check_device_config_flag CONTEXT FLAG VALUE
62# -------------------------------------------
63# Check that the device configuration flag FLAG is set to VALUE. Use CONTEXT in
64# logging.
65function check_device_config_flag {
66  local context=$1
67  local flag=$2
68  local value=$3
69
70  say "[$context] Check that the device configuration flag is set..."
71  local flag_value=$(adb shell device_config get "$namespace" "$flag")
72  [[ "$flag_value" = "$value" ]] \
73    || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected \`$value\`)"
74}
75
76# check_no_device_config_flag CONTEXT FLAG
77# ----------------------------------------
78# Check that the device configuration flag FLAG is not set. Use CONTEXT in
79# logging.
80function check_no_device_config_flag {
81  local context=$1
82  local flag=$2
83
84  say "[$context] Check that the device configuration flag is not set..."
85  local flag_value=$(adb shell device_config get "$namespace" "$flag")
86  [[ "$flag_value" = null ]] \
87    || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected `null`)"
88}
89
90# get_system_property PROP
91# ------------------------
92# Get system property PROP associated with a device configuration flag.
93function get_system_property {
94  local prop=$1
95
96  # Note that we need to be root to read that system property.
97  adb root >/dev/null
98  local prop_value=$(adb shell getprop "$prop")
99  adb unroot >/dev/null
100  echo "$prop_value"
101}
102
103# check_system_property CONTEXT PROP VALUE
104# ----------------------------------------
105# Check that the system property PROP associated with a device configuration
106# flag is set to VALUE. Use CONTEXT in logging.
107function check_system_property {
108  local context=$1
109  local prop=$2
110  local value=$3
111
112  say "[$context] Check that the persistent system property is set..."
113  local prop_value=$(get_system_property "$prop")
114  [[ "$prop_value" = "$value" ]] \
115    || fail "System property \`$prop\` set to \`$prop_value\` (expected \`$value\`)"
116}
117
118# check_no_system_property CONTEXT PROP
119# -------------------------------------
120# Check that the system property PROP associated with a device configuration
121# flag is not set. Use CONTEXT in logging.
122function check_no_system_property {
123  local context=$1
124  local prop=$2
125
126  say "[$context] Check that the persistent system property is not set..."
127  local prop_value=$(get_system_property "$prop")
128  [[ -z "$prop_value" ]] \
129    || fail "System property \`$prop\` set to \`$prop_value\` (expected unset property)"
130}
131
132# find_zygote_runtime_option ZYGOTE RUNTIME_OPTION
133# ------------------------------------------------
134# Return whether ZYGOTE is passed RUNTIME_OPTION.
135function find_zygote_runtime_option {
136  local zygote=$1
137  local runtime_option=$2
138
139  adb logcat -d -s "$zygote" | grep -q -e "option\[[0-9]\+\]=$runtime_option"
140}
141
142# check_zygote_runtime_option CONTEXT RUNTIME_OPTION
143# --------------------------------------------------
144# Check that all zygote processes are passed RUNTIME_OPTION as runtime option. Use
145# CONTEXT in logging.
146function check_zygote_runtime_option {
147  local context=$1
148  local runtime_option=$2
149
150  say \
151    "[$context] Check that all zygote processes are passed \`$runtime_option\` as runtime option..."
152  for zygote in $zygotes; do
153    find_zygote_runtime_option "$zygote" "$runtime_option" \
154      || fail "Found no \`$runtime_option\` among runtime options passed to \`$zygote\`"
155  done
156}
157
158# check_no_zygote_runtime_option CONTEXT RUNTIME_OPTION
159# -----------------------------------------------------
160# Check that no zygote process is passed RUNTIME_OPTION as runtime option.  Use
161# CONTEXT in logging.
162function check_no_zygote_runtime_option {
163  local context=$1
164  local runtime_option=$2
165
166  say "[$context] Check that no zygote process is passed \`$runtime_option\` as runtime option..."
167  for zygote in $zygotes; do
168    find_zygote_runtime_option "$zygote" "$runtime_option" \
169      && fail "Found \`$runtime_option\` among runtime options passed to \`$zygote\`"
170  done
171}
172
173# check_android_runtime_message CONTEXT MESSAGE
174# ---------------------------------------------
175# Return whether AndroidRuntime generated MESSAGE in logcat. Use CONTEXT in
176# logging.
177function check_android_runtime_message {
178  local context=$1
179  local message=$2
180
181  say "[$context] Check that AndroidRuntime generated expected message in logcat..."
182  adb logcat -d -s AndroidRuntime | grep -F -q "$message" \
183    || fail "Found no message \"$message\" generated by AndroidRuntime"
184}
185
186# check_no_android_runtime_message CONTEXT MESSAGE
187# ------------------------------------------------
188# Return whether AndroidRuntime did not generate MESSAGE in logcat. Use CONTEXT
189# in logging.
190function check_no_android_runtime_message {
191  local context=$1
192  local message=$2
193
194  say "[$context] Check that AndroidRuntime did not generate unexpected message in logcat..."
195  adb logcat -d -s AndroidRuntime | grep -F -q -v "$message" \
196    || fail "Found message \"$message\" generated by AndroidRuntime"
197}
198
199# test_android_runtime_flag FLAG VALUE CHECK_EFFECT CHECK_NO_EFFECT
200# -----------------------------------------------------------------
201# Test device configuration FLAG with VALUE. CHECK_EFFECT and CHECK_NO_EFFECT
202# are functions that are passed a context as sole argument and that respectively
203# check the effect or the absence of effect of the flag.
204function test_android_runtime_flag {
205  local flag=$1
206  local value=$2
207  local check_effect=$3
208  local check_no_effect=$4
209
210  # Persistent system property (set after a reboot) associated with the device
211  # configuration flag.
212  local prop="persist.device_config.$namespace.$flag"
213
214  banner "Testing \`$flag\` value \`$value\`."
215
216  say "Setting device configuration flag..."
217  adb shell device_config put "$namespace" "$flag" "$value"
218  # Give some time to the device to digest this change before rebooting.
219  sleep 3
220
221  # Check that both the device configuration flag and the associated system
222  # property are set, but that flag has not produced an effect on the system (as
223  # we haven't rebooted yet).
224  local context="Flag set, before reboot"
225  check_device_config_flag "$context" "$flag" "$value"
226  check_system_property "$context" "$prop" "$value"
227  $check_no_effect "$context"
228
229  # Reboot device for the flag value to take effect.
230  reboot_and_wait_for_device
231  context="Flag set, after 1st reboot"
232  check_device_config_flag "$context" "$flag" "$value"
233  check_system_property "$context" "$prop" "$value"
234  $check_effect "$context"
235
236  # Reboot device a second time and check that the state has persisted.
237  reboot_and_wait_for_device
238  context="Flag set, after 2nd reboot"
239  check_device_config_flag "$context" "$flag" "$value"
240  check_system_property "$context" "$prop" "$value"
241  $check_effect "$context"
242
243  say "Unsetting device configuration flag..."
244  adb shell device_config delete "$namespace" "$flag" >/dev/null
245  # Give some time to the device to digest this change before rebooting.
246  sleep 3
247
248  # Reboot and check that the device is back to its default state.
249  reboot_and_wait_for_device
250  context="Flag unset, after 3rd reboot"
251  check_no_device_config_flag "$context" "$flag"
252  check_no_system_property "$context" "$prop"
253  $check_no_effect "$context"
254}
255
256
257# Pre-test actions.
258# =================
259
260# Enumerate Zygote processes.
261case $(adb shell getprop ro.zygote) in
262  (zygote32) zygotes="zygote";;
263  (zygote64) zygotes="zygote64";;
264  (zygote32_64|zygote64_32) zygotes="zygote zygote64";;
265esac
266
267# Test "enable_generational_cc" flag values.
268# ==========================================
269
270function check_nogenerational_cc {
271  check_zygote_runtime_option "$1" "-Xgc:nogenerational_cc"
272}
273function check_no_nogenerational_cc {
274  check_no_zygote_runtime_option "$1" "-Xgc:nogenerational_cc"
275}
276
277function check_generational_cc {
278  check_zygote_runtime_option "$1" "-Xgc:generational_cc"
279}
280function check_no_generational_cc {
281  check_no_zygote_runtime_option "$1" "-Xgc:generational_cc"
282}
283
284test_android_runtime_flag \
285  enable_generational_cc false check_nogenerational_cc check_no_nogenerational_cc
286test_android_runtime_flag \
287  enable_generational_cc true check_generational_cc check_no_generational_cc
288
289# Test "enable_apex_image" flag values.
290# =====================================
291
292default_boot_image_message="Using default boot image"
293function check_default_boot_image {
294  check_android_runtime_message "$1" "$default_boot_image_message"
295}
296function check_no_default_boot_image {
297  check_no_android_runtime_message "$1" "$default_boot_image_message"
298}
299
300apex_boot_image_option="-Ximage:/system/framework/apex.art"
301apex_boot_image_message="Using Apex boot image: '$apex_boot_image_option'"
302function check_apex_boot_image {
303  check_zygote_runtime_option "$1" "$apex_boot_image_option"
304  check_android_runtime_message "$1" "$apex_boot_image_message"
305}
306function check_no_apex_boot_image {
307  check_no_zygote_runtime_option "$1" "$apex_boot_image_option"
308  check_no_android_runtime_message "$1" "$apex_boot_image_message"
309}
310
311test_android_runtime_flag \
312  enable_apex_image false check_default_boot_image check_no_default_boot_image
313test_android_runtime_flag \
314  enable_apex_image true check_apex_boot_image check_no_apex_boot_image
315
316# Post-test actions.
317# ==================
318
319if [[ "$exit_status" -eq 0 ]]; then
320  banner "All tests passed."
321else
322  banner "Test(s) failed."
323fi
324exit $exit_status
325