#!/usr/bin/python3 # # Copyright (C) 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import os import sys import tempfile import threading import time import traceback from android_device import * from avd import * from queue import Queue, Empty # This dict should contain one entry for every density listed in CDD 7.1.1.3. CTS_THEME_dict = { 120: "ldpi", 140: "140dpi", 160: "mdpi", 180: "180dpi", 200: "200dpi", 213: "tvdpi", 220: "220dpi", 240: "hdpi", 260: "260dpi", 280: "280dpi", 300: "300dpi", 320: "xhdpi", 340: "340dpi", 360: "360dpi", 400: "400dpi", 420: "420dpi", 440: "440dpi", 480: "xxhdpi", 560: "560dpi", 640: "xxxhdpi", } OUT_FILE = "/sdcard/cts-theme-assets.zip" class ParallelExecutor(threading.Thread): def __init__(self, tasks, setup, q): threading.Thread.__init__(self) self._q = q self._tasks = tasks self._setup = setup self._result = 0 def run(self): try: while True: config = self._q.get(block=True, timeout=2) for t in self._tasks: try: if t(self._setup, config): self._result += 1 except KeyboardInterrupt: raise except: print("Failed to execute thread:", sys.exc_info()[0]) traceback.print_exc() self._q.task_done() except KeyboardInterrupt: raise except Empty: pass def get_result(self): return self._result # pass a function with number of instances to be executed in parallel # each thread continues until config q is empty. def execute_parallel(tasks, setup, q, num_threads): result = 0 threads = [] for i in range(num_threads): t = ParallelExecutor(tasks, setup, q) t.start() threads.append(t) for t in threads: t.join() result += t.get_result() return result def print_adb_result(device, out, err): print("device: " + device) if out is not None: print("out:\n" + out) if err is not None: print("err:\n" + err) def do_capture(setup, device_serial): (themeApkPath, out_path) = setup device = AndroidDevice(device_serial) version = device.get_version_codename() if version == "REL": version = str(device.get_version_sdk()) density = device.get_density() if CTS_THEME_dict[density]: density_bucket = CTS_THEME_dict[density] else: density_bucket = str(density) + "dpi" out_file = os.path.join(out_path, os.path.join(version, "%s.zip" % density_bucket)) device.uninstall_package('android.theme.app') (out, err, success) = device.install_apk(themeApkPath) if not success: print("Failed to install APK on " + device_serial) print_adb_result(device_serial, out, err) return False print("Generating images on " + device_serial + "...") try: (out, err) = device.run_instrumentation_test( "android.theme.app/androidx.test.runner.AndroidJUnitRunner") except KeyboardInterrupt: raise except: (out, err) = device.run_instrumentation_test( "android.theme.app/android.test.InstrumentationTestRunner") # Detect test failure and abort. if "FAILURES!!!" in out.split(): print_adb_result(device_serial, out, err) return False # Make sure that the run is complete by checking the process itself print("Waiting for " + device_serial + "...") wait_time = 0 while device.is_process_alive("android.theme.app"): time.sleep(1) wait_time = wait_time + 1 if wait_time > 180: print("Timed out") break time.sleep(10) print("Pulling images from " + device_serial + " to " + out_file) device.run_adb_command("pull " + OUT_FILE + " " + out_file) device.run_adb_command("shell rm -rf " + OUT_FILE) return True def get_emulator_path(): if 'ANDROID_SDK_ROOT' not in os.environ: print('Environment variable ANDROID_SDK_ROOT must point to your Android SDK root.') sys.exit(1) sdk_path = os.environ['ANDROID_SDK_ROOT'] if not os.path.isdir(sdk_path): print("Failed to find Android SDK at ANDROID_SDK_ROOT: %s" % sdk_path) sys.exit(1) emu_path = os.path.join(os.path.join(sdk_path, 'tools'), 'emulator') if not os.path.isfile(emu_path): print("Failed to find emulator within ANDROID_SDK_ROOT: %s" % sdk_path) sys.exit(1) return emu_path def start_emulator(name, density): if name == "local": emu_path = "" else: emu_path = get_emulator_path() # Start emulator for 560dpi, normal screen size. test_avd = AVD(name, emu_path) test_avd.configure_screen(density, 360, 640) test_avd.start() try: test_avd_device = test_avd.get_device() test_avd_device.wait_for_device() test_avd_device.wait_for_boot_complete() return test_avd except: test_avd.stop() return None def main(argv): if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_HOST_OUT' not in os.environ: print('Missing environment variables. Did you run build/envsetup.sh and lunch?') sys.exit(1) theme_apk = os.path.join(os.environ['ANDROID_HOST_OUT'], 'cts/android-cts/testcases/CtsThemeDeviceApp.apk') if not os.path.isfile(theme_apk): print('Couldn\'t find test APK. Did you run make cts?') sys.exit(1) out_path = os.path.join(os.environ['ANDROID_BUILD_TOP'], 'cts/hostsidetests/theme/assets') os.system("mkdir -p %s" % out_path) if len(argv) is 2: for density in CTS_THEME_dict.keys(): emulator = start_emulator(argv[1], density) result = do_capture(setup=(theme_apk, out_path), device_serial=emulator.get_serial()) emulator.stop() if result: print("Generated reference images for %ddpi" % density) else: print("Failed to generate reference images for %ddpi" % density) break else: tasks = [do_capture] setup = (theme_apk, out_path) devices = enumerate_android_devices() if len(devices) > 0: device_queue = Queue() for device in devices: device_queue.put(device) result = execute_parallel(tasks, setup, device_queue, len(devices)) if result > 0: print('Generated reference images for %(count)d devices' % {"count": result}) else: print('Failed to generate reference images') else: print('No devices found') if __name__ == '__main__': main(sys.argv)