1#!/usr/bin/python3 2# 3# Copyright (C) 2015 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 18import os 19import sys 20import tempfile 21import threading 22import time 23import traceback 24 25from android_device import * 26from avd import * 27from queue import Queue, Empty 28 29 30# This dict should contain one entry for every density listed in DisplayMetrics. 31# See CDD 7.1.1.3 for more information on densities at which CTS can run. If you 32# are only generating reference images for a single density, you can comment out 33# the other densities and then run the script. 34CTS_THEME_dict = { 35 120: "ldpi", 36 140: "140dpi", 37 160: "mdpi", 38 180: "180dpi", 39 200: "200dpi", 40 213: "tvdpi", 41 220: "220dpi", 42 240: "hdpi", 43 260: "260dpi", 44 280: "280dpi", 45 300: "300dpi", 46 320: "xhdpi", 47 340: "340dpi", 48 360: "360dpi", 49 390: "390dpi", 50 400: "400dpi", 51 420: "420dpi", 52 440: "440dpi", 53 450: "450dpi", 54 480: "xxhdpi", 55 520: "520dpi", 56 560: "560dpi", 57 600: "600dpi", 58 640: "xxxhdpi", 59} 60 61OUT_FILE = "/sdcard/cts-theme-assets.zip" 62 63 64class ParallelExecutor(threading.Thread): 65 def __init__(self, tasks, setup, q): 66 threading.Thread.__init__(self) 67 self._q = q 68 self._tasks = tasks 69 self._setup = setup 70 self._result = 0 71 72 def run(self): 73 try: 74 while True: 75 config = self._q.get(block=True, timeout=2) 76 for t in self._tasks: 77 try: 78 if t(self._setup, config): 79 self._result += 1 80 except KeyboardInterrupt: 81 raise 82 except: 83 print("Failed to execute thread:", sys.exc_info()[0]) 84 traceback.print_exc() 85 self._q.task_done() 86 except KeyboardInterrupt: 87 raise 88 except Empty: 89 pass 90 91 def get_result(self): 92 return self._result 93 94 95# pass a function with number of instances to be executed in parallel 96# each thread continues until config q is empty. 97def execute_parallel(tasks, setup, q, num_threads): 98 result = 0 99 threads = [] 100 for i in range(num_threads): 101 t = ParallelExecutor(tasks, setup, q) 102 t.start() 103 threads.append(t) 104 for t in threads: 105 t.join() 106 result += t.get_result() 107 return result 108 109 110def print_adb_result(device, out, err): 111 print("device: " + device) 112 if out is not None: 113 print("out:\n" + out) 114 if err is not None: 115 print("err:\n" + err) 116 117 118def do_capture(setup, device_serial): 119 (themeApkPath, out_path) = setup 120 121 device = AndroidDevice(device_serial) 122 123 version = device.get_version_codename() 124 if version == "REL": 125 version = str(device.get_version_sdk()) 126 127 density = device.get_density() 128 129 if CTS_THEME_dict[density]: 130 density_bucket = CTS_THEME_dict[density] 131 else: 132 density_bucket = str(density) + "dpi" 133 134 out_file = os.path.join(out_path, os.path.join(version, "%s.zip" % density_bucket)) 135 136 device.uninstall_package('android.theme.app') 137 138 (out, err, success) = device.install_apk(themeApkPath) 139 if not success: 140 print("Failed to install APK on " + device_serial) 141 print_adb_result(device_serial, out, err) 142 return False 143 144 print("Generating images on " + device_serial + "...") 145 try: 146 (out, err) = device.run_instrumentation_test( 147 "android.theme.app/androidx.test.runner.AndroidJUnitRunner") 148 except KeyboardInterrupt: 149 raise 150 except: 151 (out, err) = device.run_instrumentation_test( 152 "android.theme.app/android.test.InstrumentationTestRunner") 153 154 # Detect test failure and abort. 155 if "FAILURES!!!" in out.split(): 156 print_adb_result(device_serial, out, err) 157 return False 158 159 # Make sure that the run is complete by checking the process itself 160 print("Waiting for " + device_serial + "...") 161 wait_time = 0 162 while device.is_process_alive("android.theme.app"): 163 time.sleep(1) 164 wait_time = wait_time + 1 165 if wait_time > 180: 166 print("Timed out") 167 break 168 169 time.sleep(10) 170 171 print("Pulling images from " + device_serial + " to " + out_file) 172 device.run_adb_command("pull " + OUT_FILE + " " + out_file) 173 device.run_adb_command("shell rm -rf " + OUT_FILE) 174 return True 175 176 177def get_emulator_path(): 178 if 'ANDROID_SDK_ROOT' not in os.environ: 179 print('Environment variable ANDROID_SDK_ROOT must point to your Android SDK root.') 180 sys.exit(1) 181 182 sdk_path = os.environ['ANDROID_SDK_ROOT'] 183 if not os.path.isdir(sdk_path): 184 print("Failed to find Android SDK at ANDROID_SDK_ROOT: %s" % sdk_path) 185 sys.exit(1) 186 187 emu_path = os.path.join(os.path.join(sdk_path, 'tools'), 'emulator') 188 if not os.path.isfile(emu_path): 189 print("Failed to find emulator within ANDROID_SDK_ROOT: %s" % sdk_path) 190 sys.exit(1) 191 192 return emu_path 193 194 195def start_emulator(name, density): 196 if name == "local": 197 emu_path = "" 198 else: 199 emu_path = get_emulator_path() 200 201 # Start emulator for 560dpi, normal screen size. 202 test_avd = AVD(name, emu_path) 203 test_avd.configure_screen(density, 360, 640) 204 test_avd.start() 205 try: 206 test_avd_device = test_avd.get_device() 207 test_avd_device.wait_for_device() 208 test_avd_device.wait_for_boot_complete() 209 return test_avd 210 except: 211 test_avd.stop() 212 return None 213 214 215def main(argv): 216 if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_HOST_OUT' not in os.environ: 217 print('Missing environment variables. Did you run build/envsetup.sh and lunch?') 218 sys.exit(1) 219 220 theme_apk = os.path.join(os.environ['ANDROID_HOST_OUT'], 221 'cts/android-cts/testcases/CtsThemeHostTestCases/CtsThemeDeviceApp.apk') 222 if not os.path.isfile(theme_apk): 223 print('Couldn\'t find test APK. Did you run make cts?') 224 sys.exit(1) 225 226 out_path = os.path.join(os.environ['ANDROID_BUILD_TOP'], 227 'cts/hostsidetests/theme/assets') 228 os.system("mkdir -p %s" % out_path) 229 230 if len(argv) == 2: 231 for density in CTS_THEME_dict.keys(): 232 retries = 0 233 result = False 234 while result != True: 235 retries += 1 236 emulator = start_emulator(argv[1], density) 237 result = do_capture(setup=(theme_apk, out_path), device_serial=emulator.get_serial()) 238 emulator.stop() 239 if result: 240 print("Generated reference images for %ddpi" % density) 241 else: 242 print("Failed to generate reference images for %ddpi" % density) 243 print("Try number %d" % retries) 244 else: 245 tasks = [do_capture] 246 setup = (theme_apk, out_path) 247 248 devices = enumerate_android_devices() 249 250 if len(devices) > 0: 251 device_queue = Queue() 252 for device in devices: 253 device_queue.put(device) 254 255 result = execute_parallel(tasks, setup, device_queue, len(devices)) 256 257 if result > 0: 258 print('Generated reference images for %(count)d devices' % {"count": result}) 259 else: 260 print('Failed to generate reference images') 261 else: 262 print('No devices found') 263 264 265if __name__ == '__main__': 266 main(sys.argv) 267