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

Side by Side Diff: appengine/swarming/swarming_bot/api/platforms/android.py

Issue 1401403002: Improve resiliency for Android. (Closed) Base URL: git@github.com:luci/luci-py.git@3_unicode
Patch Set: Return None Created 5 years, 2 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 | « no previous file | appengine/swarming/swarming_bot/api/platforms/android_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
1 # Copyright 2015 The Swarming Authors. All rights reserved. 1 # Copyright 2015 The Swarming Authors. All rights reserved.
2 # Use of this source code is governed by the Apache v2.0 license that can be 2 # Use of this source code is governed by the Apache v2.0 license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Android specific utility functions. 5 """Android specific utility functions.
6 6
7 This file serves as an API to bot_config.py. bot_config.py can be replaced on 7 This file serves as an API to bot_config.py. bot_config.py can be replaced on
8 the server to allow additional server-specific functionality. 8 the server to allow additional server-specific functionality.
9 """ 9 """
10 10
11 import logging 11 import logging
12 import os 12 import os
13 import re 13 import re
14 import subprocess 14 import subprocess
15 import sys 15 import sys
16 import time 16 import time
17 17
18 # This file must be imported from swarming_bot.zip (or with '..' in sys.path). 18 # This file must be imported from swarming_bot.zip (or with '../..' in
19 # libusb1 must have been put in the path already. 19 # sys.path). libusb1 must have been put in the path already.
20 20
21 import adb 21 import adb
22 import adb.adb_commands 22 import adb.adb_commands
23 23
24 24
25 # Find abs path to third_party/ dir in the bot root dir. 25 # Find abs path to third_party/ dir in the bot root dir.
26 import third_party 26 import third_party
27 THIRD_PARTY_DIR = os.path.dirname(os.path.abspath(third_party.__file__)) 27 THIRD_PARTY_DIR = os.path.dirname(os.path.abspath(third_party.__file__))
28 sys.path.insert(0, os.path.join(THIRD_PARTY_DIR, 'rsa')) 28 sys.path.insert(0, os.path.join(THIRD_PARTY_DIR, 'rsa'))
29 sys.path.insert(0, os.path.join(THIRD_PARTY_DIR, 'pyasn1')) 29 sys.path.insert(0, os.path.join(THIRD_PARTY_DIR, 'pyasn1'))
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 for line in out.splitlines(): 448 for line in out.splitlines():
449 if line.startswith(u'#') or not line: 449 if line.startswith(u'#') or not line:
450 continue 450 continue
451 key, value = line.split(u'=', 1) 451 key, value = line.split(u'=', 1)
452 properties[key] = value 452 properties[key] = value
453 _BUILD_PROP_ANDROID[device.serial] = properties 453 _BUILD_PROP_ANDROID[device.serial] = properties
454 return _BUILD_PROP_ANDROID[device.serial] 454 return _BUILD_PROP_ANDROID[device.serial]
455 455
456 456
457 def get_temp(device): 457 def get_temp(device):
458 """Returns the device's 2 temperatures if available.""" 458 """Returns the device's 2 temperatures if available.
459
460 Returns None otherwise.
461 """
462 assert isinstance(device, Device), device
459 # Not all devices export this file. On other devices, the only real way to 463 # Not all devices export this file. On other devices, the only real way to
460 # read it is via Java 464 # read it is via Java
461 # developer.android.com/guide/topics/sensors/sensors_environment.html 465 # developer.android.com/guide/topics/sensors/sensors_environment.html
462 temps = [] 466 temps = []
463 for i in xrange(2): 467 try:
464 out, _ = device.shell('cat /sys/class/thermal/thermal_zone%d/temp' % i) 468 for i in xrange(2):
465 if out: 469 out, _ = device.shell('cat /sys/class/thermal/thermal_zone%d/temp' % i)
466 temps.append(int(out)) 470 temps.append(int(out))
471 except ValueError:
472 return None
467 return temps 473 return temps
468 474
469 475
470 def get_battery(device): 476 def get_battery(device):
471 """Returns details about the battery's state.""" 477 """Returns details about the battery's state."""
478 assert isinstance(device, Device), device
472 props = {} 479 props = {}
473 out = _dumpsys(device, 'battery') 480 out = _dumpsys(device, 'battery')
474 if not out: 481 if not out:
475 return props 482 return props
476 for line in out.splitlines(): 483 for line in out.splitlines():
477 if line.endswith(u':'): 484 if line.endswith(u':'):
478 continue 485 continue
479 # On Android 4.1.2, it uses "voltage:123" instead of "voltage: 123". 486 # On Android 4.1.2, it uses "voltage:123" instead of "voltage: 123".
480 key, value = line.split(u':', 2) 487 parts = line.split(u':', 2)
481 props[key.lstrip()] = value.strip() 488 if len(parts) == 2:
489 key, value = parts
490 props[key.lstrip()] = value.strip()
482 out = {u'power': []} 491 out = {u'power': []}
483 if props[u'AC powered'] == u'true': 492 if props.get(u'AC powered') == u'true':
484 out[u'power'].append(u'AC') 493 out[u'power'].append(u'AC')
485 if props[u'USB powered'] == u'true': 494 if props.get(u'USB powered') == u'true':
486 out[u'power'].append(u'USB') 495 out[u'power'].append(u'USB')
487 if props.get(u'Wireless powered') == u'true': 496 if props.get(u'Wireless powered') == u'true':
488 out[u'power'].append(u'Wireless') 497 out[u'power'].append(u'Wireless')
489 for key in (u'health', u'level', u'status', u'temperature', u'voltage'): 498 for key in (u'health', u'level', u'status', u'temperature', u'voltage'):
490 out[key] = int(props[key]) 499 out[key] = int(props[key])
491 return out 500 return out
492 501
493 502
494 def get_cpu_scale(device): 503 def get_cpu_scale(device):
495 """Returns the CPU scaling factor.""" 504 """Returns the CPU scaling factor."""
505 assert isinstance(device, Device), device
496 mapping = { 506 mapping = {
497 'cpuinfo_max_freq': u'max', 507 'cpuinfo_max_freq': u'max',
498 'cpuinfo_min_freq': u'min', 508 'cpuinfo_min_freq': u'min',
499 'scaling_cur_freq': u'cur', 509 'scaling_cur_freq': u'cur',
500 'scaling_governor': u'governor', 510 'scaling_governor': u'governor',
501 } 511 }
502 return { 512 return {
503 v: device.shell('cat /sys/devices/system/cpu/cpu0/cpufreq/' + k)[0] 513 v: device.shell('cat /sys/devices/system/cpu/cpu0/cpufreq/' + k)[0]
504 for k, v in mapping.iteritems() 514 for k, v in mapping.iteritems()
505 } 515 }
506 516
507 517
508 def get_uptime(device): 518 def get_uptime(device):
509 """Returns the device's uptime in second.""" 519 """Returns the device's uptime in second."""
520 assert isinstance(device, Device), device
510 out, _ = device.shell('cat /proc/uptime') 521 out, _ = device.shell('cat /proc/uptime')
511 if out: 522 if out:
512 return float(out.split()[1]) 523 return float(out.split()[1])
513 return None 524 return None
514 525
515 526
516 def get_disk(device): 527 def get_disk(device):
517 """Returns details about the battery's state.""" 528 """Returns details about the battery's state."""
529 assert isinstance(device, Device), device
518 props = {} 530 props = {}
519 out = _dumpsys(device, 'diskstats') 531 out = _dumpsys(device, 'diskstats')
520 if not out: 532 if not out:
521 return props 533 return props
522 for line in out.splitlines(): 534 for line in out.splitlines():
523 if line.endswith(u':'): 535 if line.endswith(u':'):
524 continue 536 continue
525 key, value = line.split(u': ', 2) 537 parts = line.split(u': ', 2)
526 match = re.match(u'^(\d+)K / (\d+)K.*', value) 538 if len(parts) == 2:
527 if match: 539 key, value = parts
528 props[key.lstrip()] = { 540 match = re.match(u'^(\d+)K / (\d+)K.*', value)
529 'free_mb': round(float(match.group(1)) / 1024., 1), 541 if match:
530 'size_mb': round(float(match.group(2)) / 1024., 1), 542 props[key.lstrip()] = {
531 } 543 'free_mb': round(float(match.group(1)) / 1024., 1),
544 'size_mb': round(float(match.group(2)) / 1024., 1),
545 }
532 return { 546 return {
533 u'cache': props[u'Cache-Free'], 547 u'cache': props[u'Cache-Free'],
534 u'data': props[u'Data-Free'], 548 u'data': props[u'Data-Free'],
535 u'system': props[u'System-Free'], 549 u'system': props[u'System-Free'],
536 } 550 }
537 551
538 552
539 def get_imei(device): 553 def get_imei(device):
540 """Returns the phone's IMEI.""" 554 """Returns the phone's IMEI."""
555 assert isinstance(device, Device), device
541 # Android <5.0. 556 # Android <5.0.
542 out = _dumpsys(device, 'iphonesubinfo') 557 out = _dumpsys(device, 'iphonesubinfo')
543 if out: 558 if out:
544 match = re.search(' Device ID = (.+)$', out) 559 match = re.search(' Device ID = (.+)$', out)
545 if match: 560 if match:
546 return match.group(1) 561 return match.group(1)
547 562
548 # Android >= 5.0. 563 # Android >= 5.0.
549 out, _ = device.shell('service call iphonesubinfo 1') 564 out, _ = device.shell('service call iphonesubinfo 1')
550 if out: 565 if out:
551 lines = out.splitlines() 566 lines = out.splitlines()
552 if len(lines) >= 4 and lines[0] == 'Result: Parcel(': 567 if len(lines) >= 4 and lines[0] == 'Result: Parcel(':
553 # Process the UTF-16 string. 568 # Process the UTF-16 string.
554 chars = _parcel_to_list(lines[1:])[4:-1] 569 chars = _parcel_to_list(lines[1:])[4:-1]
555 return u''.join(map(unichr, (int(i, 16) for i in chars))) 570 return u''.join(map(unichr, (int(i, 16) for i in chars)))
556 return None 571 return None
557 572
558 573
559 def get_ip(device): 574 def get_ip(device):
560 """Returns the IP address.""" 575 """Returns the IP address."""
576 assert isinstance(device, Device), device
561 # If ever needed, read wifi.interface from /system/build.prop if a device 577 # If ever needed, read wifi.interface from /system/build.prop if a device
562 # doesn't use wlan0. 578 # doesn't use wlan0.
563 ip, _ = device.shell('getprop dhcp.wlan0.ipaddress') 579 ip, _ = device.shell('getprop dhcp.wlan0.ipaddress')
564 if not ip: 580 if not ip:
565 return None 581 return None
566 return ip.strip() 582 return ip.strip()
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/swarming_bot/api/platforms/android_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698