1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import telemetry.core.platform.power_monitor as power_monitor
6
7_TEMPERATURE_FILE = '/sys/class/thermal/thermal_zone0/temp'
8
9
10class AndroidTemperatureMonitor(power_monitor.PowerMonitor):
11  """
12  Delegates monitoring to another PowerMonitor and adds temperature measurements
13  to overall results.
14  """
15  def __init__(self, monitor, device):
16    super(AndroidTemperatureMonitor, self).__init__()
17    self._device = device
18    self._power_monitor = monitor
19    self._can_monitor_with_power_monitor = None
20
21  def CanMonitorPower(self):
22    self._can_monitor_with_power_monitor = (
23        self._power_monitor.CanMonitorPower())
24    # Always report ability to monitor power to be able to provide temperature
25    # metrics and other useful power-related data from sensors.
26    return True
27
28  def StartMonitoringPower(self, browser):
29    if self._can_monitor_with_power_monitor:
30      self._power_monitor.StartMonitoringPower(browser)
31
32  def StopMonitoringPower(self):
33    if self._can_monitor_with_power_monitor:
34      power_data = self._power_monitor.StopMonitoringPower()
35    else:
36      power_data = {'identifier': 'android_temperature_monitor'}
37
38    # Take the current temperature as average based on the assumption that the
39    # temperature changes slowly during measurement time.
40    average_temperature = self._GetBoardTemperatureCelsius()
41    if average_temperature is None:
42      return power_data
43
44    # Insert temperature into the appropriate position in the dictionary
45    # returned by StopMonitoringPower() creating appropriate sub-dictionaries on
46    # the way if necessary.
47    temperature_path = [
48        'component_utilization', 'whole_package', 'average_temperature_c']
49    temperature_insertion_point = power_data
50    for path_element in temperature_path[:-1]:
51      if not path_element in temperature_insertion_point:
52        temperature_insertion_point[path_element] = {}
53      temperature_insertion_point = temperature_insertion_point[path_element]
54    assert temperature_path[-1] not in temperature_insertion_point
55    temperature_insertion_point[temperature_path[-1]] = average_temperature
56
57    return power_data
58
59  def _GetBoardTemperatureCelsius(self):
60    contents = self._device.ReadFile(_TEMPERATURE_FILE)
61    if len(contents) > 0:
62      return float(contents[0])
63    return None
64