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