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