Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: build/android/pylib/device/battery_utils.py

Issue 1040473002: [android] Create Battery Utils to seperate power functionality (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/PRESUBMIT.py ('k') | build/android/pylib/device/battery_utils_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2015 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
5 """Provides a variety of device interactions with power.
6 """
7 # pylint: disable=unused-argument
8
9 import collections
10 import contextlib
11 import csv
12 import logging
13
14 from pylib import constants
15 from pylib.device import decorators
16 from pylib.device import device_errors
17 from pylib.device import device_utils
18 from pylib.utils import timeout_retry
19
20 _DEFAULT_TIMEOUT = 30
21 _DEFAULT_RETRIES = 3
22
23 _CONTROL_CHARGING_COMMANDS = [
24 {
25 # Nexus 4
26 'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
27 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
28 'disable_command':
29 'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
30 },
31 {
32 # Nexus 5
33 # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
34 # energy coming from USB. Setting the power_supply offline just updates the
35 # Android system to reflect that.
36 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
37 'enable_command': (
38 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
39 'echo 1 > /sys/class/power_supply/usb/online'),
40 'disable_command': (
41 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
42 'chmod 644 /sys/class/power_supply/usb/online && '
43 'echo 0 > /sys/class/power_supply/usb/online'),
44 },
45 ]
46
47 # The list of useful dumpsys columns.
48 # Index of the column containing the format version.
49 _DUMP_VERSION_INDEX = 0
50 # Index of the column containing the type of the row.
51 _ROW_TYPE_INDEX = 3
52 # Index of the column containing the uid.
53 _PACKAGE_UID_INDEX = 4
54 # Index of the column containing the application package.
55 _PACKAGE_NAME_INDEX = 5
56 # The column containing the uid of the power data.
57 _PWI_UID_INDEX = 1
58 # The column containing the type of consumption. Only consumtion since last
59 # charge are of interest here.
60 _PWI_AGGREGATION_INDEX = 2
61 # The column containing the amount of power used, in mah.
62 _PWI_POWER_CONSUMPTION_INDEX = 5
63
64
65 class BatteryUtils(object):
66
67 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
68 default_retries=_DEFAULT_RETRIES):
69 """BatteryUtils constructor.
70
71 Args:
72 device: A DeviceUtils instance.
73 default_timeout: An integer containing the default number of seconds to
74 wait for an operation to complete if no explicit value
75 is provided.
76 default_retries: An integer containing the default number or times an
77 operation should be retried on failure if no explicit
78 value is provided.
79
80 Raises:
81 TypeError: If it is not passed a DeviceUtils instance.
82 """
83 if not isinstance(device, device_utils.DeviceUtils):
84 raise TypeError('Must be initialized with DeviceUtils object.')
85 self._device = device
86 self._cache = device.GetClientCache(self.__class__.__name__)
87 self._default_timeout = default_timeout
88 self._default_retries = default_retries
89
90 @decorators.WithTimeoutAndRetriesFromInstance()
91 def GetPowerData(self, timeout=None, retries=None):
92 """ Get power data for device.
93 Args:
94 timeout: timeout in seconds
95 retries: number of retries
96
97 Returns:
98 Dict of power data, keyed on package names.
99 {
100 package_name: {
101 'uid': uid,
102 'data': [1,2,3]
103 },
104 }
105 """
106 dumpsys_output = self._device.RunShellCommand(
107 ['dumpsys', 'batterystats', '-c'], check_return=True)
108 csvreader = csv.reader(dumpsys_output)
109 uid_entries = {}
110 pwi_entries = collections.defaultdict(list)
111 for entry in csvreader:
112 if entry[_DUMP_VERSION_INDEX] not in ['8', '9']:
113 # Wrong dumpsys version.
114 raise device_errors.DeviceVersionError(
115 'Dumpsys version must be 8 or 9. %s found.'
116 % entry[_DUMP_VERSION_INDEX])
117 if _ROW_TYPE_INDEX >= len(entry):
118 continue
119 if entry[_ROW_TYPE_INDEX] == 'uid':
120 current_package = entry[_PACKAGE_NAME_INDEX]
121 if current_package in uid_entries:
122 raise device_errors.CommandFailedError(
123 'Package %s found multiple times' % (current_package))
124 uid_entries[current_package] = entry[_PACKAGE_UID_INDEX]
125 elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry)
126 and entry[_ROW_TYPE_INDEX] == 'pwi'
127 and entry[_PWI_AGGREGATION_INDEX] == 'l'):
128 pwi_entries[entry[_PWI_UID_INDEX]].append(
129 float(entry[_PWI_POWER_CONSUMPTION_INDEX]))
130
131 return {p: {'uid': uid, 'data': pwi_entries[uid]}
132 for p, uid in uid_entries.iteritems()}
133
134 def GetPackagePowerData(self, package, timeout=None, retries=None):
135 """ Get power data for particular package.
136
137 Args:
138 package: Package to get power data on.
139
140 returns:
141 Dict of UID and power data.
142 {
143 'uid': uid,
144 'data': [1,2,3]
145 }
146 None if the package is not found in the power data.
147 """
148 return self.GetPowerData().get(package)
149
150 # TODO(rnephew): Move implementation from device_utils when this is used.
151 def GetBatteryInfo(self, timeout=None, retries=None):
152 """Gets battery info for the device.
153
154 Args:
155 timeout: timeout in seconds
156 retries: number of retries
157 Returns:
158 A dict containing various battery information as reported by dumpsys
159 battery.
160 """
161 return self._device.GetBatteryInfo(timeout=None, retries=None)
162
163 # TODO(rnephew): Move implementation from device_utils when this is used.
164 def GetCharging(self, timeout=None, retries=None):
165 """Gets the charging state of the device.
166
167 Args:
168 timeout: timeout in seconds
169 retries: number of retries
170 Returns:
171 True if the device is charging, false otherwise.
172 """
173 return self._device.GetCharging(timeout=None, retries=None)
174
175 # TODO(rnephew): Move implementation from device_utils when this is used.
176 def SetCharging(self, enabled, timeout=None, retries=None):
177 """Enables or disables charging on the device.
178
179 Args:
180 enabled: A boolean indicating whether charging should be enabled or
181 disabled.
182 timeout: timeout in seconds
183 retries: number of retries
184
185 Raises:
186 device_errors.CommandFailedError: If method of disabling charging cannot
187 be determined.
188 """
189 self._device.SetCharging(enabled, timeout=None, retries=None)
190
191 # TODO(rnephew): Move implementation from device_utils when this is used.
192 # TODO(rnephew): Make private when all use cases can use the context manager.
193 def DisableBatteryUpdates(self, timeout=None, retries=None):
194 """ Resets battery data and makes device appear like it is not
195 charging so that it will collect power data since last charge.
196
197 Args:
198 timeout: timeout in seconds
199 retries: number of retries
200
201 Raises:
202 device_errors.CommandFailedError: When resetting batterystats fails to
203 reset power values.
204 """
205 self._device.DisableBatteryUpdates(timeout=None, retries=None)
206
207 # TODO(rnephew): Move implementation from device_utils when this is used.
208 # TODO(rnephew): Make private when all use cases can use the context manager.
209 def EnableBatteryUpdates(self, timeout=None, retries=None):
210 """ Restarts device charging so that dumpsys no longer collects power data.
211
212 Args:
213 timeout: timeout in seconds
214 retries: number of retries
215 """
216 self._device.EnableBatteryUpdates(timeout=None, retries=None)
217
218 @contextlib.contextmanager
219 def BatteryMeasurement(self, timeout=None, retries=None):
220 """Context manager that enables battery data collection. It makes
221 the device appear to stop charging so that dumpsys will start collecting
222 power data since last charge. Once the with block is exited, charging is
223 resumed and power data since last charge is no longer collected.
224
225 Only for devices L and higher.
226
227 Example usage:
228 with BatteryMeasurement():
229 browser_actions()
230 get_power_data() # report usage within this block
231 after_measurements() # Anything that runs after power
232 # measurements are collected
233
234 Args:
235 timeout: timeout in seconds
236 retries: number of retries
237
238 Raises:
239 device_errors.CommandFailedError: If device is not L or higher.
240 """
241 if (self._device.build_version_sdk <
242 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
243 raise device_errors.DeviceVersionError('Device must be L or higher.')
244 try:
245 self.DisableBatteryUpdates(timeout=timeout, retries=retries)
246 yield
247 finally:
248 self.EnableBatteryUpdates(timeout=timeout, retries=retries)
OLDNEW
« no previous file with comments | « build/android/PRESUBMIT.py ('k') | build/android/pylib/device/battery_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698