• 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 CDD 7.1.1.3.
31CTS_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
54OUT_FILE = "/sdcard/cts-theme-assets.zip"
55
56
57class 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.
90def 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
103def 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
111def 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
170def 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
188def 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
208def 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
254if __name__ == '__main__':
255    main(sys.argv)
256