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

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

Issue 1222313015: Manual partial update from from https://crrev.com/337502 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 5 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
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Provides a variety of device interactions with power. 5 """Provides a variety of device interactions with power.
6 """ 6 """
7 # pylint: disable=unused-argument 7 # pylint: disable=unused-argument
8 8
9 import collections 9 import collections
10 import contextlib 10 import contextlib
11 import csv 11 import csv
12 import logging 12 import logging
13 13
14 from pylib import constants 14 from pylib import constants
15 from pylib.device import decorators 15 from pylib.device import decorators
16 from pylib.device import device_errors 16 from pylib.device import device_errors
17 from pylib.device import device_utils 17 from pylib.device import device_utils
18 from pylib.utils import timeout_retry 18 from pylib.utils import timeout_retry
19 19
20 _DEFAULT_TIMEOUT = 30 20 _DEFAULT_TIMEOUT = 30
21 _DEFAULT_RETRIES = 3 21 _DEFAULT_RETRIES = 3
22 22
23 _CONTROL_CHARGING_COMMANDS = [ 23
24 _DEVICE_PROFILES = [
24 { 25 {
25 # Nexus 4 26 'name': 'Nexus 4',
26 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', 27 'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
27 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', 28 'enable_command': (
28 'disable_command': 29 'echo 0 > /sys/module/pm8921_charger/parameters/disabled && '
29 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', 30 'dumpsys battery reset'),
31 'disable_command': (
32 'echo 1 > /sys/module/pm8921_charger/parameters/disabled && '
33 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
34 'charge_counter': None,
35 'voltage': None,
36 'current': None,
30 }, 37 },
31 { 38 {
39 'name': 'Nexus 5',
32 # Nexus 5 40 # Nexus 5
33 # Setting the HIZ bit of the bq24192 causes the charger to actually ignore 41 # 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 42 # energy coming from USB. Setting the power_supply offline just updates the
35 # Android system to reflect that. 43 # Android system to reflect that.
36 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT', 44 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
37 'enable_command': ( 45 'enable_command': (
38 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' 46 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
39 'echo 1 > /sys/class/power_supply/usb/online'), 47 'echo 1 > /sys/class/power_supply/usb/online &&'
48 'dumpsys battery reset'),
40 'disable_command': ( 49 'disable_command': (
41 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' 50 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
42 'chmod 644 /sys/class/power_supply/usb/online && ' 51 'chmod 644 /sys/class/power_supply/usb/online && '
43 'echo 0 > /sys/class/power_supply/usb/online'), 52 'echo 0 > /sys/class/power_supply/usb/online && '
53 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
54 'charge_counter': None,
55 'voltage': None,
56 'current': None,
57 },
58 {
59 'name': 'Nexus 6',
60 'witness_file': None,
61 'enable_command': (
62 'echo 1 > /sys/class/power_supply/battery/charging_enabled && '
63 'dumpsys battery reset'),
64 'disable_command': (
65 'echo 0 > /sys/class/power_supply/battery/charging_enabled && '
66 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
67 'charge_counter': (
68 '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
69 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
70 'current': '/sys/class/power_supply/max170xx_battery/current_now',
71 },
72 {
73 'name': 'Nexus 9',
74 'witness_file': None,
75 'enable_command': (
76 'echo Disconnected > '
77 '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
78 'dumpsys battery reset'),
79 'disable_command': (
80 'echo Connected > '
81 '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
82 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
83 'charge_counter': (
84 '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
85 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
86 'current': '/sys/class/power_supply/max170xx_battery/current_now',
87 },
88 {
89 'name': 'Nexus 10',
90 'witness_file': None,
91 'enable_command': None,
92 'disable_command': None,
93 'charge_counter': (
94 '/sys/class/power_supply/ds2784-fuelgauge/charge_counter_ext'),
95 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
96 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
97
44 }, 98 },
45 ] 99 ]
46 100
47 # The list of useful dumpsys columns. 101 # The list of useful dumpsys columns.
48 # Index of the column containing the format version. 102 # Index of the column containing the format version.
49 _DUMP_VERSION_INDEX = 0 103 _DUMP_VERSION_INDEX = 0
50 # Index of the column containing the type of the row. 104 # Index of the column containing the type of the row.
51 _ROW_TYPE_INDEX = 3 105 _ROW_TYPE_INDEX = 3
52 # Index of the column containing the uid. 106 # Index of the column containing the uid.
53 _PACKAGE_UID_INDEX = 4 107 _PACKAGE_UID_INDEX = 4
(...skipping 27 matching lines...) Expand all
81 TypeError: If it is not passed a DeviceUtils instance. 135 TypeError: If it is not passed a DeviceUtils instance.
82 """ 136 """
83 if not isinstance(device, device_utils.DeviceUtils): 137 if not isinstance(device, device_utils.DeviceUtils):
84 raise TypeError('Must be initialized with DeviceUtils object.') 138 raise TypeError('Must be initialized with DeviceUtils object.')
85 self._device = device 139 self._device = device
86 self._cache = device.GetClientCache(self.__class__.__name__) 140 self._cache = device.GetClientCache(self.__class__.__name__)
87 self._default_timeout = default_timeout 141 self._default_timeout = default_timeout
88 self._default_retries = default_retries 142 self._default_retries = default_retries
89 143
90 @decorators.WithTimeoutAndRetriesFromInstance() 144 @decorators.WithTimeoutAndRetriesFromInstance()
145 def SupportsFuelGauge(self, timeout=None, retries=None):
146 """Detect if fuel gauge chip is present.
147
148 Args:
149 timeout: timeout in seconds
150 retries: number of retries
151
152 Returns:
153 True if known fuel gauge files are present.
154 False otherwise.
155 """
156 self._DiscoverDeviceProfile()
157 return (self._cache['profile']['enable_command'] != None
158 and self._cache['profile']['charge_counter'] != None)
159
160 @decorators.WithTimeoutAndRetriesFromInstance()
161 def GetFuelGaugeChargeCounter(self, timeout=None, retries=None):
162 """Get value of charge_counter on fuel gauge chip.
163
164 Device must have charging disabled for this, not just battery updates
165 disabled. The only device that this currently works with is the nexus 5.
166
167 Args:
168 timeout: timeout in seconds
169 retries: number of retries
170
171 Returns:
172 value of charge_counter for fuel gauge chip in units of nAh.
173
174 Raises:
175 device_errors.CommandFailedError: If fuel gauge chip not found.
176 """
177 if self.SupportsFuelGauge():
178 return int(self._device.ReadFile(
179 self._cache['profile']['charge_counter']))
180 raise device_errors.CommandFailedError(
181 'Unable to find fuel gauge.')
182
183 @decorators.WithTimeoutAndRetriesFromInstance()
91 def GetNetworkData(self, package, timeout=None, retries=None): 184 def GetNetworkData(self, package, timeout=None, retries=None):
92 """ Get network data for specific package. 185 """Get network data for specific package.
93 186
94 Args: 187 Args:
95 package: package name you want network data for. 188 package: package name you want network data for.
96 timeout: timeout in seconds 189 timeout: timeout in seconds
97 retries: number of retries 190 retries: number of retries
98 191
99 Returns: 192 Returns:
100 Tuple of (sent_data, recieved_data) 193 Tuple of (sent_data, recieved_data)
101 None if no network data found 194 None if no network data found
102 """ 195 """
(...skipping 17 matching lines...) Expand all
120 send_data = 0 213 send_data = 0
121 try: 214 try:
122 recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv')) 215 recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv'))
123 except device_errors.AdbShellCommandFailedError: 216 except device_errors.AdbShellCommandFailedError:
124 logging.warning('No received data found for package %s', package) 217 logging.warning('No received data found for package %s', package)
125 recv_data = 0 218 recv_data = 0
126 return (send_data, recv_data) 219 return (send_data, recv_data)
127 220
128 @decorators.WithTimeoutAndRetriesFromInstance() 221 @decorators.WithTimeoutAndRetriesFromInstance()
129 def GetPowerData(self, timeout=None, retries=None): 222 def GetPowerData(self, timeout=None, retries=None):
130 """ Get power data for device. 223 """Get power data for device.
224
131 Args: 225 Args:
132 timeout: timeout in seconds 226 timeout: timeout in seconds
133 retries: number of retries 227 retries: number of retries
134 228
135 Returns: 229 Returns:
136 Dict of power data, keyed on package names. 230 Dict of power data, keyed on package names.
137 { 231 {
138 package_name: { 232 package_name: {
139 'uid': uid, 233 'uid': uid,
140 'data': [1,2,3] 234 'data': [1,2,3]
(...skipping 26 matching lines...) Expand all
167 and entry[_ROW_TYPE_INDEX] == 'pwi' 261 and entry[_ROW_TYPE_INDEX] == 'pwi'
168 and entry[_PWI_AGGREGATION_INDEX] == 'l'): 262 and entry[_PWI_AGGREGATION_INDEX] == 'l'):
169 pwi_entries[entry[_PWI_UID_INDEX]].append( 263 pwi_entries[entry[_PWI_UID_INDEX]].append(
170 float(entry[_PWI_POWER_CONSUMPTION_INDEX])) 264 float(entry[_PWI_POWER_CONSUMPTION_INDEX]))
171 265
172 return {p: {'uid': uid, 'data': pwi_entries[uid]} 266 return {p: {'uid': uid, 'data': pwi_entries[uid]}
173 for p, uid in self._cache['uids'].iteritems()} 267 for p, uid in self._cache['uids'].iteritems()}
174 268
175 @decorators.WithTimeoutAndRetriesFromInstance() 269 @decorators.WithTimeoutAndRetriesFromInstance()
176 def GetPackagePowerData(self, package, timeout=None, retries=None): 270 def GetPackagePowerData(self, package, timeout=None, retries=None):
177 """ Get power data for particular package. 271 """Get power data for particular package.
178 272
179 Args: 273 Args:
180 package: Package to get power data on. 274 package: Package to get power data on.
181 275
182 returns: 276 returns:
183 Dict of UID and power data. 277 Dict of UID and power data.
184 { 278 {
185 'uid': uid, 279 'uid': uid,
186 'data': [1,2,3] 280 'data': [1,2,3]
187 } 281 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 Args: 333 Args:
240 enabled: A boolean indicating whether charging should be enabled or 334 enabled: A boolean indicating whether charging should be enabled or
241 disabled. 335 disabled.
242 timeout: timeout in seconds 336 timeout: timeout in seconds
243 retries: number of retries 337 retries: number of retries
244 338
245 Raises: 339 Raises:
246 device_errors.CommandFailedError: If method of disabling charging cannot 340 device_errors.CommandFailedError: If method of disabling charging cannot
247 be determined. 341 be determined.
248 """ 342 """
249 if 'charging_config' not in self._cache: 343 self._DiscoverDeviceProfile()
250 for c in _CONTROL_CHARGING_COMMANDS: 344 if not self._cache['profile']['enable_command']:
251 if self._device.FileExists(c['witness_file']): 345 raise device_errors.CommandFailedError(
252 self._cache['charging_config'] = c 346 'Unable to find charging commands.')
253 break
254 else:
255 raise device_errors.CommandFailedError(
256 'Unable to find charging commands.')
257 347
258 if enabled: 348 if enabled:
259 command = self._cache['charging_config']['enable_command'] 349 command = self._cache['profile']['enable_command']
260 else: 350 else:
261 command = self._cache['charging_config']['disable_command'] 351 command = self._cache['profile']['disable_command']
262 352
263 def set_and_verify_charging(): 353 def set_and_verify_charging():
264 self._device.RunShellCommand(command, check_return=True) 354 self._device.RunShellCommand(command, check_return=True)
265 return self.GetCharging() == enabled 355 return self.GetCharging() == enabled
266 356
267 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1) 357 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1)
268 358
269 # TODO(rnephew): Make private when all use cases can use the context manager. 359 # TODO(rnephew): Make private when all use cases can use the context manager.
270 @decorators.WithTimeoutAndRetriesFromInstance() 360 @decorators.WithTimeoutAndRetriesFromInstance()
271 def DisableBatteryUpdates(self, timeout=None, retries=None): 361 def DisableBatteryUpdates(self, timeout=None, retries=None):
272 """ Resets battery data and makes device appear like it is not 362 """Resets battery data and makes device appear like it is not
273 charging so that it will collect power data since last charge. 363 charging so that it will collect power data since last charge.
274 364
275 Args: 365 Args:
276 timeout: timeout in seconds 366 timeout: timeout in seconds
277 retries: number of retries 367 retries: number of retries
278 368
279 Raises: 369 Raises:
280 device_errors.CommandFailedError: When resetting batterystats fails to 370 device_errors.CommandFailedError: When resetting batterystats fails to
281 reset power values. 371 reset power values.
282 device_errors.DeviceVersionError: If device is not L or higher. 372 device_errors.DeviceVersionError: If device is not L or higher.
283 """ 373 """
284 def battery_updates_disabled(): 374 def battery_updates_disabled():
285 return self.GetCharging() is False 375 return self.GetCharging() is False
286 376
287 if (self._device.build_version_sdk < 377 self._ClearPowerData()
288 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
289 raise device_errors.DeviceVersionError('Device must be L or higher.')
290
291 self._device.RunShellCommand(
292 ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
293 self._device.RunShellCommand(
294 ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
295 self._device.RunShellCommand(
296 ['dumpsys', 'batterystats', '--reset'], check_return=True)
297 battery_data = self._device.RunShellCommand(
298 ['dumpsys', 'batterystats', '--charged', '--checkin'],
299 check_return=True, large_output=True)
300 ROW_TYPE_INDEX = 3
301 PWI_POWER_INDEX = 5
302 for line in battery_data:
303 l = line.split(',')
304 if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi'
305 and l[PWI_POWER_INDEX] != 0):
306 raise device_errors.CommandFailedError(
307 'Non-zero pmi value found after reset.')
308 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'], 378 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'],
309 check_return=True) 379 check_return=True)
310 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], 380 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
311 check_return=True) 381 check_return=True)
312 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1) 382 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
313 383
314 # TODO(rnephew): Make private when all use cases can use the context manager. 384 # TODO(rnephew): Make private when all use cases can use the context manager.
315 @decorators.WithTimeoutAndRetriesFromInstance() 385 @decorators.WithTimeoutAndRetriesFromInstance()
316 def EnableBatteryUpdates(self, timeout=None, retries=None): 386 def EnableBatteryUpdates(self, timeout=None, retries=None):
317 """ Restarts device charging so that dumpsys no longer collects power data. 387 """Restarts device charging so that dumpsys no longer collects power data.
318 388
319 Args: 389 Args:
320 timeout: timeout in seconds 390 timeout: timeout in seconds
321 retries: number of retries 391 retries: number of retries
322 392
323 Raises: 393 Raises:
324 device_errors.DeviceVersionError: If device is not L or higher. 394 device_errors.DeviceVersionError: If device is not L or higher.
325 """ 395 """
326 def battery_updates_enabled(): 396 def battery_updates_enabled():
327 return self.GetCharging() is True 397 return (self.GetCharging()
328 398 or not bool('UPDATES STOPPED' in self._device.RunShellCommand(
329 if (self._device.build_version_sdk < 399 ['dumpsys', 'battery'], check_return=True)))
330 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
331 raise device_errors.DeviceVersionError('Device must be L or higher.')
332 400
333 self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], 401 self._device.RunShellCommand(['dumpsys', 'battery', 'reset'],
334 check_return=True) 402 check_return=True)
335 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1) 403 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
336 404
337 @contextlib.contextmanager 405 @contextlib.contextmanager
338 def BatteryMeasurement(self, timeout=None, retries=None): 406 def BatteryMeasurement(self, timeout=None, retries=None):
339 """Context manager that enables battery data collection. It makes 407 """Context manager that enables battery data collection. It makes
340 the device appear to stop charging so that dumpsys will start collecting 408 the device appear to stop charging so that dumpsys will start collecting
341 power data since last charge. Once the with block is exited, charging is 409 power data since last charge. Once the with block is exited, charging is
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 wait_period: time in seconds to wait between checking. 462 wait_period: time in seconds to wait between checking.
395 """ 463 """
396 def cool_device(): 464 def cool_device():
397 temp = self.GetBatteryInfo().get('temperature') 465 temp = self.GetBatteryInfo().get('temperature')
398 if temp is None: 466 if temp is None:
399 logging.warning('Unable to find current battery temperature.') 467 logging.warning('Unable to find current battery temperature.')
400 temp = 0 468 temp = 0
401 else: 469 else:
402 logging.info('Current battery temperature: %s', temp) 470 logging.info('Current battery temperature: %s', temp)
403 return int(temp) <= target_temp 471 return int(temp) <= target_temp
404 472 self.EnableBatteryUpdates()
405 logging.info('Waiting for the device to cool down to %s degrees.', 473 logging.info('Waiting for the device to cool down to %s (0.1 C)',
406 target_temp) 474 target_temp)
407 timeout_retry.WaitFor(cool_device, wait_period=wait_period) 475 timeout_retry.WaitFor(cool_device, wait_period=wait_period)
476
477 @decorators.WithTimeoutAndRetriesFromInstance()
478 def TieredSetCharging(self, enabled, timeout=None, retries=None):
479 """Enables or disables charging on the device.
480
481 Args:
482 enabled: A boolean indicating whether charging should be enabled or
483 disabled.
484 timeout: timeout in seconds
485 retries: number of retries
486 """
487 if self.GetCharging() == enabled:
488 logging.warning('Device charging already in expected state: %s', enabled)
489 return
490
491 if enabled:
492 try:
493 self.SetCharging(enabled)
494 except device_errors.CommandFailedError:
495 logging.info('Unable to enable charging via hardware.'
496 ' Falling back to software enabling.')
497 self.EnableBatteryUpdates()
498 else:
499 try:
500 self._ClearPowerData()
501 self.SetCharging(enabled)
502 except device_errors.CommandFailedError:
503 logging.info('Unable to disable charging via hardware.'
504 ' Falling back to software disabling.')
505 self.DisableBatteryUpdates()
506
507 @contextlib.contextmanager
508 def PowerMeasurement(self, timeout=None, retries=None):
509 """Context manager that enables battery power collection.
510
511 Once the with block is exited, charging is resumed. Will attempt to disable
512 charging at the hardware level, and if that fails will fall back to software
513 disabling of battery updates.
514
515 Only for devices L and higher.
516
517 Example usage:
518 with PowerMeasurement():
519 browser_actions()
520 get_power_data() # report usage within this block
521 after_measurements() # Anything that runs after power
522 # measurements are collected
523
524 Args:
525 timeout: timeout in seconds
526 retries: number of retries
527 """
528 try:
529 self.TieredSetCharging(False, timeout=timeout, retries=retries)
530 yield
531 finally:
532 self.TieredSetCharging(True, timeout=timeout, retries=retries)
533
534 def _ClearPowerData(self):
535 """Resets battery data and makes device appear like it is not
536 charging so that it will collect power data since last charge.
537
538 Returns:
539 True if power data cleared.
540 False if power data clearing is not supported (pre-L)
541
542 Raises:
543 device_errors.DeviceVersionError: If power clearing is supported,
544 but fails.
545 """
546 if (self._device.build_version_sdk <
547 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
548 logging.warning('Dumpsys power data only available on 5.0 and above. '
549 'Cannot clear power data.')
550 return False
551
552 self._device.RunShellCommand(
553 ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
554 self._device.RunShellCommand(
555 ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
556 self._device.RunShellCommand(
557 ['dumpsys', 'batterystats', '--reset'], check_return=True)
558 battery_data = self._device.RunShellCommand(
559 ['dumpsys', 'batterystats', '--charged', '--checkin'],
560 check_return=True, large_output=True)
561 for line in battery_data:
562 l = line.split(',')
563 if (len(l) > _PWI_POWER_CONSUMPTION_INDEX and l[_ROW_TYPE_INDEX] == 'pwi'
564 and l[_PWI_POWER_CONSUMPTION_INDEX] != 0):
565 self._device.RunShellCommand(
566 ['dumpsys', 'battery', 'reset'], check_return=True)
567 raise device_errors.CommandFailedError(
568 'Non-zero pmi value found after reset.')
569 self._device.RunShellCommand(
570 ['dumpsys', 'battery', 'reset'], check_return=True)
571 return True
572
573 def _DiscoverDeviceProfile(self):
574 """Checks and caches device information.
575
576 Returns:
577 True if profile is found, false otherwise.
578 """
579
580 if 'profile' in self._cache:
581 return True
582 for profile in _DEVICE_PROFILES:
583 if self._device.product_model == profile['name']:
584 self._cache['profile'] = profile
585 return True
586 self._cache['profile'] = {
587 'name': None,
588 'witness_file': None,
589 'enable_command': None,
590 'disable_command': None,
591 'charge_counter': None,
592 'voltage': None,
593 'current': None,
594 }
595 return False
OLDNEW
« no previous file with comments | « build/android/pylib/base/base_setup.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