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     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