Home | History | Annotate | Download | only in theme
      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     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 
     54 OUT_FILE = "/sdcard/cts-theme-assets.zip"
     55 
     56 
     57 class 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.
     90 def 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 
    103 def 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 
    111 def 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 
    170 def 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 
    188 def 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 
    208 def 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 
    254 if __name__ == '__main__':
    255     main(sys.argv)
    256