1e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# SPDX-License-Identifier: Apache-2.0
2e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider#
3e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# Copyright (C) 2017, Arm Limited and contributors.
4e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider#
5e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# Licensed under the Apache License, Version 2.0 (the "License"); you may
6e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# not use this file except in compliance with the License.
7e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# You may obtain a copy of the License at
8e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider#
9e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# http://www.apache.org/licenses/LICENSE-2.0
10e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider#
11e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# Unless required by applicable law or agreed to in writing, software
12e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# See the License for the specific language governing permissions and
15e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# limitations under the License.
16e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider#
17e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
18e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderimport re
19e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderimport os
20e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderimport logging
21e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
22e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderfrom subprocess import Popen, PIPE
23e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
24e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderfrom time import sleep
25e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
26e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderfrom android import Screen, System, Workload
27e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderfrom devlib.utils.android import grant_app_permissions
28e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
29e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# Regexps for benchmark synchronization
30e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
31e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin SchneiderREGEXPS = {
32e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    'start'    : '.*Displayed com.google.android.exoplayer2.demo/.PlayerActivity',
33e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    'duration' : '.*period \[(?P<duration>[0-9]+.*)\]',
34e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    'end'      : '.*state \[.+, .+, E\]'
35e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider}
36e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
37e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneiderclass ExoPlayer(Workload):
38e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    """
39e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    Android ExoPlayer workload
40e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
41e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    Exoplayer sources: https://github.com/google/ExoPlayer
42e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
43e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    The 'demo' application is used by this workload.
44e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    It can easily be built by loading the ExoPlayer sources
45e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    into Android Studio
46e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
47e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    Expected apk is 'demo-noExtensions-debug.apk'
48e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
49e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    Version r2.4.0 (d979469) is known to work
50e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    """
51e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
52e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    # Package required by this workload
53e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    package = 'com.google.android.exoplayer2.demo'
54e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    action = 'com.google.android.exoplayer.demo.action.VIEW'
55e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
56e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    def __init__(self, test_env):
57e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        super(ExoPlayer, self).__init__(test_env)
58e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._log = logging.getLogger('ExoPlayer')
59e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
60e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    def _play(self):
61e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
62e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Grant app all permissions
63e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        grant_app_permissions(self._target, self.package)
64e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
65e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Handle media file location
66e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        if not self.from_device:
67e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            remote_file = self._target.path.join(
68e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                self._target.working_directory,
69e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                os.path.basename(self.media_file)
70e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            )
71e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
72e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._log.info('Pushing media file to device...')
73e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._target.push(
74e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                self.media_file,
75e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                remote_file,
76e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                timeout = 60
77e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            )
78e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._log.info('Media file transfer complete')
79e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        else:
80e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            remote_file = self.media_file
81e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
82e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Prepare logcat monitor
83e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        monitor = self._target.get_logcat_monitor(REGEXPS.values())
84e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        monitor.start()
85e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
86e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Play media file
87e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        play_cmd = 'am start -a "{}" -d "file://{}"'\
88e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                   .format(self.action, remote_file)
89e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._log.info(play_cmd)
90e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._target.execute(play_cmd)
91e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
92e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        monitor.wait_for(REGEXPS['start'])
93e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.tracingStart()
94e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._log.info('Playing media file')
95e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
96e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        line = monitor.wait_for(REGEXPS['duration'])[0]
97e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        media_duration_s = int(round(float(re.search(REGEXPS['duration'], line)
98e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                                   .group('duration'))))
99e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
100e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._log.info('Media duration is {}'.format(media_duration_s))
101e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
102e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        if self.play_duration_s and self.play_duration_s < media_duration_s:
103e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._log.info('Waiting {} seconds before ending playback'
104e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                           .format(self.play_duration_s))
105e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            sleep(self.play_duration_s)
106e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        else:
107e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._log.info('Waiting for playback completion ({} seconds)'
108e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                           .format(media_duration_s))
109e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            monitor.wait_for(REGEXPS['end'], timeout = media_duration_s + 30)
110e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
111e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.tracingStop()
112e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        monitor.stop()
113e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._log.info('Media file playback completed')
114e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
115e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Remove file if it was pushed
116e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        if not self.from_device:
117e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            self._target.remove(remote_file)
118e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
119e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider    def run(self, out_dir, collect, media_file, from_device=False, play_duration_s=None):
120e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        """
121e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Run Exoplayer workload
122e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
123e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :param out_dir: Path to experiment directory on the host
124e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                        where to store results.
125e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :type out_dir: str
126e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
127e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :param collect: Specifies what to collect. Possible values:
128e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            - 'energy'
129e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            - 'systrace'
130e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            - 'ftrace'
131e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            - any combination of the above as a single space-separated string.
132e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :type collect: list(str)
133e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
134e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :param media_file: Filepath of the media to play
135e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            Path on device if 'from_device' is True
136e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            Path on host   if 'from_device' is False (default)
137e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :type media_file: str
138e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
139e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :param from_device: Whether file to play is already on the device
140e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :type from_device: bool
141e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
142e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :param play_duration_s: If set, maximum duration (seconds) of the media playback
143e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider                                If not set, media will play to completion
144e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        :type play_duration_s: int
145e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        """
146e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
147e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Keep track of mandatory parameters
148e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.out_dir = out_dir
149e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.collect = collect
150e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.media_file = media_file
151e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.from_device = from_device
152e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self.play_duration_s = play_duration_s
153e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
154e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Check media file exists
155e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        if from_device and not self._target.file_exists(self.media_file):
156e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            raise RuntimeError('Cannot find "{}" on target'.format(self.media_file))
157e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        elif not from_device and not os.path.isfile(self.media_file):
158e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider            raise RuntimeError('Cannot find "{}" on host'.format(self.media_file))
159e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
160e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Unlock device screen (assume no password required)
161e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Screen.unlock(self._target)
162e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
163e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Close and clear application
164e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        System.force_stop(self._target, self.package, clear=True)
165e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
166e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Enable airplane mode
167e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        System.set_airplane_mode(self._target, on=True)
168e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
169e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Set min brightness
170e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Screen.set_brightness(self._target, auto=False, percent=0)
171e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
172e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Force screen in PORTRAIT mode
173e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Screen.set_orientation(self._target, portrait=True)
174e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
175e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Launch Exoplayer benchmark
176e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        self._play()
177e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
178e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Go back to home screen
179e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        System.home(self._target)
180e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
181e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Set orientation back to auto
182e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Screen.set_orientation(self._target, auto=True)
183e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
184e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Set brightness back to auto
185e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        Screen.set_brightness(self._target, auto=True)
186e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
187e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Turn off airplane mode
188e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        System.set_airplane_mode(self._target, on=False)
189e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
190e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        # Close and clear application
191e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider        System.force_stop(self._target, self.package, clear=True)
192e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider
193e30f1aeedbfa5ba20a438c12b1af7078ac64b776Valentin Schneider# vim :set tabstop=4 shiftwidth=4 expandtab
194