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