blob: e10017db42dceb25482cb950a9ea91c6b31bcfd2 [file] [log] [blame]
#!/usr/bin/python
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import glob
import logging
import netifaces
import os
import re
import subprocess
import threading
import factory_common # pylint: disable=W0611
from cros.factory.system.board import Board
from cros.factory.test import factory
from cros.factory.test import shopfloor
from cros.factory.test.utils import ReadOneLine
from cros.factory.utils.process_utils import Spawn
# pylint: disable=W0702
# Disable checking of exception types, since we catch all exceptions
# in many places.
_board = None
_lock = threading.Lock()
def GetBoard():
'''Initializes a board instance from environment variable
CROS_FACTORY_BOARD_CLASS, or use the default board class ChromeOSBoard
if the variable is empty.
The board-specific CROS_FACTORY_BOARD_CLASS environment variable is set in
board_setup_factory.sh.
Returns:
An instance of the specified Board class implementation.'''
# pylint: disable=W0603
with _lock:
global _board
if _board:
return _board
board = os.environ.get('CROS_FACTORY_BOARD_CLASS',
'cros.factory.board.chromeos_board.ChromeOSBoard')
module, cls = board.rsplit('.', 1)
_board = getattr(__import__(module, fromlist=[cls]), cls)()
return _board
class SystemInfo(object):
'''Static information about the system.
This is mostly static information that changes rarely if ever
(e.g., version numbers, serial numbers, etc.).
'''
# If not None, an update that is available from the update server.
update_md5sum = None
def __init__(self):
self.mlb_serial_number = None
try:
self.mlb_serial_number = shopfloor.GetDeviceData()['mlb_serial_number']
except:
pass
self.serial_number = None
try:
self.serial_number = shopfloor.get_serial_number()
if self.serial_number is not None:
self.serial_number = str(self.serial_number)
except:
pass
self.factory_image_version = None
try:
lsb_release = open('/etc/lsb-release').read()
match = re.search('^GOOGLE_RELEASE=(.+)$', lsb_release,
re.MULTILINE)
if match:
self.factory_image_version = match.group(1)
except:
pass
self.wlan0_mac = None
try:
for wlan_interface in ['mlan0', 'wlan0']:
address_path = os.path.join('/sys/class/net/',
wlan_interface, 'address')
if os.path.exists(address_path):
self.wlan0_mac = open(address_path).read().strip()
except:
pass
self.kernel_version = None
try:
uname = subprocess.Popen(['uname', '-r'], stdout=subprocess.PIPE)
stdout, _ = uname.communicate()
self.kernel_version = stdout.strip()
except:
pass
self.architecture = None
try:
self.architecture = Spawn(['uname', '-m'],
check_output=True).stdout_data.strip()
except:
pass
self.ec_version = None
try:
self.ec_version = GetBoard().GetECVersion()
except:
pass
self.firmware_version = None
try:
crossystem = subprocess.Popen(['crossystem', 'fwid'],
stdout=subprocess.PIPE)
stdout, _ = crossystem.communicate()
self.firmware_version = stdout.strip() or None
except:
pass
self.root_device = None
try:
rootdev = Spawn(['rootdev', '-s'],
stdout=subprocess.PIPE)
stdout, _ = rootdev.communicate()
self.root_device = stdout.strip()
except:
pass
self.factory_md5sum = factory.get_current_md5sum()
# update_md5sum is currently in SystemInfo's __dict__ but not this
# object's. Copy it from SystemInfo into this object's __dict__.
self.update_md5sum = SystemInfo.update_md5sum
def GetIPv4Interfaces():
'''Returns a list of IPv4 interfaces.'''
interfaces = sorted(netifaces.interfaces())
return [x for x in interfaces if not x.startswith('lo')]
def GetIPv4InterfaceAddresses(interface):
'''Returns a list of ips of an interface'''
try:
addresses = netifaces.ifaddresses(interface).get(netifaces.AF_INET, [])
except ValueError:
pass
ips = [x.get('addr') for x in addresses
if 'addr' in x] or ['none']
return ips
def IsInterfaceConnected(prefix):
'''Returns whether any interface starting with prefix is connected'''
ips = []
for interface in GetIPv4Interfaces():
if interface.startswith(prefix):
ips += [x for x in GetIPv4InterfaceAddresses(interface) if x != 'none']
return ips != []
def GetIPv4Addresses():
'''Returns a string describing interfaces' IPv4 addresses.
The returned string is of the format
eth0=192.168.1.10, wlan0=192.168.16.14
'''
ret = []
interfaces = GetIPv4Interfaces()
for interface in interfaces:
ips = GetIPv4InterfaceAddresses(interface)
ret.append('%s=%s' % (interface, '+'.join(ips)))
return ', '.join(ret)
class SystemStatus(object):
'''Information about the current system status.
This is information that changes frequently, e.g., load average
or battery information.
We log a bunch of system status here.
'''
# Class variable: a charge_manager instance for checking force
# charge status.
charge_manager = None
def __init__(self):
def _CalculateBatteryFractionFull(battery):
for t in ['charge', 'energy']:
now = battery['%s_now' % t]
full = battery['%s_full' % t]
if (now is not None and full is not None and full > 0 and now >= 0):
return float(now) / full
return None
self.battery = {}
self.battery_sysfs_path = None
path_list = glob.glob('/sys/class/power_supply/*/type')
for p in path_list:
if open(p).read().strip() == 'Battery':
self.battery_sysfs_path = os.path.dirname(p)
break
for k, item_type in [('charge_full', int),
('charge_full_design', int),
('charge_now', int),
('current_now', int),
('present', bool),
('status', str),
('voltage_min_design', int),
('voltage_now', int),
('energy_full', int),
('energy_full_design', int),
('energy_now', int)]:
try:
self.battery[k] = item_type(
open(os.path.join(self.battery_sysfs_path, k)).read().strip())
except:
self.battery[k] = None
self.battery['fraction_full'] = _CalculateBatteryFractionFull(self.battery)
self.battery['force'] = False
if self.charge_manager:
force_status = {
Board.ChargeState.DISCHARGE: 'Discharging',
Board.ChargeState.CHARGE: 'Charging',
Board.ChargeState.IDLE: 'Idle'}.get(
self.charge_manager.state)
if force_status:
self.battery['status'] = force_status
self.battery['force'] = True
# Get fan speed
try:
self.fan_rpm = GetBoard().GetFanRPM()
except:
self.fan_rpm = None
# Get temperatures from sensors
try:
self.temperatures = GetBoard().GetTemperatures()
except:
self.temperatures = []
try:
self.main_temperature_index = GetBoard().GetMainTemperatureIndex()
except:
self.main_temperature_index = None
try:
self.load_avg = map(
float, open('/proc/loadavg').read().split()[0:3])
except:
self.load_avg = None
try:
self.cpu = map(int, open('/proc/stat').readline().split()[1:])
except:
self.cpu = None
try:
self.ips = GetIPv4Addresses()
except:
self.ips = None
try:
self.eth_on = IsInterfaceConnected('eth')
except:
self.eth_on = None
try:
self.wlan_on = (IsInterfaceConnected('mlan') or
IsInterfaceConnected('wlan'))
except:
self.wlan_on = None
if __name__ == '__main__':
import yaml
print yaml.dump(dict(system_info=SystemInfo(None, None).__dict__,
system_status=SystemStatus().__dict__),
default_flow_style=False)
def SetBacklightBrightness(level):
'''Sets the backlight brightness level.
Args:
level: A floating-point value in [0.0, 1.0] indicating the backlight
brightness level.
Raises:
ValueError if the specified value is invalid.
'''
if not (level >= 0.0 and level <= 1.0):
raise ValueError('Invalid brightness level.')
interfaces = glob.glob('/sys/class/backlight/*')
for i in interfaces:
with open(os.path.join(i, 'brightness'), 'w') as f:
f.write('%d' % int(
level * float(ReadOneLine(os.path.join(i, 'max_brightness')))))