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