Home | History | Annotate | Download | only in bin
      1 # Copyright 2017 The Chromium OS 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 """
      6 Convenience functions for use by tests or whomever.
      7 """
      8 
      9 # pylint: disable=missing-docstring
     10 
     11 import commands
     12 import fnmatch
     13 import glob
     14 import json
     15 import logging
     16 import math
     17 import multiprocessing
     18 import os
     19 import pickle
     20 import platform
     21 import re
     22 import shutil
     23 import signal
     24 import tempfile
     25 import time
     26 import uuid
     27 
     28 from autotest_lib.client.common_lib import error
     29 from autotest_lib.client.common_lib import magic
     30 from autotest_lib.client.common_lib import utils
     31 
     32 from autotest_lib.client.common_lib.utils import *
     33 
     34 
     35 def grep(pattern, file):
     36     """
     37     This is mainly to fix the return code inversion from grep
     38     Also handles compressed files.
     39 
     40     returns 1 if the pattern is present in the file, 0 if not.
     41     """
     42     command = 'grep "%s" > /dev/null' % pattern
     43     ret = cat_file_to_cmd(file, command, ignore_status=True)
     44     return not ret
     45 
     46 
     47 def difflist(list1, list2):
     48     """returns items in list2 that are not in list1"""
     49     diff = [];
     50     for x in list2:
     51         if x not in list1:
     52             diff.append(x)
     53     return diff
     54 
     55 
     56 def cat_file_to_cmd(file, command, ignore_status=0, return_output=False):
     57     """
     58     equivalent to 'cat file | command' but knows to use
     59     zcat or bzcat if appropriate
     60     """
     61     if not os.path.isfile(file):
     62         raise NameError('invalid file %s to cat to command %s'
     63                 % (file, command))
     64 
     65     if return_output:
     66         run_cmd = utils.system_output
     67     else:
     68         run_cmd = utils.system
     69 
     70     if magic.guess_type(file) == 'application/x-bzip2':
     71         cat = 'bzcat'
     72     elif magic.guess_type(file) == 'application/x-gzip':
     73         cat = 'zcat'
     74     else:
     75         cat = 'cat'
     76     return run_cmd('%s %s | %s' % (cat, file, command),
     77                    ignore_status=ignore_status)
     78 
     79 
     80 def extract_tarball_to_dir(tarball, dir):
     81     """
     82     Extract a tarball to a specified directory name instead of whatever
     83     the top level of a tarball is - useful for versioned directory names, etc
     84     """
     85     if os.path.exists(dir):
     86         if os.path.isdir(dir):
     87             shutil.rmtree(dir)
     88         else:
     89             os.remove(dir)
     90     pwd = os.getcwd()
     91     os.chdir(os.path.dirname(os.path.abspath(dir)))
     92     newdir = extract_tarball(tarball)
     93     os.rename(newdir, dir)
     94     os.chdir(pwd)
     95 
     96 
     97 def extract_tarball(tarball):
     98     """Returns the directory extracted by the tarball."""
     99     extracted = cat_file_to_cmd(tarball, 'tar xvf - 2>/dev/null',
    100                                     return_output=True).splitlines()
    101 
    102     dir = None
    103 
    104     for line in extracted:
    105         if line.startswith('./'):
    106             line = line[2:]
    107         if not line or line == '.':
    108             continue
    109         topdir = line.split('/')[0]
    110         if os.path.isdir(topdir):
    111             if dir:
    112                 assert(dir == topdir)
    113             else:
    114                 dir = topdir
    115     if dir:
    116         return dir
    117     else:
    118         raise NameError('extracting tarball produced no dir')
    119 
    120 
    121 def unmap_url_cache(cachedir, url, expected_hash, method="md5"):
    122     """
    123     Downloads a file from a URL to a cache directory. If the file is already
    124     at the expected position and has the expected hash, let's not download it
    125     again.
    126 
    127     @param cachedir: Directory that might hold a copy of the file we want to
    128             download.
    129     @param url: URL for the file we want to download.
    130     @param expected_hash: Hash string that we expect the file downloaded to
    131             have.
    132     @param method: Method used to calculate the hash string (md5, sha1).
    133     """
    134     # Let's convert cachedir to a canonical path, if it's not already
    135     cachedir = os.path.realpath(cachedir)
    136     if not os.path.isdir(cachedir):
    137         try:
    138             os.makedirs(cachedir)
    139         except:
    140             raise ValueError('Could not create cache directory %s' % cachedir)
    141     file_from_url = os.path.basename(url)
    142     file_local_path = os.path.join(cachedir, file_from_url)
    143 
    144     file_hash = None
    145     failure_counter = 0
    146     while not file_hash == expected_hash:
    147         if os.path.isfile(file_local_path):
    148             file_hash = hash_file(file_local_path, method)
    149             if file_hash == expected_hash:
    150                 # File is already at the expected position and ready to go
    151                 src = file_from_url
    152             else:
    153                 # Let's download the package again, it's corrupted...
    154                 logging.error("Seems that file %s is corrupted, trying to "
    155                               "download it again", file_from_url)
    156                 src = url
    157                 failure_counter += 1
    158         else:
    159             # File is not there, let's download it
    160             src = url
    161         if failure_counter > 1:
    162             raise EnvironmentError("Consistently failed to download the "
    163                                    "package %s. Aborting further download "
    164                                    "attempts. This might mean either the "
    165                                    "network connection has problems or the "
    166                                    "expected hash string that was determined "
    167                                    "for this file is wrong", file_from_url)
    168         file_path = utils.unmap_url(cachedir, src, cachedir)
    169 
    170     return file_path
    171 
    172 
    173 def force_copy(src, dest):
    174     """Replace dest with a new copy of src, even if it exists"""
    175     if os.path.isfile(dest):
    176         os.remove(dest)
    177     if os.path.isdir(dest):
    178         dest = os.path.join(dest, os.path.basename(src))
    179     shutil.copyfile(src, dest)
    180     return dest
    181 
    182 
    183 def force_link(src, dest):
    184     """Link src to dest, overwriting it if it exists"""
    185     return utils.system("ln -sf %s %s" % (src, dest))
    186 
    187 
    188 def file_contains_pattern(file, pattern):
    189     """Return true if file contains the specified egrep pattern"""
    190     if not os.path.isfile(file):
    191         raise NameError('file %s does not exist' % file)
    192     return not utils.system('egrep -q "' + pattern + '" ' + file,
    193                             ignore_status=True)
    194 
    195 
    196 def list_grep(list, pattern):
    197     """True if any item in list matches the specified pattern."""
    198     compiled = re.compile(pattern)
    199     for line in list:
    200         match = compiled.search(line)
    201         if (match):
    202             return 1
    203     return 0
    204 
    205 
    206 def get_os_vendor():
    207     """Try to guess what's the os vendor
    208     """
    209     if os.path.isfile('/etc/SuSE-release'):
    210         return 'SUSE'
    211 
    212     issue = '/etc/issue'
    213 
    214     if not os.path.isfile(issue):
    215         return 'Unknown'
    216 
    217     if file_contains_pattern(issue, 'Red Hat'):
    218         return 'Red Hat'
    219     elif file_contains_pattern(issue, 'Fedora'):
    220         return 'Fedora Core'
    221     elif file_contains_pattern(issue, 'SUSE'):
    222         return 'SUSE'
    223     elif file_contains_pattern(issue, 'Ubuntu'):
    224         return 'Ubuntu'
    225     elif file_contains_pattern(issue, 'Debian'):
    226         return 'Debian'
    227     else:
    228         return 'Unknown'
    229 
    230 
    231 def get_cc():
    232     try:
    233         return os.environ['CC']
    234     except KeyError:
    235         return 'gcc'
    236 
    237 
    238 def get_vmlinux():
    239     """Return the full path to vmlinux
    240 
    241     Ahem. This is crap. Pray harder. Bad Martin.
    242     """
    243     vmlinux = '/boot/vmlinux-%s' % utils.system_output('uname -r')
    244     if os.path.isfile(vmlinux):
    245         return vmlinux
    246     vmlinux = '/lib/modules/%s/build/vmlinux' % utils.system_output('uname -r')
    247     if os.path.isfile(vmlinux):
    248         return vmlinux
    249     return None
    250 
    251 
    252 def get_systemmap():
    253     """Return the full path to System.map
    254 
    255     Ahem. This is crap. Pray harder. Bad Martin.
    256     """
    257     map = '/boot/System.map-%s' % utils.system_output('uname -r')
    258     if os.path.isfile(map):
    259         return map
    260     map = '/lib/modules/%s/build/System.map' % utils.system_output('uname -r')
    261     if os.path.isfile(map):
    262         return map
    263     return None
    264 
    265 
    266 def get_modules_dir():
    267     """Return the modules dir for the running kernel version"""
    268     kernel_version = utils.system_output('uname -r')
    269     return '/lib/modules/%s/kernel' % kernel_version
    270 
    271 
    272 _CPUINFO_RE = re.compile(r'^(?P<key>[^\t]*)\t*: ?(?P<value>.*)$')
    273 
    274 
    275 def get_cpuinfo():
    276     """Read /proc/cpuinfo and convert to a list of dicts."""
    277     cpuinfo = []
    278     with open('/proc/cpuinfo', 'r') as f:
    279         cpu = {}
    280         for line in f:
    281             line = line.strip()
    282             if not line:
    283                 cpuinfo.append(cpu)
    284                 cpu = {}
    285                 continue
    286             match = _CPUINFO_RE.match(line)
    287             cpu[match.group('key')] = match.group('value')
    288         if cpu:
    289             # cpuinfo usually ends in a blank line, so this shouldn't happen.
    290             cpuinfo.append(cpu)
    291     return cpuinfo
    292 
    293 
    294 def get_cpu_arch():
    295     """Work out which CPU architecture we're running on"""
    296     f = open('/proc/cpuinfo', 'r')
    297     cpuinfo = f.readlines()
    298     f.close()
    299     if list_grep(cpuinfo, '^cpu.*(RS64|POWER3|Broadband Engine)'):
    300         return 'power'
    301     elif list_grep(cpuinfo, '^cpu.*POWER4'):
    302         return 'power4'
    303     elif list_grep(cpuinfo, '^cpu.*POWER5'):
    304         return 'power5'
    305     elif list_grep(cpuinfo, '^cpu.*POWER6'):
    306         return 'power6'
    307     elif list_grep(cpuinfo, '^cpu.*POWER7'):
    308         return 'power7'
    309     elif list_grep(cpuinfo, '^cpu.*PPC970'):
    310         return 'power970'
    311     elif list_grep(cpuinfo, 'ARM'):
    312         return 'arm'
    313     elif list_grep(cpuinfo, '^flags.*:.* lm .*'):
    314         return 'x86_64'
    315     elif list_grep(cpuinfo, 'CPU.*implementer.*0x41'):
    316         return 'arm'
    317     else:
    318         return 'i386'
    319 
    320 
    321 def get_arm_soc_family_from_devicetree():
    322     """
    323     Work out which ARM SoC we're running on based on the 'compatible' property
    324     of the base node of devicetree, if it exists.
    325     """
    326     devicetree_compatible = '/sys/firmware/devicetree/base/compatible'
    327     if not os.path.isfile(devicetree_compatible):
    328         return None
    329     f = open(devicetree_compatible, 'r')
    330     compatible = f.readlines()
    331     f.close()
    332     if list_grep(compatible, 'rk3399'):
    333         return 'rockchip'
    334     elif list_grep(compatible, 'mt8173'):
    335         return 'mediatek'
    336     return None
    337 
    338 
    339 def get_arm_soc_family():
    340     """Work out which ARM SoC we're running on"""
    341     family = get_arm_soc_family_from_devicetree()
    342     if family is not None:
    343         return family
    344 
    345     f = open('/proc/cpuinfo', 'r')
    346     cpuinfo = f.readlines()
    347     f.close()
    348     if list_grep(cpuinfo, 'EXYNOS5'):
    349         return 'exynos5'
    350     elif list_grep(cpuinfo, 'Tegra'):
    351         return 'tegra'
    352     elif list_grep(cpuinfo, 'Rockchip'):
    353         return 'rockchip'
    354     return 'arm'
    355 
    356 
    357 def get_cpu_soc_family():
    358     """Like get_cpu_arch, but for ARM, returns the SoC family name"""
    359     f = open('/proc/cpuinfo', 'r')
    360     cpuinfo = f.readlines()
    361     f.close()
    362     family = get_cpu_arch()
    363     if family == 'arm':
    364         family = get_arm_soc_family()
    365     if list_grep(cpuinfo, '^vendor_id.*:.*AMD'):
    366         family = 'amd'
    367     return family
    368 
    369 
    370 INTEL_UARCH_TABLE = {
    371     '06_1C': 'Atom',
    372     '06_26': 'Atom',
    373     '06_36': 'Atom',
    374     '06_4C': 'Braswell',
    375     '06_3D': 'Broadwell',
    376     '06_0D': 'Dothan',
    377     '06_3A': 'IvyBridge',
    378     '06_3E': 'IvyBridge',
    379     '06_3C': 'Haswell',
    380     '06_3F': 'Haswell',
    381     '06_45': 'Haswell',
    382     '06_46': 'Haswell',
    383     '06_0F': 'Merom',
    384     '06_16': 'Merom',
    385     '06_17': 'Nehalem',
    386     '06_1A': 'Nehalem',
    387     '06_1D': 'Nehalem',
    388     '06_1E': 'Nehalem',
    389     '06_1F': 'Nehalem',
    390     '06_2E': 'Nehalem',
    391     '06_2A': 'SandyBridge',
    392     '06_2D': 'SandyBridge',
    393     '06_4E': 'Skylake',
    394     '0F_03': 'Prescott',
    395     '0F_04': 'Prescott',
    396     '0F_06': 'Presler',
    397     '06_25': 'Westmere',
    398     '06_2C': 'Westmere',
    399     '06_2F': 'Westmere',
    400 }
    401 
    402 
    403 def get_intel_cpu_uarch(numeric=False):
    404     """Return the Intel microarchitecture we're running on, or None.
    405 
    406     Returns None if this is not an Intel CPU. Returns the family and model as
    407     underscore-separated hex (per Intel manual convention) if the uarch is not
    408     known, or if numeric is True.
    409     """
    410     if not get_current_kernel_arch().startswith('x86'):
    411         return None
    412     cpuinfo = get_cpuinfo()[0]
    413     if cpuinfo['vendor_id'] != 'GenuineIntel':
    414         return None
    415     family_model = '%02X_%02X' % (int(cpuinfo['cpu family']),
    416                                   int(cpuinfo['model']))
    417     if numeric:
    418         return family_model
    419     return INTEL_UARCH_TABLE.get(family_model, family_model)
    420 
    421 
    422 def get_current_kernel_arch():
    423     """Get the machine architecture, now just a wrap of 'uname -m'."""
    424     return os.popen('uname -m').read().rstrip()
    425 
    426 
    427 def get_file_arch(filename):
    428     # -L means follow symlinks
    429     file_data = utils.system_output('file -L ' + filename)
    430     if file_data.count('80386'):
    431         return 'i386'
    432     return None
    433 
    434 
    435 def count_cpus():
    436     """number of CPUs in the local machine according to /proc/cpuinfo"""
    437     try:
    438        return multiprocessing.cpu_count()
    439     except Exception:
    440        logging.exception('can not get cpu count from'
    441                         ' multiprocessing.cpu_count()')
    442     cpuinfo = get_cpuinfo()
    443     # Returns at least one cpu. Check comment #1 in crosbug.com/p/9582.
    444     return len(cpuinfo) or 1
    445 
    446 
    447 def cpu_online_map():
    448     """
    449     Check out the available cpu online map
    450     """
    451     cpuinfo = get_cpuinfo()
    452     cpus = []
    453     for cpu in cpuinfo:
    454         cpus.append(cpu['processor'])  # grab cpu number
    455     return cpus
    456 
    457 
    458 def get_cpu_family():
    459     cpuinfo = get_cpuinfo()[0]
    460     return int(cpuinfo['cpu_family'])
    461 
    462 
    463 def get_cpu_vendor():
    464     cpuinfo = get_cpuinfo()
    465     vendors = [cpu['vendor_id'] for cpu in cpuinfo]
    466     for v in vendors[1:]:
    467         if v != vendors[0]:
    468             raise error.TestError('multiple cpu vendors found: ' + str(vendors))
    469     return vendors[0]
    470 
    471 
    472 def probe_cpus():
    473     """
    474     This routine returns a list of cpu devices found under
    475     /sys/devices/system/cpu.
    476     """
    477     cmd = 'find /sys/devices/system/cpu/ -maxdepth 1 -type d -name cpu*'
    478     return utils.system_output(cmd).splitlines()
    479 
    480 
    481 # Returns total memory in kb
    482 def read_from_meminfo(key):
    483     meminfo = utils.system_output('grep %s /proc/meminfo' % key)
    484     return int(re.search(r'\d+', meminfo).group(0))
    485 
    486 
    487 def memtotal():
    488     return read_from_meminfo('MemTotal')
    489 
    490 
    491 def freememtotal():
    492     return read_from_meminfo('MemFree')
    493 
    494 def usable_memtotal():
    495     # Reserved 5% for OS use
    496     return int(read_from_meminfo('MemFree') * 0.95)
    497 
    498 
    499 def rounded_memtotal():
    500     # Get total of all physical mem, in kbytes
    501     usable_kbytes = memtotal()
    502     # usable_kbytes is system's usable DRAM in kbytes,
    503     #   as reported by memtotal() from device /proc/meminfo memtotal
    504     #   after Linux deducts 1.5% to 5.1% for system table overhead
    505     # Undo the unknown actual deduction by rounding up
    506     #   to next small multiple of a big power-of-two
    507     #   eg  12GB - 5.1% gets rounded back up to 12GB
    508     mindeduct = 0.015  # 1.5 percent
    509     maxdeduct = 0.055  # 5.5 percent
    510     # deduction range 1.5% .. 5.5% supports physical mem sizes
    511     #    6GB .. 12GB in steps of .5GB
    512     #   12GB .. 24GB in steps of 1 GB
    513     #   24GB .. 48GB in steps of 2 GB ...
    514     # Finer granularity in physical mem sizes would require
    515     #   tighter spread between min and max possible deductions
    516 
    517     # increase mem size by at least min deduction, without rounding
    518     min_kbytes = int(usable_kbytes / (1.0 - mindeduct))
    519     # increase mem size further by 2**n rounding, by 0..roundKb or more
    520     round_kbytes = int(usable_kbytes / (1.0 - maxdeduct)) - min_kbytes
    521     # find least binary roundup 2**n that covers worst-cast roundKb
    522     mod2n = 1 << int(math.ceil(math.log(round_kbytes, 2)))
    523     # have round_kbytes <= mod2n < round_kbytes*2
    524     # round min_kbytes up to next multiple of mod2n
    525     phys_kbytes = min_kbytes + mod2n - 1
    526     phys_kbytes = phys_kbytes - (phys_kbytes % mod2n)  # clear low bits
    527     return phys_kbytes
    528 
    529 
    530 def sysctl(key, value=None):
    531     """Generic implementation of sysctl, to read and write.
    532 
    533     @param key: A location under /proc/sys
    534     @param value: If not None, a value to write into the sysctl.
    535 
    536     @return The single-line sysctl value as a string.
    537     """
    538     path = '/proc/sys/%s' % key
    539     if value is not None:
    540         utils.write_one_line(path, str(value))
    541     return utils.read_one_line(path)
    542 
    543 
    544 def sysctl_kernel(key, value=None):
    545     """(Very) partial implementation of sysctl, for kernel params"""
    546     if value is not None:
    547         # write
    548         utils.write_one_line('/proc/sys/kernel/%s' % key, str(value))
    549     else:
    550         # read
    551         out = utils.read_one_line('/proc/sys/kernel/%s' % key)
    552         return int(re.search(r'\d+', out).group(0))
    553 
    554 
    555 def _convert_exit_status(sts):
    556     if os.WIFSIGNALED(sts):
    557         return -os.WTERMSIG(sts)
    558     elif os.WIFEXITED(sts):
    559         return os.WEXITSTATUS(sts)
    560     else:
    561         # impossible?
    562         raise RuntimeError("Unknown exit status %d!" % sts)
    563 
    564 
    565 def where_art_thy_filehandles():
    566     """Dump the current list of filehandles"""
    567     os.system("ls -l /proc/%d/fd >> /dev/tty" % os.getpid())
    568 
    569 
    570 def print_to_tty(string):
    571     """Output string straight to the tty"""
    572     open('/dev/tty', 'w').write(string + '\n')
    573 
    574 
    575 def dump_object(object):
    576     """Dump an object's attributes and methods
    577 
    578     kind of like dir()
    579     """
    580     for item in object.__dict__.iteritems():
    581         print item
    582         try:
    583             (key, value) = item
    584             dump_object(value)
    585         except:
    586             continue
    587 
    588 
    589 def environ(env_key):
    590     """return the requested environment variable, or '' if unset"""
    591     if (os.environ.has_key(env_key)):
    592         return os.environ[env_key]
    593     else:
    594         return ''
    595 
    596 
    597 def prepend_path(newpath, oldpath):
    598     """prepend newpath to oldpath"""
    599     if (oldpath):
    600         return newpath + ':' + oldpath
    601     else:
    602         return newpath
    603 
    604 
    605 def append_path(oldpath, newpath):
    606     """append newpath to oldpath"""
    607     if (oldpath):
    608         return oldpath + ':' + newpath
    609     else:
    610         return newpath
    611 
    612 
    613 _TIME_OUTPUT_RE = re.compile(
    614         r'([\d\.]*)user ([\d\.]*)system '
    615         r'(\d*):([\d\.]*)elapsed (\d*)%CPU')
    616 
    617 
    618 def avgtime_print(dir):
    619     """ Calculate some benchmarking statistics.
    620         Input is a directory containing a file called 'time'.
    621         File contains one-per-line results of /usr/bin/time.
    622         Output is average Elapsed, User, and System time in seconds,
    623           and average CPU percentage.
    624     """
    625     user = system = elapsed = cpu = count = 0
    626     with open(dir + "/time") as f:
    627         for line in f:
    628             try:
    629                 m = _TIME_OUTPUT_RE.match(line);
    630                 user += float(m.group(1))
    631                 system += float(m.group(2))
    632                 elapsed += (float(m.group(3)) * 60) + float(m.group(4))
    633                 cpu += float(m.group(5))
    634                 count += 1
    635             except:
    636                 raise ValueError("badly formatted times")
    637 
    638     return "Elapsed: %0.2fs User: %0.2fs System: %0.2fs CPU: %0.0f%%" % \
    639           (elapsed / count, user / count, system / count, cpu / count)
    640 
    641 
    642 def to_seconds(time_string):
    643     """Converts a string in M+:SS.SS format to S+.SS"""
    644     elts = time_string.split(':')
    645     if len(elts) == 1:
    646         return time_string
    647     return str(int(elts[0]) * 60 + float(elts[1]))
    648 
    649 
    650 _TIME_OUTPUT_RE_2 = re.compile(r'(.*?)user (.*?)system (.*?)elapsed')
    651 
    652 
    653 def extract_all_time_results(results_string):
    654     """Extract user, system, and elapsed times into a list of tuples"""
    655     results = []
    656     for result in _TIME_OUTPUT_RE_2.findall(results_string):
    657         results.append(tuple([to_seconds(elt) for elt in result]))
    658     return results
    659 
    660 
    661 def running_config():
    662     """
    663     Return path of config file of the currently running kernel
    664     """
    665     version = utils.system_output('uname -r')
    666     for config in ('/proc/config.gz', \
    667                    '/boot/config-%s' % version,
    668                    '/lib/modules/%s/build/.config' % version):
    669         if os.path.isfile(config):
    670             return config
    671     return None
    672 
    673 
    674 def check_for_kernel_feature(feature):
    675     config = running_config()
    676 
    677     if not config:
    678         raise TypeError("Can't find kernel config file")
    679 
    680     if magic.guess_type(config) == 'application/x-gzip':
    681         grep = 'zgrep'
    682     else:
    683         grep = 'grep'
    684     grep += ' ^CONFIG_%s= %s' % (feature, config)
    685 
    686     if not utils.system_output(grep, ignore_status=True):
    687         raise ValueError("Kernel doesn't have a %s feature" % (feature))
    688 
    689 
    690 def check_glibc_ver(ver):
    691     glibc_ver = commands.getoutput('ldd --version').splitlines()[0]
    692     glibc_ver = re.search(r'(\d+\.\d+(\.\d+)?)', glibc_ver).group()
    693     if utils.compare_versions(glibc_ver, ver) == -1:
    694         raise error.TestError("Glibc too old (%s). Glibc >= %s is needed." %
    695                               (glibc_ver, ver))
    696 
    697 def check_kernel_ver(ver):
    698     kernel_ver = utils.system_output('uname -r')
    699     kv_tmp = re.split(r'[-]', kernel_ver)[0:3]
    700     # In compare_versions, if v1 < v2, return value == -1
    701     if utils.compare_versions(kv_tmp[0], ver) == -1:
    702         raise error.TestError("Kernel too old (%s). Kernel > %s is needed." %
    703                               (kernel_ver, ver))
    704 
    705 
    706 def human_format(number):
    707     # Convert number to kilo / mega / giga format.
    708     if number < 1024:
    709         return "%d" % number
    710     kilo = float(number) / 1024.0
    711     if kilo < 1024:
    712         return "%.2fk" % kilo
    713     meg = kilo / 1024.0
    714     if meg < 1024:
    715         return "%.2fM" % meg
    716     gig = meg / 1024.0
    717     return "%.2fG" % gig
    718 
    719 
    720 def numa_nodes():
    721     node_paths = glob.glob('/sys/devices/system/node/node*')
    722     nodes = [int(re.sub(r'.*node(\d+)', r'\1', x)) for x in node_paths]
    723     return (sorted(nodes))
    724 
    725 
    726 def node_size():
    727     nodes = max(len(numa_nodes()), 1)
    728     return ((memtotal() * 1024) / nodes)
    729 
    730 
    731 def pickle_load(filename):
    732     return pickle.load(open(filename, 'r'))
    733 
    734 
    735 # Return the kernel version and build timestamp.
    736 def running_os_release():
    737     return os.uname()[2:4]
    738 
    739 
    740 def running_os_ident():
    741     (version, timestamp) = running_os_release()
    742     return version + '::' + timestamp
    743 
    744 
    745 def running_os_full_version():
    746     (version, timestamp) = running_os_release()
    747     return version
    748 
    749 
    750 # much like find . -name 'pattern'
    751 def locate(pattern, root=os.getcwd()):
    752     for path, dirs, files in os.walk(root):
    753         for f in files:
    754             if fnmatch.fnmatch(f, pattern):
    755                 yield os.path.abspath(os.path.join(path, f))
    756 
    757 
    758 def freespace(path):
    759     """Return the disk free space, in bytes"""
    760     s = os.statvfs(path)
    761     return s.f_bavail * s.f_bsize
    762 
    763 
    764 def disk_block_size(path):
    765     """Return the disk block size, in bytes"""
    766     return os.statvfs(path).f_bsize
    767 
    768 
    769 _DISK_PARTITION_3_RE = re.compile(r'^(/dev/hd[a-z]+)3', re.M)
    770 
    771 def get_disks():
    772     df_output = utils.system_output('df')
    773     return _DISK_PARTITION_3_RE.findall(df_output)
    774 
    775 
    776 def get_disk_size(disk_name):
    777     """
    778     Return size of disk in byte. Return 0 in Error Case
    779 
    780     @param disk_name: disk name to find size
    781     """
    782     device = os.path.basename(disk_name)
    783     for line in file('/proc/partitions'):
    784         try:
    785             _, _, blocks, name = re.split(r' +', line.strip())
    786         except ValueError:
    787             continue
    788         if name == device:
    789             return 1024 * int(blocks)
    790     return 0
    791 
    792 
    793 def get_disk_size_gb(disk_name):
    794     """
    795     Return size of disk in GB (10^9). Return 0 in Error Case
    796 
    797     @param disk_name: disk name to find size
    798     """
    799     return int(get_disk_size(disk_name) / (10.0 ** 9) + 0.5)
    800 
    801 
    802 def get_disk_model(disk_name):
    803     """
    804     Return model name for internal storage device
    805 
    806     @param disk_name: disk name to find model
    807     """
    808     cmd1 = 'udevadm info --query=property --name=%s' % disk_name
    809     cmd2 = 'grep -E "ID_(NAME|MODEL)="'
    810     cmd3 = 'cut -f 2 -d"="'
    811     cmd = ' | '.join([cmd1, cmd2, cmd3])
    812     return utils.system_output(cmd)
    813 
    814 
    815 _DISK_DEV_RE = re.compile(r'/dev/sd[a-z]|'
    816                           r'/dev/mmcblk[0-9]+|'
    817                           r'/dev/nvme[0-9]+n[0-9]+')
    818 
    819 
    820 def get_disk_from_filename(filename):
    821     """
    822     Return the disk device the filename is on.
    823     If the file is on tmpfs or other special file systems,
    824     return None.
    825 
    826     @param filename: name of file, full path.
    827     """
    828 
    829     if not os.path.exists(filename):
    830         raise error.TestError('file %s missing' % filename)
    831 
    832     if filename[0] != '/':
    833         raise error.TestError('This code works only with full path')
    834 
    835     m = _DISK_DEV_RE.match(filename)
    836     while not m:
    837         if filename[0] != '/':
    838             return None
    839         if filename == '/dev/root':
    840             cmd = 'rootdev -d -s'
    841         elif filename.startswith('/dev/mapper'):
    842             cmd = 'dmsetup table "%s"' % os.path.basename(filename)
    843             dmsetup_output = utils.system_output(cmd).split(' ')
    844             if dmsetup_output[2] == 'verity':
    845                 maj_min = dmsetup_output[4]
    846             elif dmsetup_output[2] == 'crypt':
    847                 maj_min = dmsetup_output[6]
    848             cmd = 'realpath "/dev/block/%s"' % maj_min
    849         elif filename.startswith('/dev/loop'):
    850             cmd = 'losetup -O BACK-FILE "%s" | tail -1' % filename
    851         else:
    852             cmd = 'df "%s" | tail -1 | cut -f 1 -d" "' % filename
    853         filename = utils.system_output(cmd)
    854         m = _DISK_DEV_RE.match(filename)
    855     return m.group(0)
    856 
    857 
    858 def get_disk_firmware_version(disk_name):
    859     """
    860     Return firmware version for internal storage device. (empty string for eMMC)
    861 
    862     @param disk_name: disk name to find model
    863     """
    864     cmd1 = 'udevadm info --query=property --name=%s' % disk_name
    865     cmd2 = 'grep -E "ID_REVISION="'
    866     cmd3 = 'cut -f 2 -d"="'
    867     cmd = ' | '.join([cmd1, cmd2, cmd3])
    868     return utils.system_output(cmd)
    869 
    870 
    871 def is_disk_scsi(disk_name):
    872     """
    873     Return true if disk is a scsi device, return false otherwise
    874 
    875     @param disk_name: disk name check
    876     """
    877     return re.match('/dev/sd[a-z]+', disk_name)
    878 
    879 
    880 def is_disk_harddisk(disk_name):
    881     """
    882     Return true if disk is a harddisk, return false otherwise
    883 
    884     @param disk_name: disk name check
    885     """
    886     cmd1 = 'udevadm info --query=property --name=%s' % disk_name
    887     cmd2 = 'grep -E "ID_ATA_ROTATION_RATE_RPM="'
    888     cmd3 = 'cut -f 2 -d"="'
    889     cmd = ' | '.join([cmd1, cmd2, cmd3])
    890 
    891     rtt = utils.system_output(cmd)
    892 
    893     # eMMC will not have this field; rtt == ''
    894     # SSD will have zero rotation rate; rtt == '0'
    895     # For harddisk rtt > 0
    896     return rtt and int(rtt) > 0
    897 
    898 
    899 def verify_hdparm_feature(disk_name, feature):
    900     """
    901     Check for feature support for SCSI disk using hdparm
    902 
    903     @param disk_name: target disk
    904     @param feature: hdparm output string of the feature
    905     """
    906     cmd = 'hdparm -I %s | grep -q "%s"' % (disk_name, feature)
    907     ret = utils.system(cmd, ignore_status=True)
    908     if ret == 0:
    909         return True
    910     elif ret == 1:
    911         return False
    912     else:
    913         raise error.TestFail('Error running command %s' % cmd)
    914 
    915 
    916 def get_storage_error_msg(disk_name, reason):
    917     """
    918     Get Error message for storage test which include disk model.
    919     and also include the firmware version for the SCSI disk
    920 
    921     @param disk_name: target disk
    922     @param reason: Reason of the error.
    923     """
    924 
    925     msg = reason
    926 
    927     model = get_disk_model(disk_name)
    928     msg += ' Disk model: %s' % model
    929 
    930     if is_disk_scsi(disk_name):
    931         fw = get_disk_firmware_version(disk_name)
    932         msg += ' firmware: %s' % fw
    933 
    934     return msg
    935 
    936 
    937 def load_module(module_name, params=None):
    938     # Checks if a module has already been loaded
    939     if module_is_loaded(module_name):
    940         return False
    941 
    942     cmd = '/sbin/modprobe ' + module_name
    943     if params:
    944         cmd += ' ' + params
    945     utils.system(cmd)
    946     return True
    947 
    948 
    949 def unload_module(module_name):
    950     """
    951     Removes a module. Handles dependencies. If even then it's not possible
    952     to remove one of the modules, it will trhow an error.CmdError exception.
    953 
    954     @param module_name: Name of the module we want to remove.
    955     """
    956     l_raw = utils.system_output("/bin/lsmod").splitlines()
    957     lsmod = [x for x in l_raw if x.split()[0] == module_name]
    958     if len(lsmod) > 0:
    959         line_parts = lsmod[0].split()
    960         if len(line_parts) == 4:
    961             submodules = line_parts[3].split(",")
    962             for submodule in submodules:
    963                 unload_module(submodule)
    964         utils.system("/sbin/modprobe -r %s" % module_name)
    965         logging.info("Module %s unloaded", module_name)
    966     else:
    967         logging.info("Module %s is already unloaded", module_name)
    968 
    969 
    970 def module_is_loaded(module_name):
    971     module_name = module_name.replace('-', '_')
    972     modules = utils.system_output('/bin/lsmod').splitlines()
    973     for module in modules:
    974         if module.startswith(module_name) and module[len(module_name)] == ' ':
    975             return True
    976     return False
    977 
    978 
    979 def get_loaded_modules():
    980     lsmod_output = utils.system_output('/bin/lsmod').splitlines()[1:]
    981     return [line.split(None, 1)[0] for line in lsmod_output]
    982 
    983 
    984 def get_huge_page_size():
    985     output = utils.system_output('grep Hugepagesize /proc/meminfo')
    986     return int(output.split()[1]) # Assumes units always in kB. :(
    987 
    988 
    989 def get_num_huge_pages():
    990     raw_hugepages = utils.system_output('/sbin/sysctl vm.nr_hugepages')
    991     return int(raw_hugepages.split()[2])
    992 
    993 
    994 def set_num_huge_pages(num):
    995     utils.system('/sbin/sysctl vm.nr_hugepages=%d' % num)
    996 
    997 
    998 def ping_default_gateway():
    999     """Ping the default gateway."""
   1000 
   1001     network = open('/etc/sysconfig/network')
   1002     m = re.search('GATEWAY=(\S+)', network.read())
   1003 
   1004     if m:
   1005         gw = m.group(1)
   1006         cmd = 'ping %s -c 5 > /dev/null' % gw
   1007         return utils.system(cmd, ignore_status=True)
   1008 
   1009     raise error.TestError('Unable to find default gateway')
   1010 
   1011 
   1012 def drop_caches():
   1013     """Writes back all dirty pages to disk and clears all the caches."""
   1014     utils.system("sync")
   1015     # We ignore failures here as this will fail on 2.6.11 kernels.
   1016     utils.system("echo 3 > /proc/sys/vm/drop_caches", ignore_status=True)
   1017 
   1018 
   1019 def process_is_alive(name_pattern):
   1020     """
   1021     'pgrep name' misses all python processes and also long process names.
   1022     'pgrep -f name' gets all shell commands with name in args.
   1023     So look only for command whose initial pathname ends with name.
   1024     Name itself is an egrep pattern, so it can use | etc for variations.
   1025     """
   1026     return utils.system("pgrep -f '^([^ /]*/)*(%s)([ ]|$)'" % name_pattern,
   1027                         ignore_status=True) == 0
   1028 
   1029 
   1030 def get_hwclock_seconds(utc=True):
   1031     """
   1032     Return the hardware clock in seconds as a floating point value.
   1033     Use Coordinated Universal Time if utc is True, local time otherwise.
   1034     Raise a ValueError if unable to read the hardware clock.
   1035     """
   1036     cmd = '/sbin/hwclock --debug'
   1037     if utc:
   1038         cmd += ' --utc'
   1039     hwclock_output = utils.system_output(cmd, ignore_status=True)
   1040     match = re.search(r'= ([0-9]+) seconds since .+ (-?[0-9.]+) seconds$',
   1041                       hwclock_output, re.DOTALL)
   1042     if match:
   1043         seconds = int(match.group(1)) + float(match.group(2))
   1044         logging.debug('hwclock seconds = %f', seconds)
   1045         return seconds
   1046 
   1047     raise ValueError('Unable to read the hardware clock -- ' +
   1048                      hwclock_output)
   1049 
   1050 
   1051 def set_wake_alarm(alarm_time):
   1052     """
   1053     Set the hardware RTC-based wake alarm to 'alarm_time'.
   1054     """
   1055     utils.write_one_line('/sys/class/rtc/rtc0/wakealarm', str(alarm_time))
   1056 
   1057 
   1058 def set_power_state(state):
   1059     """
   1060     Set the system power state to 'state'.
   1061     """
   1062     utils.write_one_line('/sys/power/state', state)
   1063 
   1064 
   1065 def standby():
   1066     """
   1067     Power-on suspend (S1)
   1068     """
   1069     set_power_state('standby')
   1070 
   1071 
   1072 def suspend_to_ram():
   1073     """
   1074     Suspend the system to RAM (S3)
   1075     """
   1076     set_power_state('mem')
   1077 
   1078 
   1079 def suspend_to_disk():
   1080     """
   1081     Suspend the system to disk (S4)
   1082     """
   1083     set_power_state('disk')
   1084 
   1085 
   1086 _AMD_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/amd_pci_ids.json'
   1087 _INTEL_PCI_IDS_FILE_PATH = '/usr/local/autotest/bin/intel_pci_ids.json'
   1088 _UI_USE_FLAGS_FILE_PATH = '/etc/ui_use_flags.txt'
   1089 
   1090 # Command to check if a package is installed. If the package is not installed
   1091 # the command shall fail.
   1092 _CHECK_PACKAGE_INSTALLED_COMMAND =(
   1093         "dpkg-query -W -f='${Status}\n' %s | head -n1 | awk '{print $3;}' | "
   1094         "grep -q '^installed$'")
   1095 
   1096 pciid_to_amd_architecture = {}
   1097 pciid_to_intel_architecture = {}
   1098 
   1099 class Crossystem(object):
   1100     """A wrapper for the crossystem utility."""
   1101 
   1102     def __init__(self, client):
   1103         self.cros_system_data = {}
   1104         self._client = client
   1105 
   1106     def init(self):
   1107         self.cros_system_data = {}
   1108         (_, fname) = tempfile.mkstemp()
   1109         f = open(fname, 'w')
   1110         self._client.run('crossystem', stdout_tee=f)
   1111         f.close()
   1112         text = utils.read_file(fname)
   1113         for line in text.splitlines():
   1114             assignment_string = line.split('#')[0]
   1115             if not assignment_string.count('='):
   1116                 continue
   1117             (name, value) = assignment_string.split('=', 1)
   1118             self.cros_system_data[name.strip()] = value.strip()
   1119         os.remove(fname)
   1120 
   1121     def __getattr__(self, name):
   1122         """
   1123         Retrieve a crosssystem attribute.
   1124 
   1125         The call crossystemobject.name() will return the crossystem reported
   1126         string.
   1127         """
   1128         return lambda: self.cros_system_data[name]
   1129 
   1130 
   1131 def get_oldest_pid_by_name(name):
   1132     """
   1133     Return the oldest pid of a process whose name perfectly matches |name|.
   1134 
   1135     name is an egrep expression, which will be matched against the entire name
   1136     of processes on the system.  For example:
   1137 
   1138       get_oldest_pid_by_name('chrome')
   1139 
   1140     on a system running
   1141       8600 ?        00:00:04 chrome
   1142       8601 ?        00:00:00 chrome
   1143       8602 ?        00:00:00 chrome-sandbox
   1144 
   1145     would return 8600, as that's the oldest process that matches.
   1146     chrome-sandbox would not be matched.
   1147 
   1148     Arguments:
   1149       name: egrep expression to match.  Will be anchored at the beginning and
   1150             end of the match string.
   1151 
   1152     Returns:
   1153       pid as an integer, or None if one cannot be found.
   1154 
   1155     Raises:
   1156       ValueError if pgrep returns something odd.
   1157     """
   1158     str_pid = utils.system_output('pgrep -o ^%s$' % name,
   1159                                   ignore_status=True).rstrip()
   1160     if str_pid:
   1161         return int(str_pid)
   1162 
   1163 
   1164 def get_oldest_by_name(name):
   1165     """Return pid and command line of oldest process whose name matches |name|.
   1166 
   1167     @param name: egrep expression to match desired process name.
   1168     @return: A tuple of (pid, command_line) of the oldest process whose name
   1169              matches |name|.
   1170 
   1171     """
   1172     pid = get_oldest_pid_by_name(name)
   1173     if pid:
   1174         command_line = utils.system_output('ps -p %i -o command=' % pid,
   1175                                            ignore_status=True).rstrip()
   1176         return (pid, command_line)
   1177 
   1178 
   1179 def get_chrome_remote_debugging_port():
   1180     """Returns remote debugging port for Chrome.
   1181 
   1182     Parse chrome process's command line argument to get the remote debugging
   1183     port.
   1184     """
   1185     _, command = get_oldest_by_name('chrome')
   1186     matches = re.search('--remote-debugging-port=([0-9]+)', command)
   1187     if matches:
   1188         return int(matches.group(1))
   1189 
   1190 
   1191 def get_process_list(name, command_line=None):
   1192     """
   1193     Return the list of pid for matching process |name command_line|.
   1194 
   1195     on a system running
   1196       31475 ?    0:06 /opt/google/chrome/chrome --allow-webui-compositing -
   1197       31478 ?    0:00 /opt/google/chrome/chrome-sandbox /opt/google/chrome/
   1198       31485 ?    0:00 /opt/google/chrome/chrome --type=zygote --log-level=1
   1199       31532 ?    1:05 /opt/google/chrome/chrome --type=renderer
   1200 
   1201     get_process_list('chrome')
   1202     would return ['31475', '31485', '31532']
   1203 
   1204     get_process_list('chrome', '--type=renderer')
   1205     would return ['31532']
   1206 
   1207     Arguments:
   1208       name: process name to search for. If command_line is provided, name is
   1209             matched against full command line. If command_line is not provided,
   1210             name is only matched against the process name.
   1211       command line: when command line is passed, the full process command line
   1212                     is used for matching.
   1213 
   1214     Returns:
   1215       list of PIDs of the matching processes.
   1216 
   1217     """
   1218     # TODO(rohitbm) crbug.com/268861
   1219     flag = '-x' if not command_line else '-f'
   1220     name = '\'%s.*%s\'' % (name, command_line) if command_line else name
   1221     str_pid = utils.system_output('pgrep %s %s' % (flag, name),
   1222                                   ignore_status=True).rstrip()
   1223     return str_pid.split()
   1224 
   1225 
   1226 def nuke_process_by_name(name, with_prejudice=False):
   1227     """Tell the oldest process specified by name to exit.
   1228 
   1229     Arguments:
   1230       name: process name specifier, as understood by pgrep.
   1231       with_prejudice: if True, don't allow for graceful exit.
   1232 
   1233     Raises:
   1234       error.AutoservPidAlreadyDeadError: no existing process matches name.
   1235     """
   1236     try:
   1237         pid = get_oldest_pid_by_name(name)
   1238     except Exception as e:
   1239         logging.error(e)
   1240         return
   1241     if pid is None:
   1242         raise error.AutoservPidAlreadyDeadError('No process matching %s.' %
   1243                                                 name)
   1244     if with_prejudice:
   1245         utils.nuke_pid(pid, [signal.SIGKILL])
   1246     else:
   1247         utils.nuke_pid(pid)
   1248 
   1249 
   1250 def ensure_processes_are_dead_by_name(name, timeout_sec=10):
   1251     """Terminate all processes specified by name and ensure they're gone.
   1252 
   1253     Arguments:
   1254       name: process name specifier, as understood by pgrep.
   1255       timeout_sec: maximum number of seconds to wait for processes to die.
   1256 
   1257     Raises:
   1258       error.AutoservPidAlreadyDeadError: no existing process matches name.
   1259       utils.TimeoutError: if processes still exist after timeout_sec.
   1260     """
   1261 
   1262     def list_and_kill_processes(name):
   1263         process_list = get_process_list(name)
   1264         try:
   1265             for pid in [int(str_pid) for str_pid in process_list]:
   1266                 utils.nuke_pid(pid)
   1267         except error.AutoservPidAlreadyDeadError:
   1268             pass
   1269         return process_list
   1270 
   1271     utils.poll_for_condition(lambda: list_and_kill_processes(name) == [],
   1272                              timeout=timeout_sec)
   1273 
   1274 
   1275 def is_virtual_machine():
   1276     return 'QEMU' in platform.processor()
   1277 
   1278 
   1279 def save_vm_state(checkpoint):
   1280     """Saves the current state of the virtual machine.
   1281 
   1282     This function is a NOOP if the test is not running under a virtual machine
   1283     with the USB serial port redirected.
   1284 
   1285     Arguments:
   1286       checkpoint - Name used to identify this state
   1287 
   1288     Returns:
   1289       None
   1290     """
   1291     # The QEMU monitor has been redirected to the guest serial port located at
   1292     # /dev/ttyUSB0. To save the state of the VM, we just send the 'savevm'
   1293     # command to the serial port.
   1294     if is_virtual_machine() and os.path.exists('/dev/ttyUSB0'):
   1295         logging.info('Saving VM state "%s"', checkpoint)
   1296         serial = open('/dev/ttyUSB0', 'w')
   1297         serial.write('savevm %s\r\n' % checkpoint)
   1298         logging.info('Done saving VM state "%s"', checkpoint)
   1299 
   1300 
   1301 def check_raw_dmesg(dmesg, message_level, whitelist):
   1302     """Checks dmesg for unexpected warnings.
   1303 
   1304     This function parses dmesg for message with message_level <= message_level
   1305     which do not appear in the whitelist.
   1306 
   1307     Arguments:
   1308       dmesg - string containing raw dmesg buffer
   1309       message_level - minimum message priority to check
   1310       whitelist - messages to ignore
   1311 
   1312     Returns:
   1313       List of unexpected warnings
   1314     """
   1315     whitelist_re = re.compile(r'(%s)' % '|'.join(whitelist))
   1316     unexpected = []
   1317     for line in dmesg.splitlines():
   1318         if int(line[1]) <= message_level:
   1319             stripped_line = line.split('] ', 1)[1]
   1320             if whitelist_re.search(stripped_line):
   1321                 continue
   1322             unexpected.append(stripped_line)
   1323     return unexpected
   1324 
   1325 
   1326 def verify_mesg_set(mesg, regex, whitelist):
   1327     """Verifies that the exact set of messages are present in a text.
   1328 
   1329     This function finds all strings in the text matching a certain regex, and
   1330     then verifies that all expected strings are present in the set, and no
   1331     unexpected strings are there.
   1332 
   1333     Arguments:
   1334       mesg - the mutiline text to be scanned
   1335       regex - regular expression to match
   1336       whitelist - messages to find in the output, a list of strings
   1337           (potentially regexes) to look for in the filtered output. All these
   1338           strings must be there, and no other strings should be present in the
   1339           filtered output.
   1340 
   1341     Returns:
   1342       string of inconsistent findings (i.e. an empty string on success).
   1343     """
   1344 
   1345     rv = []
   1346 
   1347     missing_strings = []
   1348     present_strings = []
   1349     for line in mesg.splitlines():
   1350         if not re.search(r'%s' % regex, line):
   1351             continue
   1352         present_strings.append(line.split('] ', 1)[1])
   1353 
   1354     for string in whitelist:
   1355         for present_string in list(present_strings):
   1356             if re.search(r'^%s$' % string, present_string):
   1357                 present_strings.remove(present_string)
   1358                 break
   1359         else:
   1360             missing_strings.append(string)
   1361 
   1362     if present_strings:
   1363         rv.append('unexpected strings:')
   1364         rv.extend(present_strings)
   1365     if missing_strings:
   1366         rv.append('missing strings:')
   1367         rv.extend(missing_strings)
   1368 
   1369     return '\n'.join(rv)
   1370 
   1371 
   1372 def target_is_pie():
   1373     """Returns whether the toolchain produces a PIE (position independent
   1374     executable) by default.
   1375 
   1376     Arguments:
   1377       None
   1378 
   1379     Returns:
   1380       True if the target toolchain produces a PIE by default.
   1381       False otherwise.
   1382     """
   1383 
   1384     command = 'echo | ${CC} -E -dD -P - | grep -i pie'
   1385     result = utils.system_output(command,
   1386                                  retain_output=True,
   1387                                  ignore_status=True)
   1388     if re.search('#define __PIE__', result):
   1389         return True
   1390     else:
   1391         return False
   1392 
   1393 
   1394 def target_is_x86():
   1395     """Returns whether the toolchain produces an x86 object
   1396 
   1397     Arguments:
   1398       None
   1399 
   1400     Returns:
   1401       True if the target toolchain produces an x86 object
   1402       False otherwise.
   1403     """
   1404 
   1405     command = 'echo | ${CC} -E -dD -P - | grep -i 86'
   1406     result = utils.system_output(command,
   1407                                  retain_output=True,
   1408                                  ignore_status=True)
   1409     if re.search('__i386__', result) or re.search('__x86_64__', result):
   1410         return True
   1411     else:
   1412         return False
   1413 
   1414 
   1415 def mounts():
   1416     ret = []
   1417     for line in file('/proc/mounts'):
   1418         m = re.match(
   1419             r'(?P<src>\S+) (?P<dest>\S+) (?P<type>\S+) (?P<opts>\S+).*', line)
   1420         if m:
   1421             ret.append(m.groupdict())
   1422     return ret
   1423 
   1424 
   1425 def is_mountpoint(path):
   1426     return path in [m['dest'] for m in mounts()]
   1427 
   1428 
   1429 def require_mountpoint(path):
   1430     """
   1431     Raises an exception if path is not a mountpoint.
   1432     """
   1433     if not is_mountpoint(path):
   1434         raise error.TestFail('Path not mounted: "%s"' % path)
   1435 
   1436 
   1437 def random_username():
   1438     return str(uuid.uuid4()) + '@example.com'
   1439 
   1440 
   1441 def get_signin_credentials(filepath):
   1442     """Returns user_id, password tuple from credentials file at filepath.
   1443 
   1444     File must have one line of the format user_id:password
   1445 
   1446     @param filepath: path of credentials file.
   1447     @return user_id, password tuple.
   1448     """
   1449     user_id, password = None, None
   1450     if os.path.isfile(filepath):
   1451         with open(filepath) as f:
   1452             user_id, password = f.read().rstrip().split(':')
   1453     return user_id, password
   1454 
   1455 
   1456 def parse_cmd_output(command, run_method=utils.run):
   1457     """Runs a command on a host object to retrieve host attributes.
   1458 
   1459     The command should output to stdout in the format of:
   1460     <key> = <value> # <optional_comment>
   1461 
   1462 
   1463     @param command: Command to execute on the host.
   1464     @param run_method: Function to use to execute the command. Defaults to
   1465                        utils.run so that the command will be executed locally.
   1466                        Can be replace with a host.run call so that it will
   1467                        execute on a DUT or external machine. Method must accept
   1468                        a command argument, stdout_tee and stderr_tee args and
   1469                        return a result object with a string attribute stdout
   1470                        which will be parsed.
   1471 
   1472     @returns a dictionary mapping host attributes to their values.
   1473     """
   1474     result = {}
   1475     # Suppresses stdout so that the files are not printed to the logs.
   1476     cmd_result = run_method(command, stdout_tee=None, stderr_tee=None)
   1477     for line in cmd_result.stdout.splitlines():
   1478         # Lines are of the format "<key>     = <value>      # <comment>"
   1479         key_value = re.match(r'^\s*(?P<key>[^ ]+)\s*=\s*(?P<value>[^ '
   1480                              r']+)(?:\s*#.*)?$', line)
   1481         if key_value:
   1482             result[key_value.group('key')] = key_value.group('value')
   1483     return result
   1484 
   1485 
   1486 def set_from_keyval_output(out, delimiter=' '):
   1487     """Parse delimiter-separated key-val output into a set of tuples.
   1488 
   1489     Output is expected to be multiline text output from a command.
   1490     Stuffs the key-vals into tuples in a set to be later compared.
   1491 
   1492     e.g.  deactivated 0
   1493           disableForceClear 0
   1494           ==>  set(('deactivated', '0'), ('disableForceClear', '0'))
   1495 
   1496     @param out: multiple lines of space-separated key-val pairs.
   1497     @param delimiter: character that separates key from val. Usually a
   1498                       space but may be '=' or something else.
   1499     @return set of key-val tuples.
   1500     """
   1501     results = set()
   1502     kv_match_re = re.compile('([^ ]+)%s(.*)' % delimiter)
   1503     for linecr in out.splitlines():
   1504         match = kv_match_re.match(linecr.strip())
   1505         if match:
   1506             results.add((match.group(1), match.group(2)))
   1507     return results
   1508 
   1509 
   1510 def get_cpu_usage():
   1511     """Returns machine's CPU usage.
   1512 
   1513     This function uses /proc/stat to identify CPU usage.
   1514     Returns:
   1515         A dictionary with 'user', 'nice', 'system' and 'idle' values.
   1516         Sample dictionary:
   1517         {
   1518             'user': 254544,
   1519             'nice': 9,
   1520             'system': 254768,
   1521             'idle': 2859878,
   1522         }
   1523     """
   1524     proc_stat = open('/proc/stat')
   1525     cpu_usage_str = proc_stat.readline().split()
   1526     proc_stat.close()
   1527     return {
   1528         'user': int(cpu_usage_str[1]),
   1529         'nice': int(cpu_usage_str[2]),
   1530         'system': int(cpu_usage_str[3]),
   1531         'idle': int(cpu_usage_str[4])
   1532     }
   1533 
   1534 
   1535 def compute_active_cpu_time(cpu_usage_start, cpu_usage_end):
   1536     """Computes the fraction of CPU time spent non-idling.
   1537 
   1538     This function should be invoked using before/after values from calls to
   1539     get_cpu_usage().
   1540     """
   1541     time_active_end = (
   1542         cpu_usage_end['user'] + cpu_usage_end['nice'] + cpu_usage_end['system'])
   1543     time_active_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
   1544                          cpu_usage_start['system'])
   1545     total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
   1546                       cpu_usage_end['system'] + cpu_usage_end['idle'])
   1547     total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
   1548                         cpu_usage_start['system'] + cpu_usage_start['idle'])
   1549     return ((float(time_active_end) - time_active_start) /
   1550             (total_time_end - total_time_start))
   1551 
   1552 
   1553 def is_pgo_mode():
   1554     return 'USE_PGO' in os.environ
   1555 
   1556 
   1557 def wait_for_idle_cpu(timeout, utilization):
   1558     """Waits for the CPU to become idle (< utilization).
   1559 
   1560     Args:
   1561         timeout: The longest time in seconds to wait before throwing an error.
   1562         utilization: The CPU usage below which the system should be considered
   1563                 idle (between 0 and 1.0 independent of cores/hyperthreads).
   1564     """
   1565     time_passed = 0.0
   1566     fraction_active_time = 1.0
   1567     sleep_time = 1
   1568     logging.info('Starting to wait up to %.1fs for idle CPU...', timeout)
   1569     while fraction_active_time >= utilization:
   1570         cpu_usage_start = get_cpu_usage()
   1571         # Split timeout interval into not too many chunks to limit log spew.
   1572         # Start at 1 second, increase exponentially
   1573         time.sleep(sleep_time)
   1574         time_passed += sleep_time
   1575         sleep_time = min(16.0, 2.0 * sleep_time)
   1576         cpu_usage_end = get_cpu_usage()
   1577         fraction_active_time = \
   1578                 compute_active_cpu_time(cpu_usage_start, cpu_usage_end)
   1579         logging.info('After waiting %.1fs CPU utilization is %.3f.',
   1580                      time_passed, fraction_active_time)
   1581         if time_passed > timeout:
   1582             logging.warning('CPU did not become idle.')
   1583             log_process_activity()
   1584             # crosbug.com/37389
   1585             if is_pgo_mode():
   1586                 logging.info('Still continuing because we are in PGO mode.')
   1587                 return True
   1588 
   1589             return False
   1590     logging.info('Wait for idle CPU took %.1fs (utilization = %.3f).',
   1591                  time_passed, fraction_active_time)
   1592     return True
   1593 
   1594 
   1595 def log_process_activity():
   1596     """Logs the output of top.
   1597 
   1598     Useful to debug performance tests and to find runaway processes.
   1599     """
   1600     logging.info('Logging current process activity using top and ps.')
   1601     cmd = 'top -b -n1 -c'
   1602     output = utils.run(cmd)
   1603     logging.info(output)
   1604     output = utils.run('ps axl')
   1605     logging.info(output)
   1606 
   1607 
   1608 def wait_for_cool_machine():
   1609     """
   1610     A simple heuristic to wait for a machine to cool.
   1611     The code looks a bit 'magic', but we don't know ambient temperature
   1612     nor machine characteristics and still would like to return the caller
   1613     a machine that cooled down as much as reasonably possible.
   1614     """
   1615     temperature = get_current_temperature_max()
   1616     # We got here with a cold machine, return immediately. This should be the
   1617     # most common case.
   1618     if temperature < 50:
   1619         return True
   1620     logging.info('Got a hot machine of %dC. Sleeping 1 minute.', temperature)
   1621     # A modest wait should cool the machine.
   1622     time.sleep(60.0)
   1623     temperature = get_current_temperature_max()
   1624     # Atoms idle below 60 and everyone else should be even lower.
   1625     if temperature < 62:
   1626         return True
   1627     # This should be rare.
   1628     logging.info('Did not cool down (%dC). Sleeping 2 minutes.', temperature)
   1629     time.sleep(120.0)
   1630     temperature = get_current_temperature_max()
   1631     # A temperature over 65'C doesn't give us much headroom to the critical
   1632     # temperatures that start at 85'C (and PerfControl as of today will fail at
   1633     # critical - 10'C).
   1634     if temperature < 65:
   1635         return True
   1636     logging.warning('Did not cool down (%dC), giving up.', temperature)
   1637     log_process_activity()
   1638     return False
   1639 
   1640 
   1641 # System paths for machine performance state.
   1642 _CPUINFO = '/proc/cpuinfo'
   1643 _DIRTY_WRITEBACK_CENTISECS = '/proc/sys/vm/dirty_writeback_centisecs'
   1644 _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
   1645 _MEMINFO = '/proc/meminfo'
   1646 _TEMP_SENSOR_RE = 'Reading temperature...([0-9]*)'
   1647 
   1648 
   1649 def _get_line_from_file(path, line):
   1650     """
   1651     line can be an integer or
   1652     line can be a string that matches the beginning of the line
   1653     """
   1654     with open(path) as f:
   1655         if isinstance(line, int):
   1656             l = f.readline()
   1657             for _ in range(0, line):
   1658                 l = f.readline()
   1659             return l
   1660         else:
   1661             for l in f:
   1662                 if l.startswith(line):
   1663                     return l
   1664     return None
   1665 
   1666 
   1667 def _get_match_from_file(path, line, prefix, postfix):
   1668     """
   1669     Matches line in path and returns string between first prefix and postfix.
   1670     """
   1671     match = _get_line_from_file(path, line)
   1672     # Strip everything from front of line including prefix.
   1673     if prefix:
   1674         match = re.split(prefix, match)[1]
   1675     # Strip everything from back of string including first occurence of postfix.
   1676     if postfix:
   1677         match = re.split(postfix, match)[0]
   1678     return match
   1679 
   1680 
   1681 def _get_float_from_file(path, line, prefix, postfix):
   1682     match = _get_match_from_file(path, line, prefix, postfix)
   1683     return float(match)
   1684 
   1685 
   1686 def _get_int_from_file(path, line, prefix, postfix):
   1687     match = _get_match_from_file(path, line, prefix, postfix)
   1688     return int(match)
   1689 
   1690 
   1691 def _get_hex_from_file(path, line, prefix, postfix):
   1692     match = _get_match_from_file(path, line, prefix, postfix)
   1693     return int(match, 16)
   1694 
   1695 
   1696 # The paths don't change. Avoid running find all the time.
   1697 _hwmon_paths = None
   1698 
   1699 def _get_hwmon_paths(file_pattern):
   1700     """
   1701     Returns a list of paths to the temperature sensors.
   1702     """
   1703     # Some systems like daisy_spring only have the virtual hwmon.
   1704     # And other systems like rambi only have coretemp.0. See crbug.com/360249.
   1705     #    /sys/class/hwmon/hwmon*/
   1706     #    /sys/devices/virtual/hwmon/hwmon*/
   1707     #    /sys/devices/platform/coretemp.0/
   1708     if not _hwmon_paths:
   1709         cmd = 'find /sys/ -name "' + file_pattern + '"'
   1710         _hwon_paths = utils.run(cmd, verbose=False).stdout.splitlines()
   1711     return _hwon_paths
   1712 
   1713 
   1714 def get_temperature_critical():
   1715     """
   1716     Returns temperature at which we will see some throttling in the system.
   1717     """
   1718     min_temperature = 1000.0
   1719     paths = _get_hwmon_paths('temp*_crit')
   1720     for path in paths:
   1721         temperature = _get_float_from_file(path, 0, None, None) * 0.001
   1722         # Today typical for Intel is 98'C to 105'C while ARM is 85'C. Clamp to
   1723         # the lowest known value.
   1724         if (min_temperature < 60.0) or min_temperature > 150.0:
   1725             logging.warning('Critical temperature of %.1fC was reset to 85.0C.',
   1726                             min_temperature)
   1727             min_temperature = 85.0
   1728 
   1729         min_temperature = min(temperature, min_temperature)
   1730     return min_temperature
   1731 
   1732 
   1733 def get_temperature_input_max():
   1734     """
   1735     Returns the maximum currently observed temperature.
   1736     """
   1737     max_temperature = -1000.0
   1738     paths = _get_hwmon_paths('temp*_input')
   1739     for path in paths:
   1740         temperature = _get_float_from_file(path, 0, None, None) * 0.001
   1741         max_temperature = max(temperature, max_temperature)
   1742     return max_temperature
   1743 
   1744 
   1745 def get_thermal_zone_temperatures():
   1746     """
   1747     Returns the maximum currently observered temperature in thermal_zones.
   1748     """
   1749     temperatures = []
   1750     for path in glob.glob('/sys/class/thermal/thermal_zone*/temp'):
   1751         try:
   1752             temperatures.append(
   1753                 _get_float_from_file(path, 0, None, None) * 0.001)
   1754         except IOError:
   1755             # Some devices (e.g. Veyron) may have reserved thermal zones that
   1756             # are not active. Trying to read the temperature value would cause a
   1757             # EINVAL IO error.
   1758             continue
   1759     return temperatures
   1760 
   1761 
   1762 def get_ec_temperatures():
   1763     """
   1764     Uses ectool to return a list of all sensor temperatures in Celsius.
   1765     """
   1766     temperatures = []
   1767     try:
   1768         full_cmd = 'ectool temps all'
   1769         lines = utils.run(full_cmd, verbose=False).stdout.splitlines()
   1770         for line in lines:
   1771             temperature = int(line.split(': ')[1]) - 273
   1772             temperatures.append(temperature)
   1773     except Exception:
   1774         logging.warning('Unable to read temperature sensors using ectool.')
   1775     for temperature in temperatures:
   1776         # Sanity check for real world values.
   1777         assert ((temperature > 10.0) and
   1778                 (temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
   1779                                          temperature)
   1780 
   1781     return temperatures
   1782 
   1783 
   1784 def get_current_temperature_max():
   1785     """
   1786     Returns the highest reported board temperature (all sensors) in Celsius.
   1787     """
   1788     temperature = max([get_temperature_input_max()] +
   1789                       get_thermal_zone_temperatures() +
   1790                       get_ec_temperatures())
   1791     # Sanity check for real world values.
   1792     assert ((temperature > 10.0) and
   1793             (temperature < 150.0)), ('Unreasonable temperature %.1fC.' %
   1794                                      temperature)
   1795     return temperature
   1796 
   1797 
   1798 def get_cpu_cache_size():
   1799     """
   1800     Returns the last level CPU cache size in kBytes.
   1801     """
   1802     cache_size = _get_int_from_file(_CPUINFO, 'cache size', ': ', ' KB')
   1803     # Sanity check.
   1804     assert cache_size >= 64, 'Unreasonably small cache.'
   1805     return cache_size
   1806 
   1807 
   1808 def get_cpu_model_frequency():
   1809     """
   1810     Returns the model frequency from the CPU model name on Intel only. This
   1811     might be redundant with get_cpu_max_frequency. Unit is Hz.
   1812     """
   1813     frequency = _get_float_from_file(_CPUINFO, 'model name', ' @ ', 'GHz')
   1814     return 1.e9 * frequency
   1815 
   1816 
   1817 def get_cpu_max_frequency():
   1818     """
   1819     Returns the largest of the max CPU core frequencies. The unit is Hz.
   1820     """
   1821     max_frequency = -1
   1822     paths = _get_cpufreq_paths('cpuinfo_max_freq')
   1823     for path in paths:
   1824         # Convert from kHz to Hz.
   1825         frequency = 1000 * _get_float_from_file(path, 0, None, None)
   1826         max_frequency = max(frequency, max_frequency)
   1827     # Sanity check.
   1828     assert max_frequency > 1e8, 'Unreasonably low CPU frequency.'
   1829     return max_frequency
   1830 
   1831 
   1832 def get_cpu_min_frequency():
   1833     """
   1834     Returns the smallest of the minimum CPU core frequencies.
   1835     """
   1836     min_frequency = 1e20
   1837     paths = _get_cpufreq_paths('cpuinfo_min_freq')
   1838     for path in paths:
   1839         frequency = _get_float_from_file(path, 0, None, None)
   1840         min_frequency = min(frequency, min_frequency)
   1841     # Sanity check.
   1842     assert min_frequency > 1e8, 'Unreasonably low CPU frequency.'
   1843     return min_frequency
   1844 
   1845 
   1846 def get_cpu_model():
   1847     """
   1848     Returns the CPU model.
   1849     Only works on Intel.
   1850     """
   1851     cpu_model = _get_int_from_file(_CPUINFO, 'model\t', ': ', None)
   1852     return cpu_model
   1853 
   1854 
   1855 def get_cpu_family():
   1856     """
   1857     Returns the CPU family.
   1858     Only works on Intel.
   1859     """
   1860     cpu_family = _get_int_from_file(_CPUINFO, 'cpu family\t', ': ', None)
   1861     return cpu_family
   1862 
   1863 
   1864 def get_board_property(key):
   1865     """
   1866     Get a specific property from /etc/lsb-release.
   1867 
   1868     @param key: board property to return value for
   1869 
   1870     @return the value or '' if not present
   1871     """
   1872     with open('/etc/lsb-release') as f:
   1873         pattern = '%s=(.*)' % key
   1874         pat = re.search(pattern, f.read())
   1875         if pat:
   1876             return pat.group(1)
   1877     return ''
   1878 
   1879 
   1880 def get_board():
   1881     """
   1882     Get the ChromeOS release board name from /etc/lsb-release.
   1883     """
   1884     return get_board_property('BOARD')
   1885 
   1886 
   1887 def get_board_type():
   1888     """
   1889     Get the ChromeOS board type from /etc/lsb-release.
   1890 
   1891     @return device type.
   1892     """
   1893     return get_board_property('DEVICETYPE')
   1894 
   1895 
   1896 def get_board_with_frequency_and_memory():
   1897     """
   1898     Returns a board name modified with CPU frequency and memory size to
   1899     differentiate between different board variants. For instance
   1900     link -> link_1.8GHz_4GB.
   1901     """
   1902     board_name = get_board()
   1903     if is_virtual_machine():
   1904         board = '%s_VM' % board_name
   1905     else:
   1906         # Rounded to nearest GB and GHz.
   1907         memory = int(round(get_mem_total() / 1024.0))
   1908         # Convert frequency to GHz with 1 digit accuracy after the
   1909         # decimal point.
   1910         frequency = int(round(get_cpu_max_frequency() * 1e-8)) * 0.1
   1911         board = '%s_%1.1fGHz_%dGB' % (board_name, frequency, memory)
   1912     return board
   1913 
   1914 
   1915 def get_mem_total():
   1916     """
   1917     Returns the total memory available in the system in MBytes.
   1918     """
   1919     mem_total = _get_float_from_file(_MEMINFO, 'MemTotal:', 'MemTotal:', ' kB')
   1920     # Sanity check, all Chromebooks have at least 1GB of memory.
   1921     assert mem_total > 256 * 1024, 'Unreasonable amount of memory.'
   1922     return mem_total / 1024
   1923 
   1924 
   1925 def get_mem_free():
   1926     """
   1927     Returns the currently free memory in the system in MBytes.
   1928     """
   1929     mem_free = _get_float_from_file(_MEMINFO, 'MemFree:', 'MemFree:', ' kB')
   1930     return mem_free / 1024
   1931 
   1932 
   1933 def get_kernel_max():
   1934     """
   1935     Returns content of kernel_max.
   1936     """
   1937     kernel_max = _get_int_from_file(_KERNEL_MAX, 0, None, None)
   1938     # Sanity check.
   1939     assert ((kernel_max > 0) and (kernel_max < 257)), 'Unreasonable kernel_max.'
   1940     return kernel_max
   1941 
   1942 
   1943 def set_high_performance_mode():
   1944     """
   1945     Sets the kernel governor mode to the highest setting.
   1946     Returns previous governor state.
   1947     """
   1948     original_governors = get_scaling_governor_states()
   1949     set_scaling_governors('performance')
   1950     return original_governors
   1951 
   1952 
   1953 def set_scaling_governors(value):
   1954     """
   1955     Sets all scaling governor to string value.
   1956     Sample values: 'performance', 'interactive', 'ondemand', 'powersave'.
   1957     """
   1958     paths = _get_cpufreq_paths('scaling_governor')
   1959     for path in paths:
   1960         cmd = 'echo %s > %s' % (value, path)
   1961         logging.info('Writing scaling governor mode \'%s\' -> %s', value, path)
   1962         # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures.
   1963         utils.system(cmd, ignore_status=True)
   1964 
   1965 
   1966 def _get_cpufreq_paths(filename):
   1967     """
   1968     Returns a list of paths to the governors.
   1969     """
   1970     cmd = 'ls /sys/devices/system/cpu/cpu*/cpufreq/' + filename
   1971     paths = utils.run(cmd, verbose=False).stdout.splitlines()
   1972     return paths
   1973 
   1974 
   1975 def get_scaling_governor_states():
   1976     """
   1977     Returns a list of (performance governor path, current state) tuples.
   1978     """
   1979     paths = _get_cpufreq_paths('scaling_governor')
   1980     path_value_list = []
   1981     for path in paths:
   1982         value = _get_line_from_file(path, 0)
   1983         path_value_list.append((path, value))
   1984     return path_value_list
   1985 
   1986 
   1987 def restore_scaling_governor_states(path_value_list):
   1988     """
   1989     Restores governor states. Inverse operation to get_scaling_governor_states.
   1990     """
   1991     for (path, value) in path_value_list:
   1992         cmd = 'echo %s > %s' % (value.rstrip('\n'), path)
   1993         # On Tegra CPUs can be dynamically enabled/disabled. Ignore failures.
   1994         utils.system(cmd, ignore_status=True)
   1995 
   1996 
   1997 def get_dirty_writeback_centisecs():
   1998     """
   1999     Reads /proc/sys/vm/dirty_writeback_centisecs.
   2000     """
   2001     time = _get_int_from_file(_DIRTY_WRITEBACK_CENTISECS, 0, None, None)
   2002     return time
   2003 
   2004 
   2005 def set_dirty_writeback_centisecs(time=60000):
   2006     """
   2007     In hundredths of a second, this is how often pdflush wakes up to write data
   2008     to disk. The default wakes up the two (or more) active threads every five
   2009     seconds. The ChromeOS default is 10 minutes.
   2010 
   2011     We use this to set as low as 1 second to flush error messages in system
   2012     logs earlier to disk.
   2013     """
   2014     # Flush buffers first to make this function synchronous.
   2015     utils.system('sync')
   2016     if time >= 0:
   2017         cmd = 'echo %d > %s' % (time, _DIRTY_WRITEBACK_CENTISECS)
   2018         utils.system(cmd)
   2019 
   2020 
   2021 def wflinfo_cmd():
   2022     """
   2023     Returns a wflinfo command appropriate to the current graphics platform/api.
   2024     """
   2025     return 'wflinfo -p %s -a %s' % (graphics_platform(), graphics_api())
   2026 
   2027 
   2028 def has_mali():
   2029     """ @return: True if system has a Mali GPU enabled."""
   2030     return os.path.exists('/dev/mali0')
   2031 
   2032 def get_gpu_family():
   2033     """Returns the GPU family name."""
   2034     global pciid_to_amd_architecture
   2035     global pciid_to_intel_architecture
   2036 
   2037     socfamily = get_cpu_soc_family()
   2038     if socfamily == 'exynos5' or socfamily == 'rockchip' or has_mali():
   2039         cmd = wflinfo_cmd()
   2040         wflinfo = utils.system_output(cmd,
   2041                                       retain_output=True,
   2042                                       ignore_status=False)
   2043         version = re.findall(r'OpenGL renderer string: '
   2044                              r'Mali-T([0-9]+)', wflinfo)
   2045         if version:
   2046             return 'mali-t%s' % version[0]
   2047         return 'mali-unrecognized'
   2048     if socfamily == 'tegra':
   2049         return 'tegra'
   2050     if os.path.exists('/sys/kernel/debug/pvr'):
   2051         return 'rogue'
   2052 
   2053     pci_vga_device = utils.run("lspci | grep VGA").stdout.rstrip('\n')
   2054     bus_device_function = pci_vga_device.partition(' ')[0]
   2055     pci_path = '/sys/bus/pci/devices/0000:' + bus_device_function + '/device'
   2056 
   2057     if not os.path.exists(pci_path):
   2058         raise error.TestError('PCI device 0000:' + bus_device_function + ' not found')
   2059 
   2060     device_id = utils.read_one_line(pci_path).lower()
   2061 
   2062     if "Advanced Micro Devices" in pci_vga_device:
   2063         if not pciid_to_amd_architecture:
   2064             with open(_AMD_PCI_IDS_FILE_PATH, 'r') as in_f:
   2065                 pciid_to_amd_architecture = json.load(in_f)
   2066 
   2067         return pciid_to_amd_architecture[device_id]
   2068 
   2069     if "Intel Corporation" in pci_vga_device:
   2070         # Only load Intel PCI ID file once and only if necessary.
   2071         if not pciid_to_intel_architecture:
   2072             with open(_INTEL_PCI_IDS_FILE_PATH, 'r') as in_f:
   2073                 pciid_to_intel_architecture = json.load(in_f)
   2074 
   2075         return pciid_to_intel_architecture[device_id]
   2076 
   2077 # TODO(ihf): Consider using /etc/lsb-release DEVICETYPE != CHROMEBOOK/CHROMEBASE
   2078 # for sanity check, but usage seems a bit inconsistent. See
   2079 # src/third_party/chromiumos-overlay/eclass/appid.eclass
   2080 _BOARDS_WITHOUT_MONITOR = [
   2081     'anglar', 'mccloud', 'monroe', 'ninja', 'rikku', 'guado', 'jecht', 'tidus',
   2082     'beltino', 'panther', 'stumpy', 'panther', 'tricky', 'zako', 'veyron_rialto'
   2083 ]
   2084 
   2085 
   2086 def has_no_monitor():
   2087     """Returns whether a machine doesn't have a built-in monitor."""
   2088     board_name = get_board()
   2089     if board_name in _BOARDS_WITHOUT_MONITOR:
   2090         return True
   2091 
   2092     return False
   2093 
   2094 
   2095 def get_fixed_dst_drive():
   2096     """
   2097     Return device name for internal disk.
   2098     Example: return /dev/sda for falco booted from usb
   2099     """
   2100     cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
   2101                     '. /usr/share/misc/chromeos-common.sh;',
   2102                     'load_base_vars;',
   2103                     'get_fixed_dst_drive'])
   2104     return utils.system_output(cmd)
   2105 
   2106 
   2107 def get_root_device():
   2108     """
   2109     Return root device.
   2110     Will return correct disk device even system boot from /dev/dm-0
   2111     Example: return /dev/sdb for falco booted from usb
   2112     """
   2113     return utils.system_output('rootdev -s -d')
   2114 
   2115 
   2116 def get_root_partition():
   2117     """
   2118     Return current root partition
   2119     Example: return /dev/sdb3 for falco booted from usb
   2120     """
   2121     return utils.system_output('rootdev -s')
   2122 
   2123 
   2124 def get_free_root_partition(root_part=None):
   2125     """
   2126     Return currently unused root partion
   2127     Example: return /dev/sdb5 for falco booted from usb
   2128 
   2129     @param root_part: cuurent root partition
   2130     """
   2131     spare_root_map = {'3': '5', '5': '3'}
   2132     if not root_part:
   2133         root_part = get_root_partition()
   2134     return root_part[:-1] + spare_root_map[root_part[-1]]
   2135 
   2136 
   2137 def get_kernel_partition(root_part=None):
   2138     """
   2139     Return current kernel partition
   2140     Example: return /dev/sda2 for falco booted from usb
   2141 
   2142     @param root_part: current root partition
   2143     """
   2144     if not root_part:
   2145          root_part = get_root_partition()
   2146     current_kernel_map = {'3': '2', '5': '4'}
   2147     return root_part[:-1] + current_kernel_map[root_part[-1]]
   2148 
   2149 
   2150 def get_free_kernel_partition(root_part=None):
   2151     """
   2152     return currently unused kernel partition
   2153     Example: return /dev/sda4 for falco booted from usb
   2154 
   2155     @param root_part: current root partition
   2156     """
   2157     kernel_part = get_kernel_partition(root_part)
   2158     spare_kernel_map = {'2': '4', '4': '2'}
   2159     return kernel_part[:-1] + spare_kernel_map[kernel_part[-1]]
   2160 
   2161 
   2162 def is_booted_from_internal_disk():
   2163     """Return True if boot from internal disk. False, otherwise."""
   2164     return get_root_device() == get_fixed_dst_drive()
   2165 
   2166 
   2167 def get_ui_use_flags():
   2168     """Parses the USE flags as listed in /etc/ui_use_flags.txt.
   2169 
   2170     @return: A list of flag strings found in the ui use flags file.
   2171     """
   2172     flags = []
   2173     for flag in utils.read_file(_UI_USE_FLAGS_FILE_PATH).splitlines():
   2174         # Removes everything after the '#'.
   2175         flag_before_comment = flag.split('#')[0].strip()
   2176         if len(flag_before_comment) != 0:
   2177             flags.append(flag_before_comment)
   2178 
   2179     return flags
   2180 
   2181 
   2182 def graphics_platform():
   2183     """
   2184     Return a string identifying the graphics platform,
   2185     e.g. 'glx' or 'x11_egl' or 'gbm'
   2186     """
   2187     return 'null'
   2188 
   2189 
   2190 def graphics_api():
   2191     """Return a string identifying the graphics api, e.g. gl or gles2."""
   2192     use_flags = get_ui_use_flags()
   2193     if 'opengles' in use_flags:
   2194         return 'gles2'
   2195     return 'gl'
   2196 
   2197 
   2198 def is_vm():
   2199     """Check if the process is running in a virtual machine.
   2200 
   2201     @return: True if the process is running in a virtual machine, otherwise
   2202              return False.
   2203     """
   2204     try:
   2205         virt = utils.run('sudo -n virt-what').stdout.strip()
   2206         logging.debug('virt-what output: %s', virt)
   2207         return bool(virt)
   2208     except error.CmdError:
   2209         logging.warn('Package virt-what is not installed, default to assume '
   2210                      'it is not a virtual machine.')
   2211         return False
   2212 
   2213 
   2214 def is_package_installed(package):
   2215     """Check if a package is installed already.
   2216 
   2217     @return: True if the package is already installed, otherwise return False.
   2218     """
   2219     try:
   2220         utils.run(_CHECK_PACKAGE_INSTALLED_COMMAND % package)
   2221         return True
   2222     except error.CmdError:
   2223         logging.warn('Package %s is not installed.', package)
   2224         return False
   2225 
   2226 
   2227 def is_python_package_installed(package):
   2228     """Check if a Python package is installed already.
   2229 
   2230     @return: True if the package is already installed, otherwise return False.
   2231     """
   2232     try:
   2233         __import__(package)
   2234         return True
   2235     except ImportError:
   2236         logging.warn('Python package %s is not installed.', package)
   2237         return False
   2238 
   2239 
   2240 def run_sql_cmd(server, user, password, command, database=''):
   2241     """Run the given sql command against the specified database.
   2242 
   2243     @param server: Hostname or IP address of the MySQL server.
   2244     @param user: User name to log in the MySQL server.
   2245     @param password: Password to log in the MySQL server.
   2246     @param command: SQL command to run.
   2247     @param database: Name of the database to run the command. Default to empty
   2248                      for command that does not require specifying database.
   2249 
   2250     @return: The stdout of the command line.
   2251     """
   2252     cmd = ('mysql -u%s -p%s --host %s %s -e "%s"' %
   2253            (user, password, server, database, command))
   2254     # Set verbose to False so the command line won't be logged, as it includes
   2255     # database credential.
   2256