1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2019 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Liimport abc 6*9c5db199SXin Liimport logging 7*9c5db199SXin Liimport time 8*9c5db199SXin Li 9*9c5db199SXin Lifrom autotest_lib.client.bin import utils 10*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import chrome 11*9c5db199SXin Lifrom autotest_lib.client.cros.audio import audio_helper 12*9c5db199SXin Lifrom autotest_lib.client.cros.input_playback import keyboard 13*9c5db199SXin Lifrom autotest_lib.client.cros.power import power_test 14*9c5db199SXin Li 15*9c5db199SXin Li 16*9c5db199SXin Liclass power_VideoTest(power_test.power_Test): 17*9c5db199SXin Li """Optional base class for power related video tests.""" 18*9c5db199SXin Li version = 1 19*9c5db199SXin Li 20*9c5db199SXin Li # Ram disk location to download video file. 21*9c5db199SXin Li # We use ram disk to avoid power hit from network / disk usage. 22*9c5db199SXin Li _RAMDISK = '/tmp/ramdisk' 23*9c5db199SXin Li 24*9c5db199SXin Li # Time in seconds to wait after set up before starting each video. 25*9c5db199SXin Li _WAIT_FOR_IDLE = 15 26*9c5db199SXin Li 27*9c5db199SXin Li # Time in seconds to measure power per video file. 28*9c5db199SXin Li _MEASUREMENT_DURATION = 120 29*9c5db199SXin Li 30*9c5db199SXin Li # Chrome arguments to disable HW video decode 31*9c5db199SXin Li _DISABLE_HW_VIDEO_DECODE_ARGS = '--disable-accelerated-video-decode' 32*9c5db199SXin Li 33*9c5db199SXin Li 34*9c5db199SXin Li def initialize(self, seconds_period=3, pdash_note='', 35*9c5db199SXin Li force_discharge=False, run_arc=True): 36*9c5db199SXin Li """Create and mount ram disk to download video.""" 37*9c5db199SXin Li super(power_VideoTest, self).initialize( 38*9c5db199SXin Li seconds_period=seconds_period, pdash_note=pdash_note, 39*9c5db199SXin Li force_discharge=force_discharge, run_arc=run_arc) 40*9c5db199SXin Li utils.run('mkdir -p %s' % self._RAMDISK) 41*9c5db199SXin Li # Don't throw an exception on errors. 42*9c5db199SXin Li result = utils.run('mount -t ramfs -o context=u:object_r:tmpfs:s0 ' 43*9c5db199SXin Li 'ramfs %s' % self._RAMDISK, ignore_status=True) 44*9c5db199SXin Li if result.exit_status: 45*9c5db199SXin Li logging.info('cannot mount ramfs with context=u:object_r:tmpfs:s0,' 46*9c5db199SXin Li ' trying plain mount') 47*9c5db199SXin Li # Try again without selinux options. This time fail on error. 48*9c5db199SXin Li utils.run('mount -t ramfs ramfs %s' % self._RAMDISK) 49*9c5db199SXin Li audio_helper.set_volume_levels(10, 10) 50*9c5db199SXin Li 51*9c5db199SXin Li @abc.abstractmethod 52*9c5db199SXin Li def _prepare_video(self, cr, url): 53*9c5db199SXin Li """Prepare browser session before playing video. 54*9c5db199SXin Li 55*9c5db199SXin Li @param cr: Autotest Chrome instance. 56*9c5db199SXin Li @param url: url of video file to play. 57*9c5db199SXin Li """ 58*9c5db199SXin Li raise NotImplementedError() 59*9c5db199SXin Li 60*9c5db199SXin Li @abc.abstractmethod 61*9c5db199SXin Li def _start_video(self, cr, url): 62*9c5db199SXin Li """Open the video and play it. 63*9c5db199SXin Li 64*9c5db199SXin Li @param cr: Autotest Chrome instance. 65*9c5db199SXin Li @param url: url of video file to play. 66*9c5db199SXin Li """ 67*9c5db199SXin Li raise NotImplementedError() 68*9c5db199SXin Li 69*9c5db199SXin Li @abc.abstractmethod 70*9c5db199SXin Li def _teardown_video(self, cr, url): 71*9c5db199SXin Li """Teardown browser session after playing video. 72*9c5db199SXin Li 73*9c5db199SXin Li @param cr: Autotest Chrome instance. 74*9c5db199SXin Li @param url: url of video file to play. 75*9c5db199SXin Li """ 76*9c5db199SXin Li raise NotImplementedError() 77*9c5db199SXin Li 78*9c5db199SXin Li def _calculate_dropped_frame_percent(self, tab): 79*9c5db199SXin Li """Calculate percent of dropped frame. 80*9c5db199SXin Li 81*9c5db199SXin Li @param tab: tab object that played video in Autotest Chrome instance. 82*9c5db199SXin Li """ 83*9c5db199SXin Li decoded_frame_count = tab.EvaluateJavaScript( 84*9c5db199SXin Li "document.getElementsByTagName" 85*9c5db199SXin Li "('video')[0].webkitDecodedFrameCount") 86*9c5db199SXin Li dropped_frame_count = tab.EvaluateJavaScript( 87*9c5db199SXin Li "document.getElementsByTagName" 88*9c5db199SXin Li "('video')[0].webkitDroppedFrameCount") 89*9c5db199SXin Li if decoded_frame_count != 0: 90*9c5db199SXin Li dropped_frame_percent = \ 91*9c5db199SXin Li 100.0 * dropped_frame_count / decoded_frame_count 92*9c5db199SXin Li else: 93*9c5db199SXin Li logging.error("No frame is decoded. Set drop percent to 100.") 94*9c5db199SXin Li dropped_frame_percent = 100.0 95*9c5db199SXin Li 96*9c5db199SXin Li logging.info("Decoded frames=%d, dropped frames=%d, percent=%f", 97*9c5db199SXin Li decoded_frame_count, dropped_frame_count, dropped_frame_percent) 98*9c5db199SXin Li return dropped_frame_percent 99*9c5db199SXin Li 100*9c5db199SXin Li def run_once(self, videos=None, secs_per_video=_MEASUREMENT_DURATION, 101*9c5db199SXin Li use_hw_decode=True): 102*9c5db199SXin Li """run_once method. 103*9c5db199SXin Li 104*9c5db199SXin Li @param videos: list of tuple of tagname and video url to test. 105*9c5db199SXin Li @param secs_per_video: time in seconds to play video and measure power. 106*9c5db199SXin Li @param use_hw_decode: if False, disable hw video decoding. 107*9c5db199SXin Li """ 108*9c5db199SXin Li # --disable-sync disables test account info sync, eg. Wi-Fi credentials, 109*9c5db199SXin Li # so that each test run does not remember info from last test run. 110*9c5db199SXin Li extra_browser_args = ['--disable-sync'] 111*9c5db199SXin Li # b/228256145 to avoid powerd restart 112*9c5db199SXin Li extra_browser_args.append('--disable-features=FirmwareUpdaterApp') 113*9c5db199SXin Li if not use_hw_decode: 114*9c5db199SXin Li extra_browser_args.append(self._DISABLE_HW_VIDEO_DECODE_ARGS) 115*9c5db199SXin Li 116*9c5db199SXin Li with chrome.Chrome(extra_browser_args=extra_browser_args, 117*9c5db199SXin Li init_network_controller=True, 118*9c5db199SXin Li arc_mode=self._arc_mode) as self.cr: 119*9c5db199SXin Li # Chrome always starts with an empty tab, so we just use that one. 120*9c5db199SXin Li tab = self.cr.browser.tabs[0] 121*9c5db199SXin Li tab.Activate() 122*9c5db199SXin Li 123*9c5db199SXin Li # Stop services again as Chrome might have restarted them. 124*9c5db199SXin Li self._services.stop_services() 125*9c5db199SXin Li 126*9c5db199SXin Li # Just measure power in full-screen. 127*9c5db199SXin Li fullscreen = tab.EvaluateJavaScript('document.webkitIsFullScreen') 128*9c5db199SXin Li if not fullscreen: 129*9c5db199SXin Li with keyboard.Keyboard() as keys: 130*9c5db199SXin Li keys.press_key('f4') 131*9c5db199SXin Li 132*9c5db199SXin Li self.start_measurements() 133*9c5db199SXin Li idle_start = time.time() 134*9c5db199SXin Li 135*9c5db199SXin Li for name, url in videos: 136*9c5db199SXin Li self._prepare_video(self.cr, url) 137*9c5db199SXin Li time.sleep(self._WAIT_FOR_IDLE) 138*9c5db199SXin Li 139*9c5db199SXin Li logging.info('Playing video: %s', name) 140*9c5db199SXin Li self._start_video(self.cr, url) 141*9c5db199SXin Li self.checkpoint_measurements('idle', idle_start) 142*9c5db199SXin Li 143*9c5db199SXin Li loop_start = time.time() 144*9c5db199SXin Li time.sleep(secs_per_video) 145*9c5db199SXin Li self.checkpoint_measurements(name, loop_start) 146*9c5db199SXin Li 147*9c5db199SXin Li idle_start = time.time() 148*9c5db199SXin Li self.keyvals[name + '_dropped_frame_percent'] = \ 149*9c5db199SXin Li self._calculate_dropped_frame_percent(tab) 150*9c5db199SXin Li self._teardown_video(self.cr, url) 151*9c5db199SXin Li 152*9c5db199SXin Li def cleanup(self): 153*9c5db199SXin Li """Unmount ram disk.""" 154*9c5db199SXin Li utils.run('umount %s' % self._RAMDISK) 155*9c5db199SXin Li super(power_VideoTest, self).cleanup() 156