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