tauto - remove non-harness client libs
BUG=none
TEST=dummy_Pass
Change-Id: Ic7adcb448570012ada1c2ba6caaa9b7058e6a65e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tauto/+/3122531
Reviewed-by: Ruben Zakarian <rzakarian@chromium.org>
Tested-by: Derek Beckett <dbeckett@chromium.org>
diff --git a/client/bin/display_chart.py b/client/bin/display_chart.py
deleted file mode 100755
index fc7818f..0000000
--- a/client/bin/display_chart.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright 2018 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.
-
-'''Login with test account and display chart file using telemetry.'''
-
-import argparse
-import contextlib
-import logging
-import os
-import signal
-import sys
-import time
-
-# Set chart process preferred logging format before overridden by importing
-# common package.
-logging.basicConfig(
- level=logging.DEBUG,
- format='%(asctime)s - %(levelname)s - %(message)s')
-
-# This sets up import paths for autotest.
-import common
-from autotest_lib.client.bin import utils
-from autotest_lib.client.cros import constants
-from autotest_lib.client.cros.multimedia import display_facade_native
-from autotest_lib.client.cros.multimedia import facade_resource
-from autotest_lib.client.common_lib.cros import chrome
-
-
-@contextlib.contextmanager
-def set_display_brightness(display_level):
- SET_BRIGHTNESS_CMD = 'backlight_tool --set_brightness_percent=%s'
-
- original_display_level = utils.system_output(
- 'backlight_tool --get_brightness_percent')
- logging.info('Save original display brightness %r '
- 'and fix display brightness to %r', original_display_level,
- display_level)
- utils.system(SET_BRIGHTNESS_CMD % display_level)
- utils.system('stop powerd', ignore_status=True)
- yield
- logging.info('Restore display brightness %r', original_display_level)
- utils.system('start powerd', ignore_status=True)
- utils.system(SET_BRIGHTNESS_CMD % original_display_level)
-
-
-def display(filepath):
- """Display chart with filepath on device by using telemetry."""
- DISPLAY_LEVEL = 96.0
- DISPLAY_ORIENTATION = 90
-
- assert os.path.isfile(filepath), 'filepath %r not found.' % filepath
- filepath = os.path.abspath(filepath)
-
- logging.info('Setup SIGINT listener for stop displaying.')
- displaying = [True]
-
- def handler(signum, frame):
- """Wait signal to clear running flag."""
- if signum == signal.SIGINT:
- displaying.pop()
-
- signal.signal(signal.SIGINT, handler)
-
- with chrome.Chrome(
- extension_paths=[constants.DISPLAY_TEST_EXTENSION],
- autotest_ext=True,
- init_network_controller=True) as cr, set_display_brightness(
- DISPLAY_LEVEL):
- logging.info('Set fullscreen.')
- facade = facade_resource.FacadeResource(cr)
- display_facade = display_facade_native.DisplayFacadeNative(facade)
- display_facade.set_fullscreen(True)
-
- logging.info('Fix screen rotation %d.', DISPLAY_ORIENTATION)
- internal_display_id = display_facade.get_internal_display_id()
- display_facade.set_display_rotation(internal_display_id,
- rotation=DISPLAY_ORIENTATION)
-
- logging.info('Display chart file of path %r.', filepath)
- cr.browser.platform.SetHTTPServerDirectories(os.path.dirname(filepath))
- tab = cr.browser.tabs[0]
- tab.Navigate(cr.browser.platform.http_server.UrlOf(filepath))
- tab.WaitForDocumentReadyStateToBeComplete()
-
- logging.info('Chart is ready.')
-
- # Flush the 'is ready' message for server test to sync with ready state.
- sys.stdout.flush()
- sys.stderr.flush()
-
- while displaying:
- time.sleep(1)
-
-
-if __name__ == '__main__':
- argparser = argparse.ArgumentParser(
- description='Display chart file on chrome by using telemetry.'
- ' Send SIGINT or keyboard interrupt to stop displaying.')
- argparser.add_argument('filepath', help='Path of displayed chart file.')
-
- args = argparser.parse_args()
- display(args.filepath)
diff --git a/client/bin/fio_util.py b/client/bin/fio_util.py
deleted file mode 100644
index 4014151..0000000
--- a/client/bin/fio_util.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2013 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.
-
-"""Library to run fio scripts.
-
-fio_runner launch fio and collect results.
-The output dictionary can be add to autotest keyval:
- results = {}
- results.update(fio_util.fio_runner(job_file, env_vars))
- self.write_perf_keyval(results)
-
-Decoding class can be invoked independently.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import json
-import logging
-import re
-
-import six
-from six.moves import range
-
-import common
-from autotest_lib.client.bin import utils
-
-
-class fio_graph_generator():
- """
- Generate graph from fio log that created when specified these options.
- - write_bw_log
- - write_iops_log
- - write_lat_log
-
- The following limitations apply
- - Log file name must be in format jobname_testpass
- - Graph is generate using Google graph api -> Internet require to view.
- """
-
- html_head = """
-<html>
- <head>
- <script type="text/javascript" src="https://www.google.com/jsapi"></script>
- <script type="text/javascript">
- google.load("visualization", "1", {packages:["corechart"]});
- google.setOnLoadCallback(drawChart);
- function drawChart() {
-"""
-
- html_tail = """
- var chart_div = document.getElementById('chart_div');
- var chart = new google.visualization.ScatterChart(chart_div);
- chart.draw(data, options);
- }
- </script>
- </head>
- <body>
- <div id="chart_div" style="width: 100%; height: 100%;"></div>
- </body>
-</html>
-"""
-
- h_title = { True: 'Percentile', False: 'Time (s)' }
- v_title = { 'bw' : 'Bandwidth (KB/s)',
- 'iops': 'IOPs',
- 'lat' : 'Total latency (us)',
- 'clat': 'Completion latency (us)',
- 'slat': 'Submission latency (us)' }
- graph_title = { 'bw' : 'bandwidth',
- 'iops': 'IOPs',
- 'lat' : 'total latency',
- 'clat': 'completion latency',
- 'slat': 'submission latency' }
-
- test_name = ''
- test_type = ''
- pass_list = ''
-
- @classmethod
- def _parse_log_file(cls, file_name, pass_index, pass_count, percentile):
- """
- Generate row for google.visualization.DataTable from one log file.
- Log file is the one that generated using write_{bw,lat,iops}_log
- option in the FIO job file.
-
- The fio log file format is timestamp, value, direction, blocksize
- The output format for each row is { c: list of { v: value} }
-
- @param file_name: log file name to read data from
- @param pass_index: index of current run pass
- @param pass_count: number of all test run passes
- @param percentile: flag to use percentile as key instead of timestamp
-
- @return: list of data rows in google.visualization.DataTable format
- """
- # Read data from log
- with open(file_name, 'r') as f:
- data = []
-
- for line in f.readlines():
- if not line:
- break
- t, v, _, _ = [int(x) for x in line.split(', ')]
- data.append([t / 1000.0, v])
-
- # Sort & calculate percentile
- if percentile:
- data.sort(key=lambda x: x[1])
- l = len(data)
- for i in range(l):
- data[i][0] = 100 * (i + 0.5) / l
-
- # Generate the data row
- all_row = []
- row = [None] * (pass_count + 1)
- for d in data:
- row[0] = {'v' : '%.3f' % d[0]}
- row[pass_index + 1] = {'v': d[1]}
- all_row.append({'c': row[:]})
-
- return all_row
-
- @classmethod
- def _gen_data_col(cls, pass_list, percentile):
- """
- Generate col for google.visualization.DataTable
-
- The output format is list of dict of label and type. In this case,
- type is always number.
-
- @param pass_list: list of test run passes
- @param percentile: flag to use percentile as key instead of timestamp
-
- @return: list of column in google.visualization.DataTable format
- """
- if percentile:
- col_name_list = ['percentile'] + [p[0] for p in pass_list]
- else:
- col_name_list = ['time'] + [p[0] for p in pass_list]
-
- return [{'label': name, 'type': 'number'} for name in col_name_list]
-
- @classmethod
- def _gen_data_row(cls, test_type, pass_list, percentile):
- """
- Generate row for google.visualization.DataTable by generate all log
- file name and call _parse_log_file for each file
-
- @param test_type: type of value collected for current test. i.e. IOPs
- @param pass_list: list of run passes for current test
- @param percentile: flag to use percentile as key instead of timestamp
-
- @return: list of data rows in google.visualization.DataTable format
- """
- all_row = []
- pass_count = len(pass_list)
- for pass_index, log_file_name in enumerate([p[1] for p in pass_list]):
- all_row.extend(cls._parse_log_file(log_file_name, pass_index,
- pass_count, percentile))
- return all_row
-
- @classmethod
- def _write_data(cls, f, test_type, pass_list, percentile):
- """
- Write google.visualization.DataTable object to output file.
- https://developers.google.com/chart/interactive/docs/reference
-
- @param f: html file to update
- @param test_type: type of value collected for current test. i.e. IOPs
- @param pass_list: list of run passes for current test
- @param percentile: flag to use percentile as key instead of timestamp
- """
- col = cls._gen_data_col(pass_list, percentile)
- row = cls._gen_data_row(test_type, pass_list, percentile)
- data_dict = {'cols' : col, 'rows' : row}
-
- f.write('var data = new google.visualization.DataTable(')
- json.dump(data_dict, f)
- f.write(');\n')
-
- @classmethod
- def _write_option(cls, f, test_name, test_type, percentile):
- """
- Write option to render scatter graph to output file.
- https://google-developers.appspot.com/chart/interactive/docs/gallery/scatterchart
-
- @param test_name: name of current workload. i.e. randwrite
- @param test_type: type of value collected for current test. i.e. IOPs
- @param percentile: flag to use percentile as key instead of timestamp
- """
- option = {'pointSize': 1}
- if percentile:
- option['title'] = ('Percentile graph of %s for %s workload' %
- (cls.graph_title[test_type], test_name))
- else:
- option['title'] = ('Graph of %s for %s workload over time' %
- (cls.graph_title[test_type], test_name))
-
- option['hAxis'] = {'title': cls.h_title[percentile]}
- option['vAxis'] = {'title': cls.v_title[test_type]}
-
- f.write('var options = ')
- json.dump(option, f)
- f.write(';\n')
-
- @classmethod
- def _write_graph(cls, test_name, test_type, pass_list, percentile=False):
- """
- Generate graph for test name / test type
-
- @param test_name: name of current workload. i.e. randwrite
- @param test_type: type of value collected for current test. i.e. IOPs
- @param pass_list: list of run passes for current test
- @param percentile: flag to use percentile as key instead of timestamp
- """
- logging.info('fio_graph_generator._write_graph %s %s %s',
- test_name, test_type, str(pass_list))
-
-
- if percentile:
- out_file_name = '%s_%s_percentile.html' % (test_name, test_type)
- else:
- out_file_name = '%s_%s.html' % (test_name, test_type)
-
- with open(out_file_name, 'w') as f:
- f.write(cls.html_head)
- cls._write_data(f, test_type, pass_list, percentile)
- cls._write_option(f, test_name, test_type, percentile)
- f.write(cls.html_tail)
-
- def __init__(self, test_name, test_type, pass_list):
- """
- @param test_name: name of current workload. i.e. randwrite
- @param test_type: type of value collected for current test. i.e. IOPs
- @param pass_list: list of run passes for current test
- """
- self.test_name = test_name
- self.test_type = test_type
- self.pass_list = pass_list
-
- def run(self):
- """
- Run the graph generator.
- """
- self._write_graph(self.test_name, self.test_type, self.pass_list, False)
- self._write_graph(self.test_name, self.test_type, self.pass_list, True)
-
-
-def fio_parse_dict(d, prefix):
- """
- Parse fio json dict
-
- Recursively flaten json dict to generate autotest perf dict
-
- @param d: input dict
- @param prefix: name prefix of the key
- """
-
- # No need to parse something that didn't run such as read stat in write job.
- if 'io_bytes' in d and d['io_bytes'] == 0:
- return {}
-
- results = {}
- for k, v in d.items():
-
- # remove >, >=, <, <=
- for c in '>=<':
- k = k.replace(c, '')
-
- key = prefix + '_' + k
-
- if type(v) is dict:
- results.update(fio_parse_dict(v, key))
- else:
- results[key] = v
- return results
-
-
-def fio_parser(lines, prefix=None):
- """
- Parse the json fio output
-
- This collects all metrics given by fio and labels them according to unit
- of measurement and test case name.
-
- @param lines: text output of json fio output.
- @param prefix: prefix for result keys.
- """
- results = {}
- fio_dict = json.loads(lines)
-
- if prefix:
- prefix = prefix + '_'
- else:
- prefix = ''
-
- results[prefix + 'fio_version'] = fio_dict['fio version']
-
- if 'disk_util' in fio_dict:
- results.update(fio_parse_dict(fio_dict['disk_util'][0],
- prefix + 'disk'))
-
- for job in fio_dict['jobs']:
- job_prefix = '_' + prefix + job['jobname']
- job.pop('jobname')
-
-
- for k, v in six.iteritems(job):
- # Igonre "job options", its alphanumerc keys confuses tko.
- # Besides, these keys are redundant.
- if k == 'job options':
- continue
- results.update(fio_parse_dict({k:v}, job_prefix))
-
- return results
-
-def fio_generate_graph():
- """
- Scan for fio log file in output directory and send data to generate each
- graph to fio_graph_generator class.
- """
- log_types = ['bw', 'iops', 'lat', 'clat', 'slat']
-
- # move fio log to result dir
- for log_type in log_types:
- logging.info('log_type %s', log_type)
- logs = utils.system_output('ls *_%s.*log' % log_type, ignore_status=True)
- if not logs:
- continue
-
- pattern = r"""(?P<jobname>.*)_ # jobname
- ((?P<runpass>p\d+)_|) # pass
- (?P<type>bw|iops|lat|clat|slat) # type
- (.(?P<thread>\d+)|) # thread id for newer fio.
- .log
- """
- matcher = re.compile(pattern, re.X)
-
- pass_list = []
- current_job = ''
-
- for log in logs.split():
- match = matcher.match(log)
- if not match:
- logging.warn('Unknown log file %s', log)
- continue
-
- jobname = match.group('jobname')
- runpass = match.group('runpass') or '1'
- if match.group('thread'):
- runpass += '_' + match.group('thread')
-
- # All files for particular job name are group together for create
- # graph that can compare performance between result from each pass.
- if jobname != current_job:
- if pass_list:
- fio_graph_generator(current_job, log_type, pass_list).run()
- current_job = jobname
- pass_list = []
- pass_list.append((runpass, log))
-
- if pass_list:
- fio_graph_generator(current_job, log_type, pass_list).run()
-
-
- cmd = 'mv *_%s.*log results' % log_type
- utils.run(cmd, ignore_status=True)
- utils.run('mv *.html results', ignore_status=True)
-
-
-def fio_runner(test, job, env_vars,
- name_prefix=None,
- graph_prefix=None):
- """
- Runs fio.
-
- Build a result keyval and performence json.
- The JSON would look like:
- {"description": "<name_prefix>_<modle>_<size>G",
- "graph": "<graph_prefix>_1m_write_wr_lat_99.00_percent_usec",
- "higher_is_better": false, "units": "us", "value": "xxxx"}
- {...
-
-
- @param test: test to upload perf value
- @param job: fio config file to use
- @param env_vars: environment variable fio will substituete in the fio
- config file.
- @param name_prefix: prefix of the descriptions to use in chrome perfi
- dashboard.
- @param graph_prefix: prefix of the graph name in chrome perf dashboard
- and result keyvals.
- @return fio results.
-
- """
-
- # running fio with ionice -c 3 so it doesn't lock out other
- # processes from the disk while it is running.
- # If you want to run the fio test for performance purposes,
- # take out the ionice and disable hung process detection:
- # "echo 0 > /proc/sys/kernel/hung_task_timeout_secs"
- # -c 3 = Idle
- # Tried lowest priority for "best effort" but still failed
- ionice = 'ionice -c 3'
- options = ['--output-format=json']
- fio_cmd_line = ' '.join([env_vars, ionice, 'fio',
- ' '.join(options),
- '"' + job + '"'])
- fio = utils.run(fio_cmd_line)
-
- logging.debug(fio.stdout)
-
- fio_generate_graph()
-
- filename = re.match('.*FILENAME=(?P<f>[^ ]*)', env_vars).group('f')
- diskname = utils.get_disk_from_filename(filename)
-
- if diskname:
- model = utils.get_disk_model(diskname)
- size = utils.get_disk_size_gb(diskname)
- perfdb_name = '%s_%dG' % (model, size)
- else:
- perfdb_name = filename.replace('/', '_')
-
- if name_prefix:
- perfdb_name = name_prefix + '_' + perfdb_name
-
- result = fio_parser(fio.stdout, prefix=name_prefix)
- if not graph_prefix:
- graph_prefix = ''
-
- for k, v in six.iteritems(result):
- # Remove the prefix for value, and replace it the graph prefix.
- if name_prefix:
- k = k.replace('_' + name_prefix, graph_prefix)
-
- # Make graph name to be same as the old code.
- if k.endswith('bw'):
- test.output_perf_value(description=perfdb_name, graph=k, value=v,
- units='KB_per_sec', higher_is_better=True)
- elif 'clat_percentile_' in k:
- test.output_perf_value(description=perfdb_name, graph=k, value=v,
- units='us', higher_is_better=False)
- elif 'clat_ns_percentile_' in k:
- test.output_perf_value(description=perfdb_name, graph=k, value=v,
- units='ns', higher_is_better=False)
- return result
diff --git a/client/bin/fps_meter.py b/client/bin/fps_meter.py
deleted file mode 100755
index 2ee5fc0..0000000
--- a/client/bin/fps_meter.py
+++ /dev/null
@@ -1,338 +0,0 @@
-#!/usr/bin/python3
-# Copyright 2018 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.
-
-"""Checks kernel tracing events to get the FPS of a CrOS device.
-
-This script requires root privilege to work properly. It may interfere
-Chrome tracing because both use ftrace.
-
-Limitation:
-It doesn't support multi-screen.
-It assumes 60 HZ screen refresh rate.
-
-This script can be used both as a stand alone script or a library.
-
-Sample output (when used as a stand alone script):
- # ./fps_meter.py
- trace method: workq
- [111111111111111111111111111111111111111111111111111111111111] FPS: 60
- [111111111111111111111111111111111111111111111111111111111111] FPS: 60
- [11111111111111111111111111111111111111111111111 111111111111] FPS: 59
- [111111111111111111111111111111111111111111111111111111111111] FPS: 60
- [11111111111111 11111111111111111111 11111111 111111111111111] FPS: 57
- [111111111111111111111111111111111 11111111111111111111111] FPS: 56
- [111 111111111111111111111111111111111111111111111111111111] FPS: 57
- ^
- 1 : Frame update count detected in this 1/60 sec interval.
-
-Sample Usage (when used as a library).
- def callback(fps):
- ...
-
- with FPSMeter(callback) as fps_meter:
- ...
-
-When used as a library, it launches two threads to monitor system FPS rate
-periodically. Each time when a FPS rate is sampled, callback() is called with
-the FPS number as its parameter.
-"""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import argparse
-import atexit
-import collections
-import common
-import functools
-import logging
-import os
-import re
-import sys
-import threading
-import time
-
-from six.moves import range
-
-from autotest_lib.client.bin import utils as bin_utils
-from autotest_lib.client.common_lib import utils as common_lib_utils
-
-TRACE_ROOT = '/sys/kernel/debug/tracing/'
-VBLANK_SWITCH = os.path.join(TRACE_ROOT, 'events/drm/drm_vblank_event/enable')
-FLIP_SWITCH = os.path.join(TRACE_ROOT, 'events/i915/i915_flip_complete/enable')
-WORKQ_SWITCH = os.path.join(
- TRACE_ROOT, 'events/workqueue/workqueue_execute_start/enable')
-WORKQ_FILTER = os.path.join(
- TRACE_ROOT, 'events/workqueue/workqueue_execute_start/filter')
-TRACE_SWITCH = os.path.join(TRACE_ROOT, 'tracing_on')
-TRACE_CLOCK = os.path.join(TRACE_ROOT, 'trace_clock')
-TRACE_LOG = os.path.join(TRACE_ROOT, 'trace')
-TRACE_PIPE = os.path.join(TRACE_ROOT, 'trace_pipe')
-TRACE_MARKER = os.path.join(TRACE_ROOT, 'trace_marker')
-REFRESH_RATE = 60
-NOTIFY_STRING = 'notify_collection'
-STOP_STRING = 'stop_tracing'
-
-
-def is_intel_gpu():
- """Determines whether it is intel GPU."""
- return os.path.isdir('/sys/bus/pci/drivers/i915')
-
-
-def get_kernel_version():
- """ Retruns the kernel version in form of xx.xx. """
- m = re.match(r'(\d+\.\d+)\.\d+', bin_utils.get_kernel_version())
- if m:
- return m.group(1)
- return 'unknown'
-
-
-def get_trace_method():
- """Gets the FPS checking method.
-
- Checks i915_flip_complete for Intel GPU on Kernel 3.18.
- Checks intel_atomic_commit_work for Intel GPU on Kernel 4.4.
- Checks drm_vblank_event otherwise.
- """
- if is_intel_gpu():
- kernel_version = get_kernel_version()
- if kernel_version == '4.4':
- return 'workq'
- elif kernel_version == '3.18':
- return 'flip'
- # Fallback.
- return 'vblank'
-
-
-def set_simple_switch(value, filename):
- """ Sets simple switch '1' to the file. """
- orig = common_lib_utils.read_file(filename).strip()
- atexit.register(common_lib_utils.open_write_close, filename, orig)
- common_lib_utils.open_write_close(filename, value)
-
-
-def set_trace_clock():
- """ Sets trace clock to mono time as chrome tracing in CrOS. """
- PREFERRED_TRACE_CLOCK = 'mono'
- clock = common_lib_utils.read_file(TRACE_CLOCK)
- m = re.match(r'.*\[(\w+)\]', clock)
- if m:
- orig_clock = m.group(1)
- atexit.register(common_lib_utils.open_write_close,
- TRACE_CLOCK, orig_clock)
- common_lib_utils.open_write_close(TRACE_CLOCK, PREFERRED_TRACE_CLOCK)
-
-
-def get_kernel_symbol_addr(symbol):
- """ Gets the kernel symple address. Example line in kallsyms:
- ffffffffbc46cb03 T sys_exit
- """
- with open('/proc/kallsyms') as kallsyms:
- for line in kallsyms:
- items = line.split()
- if items[2] == symbol:
- addr = items[0]
- return addr
- return None
-
-
-def set_workq_filter(function_name):
- """ Sets the workq filter. """
- addr = get_kernel_symbol_addr(function_name)
- if addr:
- filter = 'function == 0x%s' % addr
- common_lib_utils.open_write_close(WORKQ_FILTER, filter)
- # Sets to 0 to remove the filter.
- atexit.register(common_lib_utils.open_write_close, WORKQ_FILTER, '0')
-
-
-def enable_tracing(trace_method):
- """Enables tracing."""
- if trace_method == 'workq':
- set_simple_switch('1', WORKQ_SWITCH)
- # There are many workqueue_execute_start events,
- # filter to reduce CPU usage.
- set_workq_filter('intel_atomic_commit_work')
- elif trace_method == 'flip':
- set_simple_switch('1', FLIP_SWITCH)
- else:
- set_simple_switch('1', VBLANK_SWITCH)
-
- set_simple_switch('1', TRACE_SWITCH)
- set_trace_clock()
-
-
-def get_fps_info(trace_buffer, end_time):
- """ Checks all vblanks in the range [end_time - 1.0, end_time]. """
- frame_info = []
- step = 1.0 / REFRESH_RATE
- step_time = end_time - 1.0 + step
- frame_times = []
- for _ in range(REFRESH_RATE):
- # Checks if there are vblanks in a refresh interval.
- step_count = 0
- while trace_buffer and trace_buffer[0] < step_time:
- frame_times.append(trace_buffer.popleft())
- step_count += 1
-
- # Each character represent an 1 / REFRESH_RATE interval.
- if step_count:
- if step_count >= 10:
- frame_info.append('*')
- else:
- frame_info.append(str(step_count))
- else:
- frame_info.append(' ')
- step_time += step
-
- return frame_info, frame_times
-
-
-def start_thread(function, args=()):
- """ Starts a thread with given argument. """
- new_thread = threading.Thread(target=function, args=args)
- new_thread.start()
-
-
-class FPSMeter():
- """ Initializes a FPSMeter to measure system FPS periodically. """
- def __init__(self, callback):
- self.is_stopping = threading.Event()
- self.callback = callback
-
-
- def __enter__(self):
- self.start()
- return self
-
-
- def __exit__(self, type, value, traceback):
- self.stop()
-
-
- def notify_collection(self, period_sec=1.0):
- """ Writes a notification mark periodically. """
- logging.info('Notification thread is started')
- next_notify_time = time.time() + period_sec
- while True:
- # Calling time.sleep(1) may suspend for more than 1 second.
- # Sleeps until a specific time to avoid error accumulation.
- sleep_time = next_notify_time - time.time()
- next_notify_time += period_sec
- # Skips if current time is larger than next_notify_time.
- if sleep_time > 0:
- if self.is_stopping.wait(sleep_time):
- logging.info('Leaving notification thread')
- # So the main loop doesn't stuck in the readline().
- common_lib_utils.open_write_close(TRACE_MARKER, STOP_STRING)
- break
- common_lib_utils.open_write_close(TRACE_MARKER, NOTIFY_STRING)
-
-
- def main_loop(self, trace_method):
- """ Main loop to parse the trace.
-
- There are 2 threads involved:
- Main thread:
- Using blocking read to get data from trace_pipe.
- Notify thread: The main thread may wait indifinitely if there
- is no new trace. Writes to the pipe once per second to avoid
- the indefinite waiting.
- """
- logging.info('Fps meter main thread is started.')
-
- # Sample trace:
- # <idle>-0 [000] dNh3 631.905961: drm_vblank_event: crtc=0, seq=65496
- # <idle>-0 [000] d.h3 631.922681: drm_vblank_event: crtc=0, seq=65497
- # fps_meter [003] ..1 632.393953: tracing_mark_write: notify_collection
- # ..
- re_notify = re.compile(
- r'.* (\d+\.\d+): tracing_mark_write: ' + NOTIFY_STRING)
- if trace_method == 'workq':
- re_trace = re.compile(
- r'.* (\d+\.\d+): workqueue_execute_start: '
- r'work struct ([\da-f]+): '
- r'function intel_atomic_commit_work')
- elif trace_method == 'flip':
- re_trace = re.compile(
- r'.* (\d+\.\d+): i915_flip_complete: '
- r'plane=(\d+), obj=([\da-f]+)')
- else:
- re_trace = re.compile(
- r'.* (\d+\.\d+): drm_vblank_event: crtc=(\d+), seq=(\d+)')
-
- trace_buffer = collections.deque()
- with open(TRACE_PIPE) as trace_pipe:
- # The pipe may block a few seconds if using:
- # for line in trace_pipe
- while not self.is_stopping.is_set():
- line = trace_pipe.readline()
- m_trace = re_trace.match(line)
- if m_trace:
- timestamp = float(m_trace.group(1))
- trace_buffer.append(timestamp)
- else:
- m_notify = re_notify.match(line)
- if m_notify:
- timestamp = float(m_notify.group(1))
- self.callback(get_fps_info(trace_buffer, timestamp))
- logging.info('Leaving fps meter main thread')
-
-
- def start(self):
- """ Starts the FPS meter by launching needed threads. """
- # The notificaiton thread.
- start_thread(self.notify_collection)
-
- # The main thread.
- trace_method = get_trace_method()
- enable_tracing(trace_method)
- start_thread(self.main_loop, [trace_method])
-
-
- def stop(self):
- """ Stops the FPS meter. Shut down threads. """
- logging.info('Shutting down FPS meter')
- self.is_stopping.set()
-
-
-def output_fps_info(verbose, fps_info):
- """ Print the fps info to the screen. """
- frame_info, frame_times = fps_info
- fps_count = len([f for f in frame_info if f != ' '])
- frame_info_str = ''.join(frame_info)
- print('[%s] FPS: %2d' % (frame_info_str, fps_count))
- if frame_times and verbose:
- print(', '.join(['%.3f' % t for t in frame_times]))
-
-
-def main(argv):
- """ Print fps information on the screen. """
- parser = argparse.ArgumentParser(description='Print fps infomation.')
- parser.add_argument('--verbose', action='store_true',
- help='print verbose frame time info')
- parser.add_argument('--debug', action='store_true',
- help='print debug message')
- options = parser.parse_args()
-
- if options.debug:
- rootLogger = logging.getLogger()
- rootLogger.setLevel(logging.DEBUG)
- # StreamHandler() defaults to stderr.
- rootLogger.addHandler(logging.StreamHandler())
-
- print('FPS meter trace method %s' % get_trace_method())
- with FPSMeter(functools.partial(output_fps_info, options.verbose)):
- while True:
- try:
- time.sleep(86400)
- except KeyboardInterrupt:
- print('Exiting...')
- break
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/client/bin/fsinfo.py b/client/bin/fsinfo.py
deleted file mode 100644
index 12dcb84..0000000
--- a/client/bin/fsinfo.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# Lint as: python2, python3
-"""This module gives the mkfs creation options for an existing filesystem.
-
-tune2fs or xfs_growfs is called according to the filesystem. The results,
-filesystem tunables, are parsed and mapped to corresponding mkfs options.
-"""
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import os, re, tempfile
-
-import six
-
-import common
-from autotest_lib.client.common_lib import error, utils
-
-
-def opt_string2dict(opt_string):
- """Breaks the mkfs.ext* option string into dictionary."""
- # Example string: '-j -q -i 8192 -b 4096'. There may be extra whitespaces.
- opt_dict = {}
-
- for item in opt_string.split('-'):
- item = item.strip()
- if ' ' in item:
- (opt, value) = item.split(' ', 1)
- opt_dict['-%s' % opt] = value
- elif item != '':
- opt_dict['-%s' % item] = None
- # Convert all the digit strings to int.
- for key, value in six.iteritems(opt_dict):
- if value and value.isdigit():
- opt_dict[key] = int(value)
-
- return opt_dict
-
-
-def parse_mke2fs_conf(fs_type, conf_file='/etc/mke2fs.conf'):
- """Parses mke2fs config file for default settings."""
- # Please see /ect/mke2fs.conf for an example.
- default_opt = {}
- fs_opt = {}
- current_fs_type = ''
- current_section = ''
- f = open(conf_file, 'r')
- for line in f:
- if '[defaults]' == line.strip():
- current_section = '[defaults]'
- elif '[fs_types]' == line.strip():
- current_section = '[fs_types]'
- elif current_section == '[defaults]':
- components = line.split('=', 1)
- if len(components) == 2:
- default_opt[components[0].strip()] = components[1].strip()
- elif current_section == '[fs_types]':
- m = re.search('(\w+) = {', line)
- if m:
- current_fs_type = m.group(1)
- else:
- components = line.split('=', 1)
- if len(components) == 2 and current_fs_type == fs_type:
- default_opt[components[0].strip()] = components[1].strip()
- f.close()
-
- # fs_types options override the defaults options
- for key, value in six.iteritems(fs_opt):
- default_opt[key] = value
-
- # Convert all the digit strings to int.
- for key, value in six.iteritems(default_opt):
- if value and value.isdigit():
- default_opt[key] = int(value)
-
- return default_opt
-
-
-def convert_conf_opt(default_opt):
- conf_opt_mapping = {'blocksize': '-b',
- 'inode_ratio': '-i',
- 'inode_size': '-I'}
- mkfs_opt = {}
-
- # Here we simply concatenate the feature string while we really need
- # to do the better and/or operations.
- if 'base_features' in default_opt:
- mkfs_opt['-O'] = default_opt['base_features']
- if 'default_features' in default_opt:
- mkfs_opt['-O'] += ',%s' % default_opt['default_features']
- if 'features' in default_opt:
- mkfs_opt['-O'] += ',%s' % default_opt['features']
-
- for key, value in six.iteritems(conf_opt_mapping):
- if key in default_opt:
- mkfs_opt[value] = default_opt[key]
-
- if '-O' in mkfs_opt:
- mkfs_opt['-O'] = mkfs_opt['-O'].split(',')
-
- return mkfs_opt
-
-
-def merge_ext_features(conf_feature, user_feature):
- user_feature_list = user_feature.split(',')
-
- merged_feature = []
- # Removes duplicate entries in conf_list.
- for item in conf_feature:
- if item not in merged_feature:
- merged_feature.append(item)
-
- # User options override config options.
- for item in user_feature_list:
- if item[0] == '^':
- if item[1:] in merged_feature:
- merged_feature.remove(item[1:])
- else:
- merged_feature.append(item)
- elif item not in merged_feature:
- merged_feature.append(item)
- return merged_feature
-
-
-def ext_tunables(dev):
- """Call tune2fs -l and parse the result."""
- cmd = 'tune2fs -l %s' % dev
- try:
- out = utils.system_output(cmd)
- except error.CmdError:
- tools_dir = os.path.join(os.environ['AUTODIR'], 'tools')
- cmd = '%s/tune2fs.ext4dev -l %s' % (tools_dir, dev)
- out = utils.system_output(cmd)
- # Load option mappings
- tune2fs_dict = {}
- for line in out.splitlines():
- components = line.split(':', 1)
- if len(components) == 2:
- value = components[1].strip()
- option = components[0]
- if value.isdigit():
- tune2fs_dict[option] = int(value)
- else:
- tune2fs_dict[option] = value
-
- return tune2fs_dict
-
-
-def ext_mkfs_options(tune2fs_dict, mkfs_option):
- """Map the tune2fs options to mkfs options."""
-
- def __inode_count(tune_dict, k):
- return (tune_dict['Block count']/tune_dict[k] + 1) * (
- tune_dict['Block size'])
-
- def __block_count(tune_dict, k):
- return int(100*tune_dict[k]/tune_dict['Block count'] + 1)
-
- def __volume_name(tune_dict, k):
- if tune_dict[k] != '<none>':
- return tune_dict[k]
- else:
- return ''
-
- # mappings between fs features and mkfs options
- ext_mapping = {'Blocks per group': '-g',
- 'Block size': '-b',
- 'Filesystem features': '-O',
- 'Filesystem OS type': '-o',
- 'Filesystem revision #': '-r',
- 'Filesystem volume name': '-L',
- 'Flex block group size': '-G',
- 'Fragment size': '-f',
- 'Inode count': '-i',
- 'Inode size': '-I',
- 'Journal inode': '-j',
- 'Reserved block count': '-m'}
-
- conversions = {
- 'Journal inode': lambda d, k: None,
- 'Filesystem volume name': __volume_name,
- 'Reserved block count': __block_count,
- 'Inode count': __inode_count,
- 'Filesystem features': lambda d, k: re.sub(' ', ',', d[k]),
- 'Filesystem revision #': lambda d, k: d[k][0]}
-
- for key, value in six.iteritems(ext_mapping):
- if key not in tune2fs_dict:
- continue
- if key in conversions:
- mkfs_option[value] = conversions[key](tune2fs_dict, key)
- else:
- mkfs_option[value] = tune2fs_dict[key]
-
-
-def xfs_tunables(dev):
- """Call xfs_grow -n to get filesystem tunables."""
- # Have to mount the filesystem to call xfs_grow.
- tmp_mount_dir = tempfile.mkdtemp()
- cmd = 'mount %s %s' % (dev, tmp_mount_dir)
- utils.system_output(cmd)
- xfs_growfs = os.path.join(os.environ['AUTODIR'], 'tools', 'xfs_growfs')
- cmd = '%s -n %s' % (xfs_growfs, dev)
- try:
- out = utils.system_output(cmd)
- finally:
- # Clean.
- cmd = 'umount %s' % dev
- utils.system_output(cmd, ignore_status=True)
- os.rmdir(tmp_mount_dir)
-
- ## The output format is given in report_info (xfs_growfs.c)
- ## "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
- ## " =%-22s sectsz=%-5u attr=%u\n"
- ## "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
- ## " =%-22s sunit=%-6u swidth=%u blks\n"
- ## "naming =version %-14u bsize=%-6u\n"
- ## "log =%-22s bsize=%-6u blocks=%u, version=%u\n"
- ## " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n"
- ## "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"
-
- tune2fs_dict = {}
- # Flag for extracting naming version number
- keep_version = False
- for line in out.splitlines():
- m = re.search('^([-\w]+)', line)
- if m:
- main_tag = m.group(1)
- pairs = line.split()
- for pair in pairs:
- # naming: version needs special treatment
- if pair == '=version':
- # 1 means the next pair is the version number we want
- keep_version = True
- continue
- if keep_version:
- tune2fs_dict['naming: version'] = pair
- # Resets the flag since we have logged the version
- keep_version = False
- continue
- # Ignores the strings without '=', such as 'blks'
- if '=' not in pair:
- continue
- key, value = pair.split('=')
- tagged_key = '%s: %s' % (main_tag, key)
- if re.match('[0-9]+', value):
- tune2fs_dict[tagged_key] = int(value.rstrip(','))
- else:
- tune2fs_dict[tagged_key] = value.rstrip(',')
-
- return tune2fs_dict
-
-
-def xfs_mkfs_options(tune2fs_dict, mkfs_option):
- """Maps filesystem tunables to their corresponding mkfs options."""
-
- # Mappings
- xfs_mapping = {'meta-data: isize': '-i size',
- 'meta-data: agcount': '-d agcount',
- 'meta-data: sectsz': '-s size',
- 'meta-data: attr': '-i attr',
- 'data: bsize': '-b size',
- 'data: imaxpct': '-i maxpct',
- 'data: sunit': '-d sunit',
- 'data: swidth': '-d swidth',
- 'data: unwritten': '-d unwritten',
- 'naming: version': '-n version',
- 'naming: bsize': '-n size',
- 'log: version': '-l version',
- 'log: sectsz': '-l sectsize',
- 'log: sunit': '-l sunit',
- 'log: lazy-count': '-l lazy-count',
- 'realtime: extsz': '-r extsize',
- 'realtime: blocks': '-r size',
- 'realtime: rtextents': '-r rtdev'}
-
- mkfs_option['-l size'] = tune2fs_dict['log: bsize'] * (
- tune2fs_dict['log: blocks'])
-
- for key, value in six.iteritems(xfs_mapping):
- mkfs_option[value] = tune2fs_dict[key]
-
-
-def compare_features(needed_feature, current_feature):
- """Compare two ext* feature lists."""
- if len(needed_feature) != len(current_feature):
- return False
- for feature in current_feature:
- if feature not in needed_feature:
- return False
- return True
-
-
-def match_ext_options(fs_type, dev, needed_options):
- """Compare the current ext* filesystem tunables with needed ones."""
- # mkfs.ext* will load default options from /etc/mke2fs.conf
- conf_opt = parse_mke2fs_conf(fs_type)
- # We need to convert the conf options to mkfs options.
- conf_mkfs_opt = convert_conf_opt(conf_opt)
- # Breaks user mkfs option string to dictionary.
- needed_opt_dict = opt_string2dict(needed_options)
- # Removes ignored options.
- ignored_option = ['-c', '-q', '-E', '-F']
- for opt in ignored_option:
- if opt in needed_opt_dict:
- del needed_opt_dict[opt]
-
- # User options override config options.
- needed_opt = conf_mkfs_opt
- for key, value in six.iteritems(needed_opt_dict):
- if key == '-N' or key == '-T':
- raise Exception('-N/T is not allowed.')
- elif key == '-O':
- needed_opt[key] = merge_ext_features(needed_opt[key], value)
- else:
- needed_opt[key] = value
-
- # '-j' option will add 'has_journal' feature.
- if '-j' in needed_opt and 'has_journal' not in needed_opt['-O']:
- needed_opt['-O'].append('has_journal')
- # 'extents' will be shown as 'extent' in the outcome of tune2fs
- if 'extents' in needed_opt['-O']:
- needed_opt['-O'].append('extent')
- needed_opt['-O'].remove('extents')
- # large_file is a byproduct of resize_inode.
- if 'large_file' not in needed_opt['-O'] and (
- 'resize_inode' in needed_opt['-O']):
- needed_opt['-O'].append('large_file')
-
- current_opt = {}
- tune2fs_dict = ext_tunables(dev)
- ext_mkfs_options(tune2fs_dict, current_opt)
-
- # Does the match
- for key, value in six.iteritems(needed_opt):
- if key == '-O':
- if not compare_features(value, current_opt[key].split(',')):
- return False
- elif key not in current_opt or value != current_opt[key]:
- return False
- return True
-
-
-def match_xfs_options(dev, needed_options):
- """Compare the current ext* filesystem tunables with needed ones."""
- tmp_mount_dir = tempfile.mkdtemp()
- cmd = 'mount %s %s' % (dev, tmp_mount_dir)
- utils.system_output(cmd)
- xfs_growfs = os.path.join(os.environ['AUTODIR'], 'tools', 'xfs_growfs')
- cmd = '%s -n %s' % (xfs_growfs, dev)
- try:
- current_option = utils.system_output(cmd)
- finally:
- # Clean.
- cmd = 'umount %s' % dev
- utils.system_output(cmd, ignore_status=True)
- os.rmdir(tmp_mount_dir)
-
- # '-N' has the same effect as '-n' in mkfs.ext*. Man mkfs.xfs for details.
- cmd = 'mkfs.xfs %s -N -f %s' % (needed_options, dev)
- needed_out = utils.system_output(cmd)
- # 'mkfs.xfs -N' produces slightly different result than 'xfs_growfs -n'
- needed_out = re.sub('internal log', 'internal ', needed_out)
- if current_option == needed_out:
- return True
- else:
- return False
-
-
-def match_mkfs_option(fs_type, dev, needed_options):
- """Compare the current filesystem tunables with needed ones."""
- if fs_type.startswith('ext'):
- ret = match_ext_options(fs_type, dev, needed_options)
- elif fs_type == 'xfs':
- ret = match_xfs_options(dev, needed_options)
- else:
- ret = False
-
- return ret
diff --git a/client/bin/fsinfo_unittest.py b/client/bin/fsinfo_unittest.py
deleted file mode 100755
index 0dcee63..0000000
--- a/client/bin/fsinfo_unittest.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/python3
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-import unittest, six
-
-import common
-from autotest_lib.client.bin import fsinfo
-from autotest_lib.client.common_lib.test_utils import mock
-
-class fsionfo_test(unittest.TestCase):
-
- def setUp(self):
- self.god = mock.mock_god()
- self.god.stub_function(fsinfo, 'open')
-
-
- def tearDown(self):
- self.god.unstub_all()
-
-
- def create_test_file(self, filename, contents):
- test_file = six.StringIO(contents)
- fsinfo.open.expect_call(filename, 'r').and_return(test_file)
-
-
- def test_ext_mkfs_options(self):
- tune2fs_dict = {'Filesystem volume name': '<none>',
- 'Last mounted on': '<not available>',
- 'Filesystem revision #': '1 (dynamic)',
- 'Block size': 4096,
- 'Block count': 263056,
- 'Fragment size': 4096,
- 'Blocks per group': 32768,
- 'Journal inode': 8,
- 'Reserved block count': 2630,
- 'Inode count': 131616,
- 'Filesystem features': 'filetype sparse_super',
- 'Filesystem OS type': 'Linux'}
- expected_option = {'-b': 4096,
- '-f': 4096,
- '-g': 32768,
- '-j': None,
- '-m': 1,
- '-O': 'filetype,sparse_super',
- '-o': 'Linux',
- '-r': '1'}
-
- mkfs_option = {}
- fsinfo.ext_mkfs_options(tune2fs_dict, mkfs_option)
-
- for option, value in six.iteritems(expected_option):
- self.assertEqual(value, mkfs_option[option])
-
-
- def test_xfs_mkfs_options(self):
- tune2fs_dict = {'meta-data: isize': 256,
- 'meta-data: agcount': 8,
- 'meta-data: agsize': 32882,
- 'meta-data: sectsz': 512,
- 'meta-data: attr': 0,
- 'data: bsize': 4096,
- 'data: imaxpct': 25,
- 'data: sunit': 0,
- 'data: swidth': 0,
- 'data: unwritten': 1,
- 'naming: version': 2,
- 'naming: bsize': 4096,
- 'log: version': 1,
- 'log: sectsz': 512,
- 'log: sunit': 0,
- 'log: lazy-count': 0,
- 'log: bsize': 4096,
- 'log: blocks': 2560,
- 'realtime: extsz': 4096,
- 'realtime: blocks': 0,
- 'realtime: rtextents': 0}
-
- expected_option = {'-i size': 256,
- '-d agcount': 8,
- '-s size': 512,
- '-b size': 4096,
- '-i attr': 0,
- '-i maxpct': 25,
- '-d sunit': 0,
- '-d swidth': 0,
- '-d unwritten': 1,
- '-n version': 2,
- '-n size': 4096,
- '-l version': 1,
- '-l sectsize': 512,
- '-l sunit': 0,
- '-l lazy-count': 0,
- '-r extsize': 4096,
- '-r size': 0,
- '-r rtdev': 0,
- '-l size': 10485760}
- mkfs_option = {}
- fsinfo.xfs_mkfs_options(tune2fs_dict, mkfs_option)
- for option, value in six.iteritems(expected_option):
- self.assertEqual(value, mkfs_option[option])
-
-
- def test_opt_string2dict(self):
- test_string = '-q -b 1234 -O fdasfa,fdasfdas -l adfas -k -L'
- result = fsinfo.opt_string2dict(test_string)
- expected_result = {'-q': None,
- '-b': 1234,
- '-O': 'fdasfa,fdasfdas',
- '-l': 'adfas',
- '-k': None,
- '-L': None}
- self.assertEqual(expected_result, result)
-
-
- def test_merge_ext_features(self):
- conf = 'a,b,d,d,d,d,d,e,e,a,f'.split(',')
- user = '^e,a,^f,g,h,i'
- expected_result = ['a', 'b', 'd', 'g', 'h', 'i']
- result = fsinfo.merge_ext_features(conf, user)
- self.assertEqual(expected_result, result)
-
-
- def test_compare_features(self):
- f1 = ['sparse_super', 'filetype', 'resize_inode', 'dir_index']
- f2 = ['filetype', 'resize_inode', 'dir_index', 'large_file']
- self.assertTrue(fsinfo.compare_features(f1, f1))
- self.assertFalse(fsinfo.compare_features(f1, f2))
-
-
- def test_mke2fs_conf(self):
- content = ('[defaults]\n'
- 'base_features = sparse_super,filetype,resize_inode\n'
- ' blocksize = 4096 \n'
- ' inode_ratio = 8192 \n'
- '\n [fs_types]\n'
- ' small = {\n'
- ' blocksize = 1024\n'
- ' inode_ratio = 4096 \n'
- ' }\n'
- ' floppy = {\n'
- ' blocksize = 4096\n'
- ' }\n')
- self.create_test_file('/etc/mke2fs.conf', content)
-
- conf_opt = fsinfo.parse_mke2fs_conf('small')
- mkfs_opt = fsinfo.convert_conf_opt(conf_opt)
- expected_conf = {'blocksize': 1024,
- 'inode_ratio': 4096,
- 'base_features': 'sparse_super,filetype,resize_inode'}
- expected_mkfs = {'-O': ['sparse_super', 'filetype', 'resize_inode'],
- '-i': 4096,
- '-b': 1024}
- self.assertEqual(conf_opt, expected_conf)
- self.assertEqual(mkfs_opt, expected_mkfs)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/client/bin/input/__init__.py b/client/bin/input/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/bin/input/__init__.py
+++ /dev/null
diff --git a/client/bin/input/input_device.py b/client/bin/input/input_device.py
deleted file mode 100755
index 64977be..0000000
--- a/client/bin/input/input_device.py
+++ /dev/null
@@ -1,739 +0,0 @@
-#!/usr/bin/env python2
-# Copyright (c) 2011 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.
-
-# Description:
-#
-# Class for handling linux 'evdev' input devices.
-#
-# Provides evtest-like functionality if run from the command line:
-# $ input_device.py -d /dev/input/event6
-
-""" Read properties and events of a linux input device. """
-
-from __future__ import division
-from __future__ import print_function
-
-import array
-import copy
-import fcntl
-import os.path
-import re
-import select
-import struct
-import time
-
-from collections import OrderedDict
-from six.moves import range
-
-# Try to import from the autotest_lib structure. If it fails try the default.
-# If this script was run outside of autotest the "except" would be the flow.
-# If run within, the "try" is the flow.
-try:
- from autotest_lib.client.bin.input.linux_input import *
-except ImportError:
- from linux_input import *
-
-# The regular expression of possible keyboard types.
-KEYBOARD_TYPES = '(keyboard|chromeos-ec-i2c|cros-ec-spi|cros-ec-i2c|cros_ec)'
-
-_DEVICE_INFO_FILE = '/proc/bus/input/devices'
-
-
-class Valuator:
- """ A Valuator just stores a value """
- def __init__(self):
- self.value = 0
-
-class SwValuator(Valuator):
- """ A Valuator used for EV_SW (switch) events """
- def __init__(self, value):
- self.value = value
-
-class AbsValuator(Valuator):
- """
- An AbsValuator, used for EV_ABS events stores a value as well as other
- properties of the corresponding absolute axis.
- """
- def __init__(self, value, min_value, max_value, fuzz, flat, resolution):
- self.value = value
- self.min = min_value
- self.max = max_value
- self.fuzz = fuzz
- self.flat = flat
- self.resolution = resolution
-
-
-class InputEvent:
- """
- Linux evdev input event
-
- An input event has the following fields which can be accessed as public
- properties of this class:
- tv_sec
- tv_usec
- type
- code
- value
- """
- def __init__(self, tv_sec=0, tv_usec=0, type=0, code=0, value=0):
- self.format = input_event_t
- self.format_size = struct.calcsize(self.format)
- (self.tv_sec, self.tv_usec, self.type, self.code,
- self.value) = (tv_sec, tv_usec, type, code, value)
-
- def read(self, stream):
- """ Read an input event from the provided stream and unpack it. """
- packed = stream.read(self.format_size)
- (self.tv_sec, self.tv_usec, self.type, self.code,
- self.value) = struct.unpack(self.format, packed)
-
- def write(self, stream):
- """ Pack an input event and write it to the provided stream. """
- packed = struct.pack(self.format, self.tv_sec, self.tv_usec, self.type,
- self.code, self.value)
- stream.write(packed)
- stream.flush()
-
- def __str__(self):
- t = EV_TYPES.get(self.type, self.type)
- if self.type in EV_STRINGS:
- c = EV_STRINGS[self.type].get(self.code, self.code)
- else:
- c = self.code
- return ('%d.%06d: %s[%s] = %d' %
- (self.tv_sec, self.tv_usec, t, c, self.value))
-
-
-class InputDevice:
- """
- Linux evdev input device
-
- A linux kernel "evdev" device sends a stream of "input events".
- These events are grouped together into "input reports", which is a set of
- input events ending in a single EV_SYN/SYN_REPORT event.
-
- Each input event is tagged with a type and a code.
- A given input device supports a subset of the possible types, and for
- each type it supports a subset of the possible codes for that type.
-
- The device maintains a "valuator" for each supported type/code pairs.
- There are two types of "valuators":
- Normal valuators represent just a value.
- Absolute valuators are only for EV_ABS events. They have more fields:
- value, minimum, maximum, resolution, fuzz, flatness
- Note: Relative and Absolute "Valuators" are also often called relative
- and absolute axis, respectively.
-
- The evdev protocol is stateful. Input events are only sent when the values
- of a valuator actually changes. This dramatically reduces the stream of
- events emenating from the kernel.
-
- Multitouch devices are a special case. There are two types of multitouch
- devices defined in the kernel:
- Multitouch type "A" (MT-A) devices:
- In each input report, the device sends an unordered list of all
- active contacts. The data for each active contact is separated
- in the input report by an EV_SYN/SYN_MT_REPORT event.
- Thus, the MT-A contact event stream is not stateful.
- Note: MT-A is not currently supported by this class.
-
- Multitouch type "B" (MT-B) devices:
- The device maintains a list of slots, where each slot contains a
- single contact. In each input report, the device only sends
- information about the slots that have changed.
- Thus, the MT-B contact event stream is stateful.
- When reporting multiple slots, the EV_ABS/MT_SLOT valuator is used
- to indicate the 'current' slot for which subsequent EV_ABS/ABS_MT_*
- valuator events apply.
- An inactive slot has EV_ABS/ABS_MT_TRACKING_ID == -1
- Active slots have EV_ABS/ABS_MT_TRACKING_ID >= 0
-
- Besides maintaining the set of supported ABS_MT valuators in the supported
- valuator list, a array of slots is also maintained. Each slot has its own
- unique copy of just the supported ABS_MT valuators. This represents the
- current state of that slot.
- """
-
- def __init__(self, path, ev_syn_cb=None):
- """
- Constructor opens the device file and probes its properties.
-
- Note: The device file is left open when the constructor exits.
- """
- self.path = path
- self.ev_syn_cb = ev_syn_cb
- self.events = {} # dict { ev_type : dict { ev_code : Valuator } }
- self.mt_slots = [] # [ dict { mt_code : AbsValuator } ] * |MT-B slots|
-
- # Open the device node, and use ioctls to probe its properties
- self.f = None
- self.f = open(path, 'rb+', buffering=0)
- self._ioctl_version()
- self._ioctl_id()
- self._ioctl_name()
- for t in self._ioctl_types():
- self._ioctl_codes(t)
- self._setup_mt_slots()
-
- def __del__(self):
- """
- Deconstructor closes the device file, if it is open.
- """
- if self.f and not self.f.closed:
- self.f.close()
-
- def process_event(self, ev):
- """
- Processes an incoming input event.
-
- Returns True for EV_SYN/SYN_REPORT events to indicate that a complete
- input report has been received.
-
- Returns False for other events.
-
- Events not supported by this device are silently ignored.
-
- For MT events, updates the slot valuator value for the current slot.
- If current slot is the 'primary' slot, also updates the events entry.
-
- For all other events, updates the corresponding valuator value.
- """
- if ev.type == EV_SYN and ev.code == SYN_REPORT:
- return True
- elif ev.type not in self.events or ev.code not in self.events[ev.type]:
- return False
- elif self.is_mt_b() and ev.type == EV_ABS and ev.code in ABS_MT_RANGE:
- # TODO: Handle MT-A
- slot = self._get_current_slot()
- slot[ev.code].value = ev.value
- # if the current slot is the "primary" slot,
- # update the events[] entry, too.
- if slot == self._get_mt_primary_slot():
- self.events[ev.type][ev.code].value = ev.value
- else:
- self.events[ev.type][ev.code].value = ev.value
- return False
-
- def _ioctl_version(self):
- """ Queries device file for version information. """
- # Version is a 32-bit integer, which encodes 8-bit major version,
- # 8-bit minor version and 16-bit revision.
- version = array.array('I', [0])
- fcntl.ioctl(self.f, EVIOCGVERSION, version, 1)
- self.version = (version[0] >> 16, (version[0] >> 8) & 0xff,
- version[0] & 0xff)
-
- def _ioctl_id(self):
- """ Queries device file for input device identification. """
- # struct input_id is 4 __u16
- gid = array.array('H', [0] * 4)
- fcntl.ioctl(self.f, EVIOCGID, gid, 1)
- self.id_bus = gid[ID_BUS]
- self.id_vendor = gid[ID_VENDOR]
- self.id_product = gid[ID_PRODUCT]
- self.id_version = gid[ID_VERSION]
-
- def _ioctl_name(self):
- """ Queries device file for the device name. """
- # Device name is a C-string up to 255 bytes in length.
- name_len = 255
- name = array.array('B', [0] * name_len)
- name_len = fcntl.ioctl(self.f, EVIOCGNAME(name_len), name, 1)
- self.name = name[0:name_len-1].tostring()
-
- def _ioctl_get_switch(self, sw):
- """
- Queries device file for current value of all switches and returns
- a boolean indicating whether the switch sw is set.
- """
- size = SW_CNT // 8 # Buffer size of one __u16
- buf = array.array('H', [0])
- fcntl.ioctl(self.f, EVIOCGSW(size), buf)
- return SwValuator(((buf[0] >> sw) & 0x01) == 1)
-
- def _ioctl_absinfo(self, axis):
- """
- Queries device file for absinfo structure for given absolute axis.
- """
- # struct input_absinfo is 6 __s32
- a = array.array('i', [0] * 6)
- fcntl.ioctl(self.f, EVIOCGABS(axis), a, 1)
- return AbsValuator(a[0], a[1], a[2], a[3], a[4], a[5])
-
- def _ioctl_codes(self, ev_type):
- """
- Queries device file for supported event codes for given event type.
- """
- self.events[ev_type] = {}
- if ev_type not in EV_SIZES:
- return
-
- size = EV_SIZES[ev_type] // 8 # Convert bits to bytes
- ev_code = array.array('B', [0] * size)
- try:
- count = fcntl.ioctl(self.f, EVIOCGBIT(ev_type, size), ev_code, 1)
- for c in range(count * 8):
- if test_bit(c, ev_code):
- if ev_type == EV_ABS:
- self.events[ev_type][c] = self._ioctl_absinfo(c)
- elif ev_type == EV_SW:
- self.events[ev_type][c] = self._ioctl_get_switch(c)
- else:
- self.events[ev_type][c] = Valuator()
- except IOError as errs:
- # Errno 22 signifies that this event type has no event codes.
- (errno, strerror) = errs.args
- if errno != 22:
- raise
-
- def _ioctl_types(self):
- """ Queries device file for supported event types. """
- ev_types = array.array('B', [0] * (EV_CNT // 8))
- fcntl.ioctl(self.f, EVIOCGBIT(EV_SYN, EV_CNT // 8), ev_types, 1)
- types = []
- for t in range(EV_CNT):
- if test_bit(t, ev_types):
- types.append(t)
- return types
-
- def _convert_slot_index_to_slot_id(self, index):
- """ Convert a slot index in self.mt_slots to its slot id. """
- return self.abs_mt_slot.min + index
-
- def _ioctl_mt_slots(self):
- """Query mt slots values using ioctl.
-
- The ioctl buffer argument should be binary equivalent to
- struct input_mt_request_layout {
- __u32 code;
- __s32 values[num_slots];
-
- Note that the slots information returned by EVIOCGMTSLOTS
- corresponds to the slot ids ranging from abs_mt_slot.min to
- abs_mt_slot.max which is not necessarily the same as the
- slot indexes ranging from 0 to num_slots - 1 in self.mt_slots.
- We need to map between the slot index and the slot id correctly.
- };
- """
- # Iterate through the absolute mt events that are supported.
- for c in range(ABS_MT_FIRST, ABS_MT_LAST):
- if c not in self.events[EV_ABS]:
- continue
- # Sync with evdev kernel driver for the specified code c.
- mt_slot_info = array.array('i', [c] + [0] * self.num_slots)
- mt_slot_info_len = (self.num_slots + 1) * mt_slot_info.itemsize
- fcntl.ioctl(self.f, EVIOCGMTSLOTS(mt_slot_info_len), mt_slot_info)
- values = mt_slot_info[1:]
- for slot_index in range(self.num_slots):
- slot_id = self._convert_slot_index_to_slot_id(slot_index)
- self.mt_slots[slot_index][c].value = values[slot_id]
-
- def _setup_mt_slots(self):
- """
- Sets up the device's mt_slots array.
-
- Each element of the mt_slots array is initialized as a deepcopy of a
- dict containing all of the MT valuators from the events dict.
- """
- # TODO(djkurtz): MT-A
- if not self.is_mt_b():
- return
- ev_abs = self.events[EV_ABS]
- # Create dict containing just the MT valuators
- mt_abs_info = dict((axis, ev_abs[axis])
- for axis in ev_abs
- if axis in ABS_MT_RANGE)
-
- # Initialize TRACKING_ID to -1
- mt_abs_info[ABS_MT_TRACKING_ID].value = -1
-
- # Make a copy of mt_abs_info for each MT slot
- self.abs_mt_slot = ev_abs[ABS_MT_SLOT]
- self.num_slots = self.abs_mt_slot.max - self.abs_mt_slot.min + 1
- for s in range(self.num_slots):
- self.mt_slots.append(copy.deepcopy(mt_abs_info))
-
- self._ioctl_mt_slots()
-
- def get_current_slot_id(self):
- """
- Return the current slot id.
- """
- if not self.is_mt_b():
- return None
- return self.events[EV_ABS][ABS_MT_SLOT].value
-
- def _get_current_slot(self):
- """
- Returns the current slot, as indicated by the last ABS_MT_SLOT event.
- """
- current_slot_id = self.get_current_slot_id()
- if current_slot_id is None:
- return None
- return self.mt_slots[current_slot_id]
-
- def _get_tid(self, slot):
- """ Returns the tracking_id for the given MT slot. """
- return slot[ABS_MT_TRACKING_ID].value
-
- def _get_mt_valid_slots(self):
- """
- Returns a list of valid slots.
-
- A valid slot is a slot whose tracking_id != -1.
- """
- return [s for s in self.mt_slots if self._get_tid(s) != -1]
-
- def _get_mt_primary_slot(self):
- """
- Returns the "primary" MT-B slot.
-
- The "primary" MT-B slot is arbitrarily chosen as the slot with lowest
- tracking_id (> -1). It is used to make an MT-B device look like
- single-touch (ST) device.
- """
- slot = None
- for s in self.mt_slots:
- tid = self._get_tid(s)
- if tid < 0:
- continue
- if not slot or tid < self._get_tid(slot):
- slot = s
- return slot
-
- def _code_if_mt(self, type, code):
- """
- Returns MT-equivalent event code for certain specific event codes
- """
- if type != EV_ABS:
- return code
- elif code == ABS_X:
- return ABS_MT_POSITION_X
- elif code == ABS_Y:
- return ABS_MT_POSITION_Y
- elif code == ABS_PRESSURE:
- return ABS_MT_PRESSURE
- elif code == ABS_TOOL_WIDTH:
- return ABS_MT_TOUCH_MAJOR
- else:
- return code
-
- def _get_valuator(self, type, code):
- """ Returns Valuator for given event type and code """
- if (not type in self.events) or (not code in self.events[type]):
- return None
- if type == EV_ABS:
- code = self._code_if_mt(type, code)
- return self.events[type][code]
-
- def _get_value(self, type, code):
- """
- Returns the value of the valuator with the give event (type, code).
- """
- axis = self._get_valuator(type, code)
- if not axis:
- return None
- return axis.value
-
- def _get_min(self, type, code):
- """
- Returns the min value of the valuator with the give event (type, code).
-
- Note: Only AbsValuators (EV_ABS) have max values.
- """
- axis = self._get_valuator(type, code)
- if not axis:
- return None
- return axis.min
-
- def _get_max(self, type, code):
- """
- Returns the min value of the valuator with the give event (type, code).
-
- Note: Only AbsValuators (EV_ABS) have max values.
- """
- axis = self._get_valuator(type, code)
- if not axis:
- return None
- return axis.max
-
- """ Public accessors """
-
- def get_num_fingers(self):
- if self.is_mt_b():
- return len(self._get_mt_valid_slots())
- elif self.is_mt_a():
- return 0 # TODO(djkurtz): MT-A
- else: # Single-Touch case
- if not self._get_value(EV_KEY, BTN_TOUCH) == 1:
- return 0
- elif self._get_value(EV_KEY, BTN_TOOL_TRIPLETAP) == 1:
- return 3
- elif self._get_value(EV_KEY, BTN_TOOL_DOUBLETAP) == 1:
- return 2
- elif self._get_value(EV_KEY, BTN_TOOL_FINGER) == 1:
- return 1
- else:
- return 0
-
- def get_x(self):
- return self._get_value(EV_ABS, ABS_X)
-
- def get_x_min(self):
- return self._get_min(EV_ABS, ABS_X)
-
- def get_x_max(self):
- return self._get_max(EV_ABS, ABS_X)
-
- def get_y(self):
- return self._get_value(EV_ABS, ABS_Y)
-
- def get_y_min(self):
- return self._get_min(EV_ABS, ABS_Y)
-
- def get_y_max(self):
- return self._get_max(EV_ABS, ABS_Y)
-
- def get_pressure(self):
- return self._get_value(EV_ABS, ABS_PRESSURE)
-
- def get_pressure_min(self):
- return self._get_min(EV_ABS, ABS_PRESSURE)
-
- def get_pressure_max(self):
- return self._get_max(EV_ABS, ABS_PRESSURE)
-
- def get_left(self):
- return int(self._get_value(EV_KEY, BTN_LEFT) == 1)
-
- def get_right(self):
- return int(self._get_value(EV_KEY, BTN_RIGHT) == 1)
-
- def get_middle(self):
- return int(self._get_value(EV_KEY, BTN_MIDDLE) == 1)
-
- def get_microphone_insert(self):
- return self._get_value(EV_SW, SW_MICROPHONE_INSERT)
-
- def get_headphone_insert(self):
- return self._get_value(EV_SW, SW_HEADPHONE_INSERT)
-
- def get_lineout_insert(self):
- return self._get_value(EV_SW, SW_LINEOUT_INSERT)
-
- def is_touchpad(self):
- return ((EV_KEY in self.events) and
- (BTN_TOOL_FINGER in self.events[EV_KEY]) and
- (EV_ABS in self.events))
-
- def is_keyboard(self):
- if EV_KEY not in self.events:
- return False
- # Check first 31 keys. This is the same method udev and the
- # Chromium browser use.
- for key in range(KEY_ESC, KEY_D + 1):
- if key not in self.events[EV_KEY]:
- return False
- return True
-
- def is_touchscreen(self):
- return ((EV_KEY in self.events) and
- (BTN_TOUCH in self.events[EV_KEY]) and
- (not BTN_TOOL_FINGER in self.events[EV_KEY]) and
- (EV_ABS in self.events))
-
- def is_lid(self):
- return ((EV_SW in self.events) and
- (SW_LID in self.events[EV_SW]))
-
- def is_mt_b(self):
- return self.is_mt() and ABS_MT_SLOT in self.events[EV_ABS]
-
- def is_mt_a(self):
- return self.is_mt() and ABS_MT_SLOT not in self.events[EV_ABS]
-
- def is_mt(self):
- return (EV_ABS in self.events and
- (set(self.events[EV_ABS]) & set(ABS_MT_RANGE)))
-
- def is_hp_jack(self):
- return (EV_SW in self.events and
- SW_HEADPHONE_INSERT in self.events[EV_SW])
-
- def is_mic_jack(self):
- return (EV_SW in self.events and
- SW_MICROPHONE_INSERT in self.events[EV_SW])
-
- def is_audio_jack(self):
- return (EV_SW in self.events and
- ((SW_HEADPHONE_INSERT in self.events[EV_SW]) or
- (SW_MICROPHONE_INSERT in self.events[EV_SW] or
- (SW_LINEOUT_INSERT in self.events[EV_SW]))))
-
- """ Debug helper print functions """
-
- def print_abs_info(self, axis):
- if EV_ABS in self.events and axis in self.events[EV_ABS]:
- a = self.events[EV_ABS][axis]
- print(' Value %6d' % a.value)
- print(' Min %6d' % a.min)
- print(' Max %6d' % a.max)
- if a.fuzz != 0:
- print(' Fuzz %6d' % a.fuzz)
- if a.flat != 0:
- print(' Flat %6d' % a.flat)
- if a.resolution != 0:
- print(' Resolution %6d' % a.resolution)
-
- def print_props(self):
- print(('Input driver Version: %d.%d.%d' %
- (self.version[0], self.version[1], self.version[2])))
- print(('Input device ID: bus %x vendor %x product %x version %x' %
- (self.id_bus, self.id_vendor, self.id_product, self.id_version)))
- print('Input device name: "%s"' % (self.name))
- for t in self.events:
- print(' Event type %d (%s)' % (t, EV_TYPES.get(t, '?')))
- for c in self.events[t]:
- if (t in EV_STRINGS):
- code = EV_STRINGS[t].get(c, '?')
- print(' Event code %s (%d)' % (code, c))
- else:
- print(' Event code (%d)' % (c))
- self.print_abs_info(c)
-
- def get_slots(self):
- """ Get those slots with positive tracking IDs. """
- slot_dict = OrderedDict()
- for slot_index in range(self.num_slots):
- slot = self.mt_slots[slot_index]
- if self._get_tid(slot) == -1:
- continue
- slot_id = self._convert_slot_index_to_slot_id(slot_index)
- slot_dict[slot_id] = slot
- return slot_dict
-
- def print_slots(self):
- slot_dict = self.get_slots()
- for slot_id, slot in slot_dict.items():
- print('slot #%d' % slot_id)
- for a in slot:
- abs = EV_STRINGS[EV_ABS].get(a, '?')
- print(' %s = %6d' % (abs, slot[a].value))
-
-
-def print_report(device):
- print('----- EV_SYN -----')
- if device.is_touchpad():
- f = device.get_num_fingers()
- if f == 0:
- return
- x = device.get_x()
- y = device.get_y()
- z = device.get_pressure()
- l = device.get_left()
- print('Left=%d Fingers=%d X=%d Y=%d Pressure=%d' % (l, f, x, y, z))
- if device.is_mt():
- device.print_slots()
-
-
-def get_device_node(device_type):
- """Get the keyboard device node through device info file.
-
- Example of the keyboard device information looks like
-
- I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
- N: Name="AT Translated Set 2 keyboard"
- P: Phys=isa0060/serio0/input0
- S: Sysfs=/devices/platform/i8042/serio0/input/input5
- U: Uniq=
- H: Handlers=sysrq kbd event5
- """
- device_node = None
- device_found = None
- device_pattern = re.compile('N: Name=.*%s' % device_type, re.I)
- event_number_pattern = re.compile(r'H: Handlers=.*event(\d?)', re.I)
- with open(_DEVICE_INFO_FILE) as info:
- for line in info:
- if device_found:
- result = event_number_pattern.search(line)
- if result:
- event_number = int(result.group(1))
- device_node = '/dev/input/event%d' % event_number
- break
- else:
- device_found = device_pattern.search(line)
- return device_node
-
-
-if __name__ == "__main__":
- from optparse import OptionParser
- import glob
- parser = OptionParser()
-
- parser.add_option("-a", "--audio_jack", action="store_true",
- dest="audio_jack", default=False,
- help="Find and use all audio jacks")
- parser.add_option("-d", "--devpath", dest="devpath",
- default="/dev/input/event0",
- help="device path (/dev/input/event0)")
- parser.add_option("-q", "--quiet", action="store_false", dest="verbose",
- default=True, help="print less messages to stdout")
- parser.add_option("-t", "--touchpad", action="store_true", dest="touchpad",
- default=False, help="Find and use first touchpad device")
- (options, args) = parser.parse_args()
-
- # TODO: Use gudev to detect touchpad
- devices = []
- if options.touchpad:
- for path in glob.glob('/dev/input/event*'):
- device = InputDevice(path)
- if device.is_touchpad():
- print('Using touchpad %s.' % path)
- options.devpath = path
- devices.append(device)
- break
- else:
- print('No touchpad found!')
- exit()
- elif options.audio_jack:
- for path in glob.glob('/dev/input/event*'):
- device = InputDevice(path)
- if device.is_audio_jack():
- devices.append(device)
- device = None
- elif os.path.exists(options.devpath):
- print('Using %s.' % options.devpath)
- devices.append(InputDevice(options.devpath))
- else:
- print('%s does not exist.' % options.devpath)
- exit()
-
- for device in devices:
- device.print_props()
- if device.is_touchpad():
- print(('x: (%d,%d), y: (%d,%d), z: (%d, %d)' %
- (device.get_x_min(), device.get_x_max(),
- device.get_y_min(), device.get_y_max(),
- device.get_pressure_min(), device.get_pressure_max())))
- device.print_slots()
- print('Number of fingers: %d' % device.get_num_fingers())
- print('Current slot id: %d' % device.get_current_slot_id())
- print('------------------')
- print()
-
- ev = InputEvent()
- while True:
- _rl, _, _ = select.select([d.f for d in devices], [], [])
- for fd in _rl:
- # Lookup for the device which owns fd.
- device = [d for d in devices if d.f == fd][0]
- try:
- ev.read(fd)
- except KeyboardInterrupt:
- exit()
- is_syn = device.process_event(ev)
- print(ev)
- if is_syn:
- print_report(device)
diff --git a/client/bin/input/input_event_player.py b/client/bin/input/input_event_player.py
deleted file mode 100755
index 0ec7c9c..0000000
--- a/client/bin/input/input_event_player.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python2
-# 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.
-
-# Description:
-#
-# Class for injecting input events to linux 'evdev' input devices.
-#
-# Provides evemu-play-like functionality if run from the command line:
-# $ input_event_player.py -d /dev/input/event6
-
-""" Playback input events on a linux input device. """
-
-from __future__ import division
-from __future__ import print_function
-
-import glob
-import os.path
-import re
-import time
-
-from optparse import OptionParser
-# Try to import from the autotest_lib structure. If it fails try the default.
-# If this script was run outside of autotest the "except" would be the flow.
-# If run within, the "try" is the flow.
-try:
- from autotest_lib.client.bin.input.input_device import InputDevice, InputEvent
-except ImportError:
- from input_device import InputDevice, InputEvent
-
-
-class InputEventPlayer:
- """ Linux evdev input event player.
-
- An "evdev" input event player injects a stream of "input events" to kernel
- evdev driver. With this player, we could easily playback an input event file
- which was recorded with the tool evemu-record previously.
-
- """
-
- def __init__(self):
- self.tv_sec = None
- self.tv_usec = None
-
- def playback(self, device, gesture_file):
- """ Play the events in gesture_file on device.
-
- Keyword arguments:
- device -- the InputDevice device object
- gesture_file -- the name of the event file recorded previously
- """
- if not device:
- raise
- event_str = 'E: (\d+)\.(\d+) ([0-9a-f]{4}) ([0-9a-f]{4}) ([-]?\d+)'
- event_pattern = re.compile(event_str)
- for line in open(gesture_file, 'rt'):
- m = event_pattern.match(line)
- if not m:
- raise
- event = InputEvent(int(m.group(1)),
- int(m.group(2)),
- int(m.group(3), 16),
- int(m.group(4), 16),
- int(m.group(5)))
- if not self.tv_sec:
- self.tv_sec = event.tv_sec
- self.tv_usec = event.tv_usec
- delta = event.tv_sec - self.tv_sec
- delta += ((event.tv_usec - self.tv_usec) / 1000000.0)
- # Sleep only if the event is 0.05 ms later than the previous one
- if delta > 0.0000500:
- time.sleep(delta)
- self.tv_sec = event.tv_sec
- self.tv_usec = event.tv_usec
- event.write(device.f)
-
-
-if __name__ == '__main__':
- parser = OptionParser()
-
- parser.add_option('-d', '--devpath', dest='devpath', default='',
- help='device path (/dev/input/event0)')
- parser.add_option('-t', '--touchpad', action='store_true', dest='touchpad',
- default=False, help='Find and use first touchpad device')
- parser.add_option('-f', '--file', action='store', dest='gesture_file',
- help='Event file to playback')
- (options, args) = parser.parse_args()
-
- if options.touchpad:
- for evdev in glob.glob('/dev/input/event*'):
- device = InputDevice(evdev)
- if device.is_touchpad():
- break
- else:
- print('Can not find a touchpad device')
- exit()
- elif not os.path.exists(options.devpath):
- print('Can not find the input device "%s".' % options.devpath)
- exit()
- else:
- device = InputDevice(options.devpath)
- if not options.gesture_file:
- print('Gesture file is not specified.')
- exit()
- if not os.path.exists(options.gesture_file):
- print('Can not find the gesture file %s.' % options.gesture_file)
- exit()
-
- InputEventPlayer().playback(device, options.gesture_file)
- print('Gesture file %s has been played.' % options.gesture_file)
diff --git a/client/bin/input/input_event_recorder.py b/client/bin/input/input_event_recorder.py
deleted file mode 100644
index 096a8ff..0000000
--- a/client/bin/input/input_event_recorder.py
+++ /dev/null
@@ -1,358 +0,0 @@
-# Lint as: python2, python3
-# Copyright 2017 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.
-
-"""This module provides functions to record input events."""
-
-from __future__ import division
-from __future__ import print_function
-
-import logging
-import re
-import select
-import subprocess
-import threading
-import time
-
-from autotest_lib.client.bin.input.linux_input import\
- EV_MSC, EV_SYN, MSC_SCAN, SYN_REPORT
-
-
-# Define extra misc events below as they are not defined in linux_input.
-MSC_SCAN_BTN_LEFT = 90001
-MSC_SCAN_BTN_RIGHT = 90002
-MSC_SCAN_BTN_MIDDLE = 90003
-
-
-class InputEventRecorderError(Exception):
- """An exception class for input_event_recorder module."""
- pass
-
-
-class Event(object):
- """An event class based on evtest constructed from an evtest event.
-
- An ordinary event looks like:
- Event: time 133082.748019, type 3 (EV_ABS), code 0 (ABS_X), value 316
-
- A SYN_REPORT event looks like:
- Event: time 10788.289613, -------------- SYN_REPORT ------------
-
- """
-
- def __init__(self, type=0, code=0, value=0):
- """Construction of an input event.
-
- @param type: the event type
- @param code: the event code
- @param value: the event value
-
- """
- self.type = type
- self.code = code
- self.value= value
-
-
- @staticmethod
- def from_string(ev_string):
- """Convert an event string to an event object.
-
- @param ev_string: an event string.
-
- @returns: an event object if the event string conforms to
- event pattern format. None otherwise.
-
- """
- # Get the pattern of an ordinary event
- ev_pattern_time = r'Event:\s*time\s*(\d+\.\d+)'
- ev_pattern_type = r'type\s*(\d+)\s*\(\w+\)'
- ev_pattern_code = r'code\s*(\d+)\s*\(\w+\)'
- ev_pattern_value = r'value\s*(-?\d+)'
- ev_sep = r',\s*'
- ev_pattern_str = ev_sep.join([ev_pattern_time,
- ev_pattern_type,
- ev_pattern_code,
- ev_pattern_value])
- ev_pattern = re.compile(ev_pattern_str, re.I)
-
- # Get the pattern of the SYN_REPORT event
- ev_pattern_type_SYN_REPORT = r'-+\s*SYN_REPORT\s-+'
- ev_pattern_SYN_REPORT_str = ev_sep.join([ev_pattern_time,
- ev_pattern_type_SYN_REPORT])
- ev_pattern_SYN_REPORT = re.compile(ev_pattern_SYN_REPORT_str, re.I)
-
- # Check if it is a SYN event.
- result = ev_pattern_SYN_REPORT.search(ev_string)
- if result:
- return Event(EV_SYN, SYN_REPORT, 0)
- else:
- # Check if it is a regular event.
- result = ev_pattern.search(ev_string)
- if result:
- ev_type = int(result.group(2))
- ev_code = int(result.group(3))
- ev_value = int(result.group(4))
- return Event(ev_type, ev_code, ev_value)
- else:
- return None
-
-
- def is_syn(self):
- """Determine if the event is a SYN report event.
-
- @returns: True if it is a SYN report event. False otherwise.
-
- """
- return self.type == EV_SYN and self.code == SYN_REPORT
-
-
- def value_tuple(self):
- """A tuple of the event type, code, and value.
-
- @returns: the tuple of the event type, code, and value.
-
- """
- return (self.type, self.code, self.value)
-
-
- def __eq__(self, other):
- """determine if two events are equal.
-
- @param line: an event string line.
-
- @returns: True if two events are equal. False otherwise.
-
- """
- return (self.type == other.type and
- self.code == other.code and
- self.value == other.value)
-
-
- def __str__(self):
- """A string representation of the event.
-
- @returns: a string representation of the event.
-
- """
- return '%d %d %d' % (self.type, self.code, self.value)
-
-
-class InputEventRecorder(object):
- """An input event recorder.
-
- Refer to recording_example() below about how to record input events.
-
- """
-
- INPUT_DEVICE_INFO_FILE = '/proc/bus/input/devices'
- SELECT_TIMEOUT_SECS = 1
-
- def __init__(self, device_name, uniq):
- """Construction of input event recorder.
-
- @param device_name: the device name of the input device node to record.
- @param uniq: Unique address of input device (None if not used)
-
- """
- self.device_name = device_name
- self.uniq = uniq
- self.device_node = self.get_device_node_by_name(device_name, uniq)
- if self.device_node is None:
- err_msg = 'Failed to find the device node of %s' % device_name
- raise InputEventRecorderError(err_msg)
- self._recording_thread = None
- self._stop_recording_thread_event = threading.Event()
- self.tmp_file = '/tmp/evtest.dat'
- self.events = []
-
-
- def get_device_node_by_name(self, device_name, uniq):
- """Get the input device node by name.
-
- Example of a RN-42 emulated mouse device information looks like
-
- I: Bus=0005 Vendor=0000 Product=0000 Version=0000
- N: Name="RNBT-A96F"
- P: Phys=6c:29:95:1a:b8:18
- S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/bluetooth/hci0/hci0:512:29/0005:0000:0000.0004/input/input15
- U: Uniq=00:06:66:75:a9:6f
- H: Handlers=event12
- B: PROP=0
- B: EV=17
- B: KEY=70000 0 0 0 0
- B: REL=103
- B: MSC=10
-
- Each group of input devices is separated by an empty line.
-
- @param device_name: the device name of the target input device node.
- @param uniq: Unique address of the device. None if unused.
-
- @returns: the corresponding device node of the device.
-
- """
- device_node = None
- device_found = None
- event_number = None
- uniq_found = None
- uniq = uniq.lower() if uniq else None
-
- entry_pattern = re.compile('^[A-Z]: ')
- device_pattern = re.compile('N: Name=.*%s' % device_name, re.I)
- event_number_pattern = re.compile('H: Handlers=.*event(\d*)', re.I)
- uniq_pattern = re.compile('U: Uniq=([a-zA-Z0-9:]+)')
-
- with open(self.INPUT_DEVICE_INFO_FILE) as info:
- for line in info:
- line = line.rstrip('\n')
-
- if not entry_pattern.search(line):
- device_found = None
- event_number = None
- uniq_found = None
- elif device_found:
- # Check if this is an event line
- find_event = event_number_pattern.search(line)
- if find_event:
- event_number = int(find_event.group(1))
-
- # Check if this a uniq line
- find_uniq = uniq_pattern.search(line)
- if find_uniq:
- uniq_found = find_uniq.group(1).lower()
-
- # If uniq matches expectations, we found the device node
- if event_number and (not uniq or uniq_found == uniq):
- device_node = '/dev/input/event%d' % event_number
- break
-
- else:
- device_found = device_pattern.search(line)
-
- return device_node
-
-
- def record(self):
- """Record input events."""
- logging.info('Recording input events of %s.', self.device_node)
- cmd = 'evtest %s' % self.device_node
- recorder = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- shell=True)
- with open(self.tmp_file, 'w') as output_f:
- while True:
- read_list, _, _ = select.select(
- [recorder.stdout], [], [], 1)
- if read_list:
- line = recorder.stdout.readline()
- output_f.write(line)
- ev = Event.from_string(line)
- if ev:
- self.events.append(ev.value_tuple())
- elif self._stop_recording_thread_event.is_set():
- self._stop_recording_thread_event.clear()
- break
-
- recorder.terminate()
-
-
- def start(self):
- """Start the recording thread."""
- logging.info('Start recording thread.')
- self._recording_thread = threading.Thread(target=self.record)
- self._recording_thread.start()
-
-
- def stop(self):
- """Stop the recording thread."""
- logging.info('Stop recording thread.')
- self._stop_recording_thread_event.set()
- self._recording_thread.join()
-
-
- def clear_events(self):
- """Clear the event list."""
- self.events = []
-
-
- def get_events(self):
- """Get the event list.
-
- @returns: the event list.
- """
- return self.events
-
-
-SYN_EVENT = Event(EV_SYN, SYN_REPORT, 0)
-MSC_SCAN_BTN_EVENT = {'LEFT': Event(EV_MSC, MSC_SCAN, MSC_SCAN_BTN_LEFT),
- 'RIGHT': Event(EV_MSC, MSC_SCAN, MSC_SCAN_BTN_RIGHT),
- 'MIDDLE': Event(EV_MSC, MSC_SCAN, MSC_SCAN_BTN_MIDDLE)}
-
-
-def recording_example():
- """Example code for capturing input events on a Samus.
-
- For a quick swipe, it outputs events in numeric format:
-
- (3, 57, 9)
- (3, 53, 641)
- (3, 54, 268)
- (3, 58, 60)
- (3, 48, 88)
- (1, 330, 1)
- (1, 325, 1)
- (3, 0, 641)
- (3, 1, 268)
- (3, 24, 60)
- (0, 0, 0)
- (3, 53, 595)
- (3, 54, 288)
- (3, 0, 595)
- (3, 1, 288)
- (0, 0, 0)
- (3, 57, -1)
- (1, 330, 0)
- (1, 325, 0)
- (3, 24, 0)
- (0, 0, 0)
-
- The above events in corresponding evtest text format are:
-
- Event: time .782950, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 9
- Event: time .782950, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 641
- Event: time .782950, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 268
- Event: time .782950, type 3 (EV_ABS), code 58 (ABS_MT_PRESSURE), value 60
- Event: time .782950, type 3 (EV_ABS), code 59 (?), value 0
- Event: time .782950, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 88
- Event: time .782950, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
- Event: time .782950, type 1 (EV_KEY), code 325 (BTN_TOOL_FINGER), value 1
- Event: time .782950, type 3 (EV_ABS), code 0 (ABS_X), value 641
- Event: time .782950, type 3 (EV_ABS), code 1 (ABS_Y), value 268
- Event: time .782950, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 60
- Event: time .782950, -------------- SYN_REPORT ------------
- Event: time .798273, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 595
- Event: time .798273, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 288
- Event: time .798273, type 3 (EV_ABS), code 0 (ABS_X), value 595
- Event: time .798273, type 3 (EV_ABS), code 1 (ABS_Y), value 288
- Event: time .798273, -------------- SYN_REPORT ------------
- Event: time .821437, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value -1
- Event: time .821437, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
- Event: time .821437, type 1 (EV_KEY), code 325 (BTN_TOOL_FINGER), value 0
- Event: time .821437, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 0
- Event: time .821437, -------------- SYN_REPORT ------------
- """
- device_name = 'Atmel maXTouch Touchpad'
- recorder = InputEventRecorder(device_name)
- print('Samus touchpad device name:', recorder.device_name)
- print('Samus touchpad device node:', recorder.device_node)
- print('Please make gestures on the touchpad for up to 5 seconds.')
- recorder.clear_events()
- recorder.start()
- time.sleep(5)
- recorder.stop()
- for e in recorder.get_events():
- print(e)
-
-
-if __name__ == '__main__':
- recording_example()
diff --git a/client/bin/input/linux_input.py b/client/bin/input/linux_input.py
deleted file mode 100644
index 2dd876d..0000000
--- a/client/bin/input/linux_input.py
+++ /dev/null
@@ -1,1337 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2011 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.
-
-# Description:
-#
-# Python version of include/linux/input.h
-# as of kernel v2.6.39
-
-from __future__ import division
-from __future__ import print_function
-from six.moves import range
-
-# Try to import from the autotest_lib structure. If it fails try the default.
-# If this script was run outside of autotest the "except" would be the flow.
-# If run within, the "try" is the flow.
-try:
- from autotest_lib.client.bin.input.linux_ioctl import *
-except ImportError:
- from linux_ioctl import *
-
-# The event structure itself
-# struct input_event {
-# struct timeval time;
-# __u16 type;
-# __u16 code;
-# __s32 value;
-# };
-#
-# struct timeval {
-# __kernel_time_t tv_sec; /* seconds */
-# __kernel_suseconds_t tv_usec; /* microseconds */
-# };
-input_event_t = 'LLHHi'
-
-
-# Protocol version.
-EV_VERSION = 0x010001
-
-# IOCTLs (0x00 - 0x7f)
-
-# struct input_id {
-# __u16 bustype;
-# __u16 vendor;
-# __u16 product;
-# __u16 version;
-# };
-input_id_t = 'HHHH'
-
-# struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
-# @value: latest reported value for the axis.
-# @minimum: specifies minimum value for the axis.
-# @maximum: specifies maximum value for the axis.
-# @fuzz: specifies fuzz value used to filter noise from the event stream.
-# @flat: values within this value are reported as 0.
-# @resolution: specifies resolution for the values reported for the axis.
-#
-# Note that input core does not clamp reported values to the
-# [minimum, maximum] limits, such task is left to userspace.
-#
-# Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
-# units per millimeter (units/mm), resolution for rotational axes
-# (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
-#
-# struct input_absinfo {
-# __s32 value;
-# __s32 minimum;
-# __s32 maximum;
-# __s32 fuzz;
-# __s32 flat;
-# __s32 resolution;
-# };
-input_absinfo_t = 'iiiiii'
-
-# struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
-# @scancode: scancode represented in machine-endian form.
-# @len: length of the scancode that resides in @scancode buffer.
-# @index: index in the keymap, may be used instead of scancode
-# @flags: allows to specify how kernel should handle the request. For
-# example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel
-# should perform lookup in keymap by @index instead of @scancode
-# @keycode: key code assigned to this scancode
-#
-# The structure is used to retrieve and modify keymap data. Users have
-# option of performing lookup either by @scancode itself or by @index
-# in keymap entry. EVIOCGKEYCODE will also return scancode or index
-# (depending on which element was used to perform lookup).
-#
-# struct input_keymap_entry {
-# __u8 flags;
-# __u8 len;
-# __u16 index;
-# __u32 keycode;
-# __u8 scancode[32];
-# };
-input_keymap_entry_t = 'BBHI32B'
-
-EVIOCGVERSION = IOR('E', 0x01, 'i') # get driver version
-EVIOCGID = IOR('E', 0x02, input_id_t) # get device ID
-EVIOCGREP = IOR('E', 0x03, '2I') # get repeat settings
-EVIOCSREP = IOW('E', 0x03, '2I') # set repeat settings
-
-EVIOCGKEYCODE = IOR('E', 0x04, '2I') # get keycode
-EVIOCGKEYCODE_V2 = IOR('E', 0x04, input_keymap_entry_t)
-EVIOCSKEYCODE = IOW('E', 0x04, '2I') # set keycode
-EVIOCSKEYCODE_V2 = IOW('E', 0x04, input_keymap_entry_t)
-
-def EVIOCGNAME(length):
- return IOC(IOC_READ, 'E', 0x06, length) # get device name
-
-def EVIOCGPHYS(length):
- return IOC(IOC_READ, 'E', 0x07, length) # get physical location
-
-def EVIOCGUNIQ(length):
- return IOC(IOC_READ, 'E', 0x08, length) # get unique identifier
-
-def EVIOCGPROP(length):
- return IOC(IOC_READ, 'E', 0x09, length) # get device properties
-
-def EVIOCGMTSLOTS(length):
- return IOC(IOC_READ, 'E', 0x0a, length) # get mt slot values
-
-def EVIOCGKEY(length):
- return IOC(IOC_READ, 'E', 0x18, length) # get global key state
-
-def EVIOCGLED(length):
- return IOC(IOC_READ, 'E', 0x19, length) # get all LEDs
-
-def EVIOCGSND(length):
- return IOC(IOC_READ, 'E', 0x1a, length) # get all sounds status
-
-def EVIOCGSW(length):
- return IOC(IOC_READ, 'E', 0x1b, length) # get all switch states
-
-def EVIOCGBIT(ev,length):
- return IOC(IOC_READ, 'E', 0x20 + ev, length) # get event bits
-
-def EVIOCGABS(axis):
- return IOR('E', 0x40 + axis, input_absinfo_t) # get abs value/limits
-
-def EVIOCSABS(axis):
- return IOW('E', 0xc0 + axis, input_absinfo_t) # set abs value/limits
-
-# send a force effect to a force feedback device
-""" TODO: Support force feedback. """
-
-
-#EVIOCSFF = IOW('E', 0x80, ff_effect_t)
-# Erase a force effect
-EVIOCRMFF = IOW('E', 0x81, 'i')
-# Report number of effects playable at the same time
-EVIOCGEFFECTS = IOR('E', 0x84, 'i')
-# Grab/Release device
-EVIOCGRAB = IOW('E', 0x90, 'i')
-
-# Device properties and quirks
-INPUT_PROP_POINTER = 0x00 # needs a pointer
-INPUT_PROP_DIRECT = 0x01 # direct input devices
-INPUT_PROP_BUTTONPAD = 0x02 # has button(s) under pad
-INPUT_PROP_SEMI_MT = 0x03 # touch rectangle only
-
-INPUT_PROP_MAX = 0x1f
-INPUT_PROP_CNT = (INPUT_PROP_MAX + 1)
-
-# Event types
-EV_SYN = 0x00
-EV_KEY = 0x01
-EV_REL = 0x02
-EV_ABS = 0x03
-EV_MSC = 0x04
-EV_SW = 0x05
-EV_LED = 0x11
-EV_SND = 0x12
-EV_REP = 0x14
-EV_FF = 0x15
-EV_PWR = 0x16
-EV_FF_STATUS = 0x17
-EV_MAX = 0x1f
-EV_CNT = (EV_MAX + 1)
-
-# Synchronization events.
-
-SYN_REPORT = 0
-SYN_CONFIG = 1
-SYN_MT_REPORT = 2
-SYN_DROPPED = 3
-
-"""
- * Keys and buttons
- *
- * Most of the keys/buttons are modeled after USB HUT 1.12
- * (see http://www.usb.org/developers/hidpage).
- * Abbreviations in the comments:
- * AC - Application Control
- * AL - Application Launch Button
- * SC - System Control
-"""
-
-KEY_RESERVED = 0
-KEY_ESC = 1
-KEY_1 = 2
-KEY_2 = 3
-KEY_3 = 4
-KEY_4 = 5
-KEY_5 = 6
-KEY_6 = 7
-KEY_7 = 8
-KEY_8 = 9
-KEY_9 = 10
-KEY_0 = 11
-KEY_MINUS = 12
-KEY_EQUAL = 13
-KEY_BACKSPACE = 14
-KEY_TAB = 15
-KEY_Q = 16
-KEY_W = 17
-KEY_E = 18
-KEY_R = 19
-KEY_T = 20
-KEY_Y = 21
-KEY_U = 22
-KEY_I = 23
-KEY_O = 24
-KEY_P = 25
-KEY_LEFTBRACE = 26
-KEY_RIGHTBRACE = 27
-KEY_ENTER = 28
-KEY_LEFTCTRL = 29
-KEY_A = 30
-KEY_S = 31
-KEY_D = 32
-KEY_F = 33
-KEY_G = 34
-KEY_H = 35
-KEY_J = 36
-KEY_K = 37
-KEY_L = 38
-KEY_SEMICOLON = 39
-KEY_APOSTROPHE = 40
-KEY_GRAVE = 41
-KEY_LEFTSHIFT = 42
-KEY_BACKSLASH = 43
-KEY_Z = 44
-KEY_X = 45
-KEY_C = 46
-KEY_V = 47
-KEY_B = 48
-KEY_N = 49
-KEY_M = 50
-KEY_COMMA = 51
-KEY_DOT = 52
-KEY_SLASH = 53
-KEY_RIGHTSHIFT = 54
-KEY_KPASTERISK = 55
-KEY_LEFTALT = 56
-KEY_SPACE = 57
-KEY_CAPSLOCK = 58
-KEY_F1 = 59
-KEY_F2 = 60
-KEY_F3 = 61
-KEY_F4 = 62
-KEY_F5 = 63
-KEY_F6 = 64
-KEY_F7 = 65
-KEY_F8 = 66
-KEY_F9 = 67
-KEY_F10 = 68
-KEY_NUMLOCK = 69
-KEY_SCROLLLOCK = 70
-KEY_KP7 = 71
-KEY_KP8 = 72
-KEY_KP9 = 73
-KEY_KPMINUS = 74
-KEY_KP4 = 75
-KEY_KP5 = 76
-KEY_KP6 = 77
-KEY_KPPLUS = 78
-KEY_KP1 = 79
-KEY_KP2 = 80
-KEY_KP3 = 81
-KEY_KP0 = 82
-KEY_KPDOT = 83
-
-KEY_ZENKAKUHANKAKU = 85
-KEY_102ND = 86
-KEY_F11 = 87
-KEY_F12 = 88
-KEY_RO = 89
-KEY_KATAKANA = 90
-KEY_HIRAGANA = 91
-KEY_HENKAN = 92
-KEY_KATAKANAHIRAGANA = 93
-KEY_MUHENKAN = 94
-KEY_KPJPCOMMA = 95
-KEY_KPENTER = 96
-KEY_RIGHTCTRL = 97
-KEY_KPSLASH = 98
-KEY_SYSRQ = 99
-KEY_RIGHTALT = 100
-KEY_LINEFEED = 101
-KEY_HOME = 102
-KEY_UP = 103
-KEY_PAGEUP = 104
-KEY_LEFT = 105
-KEY_RIGHT = 106
-KEY_END = 107
-KEY_DOWN = 108
-KEY_PAGEDOWN = 109
-KEY_INSERT = 110
-KEY_DELETE = 111
-KEY_MACRO = 112
-KEY_MUTE = 113
-KEY_VOLUMEDOWN = 114
-KEY_VOLUMEUP = 115
-KEY_POWER = 116 # SC System Power Down
-KEY_KPEQUAL = 117
-KEY_KPPLUSMINUS = 118
-KEY_PAUSE = 119
-KEY_SCALE = 120 # AL Compiz Scale (Expose)
-
-KEY_KPCOMMA = 121
-KEY_HANGEUL = 122
-KEY_HANGUEL = KEY_HANGEUL
-KEY_HANJA = 123
-KEY_YEN = 124
-KEY_LEFTMETA = 125
-KEY_RIGHTMETA = 126
-KEY_COMPOSE = 127
-
-KEY_STOP = 128 # AC Stop
-KEY_AGAIN = 129
-KEY_PROPS = 130 # AC Properties
-KEY_UNDO = 131 # AC Undo
-KEY_FRONT = 132
-KEY_COPY = 133 # AC Copy
-KEY_OPEN = 134 # AC Open
-KEY_PASTE = 135 # AC Paste
-KEY_FIND = 136 # AC Search
-KEY_CUT = 137 # AC Cut
-KEY_HELP = 138 # AL Integrated Help Center
-KEY_MENU = 139 # Menu (show menu)
-KEY_CALC = 140 # AL Calculator
-KEY_SETUP = 141
-KEY_SLEEP = 142 # SC System Sleep
-KEY_WAKEUP = 143 # System Wake Up
-KEY_FILE = 144 # AL Local Machine Browser
-KEY_SENDFILE = 145
-KEY_DELETEFILE = 146
-KEY_XFER = 147
-KEY_PROG1 = 148
-KEY_PROG2 = 149
-KEY_WWW = 150 # AL Internet Browser
-KEY_MSDOS = 151
-KEY_COFFEE = 152 # AL Terminal Lock/Screensaver
-KEY_SCREENLOCK = KEY_COFFEE
-KEY_DIRECTION = 153
-KEY_CYCLEWINDOWS = 154
-KEY_MAIL = 155
-KEY_BOOKMARKS = 156 # AC Bookmarks
-KEY_COMPUTER = 157
-KEY_BACK = 158 # AC Back
-KEY_FORWARD = 159 # AC Forward
-KEY_CLOSECD = 160
-KEY_EJECTCD = 161
-KEY_EJECTCLOSECD = 162
-KEY_NEXTSONG = 163
-KEY_PLAYPAUSE = 164
-KEY_PREVIOUSSONG = 165
-KEY_STOPCD = 166
-KEY_RECORD = 167
-KEY_REWIND = 168
-KEY_PHONE = 169 # Media Select Telephone
-KEY_ISO = 170
-KEY_CONFIG = 171 # AL Consumer Control Configuration
-KEY_HOMEPAGE = 172 # AC Home
-KEY_REFRESH = 173 # AC Refresh
-KEY_EXIT = 174 # AC Exit
-KEY_MOVE = 175
-KEY_EDIT = 176
-KEY_SCROLLUP = 177
-KEY_SCROLLDOWN = 178
-KEY_KPLEFTPAREN = 179
-KEY_KPRIGHTPAREN = 180
-KEY_NEW = 181 # AC New
-KEY_REDO = 182 # AC Redo/Repeat
-
-KEY_F13 = 183
-KEY_F14 = 184
-KEY_F15 = 185
-KEY_F16 = 186
-KEY_F17 = 187
-KEY_F18 = 188
-KEY_F19 = 189
-KEY_F20 = 190
-KEY_F21 = 191
-KEY_F22 = 192
-KEY_F23 = 193
-KEY_F24 = 194
-
-KEY_PLAYCD = 200
-KEY_PAUSECD = 201
-KEY_PROG3 = 202
-KEY_PROG4 = 203
-KEY_DASHBOARD = 204 # AL Dashboard
-KEY_SUSPEND = 205
-KEY_CLOSE = 206 # AC Close
-KEY_PLAY = 207
-KEY_FASTFORWARD = 208
-KEY_BASSBOOST = 209
-KEY_PRINT = 210 # AC Print
-KEY_HP = 211
-KEY_CAMERA = 212
-KEY_SOUND = 213
-KEY_QUESTION = 214
-KEY_EMAIL = 215
-KEY_CHAT = 216
-KEY_SEARCH = 217
-KEY_CONNECT = 218
-KEY_FINANCE = 219 #AL Checkbook/Finance
-KEY_SPORT = 220
-KEY_SHOP = 221
-KEY_ALTERASE = 222
-KEY_CANCEL = 223 # AC Cancel
-KEY_BRIGHTNESSDOWN = 224
-KEY_BRIGHTNESSUP = 225
-KEY_MEDIA = 226
-
-KEY_SWITCHVIDEOMODE = 227 # Cycle between available video
- # outputs (Monitor/LCD/TV-out/etc)
-KEY_KBDILLUMTOGGLE = 228
-KEY_KBDILLUMDOWN = 229
-KEY_KBDILLUMUP = 230
-
-KEY_SEND = 231 # AC Send
-KEY_REPLY = 232 # AC Reply
-KEY_FORWARDMAIL = 233 # AC Forward Msg
-KEY_SAVE = 234 # AC Save
-KEY_DOCUMENTS = 235
-
-KEY_BATTERY = 236
-
-KEY_BLUETOOTH = 237
-KEY_WLAN = 238
-KEY_UWB = 239
-
-KEY_UNKNOWN = 240
-
-KEY_VIDEO_NEXT = 241 # drive next video source
-KEY_VIDEO_PREV = 242 # drive previous video source
-KEY_BRIGHTNESS_CYCLE = 243 # brightness up, after max is min
-KEY_BRIGHTNESS_ZERO = 244 # brightness off, use ambient
-KEY_DISPLAY_OFF = 245 # display device to off state
-
-KEY_WIMAX = 246
-KEY_RFKILL = 247 # Key that controls all radios
-
-# Code 255 is reserved for special needs of AT keyboard driver
-
-BTN_MISC = 0x100
-BTN_0 = 0x100
-BTN_1 = 0x101
-BTN_2 = 0x102
-BTN_3 = 0x103
-BTN_4 = 0x104
-BTN_5 = 0x105
-BTN_6 = 0x106
-BTN_7 = 0x107
-BTN_8 = 0x108
-BTN_9 = 0x109
-
-BTN_MOUSE = 0x110
-BTN_LEFT = 0x110
-BTN_RIGHT = 0x111
-BTN_MIDDLE = 0x112
-BTN_SIDE = 0x113
-BTN_EXTRA = 0x114
-BTN_FORWARD = 0x115
-BTN_BACK = 0x116
-BTN_TASK = 0x117
-
-BTN_JOYSTICK = 0x120
-BTN_TRIGGER = 0x120
-BTN_THUMB = 0x121
-BTN_THUMB2 = 0x122
-BTN_TOP = 0x123
-BTN_TOP2 = 0x124
-BTN_PINKIE = 0x125
-BTN_BASE = 0x126
-BTN_BASE2 = 0x127
-BTN_BASE3 = 0x128
-BTN_BASE4 = 0x129
-BTN_BASE5 = 0x12a
-BTN_BASE6 = 0x12b
-BTN_DEAD = 0x12f
-
-BTN_GAMEPAD = 0x130
-BTN_A = 0x130
-BTN_B = 0x131
-BTN_C = 0x132
-BTN_X = 0x133
-BTN_Y = 0x134
-BTN_Z = 0x135
-BTN_TL = 0x136
-BTN_TR = 0x137
-BTN_TL2 = 0x138
-BTN_TR2 = 0x139
-BTN_SELECT = 0x13a
-BTN_START = 0x13b
-BTN_MODE = 0x13c
-BTN_THUMBL = 0x13d
-BTN_THUMBR = 0x13e
-
-BTN_DIGI = 0x140
-BTN_TOOL_PEN = 0x140
-BTN_TOOL_RUBBER = 0x141
-BTN_TOOL_BRUSH = 0x142
-BTN_TOOL_PENCIL = 0x143
-BTN_TOOL_AIRBRUSH = 0x144
-BTN_TOOL_FINGER = 0x145
-BTN_TOOL_MOUSE = 0x146
-BTN_TOOL_LENS = 0x147
-BTN_TOOL_QUINTTAP = 0x148 # Five fingers on trackpad
-BTN_TOUCH = 0x14a
-BTN_STYLUS = 0x14b
-BTN_STYLUS2 = 0x14c
-BTN_TOOL_DOUBLETAP = 0x14d
-BTN_TOOL_TRIPLETAP = 0x14e
-BTN_TOOL_QUADTAP = 0x14f # Four fingers on trackpad
-
-BTN_WHEEL = 0x150
-BTN_GEAR_DOWN = 0x150
-BTN_GEAR_UP = 0x151
-
-
-KEY_OK = 0x160
-KEY_SELECT = 0x161
-KEY_GOTO = 0x162
-KEY_CLEAR = 0x163
-KEY_POWER2 = 0x164
-KEY_OPTION = 0x165
-KEY_INFO = 0x166 #AL OEM Features/Tips/Tutorial
-KEY_TIME = 0x167
-KEY_VENDOR = 0x168
-KEY_ARCHIVE = 0x169
-KEY_PROGRAM = 0x16a # Media Select Program Guide
-KEY_CHANNEL = 0x16b
-KEY_FAVORITES = 0x16c
-KEY_EPG = 0x16d
-KEY_PVR = 0x16e # Media Select Home
-KEY_MHP = 0x16f
-KEY_LANGUAGE = 0x170
-KEY_TITLE = 0x171
-KEY_SUBTITLE = 0x172
-KEY_ANGLE = 0x173
-KEY_ZOOM = 0x174
-KEY_MODE = 0x175
-KEY_KEYBOARD = 0x176
-KEY_SCREEN = 0x177
-KEY_PC = 0x178 # Media Select Computer
-KEY_TV = 0x179 # Media Select TV
-KEY_TV2 = 0x17a # Media Select Cable
-KEY_VCR = 0x17b # Media Select VCR
-KEY_VCR2 = 0x17c # VCR Plus
-KEY_SAT = 0x17d # Media Select Satellite
-KEY_SAT2 = 0x17e
-KEY_CD = 0x17f # Media Select CD
-KEY_TAPE = 0x180 # Select Tape
-KEY_RADIO = 0x181
-KEY_TUNER = 0x182 # Media Select Tuner
-KEY_PLAYER = 0x183
-KEY_TEXT = 0x184
-KEY_DVD = 0x185 # Media Select DVD
-KEY_AUX = 0x186
-KEY_MP3 = 0x187
-KEY_AUDIO = 0x188 # AL Audio Browser
-KEY_VIDEO = 0x189 # AL Movie Browser
-KEY_DIRECTORY = 0x18a
-KEY_LIST = 0x18b
-KEY_MEMO = 0x18 # Media Select Messages
-KEY_CALENDAR = 0x18d
-KEY_RED = 0x18e
-KEY_GREEN = 0x18f
-KEY_YELLOW = 0x190
-KEY_BLUE = 0x191
-KEY_CHANNELUP = 0x192 # Channel Increment
-KEY_CHANNELDOWN = 0x193 # Channel Decrement
-KEY_FIRST = 0x194
-KEY_LAST = 0x195 # Recall Last
-KEY_AB = 0x196
-KEY_NEXT = 0x197
-KEY_RESTART = 0x198
-KEY_SLOW = 0x199
-KEY_SHUFFLE = 0x19a
-KEY_BREAK = 0x19b
-KEY_PREVIOUS = 0x19c
-KEY_DIGITS = 0x19d
-KEY_TEEN = 0x19e
-KEY_TWEN = 0x19f
-KEY_VIDEOPHONE = 0x1a0 # Media Select Video Phone
-KEY_GAMES = 0x1a1 # Media Select Games
-KEY_ZOOMIN = 0x1a2 # AC Zoom In
-KEY_ZOOMOUT = 0x1a3 # AC Zoom Out
-KEY_ZOOMRESET = 0x1a4 # AC Zoom
-KEY_WORDPROCESSOR = 0x1a5 # AL Word Processor
-KEY_EDITOR = 0x1a6 # AL Text Editor
-KEY_SPREADSHEET = 0x1a7 # AL Spreadsheet
-KEY_GRAPHICSEDITOR = 0x1a8 # AL Graphics Editor
-KEY_PRESENTATION = 0x1a9 # AL Presentation App
-KEY_DATABASE = 0x1aa # AL Database App
-KEY_NEWS = 0x1ab # AL Newsreader
-KEY_VOICEMAIL = 0x1ac # AL Voicemail
-KEY_ADDRESSBOOK = 0x1ad # AL Contacts/Address Book
-KEY_MESSENGER = 0x1ae # AL Instant Messaging
-KEY_DISPLAYTOGGLE = 0x1af # Turn display (LCD) on and off
-KEY_SPELLCHECK = 0x1b0 # AL Spell Check
-KEY_LOGOFF = 0x1b1 #* AL Logoff
-
-KEY_DOLLAR = 0x1b2
-KEY_EURO = 0x1b3
-
-KEY_FRAMEBACK = 0x1b4 # Consumer - transport controls
-KEY_FRAMEFORWARD = 0x1b5
-KEY_CONTEXT_MENU = 0x1b6 # GenDesc - system context menu
-KEY_MEDIA_REPEAT = 0x1b7 # Consumer - transport control
-KEY_10CHANNELSUP = 0x1b8 # 10 channels up (10+)
-KEY_10CHANNELSDOWN = 0x1b9 # 10 channels down (10-)
-KEY_IMAGES = 0x1ba # AL Image Browser
-
-KEY_DEL_EOL = 0x1c0
-KEY_DEL_EOS = 0x1c1
-KEY_INS_LINE = 0x1c2
-KEY_DEL_LINE = 0x1c3
-
-KEY_FN = 0x1d0
-KEY_FN_ESC = 0x1d1
-KEY_FN_F1 = 0x1d2
-KEY_FN_F2 = 0x1d3
-KEY_FN_F3 = 0x1d4
-KEY_FN_F4 = 0x1d5
-KEY_FN_F5 = 0x1d6
-KEY_FN_F6 = 0x1d7
-KEY_FN_F7 = 0x1d8
-KEY_FN_F8 = 0x1d9
-KEY_FN_F9 = 0x1da
-KEY_FN_F10 = 0x1db
-KEY_FN_F11 = 0x1dc
-KEY_FN_F12 = 0x1dd
-KEY_FN_1 = 0x1de
-KEY_FN_2 = 0x1df
-KEY_FN_D = 0x1e0
-KEY_FN_E = 0x1e1
-KEY_FN_F = 0x1e2
-KEY_FN_S = 0x1e3
-KEY_FN_B = 0x1e4
-
-KEY_BRL_DOT1 = 0x1f1
-KEY_BRL_DOT2 = 0x1f2
-KEY_BRL_DOT3 = 0x1f3
-KEY_BRL_DOT4 = 0x1f4
-KEY_BRL_DOT5 = 0x1f5
-KEY_BRL_DOT6 = 0x1f6
-KEY_BRL_DOT7 = 0x1f7
-KEY_BRL_DOT8 = 0x1f8
-KEY_BRL_DOT9 = 0x1f9
-KEY_BRL_DOT10 = 0x1fa
-
-KEY_NUMERIC_0 = 0x200 # used by phones, remote controls,
-KEY_NUMERIC_1 = 0x201 # and other keypads
-KEY_NUMERIC_2 = 0x202
-KEY_NUMERIC_3 = 0x203
-KEY_NUMERIC_4 = 0x204
-KEY_NUMERIC_5 = 0x205
-KEY_NUMERIC_6 = 0x206
-KEY_NUMERIC_7 = 0x207
-KEY_NUMERIC_8 = 0x208
-KEY_NUMERIC_9 = 0x209
-KEY_NUMERIC_STAR = 0x20a
-KEY_NUMERIC_POUND = 0x20b
-
-KEY_CAMERA_FOCUS = 0x210
-KEY_WPS_BUTTON = 0x211 # WiFi Protected Setup key
-
-KEY_TOUCHPAD_TOGGLE = 0x212 # Request switch touchpad on or off
-KEY_TOUCHPAD_ON = 0x213
-KEY_TOUCHPAD_OFF = 0x214
-
-KEY_CAMERA_ZOOMIN = 0x215
-KEY_CAMERA_ZOOMOUT = 0x216
-KEY_CAMERA_UP = 0x217
-KEY_CAMERA_DOWN = 0x218
-KEY_CAMERA_LEFT = 0x219
-KEY_CAMERA_RIGHT = 0x21a
-
-BTN_TRIGGER_HAPPY = 0x2c0
-BTN_TRIGGER_HAPPY1 = 0x2c0
-BTN_TRIGGER_HAPPY2 = 0x2c1
-BTN_TRIGGER_HAPPY3 = 0x2c2
-BTN_TRIGGER_HAPPY4 = 0x2c3
-BTN_TRIGGER_HAPPY5 = 0x2c4
-BTN_TRIGGER_HAPPY6 = 0x2c5
-BTN_TRIGGER_HAPPY7 = 0x2c6
-BTN_TRIGGER_HAPPY8 = 0x2c7
-BTN_TRIGGER_HAPPY9 = 0x2c8
-BTN_TRIGGER_HAPPY10 = 0x2c9
-BTN_TRIGGER_HAPPY11 = 0x2ca
-BTN_TRIGGER_HAPPY12 = 0x2cb
-BTN_TRIGGER_HAPPY13 = 0x2cc
-BTN_TRIGGER_HAPPY14 = 0x2cd
-BTN_TRIGGER_HAPPY15 = 0x2ce
-BTN_TRIGGER_HAPPY16 = 0x2cf
-BTN_TRIGGER_HAPPY17 = 0x2d0
-BTN_TRIGGER_HAPPY18 = 0x2d1
-BTN_TRIGGER_HAPPY19 = 0x2d2
-BTN_TRIGGER_HAPPY20 = 0x2d3
-BTN_TRIGGER_HAPPY21 = 0x2d4
-BTN_TRIGGER_HAPPY22 = 0x2d5
-BTN_TRIGGER_HAPPY23 = 0x2d6
-BTN_TRIGGER_HAPPY24 = 0x2d7
-BTN_TRIGGER_HAPPY25 = 0x2d8
-BTN_TRIGGER_HAPPY26 = 0x2d9
-BTN_TRIGGER_HAPPY27 = 0x2da
-BTN_TRIGGER_HAPPY28 = 0x2db
-BTN_TRIGGER_HAPPY29 = 0x2dc
-BTN_TRIGGER_HAPPY30 = 0x2dd
-BTN_TRIGGER_HAPPY31 = 0x2de
-BTN_TRIGGER_HAPPY32 = 0x2df
-BTN_TRIGGER_HAPPY33 = 0x2e0
-BTN_TRIGGER_HAPPY34 = 0x2e1
-BTN_TRIGGER_HAPPY35 = 0x2e2
-BTN_TRIGGER_HAPPY36 = 0x2e3
-BTN_TRIGGER_HAPPY37 = 0x2e4
-BTN_TRIGGER_HAPPY38 = 0x2e5
-BTN_TRIGGER_HAPPY39 = 0x2e6
-BTN_TRIGGER_HAPPY40 = 0x2e7
-
-
-# We avoid low common keys in module aliases so they don't get huge
-#KEY_MIN_INTERESTING = KEY_MUTE
-KEY_MAX = 0x2ff
-KEY_CNT = (KEY_MAX + 1)
-
-# Relative axes
-REL_X = 0x00
-REL_Y = 0x01
-REL_Z = 0x02
-REL_RX = 0x03
-REL_RY = 0x04
-REL_RZ = 0x05
-REL_HWHEEL = 0x06
-REL_DIAL = 0x07
-REL_WHEEL = 0x08
-REL_MISC = 0x09
-REL_RESERVED = 0x0a
-REL_WHEEL_HI_RES = 0x0b
-REL_HWHEEL_HI_RES = 0x0c
-REL_MAX = 0x0f
-REL_CNT = (REL_MAX + 1)
-
-# Absolute axes
-ABS_X = 0x00
-ABS_Y = 0x01
-ABS_Z = 0x02
-ABS_RX = 0x03
-ABS_RY = 0x04
-ABS_RZ = 0x05
-ABS_THROTTLE = 0x06
-ABS_RUDDER = 0x07
-ABS_WHEEL = 0x08
-ABS_GAS = 0x09
-ABS_BRAKE = 0x0a
-ABS_HAT0X = 0x10
-ABS_HAT0Y = 0x11
-ABS_HAT1X = 0x12
-ABS_HAT1Y = 0x13
-ABS_HAT2X = 0x14
-ABS_HAT2Y = 0x15
-ABS_HAT3X = 0x16
-ABS_HAT3Y = 0x17
-ABS_PRESSURE = 0x18
-ABS_DISTANCE = 0x19
-ABS_TILT_X = 0x1a
-ABS_TILT_Y = 0x1b
-ABS_TOOL_WIDTH = 0x1c
-
-ABS_VOLUME = 0x20
-
-ABS_MISC = 0x28
-
-ABS_MT_SLOT = 0x2f # MT slot being modified
-ABS_MT_TOUCH_MAJOR = 0x30 # Major axis of touching ellipse
-ABS_MT_TOUCH_MINOR = 0x31 # Minor axis (omit if circular)
-ABS_MT_WIDTH_MAJOR = 0x32 # Major axis of approaching ellipse
-ABS_MT_WIDTH_MINOR = 0x33 # Minor axis (omit if circular)
-ABS_MT_ORIENTATION = 0x34 # Ellipse orientation
-ABS_MT_POSITION_X = 0x35 # Center X ellipse position
-ABS_MT_POSITION_Y = 0x36 # Center Y ellipse position
-ABS_MT_TOOL_TYPE = 0x37 # Type of touching device
-ABS_MT_BLOB_ID = 0x38 # Group a set of packets as a blob
-ABS_MT_TRACKING_ID = 0x39 # Unique ID of initiated contact
-ABS_MT_PRESSURE = 0x3a # Pressure on contact area
-ABS_MT_DISTANCE = 0x3b # Contact hover distance
-
-ABS_MT_FIRST = ABS_MT_TOUCH_MAJOR
-ABS_MT_LAST = ABS_MT_DISTANCE
-ABS_MT_RANGE = list(range(ABS_MT_FIRST, ABS_MT_LAST+1))
-
-ABS_MAX = 0x3f
-ABS_CNT = (ABS_MAX + 1)
-
-# Switch events
-SW_LID = 0x00 # set = lid shut
-SW_TABLET_MODE = 0x01 # set = tablet mode
-SW_HEADPHONE_INSERT = 0x02 # set = inserted
-SW_RFKILL_ALL = 0x03 # rfkill main switch, type "any"
- # set = radio enabled
-SW_RADIO = SW_RFKILL_ALL # deprecated
-SW_MICROPHONE_INSERT = 0x04 # set = inserted
-SW_DOCK = 0x05 # set = plugged into dock
-SW_LINEOUT_INSERT = 0x06 # set = inserted
-SW_JACK_PHYSICAL_INSERT = 0x07 # set = mechanical switch set
-SW_VIDEOOUT_INSERT = 0x08 # set = inserted
-SW_CAMERA_LENS_COVER = 0x09 # set = lens covered
-SW_KEYPAD_SLIDE = 0x0a # set = keypad slide out
-SW_FRONT_PROXIMITY = 0x0b # set = front proximity sensor active
-SW_ROTATE_LOCK = 0x0c # set = rotate locked/disabled
-SW_MAX = 0x0f
-SW_CNT = (SW_MAX + 1)
-
-# Misc events
-MSC_SERIAL = 0x00
-MSC_PULSELED = 0x01
-MSC_GESTURE = 0x02
-MSC_RAW = 0x03
-MSC_SCAN = 0x04
-MSC_MAX = 0x07
-MSC_CNT = (MSC_MAX + 1)
-
-# LEDs
-LED_NUML = 0x00
-LED_CAPSL = 0x01
-LED_SCROLLL = 0x02
-LED_COMPOSE = 0x03
-LED_KANA = 0x04
-LED_SLEEP = 0x05
-LED_SUSPEND = 0x06
-LED_MUTE = 0x07
-LED_MISC = 0x08
-LED_MAIL = 0x09
-LED_CHARGING = 0x0a
-LED_MAX = 0x0f
-LED_CNT = (LED_MAX + 1)
-
-# Autorepeat values
-REP_DELAY = 0x00
-REP_PERIOD = 0x01
-REP_MAX = 0x01
-REP_CNT = (REP_MAX + 1)
-
-# Sounds
-SND_CLICK = 0x00
-SND_BELL = 0x01
-SND_TONE = 0x02
-SND_MAX = 0x07
-SND_CNT = (SND_MAX + 1)
-
-# IDs.
-ID_BUS = 0
-ID_VENDOR = 1
-ID_PRODUCT = 2
-ID_VERSION = 3
-
-BUS_PCI = 0x01
-BUS_ISAPNP = 0x02
-BUS_USB = 0x03
-BUS_HIL = 0x04
-BUS_BLUETOOTH = 0x05
-BUS_VIRTUAL = 0x06
-
-BUS_ISA = 0x10
-BUS_I8042 = 0x11
-BUS_XTKBD = 0x12
-BUS_RS232 = 0x13
-BUS_GAMEPORT = 0x14
-BUS_PARPORT = 0x15
-BUS_AMIGA = 0x16
-BUS_ADB = 0x17
-BUS_I2C = 0x18
-BUS_HOST = 0x19
-BUS_GSC = 0x1A
-BUS_ATARI = 0x1B
-BUS_SPI = 0x1C
-
-# MT_TOOL types
-MT_TOOL_FINGER = 0
-MT_TOOL_PEN = 1
-MT_TOOL_MAX = 1
-
-# Values describing the status of a force-feedback effect
-FF_STATUS_STOPPED = 0x00
-FF_STATUS_PLAYING = 0x01
-FF_STATUS_MAX = 0x01
-FF_STATUS_CNT = (FF_STATUS_MAX + 1)
-
-# Structures used in ioctls to upload effects to a device
-# They are pieces of a bigger structure (called ff_effect)
-
-# All duration values are expressed in ms. Values above 32767 ms (0x7fff)
-# should not be used and have unspecified results.
-
-"""
- * struct ff_replay - defines scheduling of the force-feedback effect
- * @length: duration of the effect
- * @delay: delay before effect should start playing
-struct ff_replay {
- __u16 length;
- __u16 delay;
-};
-"""
-
-"""
- * struct ff_trigger - defines what triggers the force-feedback effect
- * @button: number of the button triggering the effect
- * @interval: controls how soon the effect can be re-triggered
-struct ff_trigger {
- __u16 button;
- __u16 interval;
-};
-"""
-
-"""
- * struct ff_envelope - generic force-feedback effect envelope
- * @attack_length: duration of the attack (ms)
- * @attack_level: level at the beginning of the attack
- * @fade_length: duration of fade (ms)
- * @fade_level: level at the end of fade
- *
- * The @attack_level and @fade_level are absolute values; when applying
- * envelope force-feedback core will convert to positive/negative
- * value based on polarity of the default level of the effect.
- * Valid range for the attack and fade levels is 0x0000 - 0x7fff
-struct ff_envelope {
- __u16 attack_length;
- __u16 attack_level;
- __u16 fade_length;
- __u16 fade_level;
-};
-"""
-
-"""
- * struct ff_constant_effect - params of a constant force-feedback effect
- * @level: strength of the effect; may be negative
- * @envelope: envelope data
-struct ff_constant_effect {
- __s16 level;
- struct ff_envelope envelope;
-};
-"""
-
-"""
- * struct ff_ramp_effect - params of a ramp force-feedback effect
- * @start_level: beginning strength of the effect; may be negative
- * @end_level: final strength of the effect; may be negative
- * @envelope: envelope data
-struct ff_ramp_effect {
- __s16 start_level;
- __s16 end_level;
- struct ff_envelope envelope;
-};
-"""
-
-"""
- * struct ff_condition_effect - spring or friction force-feedback effect
- * @right_saturation: maximum level when joystick moved all way to the right
- * @left_saturation: same for the left side
- * @right_coeff: controls how fast the force grows when the joystick moves
- * to the right
- * @left_coeff: same for the left side
- * @deadband: size of the dead zone, where no force is produced
- * @center: position of the dead zone
-struct ff_condition_effect {
- __u16 right_saturation;
- __u16 left_saturation;
-
- __s16 right_coeff;
- __s16 left_coeff;
-
- __u16 deadband;
- __s16 center;
-};
-"""
-
-
-"""
- * struct ff_periodic_effect - params of a periodic force-feedback effect
- * @waveform: kind of the effect (wave)
- * @period: period of the wave (ms)
- * @magnitude: peak value
- * @offset: mean value of the wave (roughly)
- * @phase: 'horizontal' shift
- * @envelope: envelope data
- * @custom_len: number of samples (FF_CUSTOM only)
- * @custom_data: buffer of samples (FF_CUSTOM only)
- *
- * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
- * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
- * for the time being as no driver supports it yet.
- *
- * Note: the data pointed by custom_data is copied by the driver.
- * You can therefore dispose of the memory after the upload/update.
-struct ff_periodic_effect {
- __u16 waveform;
- __u16 period;
- __s16 magnitude;
- __s16 offset;
- __u16 phase;
-
- struct ff_envelope envelope;
-
- __u32 custom_len;
- __s16 __user *custom_data;
-};
-"""
-
-"""
- * struct ff_rumble_effect - params of a periodic force-feedback effect
- * @strong_magnitude: magnitude of the heavy motor
- * @weak_magnitude: magnitude of the light one
- *
- * Some rumble pads have two motors of different weight. Strong_magnitude
- * represents the magnitude of the vibration generated by the heavy one.
-struct ff_rumble_effect {
- __u16 strong_magnitude;
- __u16 weak_magnitude;
-};
-"""
-
-"""
- * struct ff_effect - defines force feedback effect
- * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
- * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
- * @id: an unique id assigned to an effect
- * @direction: direction of the effect
- * @trigger: trigger conditions (struct ff_trigger)
- * @replay: scheduling of the effect (struct ff_replay)
- * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
- * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
- * defining effect parameters
- *
- * This structure is sent through ioctl from the application to the driver.
- * To create a new effect application should set its @id to -1; the kernel
- * will return assigned @id which can later be used to update or delete
- * this effect.
- *
- * Direction of the effect is encoded as follows:
- * 0 deg -> 0x0000 (down)
- * 90 deg -> 0x4000 (left)
- * 180 deg -> 0x8000 (up)
- * 270 deg -> 0xC000 (right)
-struct ff_effect {
- __u16 type;
- __s16 id;
- __u16 direction;
- struct ff_trigger trigger;
- struct ff_replay replay;
-
- union {
- struct ff_constant_effect constant;
- struct ff_ramp_effect ramp;
- struct ff_periodic_effect periodic;
- struct ff_condition_effect condition[2]; /* One for each axis */
- struct ff_rumble_effect rumble;
- } u;
-};
-"""
-
-# Force feedback effect types
-FF_RUMBLE = 0x50
-FF_PERIODIC = 0x51
-FF_CONSTANT = 0x52
-FF_SPRING = 0x53
-FF_FRICTION = 0x54
-FF_DAMPER = 0x55
-FF_INERTIA = 0x56
-FF_RAMP = 0x57
-
-FF_EFFECT_MIN = FF_RUMBLE
-FF_EFFECT_MAX = FF_RAMP
-
-# Force feedback periodic effect types
-FF_SQUARE = 0x58
-FF_TRIANGLE = 0x59
-FF_SINE = 0x5a
-FF_SAW_UP = 0x5b
-FF_SAW_DOWN = 0x5c
-FF_CUSTOM = 0x5d
-
-FF_WAVEFORM_MIN = FF_SQUARE
-FF_WAVEFORM_MAX = FF_CUSTOM
-
-# Set ff device properties
-FF_GAIN = 0x60
-FF_AUTOCENTER = 0x61
-
-FF_MAX = 0x7f
-FF_CNT = (FF_MAX + 1)
-
-
-"""
-The following constants, functions and dicts are not part of the original linux
-input header file. They are included here to make it easier to use the linux
-input subsystem from python scripts.
-"""
-
-BITS_PER_WORD = 8
-
-def NBITS(x):
- return ((x - 1) // BITS_PER_WORD) + 1
-
-def OFFSET(x):
- return (x % BITS_PER_WORD)
-
-def BIT(x):
- return (1 << OFFSET(x))
-
-def INDEX(x):
- return (x // BITS_PER_WORD)
-
-def test_bit(b, a):
- return ((a[INDEX(b)] >> OFFSET(b)) & 1)
-
-EV_TYPES = {
- EV_SYN : 'EV_SYN',
- EV_KEY : 'EV_KEY',
- EV_REL : 'EV_REL',
- EV_ABS : 'EV_ABS',
- EV_MSC : 'EV_MSC',
- EV_SW : 'EV_SW',
- EV_LED : 'EV_LED',
- EV_SND : 'EV_SND',
- EV_REP : 'EV_REP',
- EV_FF : 'EV_FF',
- EV_PWR : 'EV_PWR',
- EV_FF_STATUS : 'EV_FF_STATUS'
-}
-
-EV_SIZES = {
- EV_KEY : KEY_CNT,
- EV_REL : REL_CNT,
- EV_ABS : ABS_CNT,
- EV_MSC : MSC_CNT,
- EV_SW : SW_CNT,
- EV_LED : LED_CNT,
- EV_SND : SND_CNT,
- EV_REP : REP_CNT,
- EV_FF : FF_CNT,
- EV_FF_STATUS : FF_STATUS_CNT
-}
-
-EV_STRINGS = {
- # Keys (only buttons, for now)
- EV_KEY: {
- BTN_0 : '0',
- BTN_1 : '1',
- BTN_2 : '0',
- BTN_3 : '3',
- BTN_4 : '4',
- BTN_5 : '5',
- BTN_6 : '6',
- BTN_7 : '7',
- BTN_8 : '8',
- BTN_9 : '9',
- BTN_LEFT : 'LEFT',
- BTN_RIGHT : 'RIGHT',
- BTN_MIDDLE : 'MIDDLE',
- BTN_SIDE : 'SIDE',
- BTN_EXTRA : 'EXTRA',
- BTN_FORWARD : 'FORWARD',
- BTN_BACK : 'BACK',
- BTN_TASK : 'TASK',
- BTN_TRIGGER : 'TRIGGER',
- BTN_THUMB : 'THUMB',
- BTN_THUMB2 : 'THUMB2',
- BTN_TOP : 'TOP',
- BTN_TOP2 : 'TOP2',
- BTN_PINKIE : 'PINKIE',
- BTN_BASE : 'BASE',
- BTN_BASE2 : 'BASE2',
- BTN_BASE3 : 'BASE3',
- BTN_BASE4 : 'BASE4',
- BTN_BASE5 : 'BASE5',
- BTN_BASE6 : 'BASE6',
- BTN_DEAD : 'DEAD',
- BTN_A : 'A',
- BTN_B : 'B',
- BTN_C : 'C',
- BTN_X : 'X',
- BTN_Y : 'Y',
- BTN_Z : 'Z',
- BTN_TL : 'TL',
- BTN_TR : 'TR',
- BTN_TL2 : 'TL2',
- BTN_TR2 : 'TR2',
- BTN_SELECT : 'SELECT',
- BTN_START : 'START',
- BTN_MODE : 'MODE',
- BTN_THUMBL : 'THUMBL',
- BTN_THUMBR : 'THUMBR',
- BTN_TOOL_PEN : 'TOOL_PEN',
- BTN_TOOL_RUBBER : 'TOOL_RUBBER',
- BTN_TOOL_BRUSH : 'TOOL_BRUSH',
- BTN_TOOL_PENCIL : 'TOOL_PENCIL',
- BTN_TOOL_AIRBRUSH : 'TOOL_AIRBRUSH',
- BTN_TOOL_FINGER : 'TOOL_FINGER',
- BTN_TOOL_MOUSE : 'TOOL_MOUSE',
- BTN_TOOL_LENS : 'TOOL_LENS',
- BTN_TOOL_QUINTTAP : 'TOOL_QUINTTAP',
- BTN_TOUCH : 'TOUCH',
- BTN_STYLUS : 'STYLUS',
- BTN_STYLUS2 : 'STYLUS2',
- BTN_TOOL_DOUBLETAP : 'TOOL_DOUBLETAP',
- BTN_TOOL_TRIPLETAP : 'TOOL_TRIPLETAP',
- BTN_TOOL_QUADTAP : 'TOOL_QUADTAP',
- BTN_GEAR_DOWN : 'TOOL_GEAR_DOWN',
- BTN_GEAR_UP : 'TOOL_GEAR_UP',
- },
-
- # Relative axes
- EV_REL: {
- REL_X : 'X',
- REL_Y : 'Y',
- REL_Z : 'Z',
- REL_RX : 'RX',
- REL_RY : 'RY',
- REL_RZ : 'RZ',
- REL_HWHEEL : 'HWHEEL',
- REL_DIAL : 'DIAL',
- REL_WHEEL : 'WHEEL',
- REL_MISC : 'MISC',
- },
-
- # Absolute axes
- EV_ABS: {
- ABS_X : 'X',
- ABS_Y : 'Y',
- ABS_Z : 'Z',
- ABS_RX : 'RX',
- ABS_RY : 'RY',
- ABS_RZ : 'RZ',
- ABS_THROTTLE : 'THROTTLE',
- ABS_RUDDER : 'RUDDER',
- ABS_WHEEL : 'WHEEL',
- ABS_GAS : 'GAS',
- ABS_BRAKE : 'BRAKE',
- ABS_HAT0X : 'HAT0X',
- ABS_HAT0Y : 'HAT0Y',
- ABS_HAT1X : 'HAT1X',
- ABS_HAT1Y : 'HAT1Y',
- ABS_HAT2X : 'HAT2X',
- ABS_HAT2Y : 'HAT2Y',
- ABS_HAT3X : 'HAT3X',
- ABS_HAT3Y : 'HAT3Y',
- ABS_PRESSURE : 'PRESSURE',
- ABS_DISTANCE : 'DISTANCE',
- ABS_TILT_X : 'TILT_X',
- ABS_TILT_Y : 'TILT_Y',
- ABS_TOOL_WIDTH : 'TOOL_WIDTH',
- ABS_VOLUME : 'VOLUME',
- ABS_MISC : 'MISC',
- ABS_MT_SLOT : 'MT_SLOT',
- ABS_MT_TOUCH_MAJOR : 'MT_TOUCH_MAJOR',
- ABS_MT_TOUCH_MINOR : 'MT_TOUCH_MINOR',
- ABS_MT_WIDTH_MAJOR : 'MT_WIDTH_MAJOR',
- ABS_MT_WIDTH_MINOR : 'MT_WIDTH_MINOR',
- ABS_MT_ORIENTATION : 'MT_ORIENTATION',
- ABS_MT_POSITION_X : 'MT_POSITION_X',
- ABS_MT_POSITION_Y : 'MT_POSITION_Y',
- ABS_MT_TOOL_TYPE : 'MT_TOOL_TYPE',
- ABS_MT_BLOB_ID : 'MT_BLOB_ID',
- ABS_MT_TRACKING_ID : 'MT_TRACKING_ID',
- ABS_MT_PRESSURE : 'MT_PRESSURE',
- ABS_MT_DISTANCE : 'MT_DISTANCE'
- },
-
- # Switches
- EV_SW: {
- SW_LID : 'LID',
- SW_TABLET_MODE : 'TABLET_MODE',
- SW_HEADPHONE_INSERT : 'HEADPHONE_INSERT',
- SW_RFKILL_ALL : 'RFKILL_ALL',
- SW_MICROPHONE_INSERT : 'MICROPHONE_INSERT',
- SW_DOCK : 'DOCK',
- SW_LINEOUT_INSERT : 'LINEOUT_INSERT',
- SW_JACK_PHYSICAL_INSERT : 'JACK_PHYSICAL_INSERT',
- SW_VIDEOOUT_INSERT : 'VIDEOOUT_INSERT',
- SW_CAMERA_LENS_COVER : 'CAMERA_LENS_COVER',
- SW_KEYPAD_SLIDE : 'KEYPAD_SLIDE',
- SW_FRONT_PROXIMITY : 'FRONT_PROXIMITY',
- SW_ROTATE_LOCK : 'ROTATE_LOCK',
- },
-
- # Misc events
- EV_MSC: {
- MSC_SERIAL : 'SERIAL',
- MSC_PULSELED : 'PULSELED',
- MSC_GESTURE : 'GESTURE',
- MSC_RAW : 'RAW',
- MSC_SCAN : 'SCAN',
- },
-
- # LEDs
- EV_LED: {
- LED_NUML : 'NUML',
- LED_CAPSL : 'CAPSL',
- LED_SCROLLL : 'SCROLLL',
- LED_COMPOSE : 'COMPOSE',
- LED_KANA : 'KANA',
- LED_SLEEP : 'SLEEP',
- LED_SUSPEND : 'SLEEP',
- LED_MUTE : 'SLEEP',
- LED_MISC : 'SLEEP',
- LED_MAIL : 'SLEEP',
- LED_CHARGING : 'SLEEP',
- },
-
- # Autorepeat values
- EV_REP: {
- REP_DELAY : 'DELAY',
- REP_PERIOD : 'PERIOD',
- },
-
- # Sounds
- EV_SND: {
- SND_CLICK : 'CLICK',
- SND_BELL : 'BELL'
- }
-}
diff --git a/client/bin/input/linux_ioctl.py b/client/bin/input/linux_ioctl.py
deleted file mode 100644
index c28ccdc..0000000
--- a/client/bin/input/linux_ioctl.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (c) 2011 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.
-
-# Description:
-#
-# Python version of include/asm-generic/ioctl.h
-
-
-import struct
-
-
-# ioctl command encoding: 32 bits total, command in lower 16 bits,
-# size of the parameter structure in the lower 14 bits of the
-# upper 16 bits.
-# Encoding the size of the parameter structure in the ioctl request
-# is useful for catching programs compiled with old versions
-# and to avoid overwriting user space outside the user buffer area.
-# The highest 2 bits are reserved for indicating the ``access mode''.
-# NOTE: This limits the max parameter size to 16kB -1 !
-
-_IOC_NRBITS = 8
-_IOC_TYPEBITS = 8
-_IOC_SIZEBITS = 14
-_IOC_DIRBITS = 2
-
-_IOC_NRMASK = ((1 << _IOC_NRBITS) - 1)
-_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
-_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
-_IOC_DIRMASK = ((1 << _IOC_DIRBITS) - 1)
-
-_IOC_NRSHIFT = 0
-_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
-_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
-_IOC_DIRSHIFT = (_IOC_SIZESHIFT + _IOC_SIZEBITS)
-
-IOC_NONE = 0
-IOC_WRITE = 1
-IOC_READ = 2
-
-# Return the byte size of a python struct format string
-def sizeof(t):
- return struct.calcsize(t)
-
-def IOC(d, t, nr, size):
- return ((d << _IOC_DIRSHIFT) | (ord(t) << _IOC_TYPESHIFT) |
- (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT))
-
-# used to create numbers
-def IO(t, nr, t_format):
- return IOC(IOC_NONE, t, nr, 0)
-
-def IOW(t, nr, t_format):
- return IOC(IOC_WRITE, t, nr, sizeof(t_format))
-
-def IOR(t, nr, t_format):
- return IOC(IOC_READ, t, nr, sizeof(t_format))
-
-def IOWR(t, nr, t_format):
- return IOC(IOC_READ|_IOC_WRITE, t, nr, sizeof(t_format))
-
-# used to decode ioctl numbers..
-def IOC_DIR(nr):
- return ((nr >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
-
-def IOC_TYPE(nr):
- return ((nr >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
-
-def IOC_NR(nr):
- return ((nr >> _IOC_NRSHIFT) & _IOC_NRMASK)
-
-def IOC_SIZE(nr):
- return ((nr >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-# ...and for the drivers/sound files...
-IOC_IN = (IOC_WRITE << _IOC_DIRSHIFT)
-IOC_OUT = (IOC_READ << _IOC_DIRSHIFT)
-IOC_INOUT = ((IOC_WRITE | IOC_READ) << _IOC_DIRSHIFT)
-IOCSIZE_MASK = (_IOC_SIZEMASK << _IOC_SIZESHIFT)
-IOCSIZE_SHIFT = (_IOC_SIZESHIFT)
-
diff --git a/client/bin/intel_pci_ids.json b/client/bin/intel_pci_ids.json
deleted file mode 100644
index c27035a..0000000
--- a/client/bin/intel_pci_ids.json
+++ /dev/null
@@ -1,243 +0,0 @@
-{
- "0x0042": "ironlake",
- "0x0046": "ironlake",
- "0x0102": "sandybridge",
- "0x0106": "sandybridge",
- "0x010a": "sandybridge",
- "0x0112": "sandybridge",
- "0x0116": "sandybridge",
- "0x0122": "sandybridge",
- "0x0126": "sandybridge",
- "0x0152": "ivybridge",
- "0x0155": "baytrail",
- "0x0156": "ivybridge",
- "0x0157": "baytrail",
- "0x015a": "ivybridge",
- "0x0162": "ivybridge",
- "0x0166": "ivybridge",
- "0x016a": "ivybridge",
- "0x0402": "haswell",
- "0x0406": "haswell",
- "0x040a": "haswell",
- "0x040b": "haswell",
- "0x040e": "haswell",
- "0x0412": "haswell",
- "0x0416": "haswell",
- "0x041a": "haswell",
- "0x041b": "haswell",
- "0x041e": "haswell",
- "0x0422": "haswell",
- "0x0426": "haswell",
- "0x042a": "haswell",
- "0x042b": "haswell",
- "0x042e": "haswell",
- "0x0a02": "haswell",
- "0x0a06": "haswell",
- "0x0a0a": "haswell",
- "0x0a0b": "haswell",
- "0x0a0e": "haswell",
- "0x0a12": "haswell",
- "0x0a16": "haswell",
- "0x0a1a": "haswell",
- "0x0a1b": "haswell",
- "0x0a1e": "haswell",
- "0x0a22": "haswell",
- "0x0a26": "haswell",
- "0x0a2a": "haswell",
- "0x0a2b": "haswell",
- "0x0a2e": "haswell",
- "0x0a84": "broxton",
- "0x0c02": "haswell",
- "0x0c06": "haswell",
- "0x0c0a": "haswell",
- "0x0c0b": "haswell",
- "0x0c0e": "haswell",
- "0x0c12": "haswell",
- "0x0c16": "haswell",
- "0x0c1a": "haswell",
- "0x0c1b": "haswell",
- "0x0c1e": "haswell",
- "0x0c22": "haswell",
- "0x0c26": "haswell",
- "0x0c2a": "haswell",
- "0x0c2b": "haswell",
- "0x0c2e": "haswell",
- "0x0d02": "haswell",
- "0x0d06": "haswell",
- "0x0d0a": "haswell",
- "0x0d0b": "haswell",
- "0x0d0e": "haswell",
- "0x0d12": "haswell",
- "0x0d16": "haswell",
- "0x0d1a": "haswell",
- "0x0d1b": "haswell",
- "0x0d1e": "haswell",
- "0x0d22": "haswell",
- "0x0d26": "haswell",
- "0x0d2a": "haswell",
- "0x0d2b": "haswell",
- "0x0d2e": "haswell",
- "0x0f31": "baytrail",
- "0x0f32": "baytrail",
- "0x0f33": "baytrail",
- "0x1602": "broadwell",
- "0x1606": "broadwell",
- "0x160a": "broadwell",
- "0x160b": "broadwell",
- "0x160d": "broadwell",
- "0x160e": "broadwell",
- "0x1612": "broadwell",
- "0x1616": "broadwell",
- "0x161a": "broadwell",
- "0x161b": "broadwell",
- "0x161d": "broadwell",
- "0x161e": "broadwell",
- "0x1622": "broadwell",
- "0x1626": "broadwell",
- "0x162a": "broadwell",
- "0x162b": "broadwell",
- "0x162d": "broadwell",
- "0x162e": "broadwell",
- "0x1902": "skylake",
- "0x1906": "skylake",
- "0x190a": "skylake",
- "0x190b": "skylake",
- "0x190e": "skylake",
- "0x1912": "skylake",
- "0x1913": "skylake",
- "0x1915": "skylake",
- "0x1916": "skylake",
- "0x1917": "skylake",
- "0x191a": "skylake",
- "0x191b": "skylake",
- "0x191d": "skylake",
- "0x191e": "skylake",
- "0x1921": "skylake",
- "0x1923": "skylake",
- "0x1926": "skylake",
- "0x1927": "skylake",
- "0x192a": "skylake",
- "0x192b": "skylake",
- "0x192d": "skylake",
- "0x1932": "skylake",
- "0x193a": "skylake",
- "0x193b": "skylake",
- "0x193d": "skylake",
- "0x1a84": "broxton",
- "0x1a85": "broxton",
- "0x22b0": "braswell",
- "0x22b1": "braswell",
- "0x22b2": "braswell",
- "0x22b3": "braswell",
- "0x3184": "geminilake",
- "0x3185": "geminilake",
- "0x3e90": "coffeelake",
- "0x3e91": "coffeelake",
- "0x3e92": "coffeelake",
- "0x3e93": "coffeelake",
- "0x3e94": "coffeelake",
- "0x3e96": "coffeelake",
- "0x3e98": "coffeelake",
- "0x3e99": "coffeelake",
- "0x3e9a": "coffeelake",
- "0x3e9b": "coffeelake",
- "0x3e9c": "coffeelake",
- "0x3ea0": "whiskeylake",
- "0x3ea1": "whiskeylake",
- "0x3ea2": "whiskeylake",
- "0x3ea3": "whiskeylake",
- "0x3ea4": "whiskeylake",
- "0x3ea5": "coffeelake",
- "0x3ea6": "coffeelake",
- "0x3ea7": "coffeelake",
- "0x3ea8": "coffeelake",
- "0x3ea9": "coffeelake",
- "0x4680": "alderlake",
- "0x4681": "alderlake",
- "0x4682": "alderlake",
- "0x4683": "alderlake",
- "0x4690": "alderlake",
- "0x4691": "alderlake",
- "0x4692": "alderlake",
- "0x4693": "alderlake",
- "0x4698": "alderlake",
- "0x4699": "alderlake",
- "0x4e51": "jasperlake",
- "0x4e55": "jasperlake",
- "0x4e57": "jasperlake",
- "0x4e61": "jasperlake",
- "0x4e71": "jasperlake",
- "0x5902": "kabylake",
- "0x5906": "kabylake",
- "0x5908": "kabylake",
- "0x590a": "kabylake",
- "0x590b": "kabylake",
- "0x590e": "kabylake",
- "0x5912": "kabylake",
- "0x5913": "kabylake",
- "0x5915": "kabylake",
- "0x5916": "kabylake",
- "0x5917": "kabylake",
- "0x591a": "kabylake",
- "0x591b": "kabylake",
- "0x591c": "kabylake",
- "0x591d": "kabylake",
- "0x591e": "kabylake",
- "0x5921": "kabylake",
- "0x5923": "kabylake",
- "0x5926": "kabylake",
- "0x5927": "kabylake",
- "0x593b": "kabylake",
- "0x5a84": "broxton",
- "0x5a85": "broxton",
- "0x87c0": "kabylake",
- "0x87ca": "coffeelake",
- "0x8a50": "icelake",
- "0x8a51": "icelake",
- "0x8a52": "icelake",
- "0x8a53": "icelake",
- "0x8a54": "icelake",
- "0x8a56": "icelake",
- "0x8a57": "icelake",
- "0x8a58": "icelake",
- "0x8a59": "icelake",
- "0x8a5a": "icelake",
- "0x8a5b": "icelake",
- "0x8a5c": "icelake",
- "0x8a5d": "icelake",
- "0x8a71": "icelake",
- "0x9a40": "tigerlake",
- "0x9a49": "tigerlake",
- "0x9a59": "tigerlake",
- "0x9a60": "tigerlake",
- "0x9a68": "tigerlake",
- "0x9a70": "tigerlake",
- "0x9a78": "tigerlake",
- "0x9ac0": "tigerlake",
- "0x9ac9": "tigerlake",
- "0x9ad9": "tigerlake",
- "0x9af8": "tigerlake",
- "0x9b21": "cometlake",
- "0x9b41": "cometlake",
- "0x9ba0": "cometlake",
- "0x9ba2": "cometlake",
- "0x9ba4": "cometlake",
- "0x9ba5": "cometlake",
- "0x9ba8": "cometlake",
- "0x9baa": "cometlake",
- "0x9bab": "cometlake",
- "0x9bac": "cometlake",
- "0x9bc0": "cometlake",
- "0x9bc2": "cometlake",
- "0x9bc4": "cometlake",
- "0x9bc5": "cometlake",
- "0x9bc6": "cometlake",
- "0x9bc8": "cometlake",
- "0x9bca": "cometlake",
- "0x9bcb": "cometlake",
- "0x9bcc": "cometlake",
- "0x9be6": "cometlake",
- "0x9bf6": "cometlake",
- "0xa001": "pinetrail",
- "0xa011": "pinetrail"
-}
diff --git a/client/bin/kernel_versions.py b/client/bin/kernel_versions.py
deleted file mode 100644
index 605fb9b..0000000
--- a/client/bin/kernel_versions.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Lint as: python2, python3
-#
-# kernel_versions.py -- linux kernel version comparisons
-#
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-__author__ = """Copyright Andy Whitcroft 2007"""
-
-import sys,re
-
-from six.moves import range
-
-#
-# Sort key for ordering versions chronologically. The key ordering
-# problem is between that introduced by -rcN. These come _before_
-# their accompanying version.
-#
-# 2.6.0 -> 2.6.1-rc1 -> 2.6.1
-#
-# In order to sort them we convert all non-rc releases to a pseudo
-# -rc99 release. We also convert all numbers to two digits. The
-# result is then sortable textually.
-#
-# 02.06.00-rc99 -> 02.06.01-rc01 -> 02.06.01-rc99
-#
-encode_sep = re.compile(r'(\D+)')
-
-def version_encode(version):
- bits = encode_sep.split(version)
- n = 9
- if len(bits[0]) == 0:
- n += 2
- if len(bits) == n or (len(bits) > n and bits[n] != '_rc'):
- # Insert missing _rc99 after 2 . 6 . 18 -smp- 220 . 0
- bits.insert(n, '_rc')
- bits.insert(n+1, '99')
- n = 5
- if len(bits[0]) == 0:
- n += 2
- if len(bits) <= n or bits[n] != '-rc':
- bits.insert(n, '-rc')
- bits.insert(n+1, '99')
- for n in range(0, len(bits), 2):
- if len(bits[n]) == 1:
- bits[n] = '0' + bits[n]
-
- return ''.join(bits)
-
-
-def version_limit(version, n):
- bits = encode_sep.split(version)
- return ''.join(bits[0:n])
-
-
-def version_len(version):
- return len(encode_sep.split(version))
-
-#
-# Given a list of versions find the nearest version which is deemed
-# less than or equal to the target. Versions are in linux order
-# as follows:
-#
-# 2.6.0 -> 2.6.1 -> 2.6.2-rc1 -> 2.6.2-rc2 -> 2.6.2 -> 2.6.3-rc1
-# | |\
-# | | 2.6.2-rc1-mm1 -> 2.6.2-rc1-mm2
-# | \
-# | 2.6.2-rc1-ac1 -> 2.6.2-rc1-ac2
-# \
-# 2.6.1-mm1 -> 2.6.1-mm2
-#
-# Note that a 2.6.1-mm1 is not a predecessor of 2.6.2-rc1-mm1.
-#
-def version_choose_config(version, candidates):
- # Check if we have an exact match ... if so magic
- if version in candidates:
- return version
-
- # Sort the search key into the list ordered by 'age'
- deco = [ (version_encode(v), i, v) for i, v in
- enumerate(candidates + [ version ]) ]
- deco.sort()
- versions = [ v for _, _, v in deco ]
-
- # Everything sorted below us is of interst.
- for n in range(len(versions) - 1, -1, -1):
- if versions[n] == version:
- break
- n -= 1
-
- # Try ever shorter 'prefixes' 2.6.20-rc3-mm, 2.6.20-rc, 2.6. etc
- # to match against the ordered list newest to oldest.
- length = version_len(version) - 1
- version = version_limit(version, length)
- while length > 1:
- for o in range(n, -1, -1):
- if version_len(versions[o]) == (length + 1) and \
- version_limit(versions[o], length) == version:
- return versions[o]
- length -= 2
- version = version_limit(version, length)
-
- return None
-
-
-def is_released_kernel(version):
- # True if version name suggests a released kernel,
- # not some release candidate or experimental kernel name
- # e.g. 2.6.18-smp-200.0 includes no other text, underscores, etc
- version = version.strip('01234567890.-')
- return version in ['', 'smp', 'smpx', 'pae']
-
-
-def is_release_candidate(version):
- # True if version names a released kernel or release candidate,
- # not some experimental name containing arbitrary text
- # e.g. 2.6.18-smp-220.0_rc3 but not 2.6.18_patched
- version = re.sub(r'[_-]rc\d+', '', version)
- return is_released_kernel(version)
diff --git a/client/bin/kernel_versions_unittest.py b/client/bin/kernel_versions_unittest.py
deleted file mode 100755
index 8fafbe3..0000000
--- a/client/bin/kernel_versions_unittest.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/python3
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-import unittest
-import common
-from autotest_lib.client.bin import kernel_versions
-from six.moves import range
-
-
-class kernel_versions_test(unittest.TestCase):
-
- def increases(self, kernels):
- for i in range(len(kernels)-1):
- k1 = kernels[i]
- k2 = kernels[i+1]
- ek1 = kernel_versions.version_encode(k1)
- ek2 = kernel_versions.version_encode(k2)
- self.assertTrue(ek1 < ek2,
- '%s (-> %s) should sort < %s (-> %s)'
- % (k1, ek1, k2, ek2) )
-
-
- def test_version_encode(self):
- series1 = [
- '2.6',
- '2.6.0',
- '2.6.1-rc1',
- '2.6.1-rc1_fix',
- '2.6.1-rc1_patch',
- '2.6.1-rc9',
- '2.6.1-rc9-mm1',
- '2.6.1-rc9-mm2',
- '2.6.1-rc10',
- '2.6.1-rc98',
- '2.6.1',
- '2.6.1_patch',
- '2.6.9',
- '2.6.10',
- '2.6.99',
- '2.7',
- '2.9.99',
- '2.10.0',
- '99.99.99',
- 'UNKNOWN',
- ]
- self.increases(series1)
- self.increases(['pathX'+k for k in series1])
- series2 = [
- '2.6.18-smp-220',
- '2.6.18-smp-220.0',
- '2.6.18-smp-220.1_rc1',
- '2.6.18-smp-220.1_rc1_fix',
- '2.6.18-smp-220.1_rc1_patch',
- '2.6.18-smp-220.1_rc9',
- '2.6.18-smp-220.1_rc9_mm1',
- '2.6.18-smp-220.1_rc9_mm2',
- '2.6.18-smp-220.1_rc10',
- '2.6.18-smp-220.1_rc98',
- '2.6.18-smp-220.1',
- '2.6.18-smp-220.1_patch',
- '2.6.18-smp-220.9',
- '2.6.18-smp-220.10',
- '2.6.18-smp-220.99',
- '2.6.18-smp-221',
- 'UNKNOWN',
- ]
- self.increases(series2)
- self.increases(['pathX'+k for k in series2])
-
-
- releases = ['2.6.1' , '2.6.18-smp-220.0' ]
- candidates = ['2.6.1-rc1' , '2.6.18-smp-220.0_rc1']
- experiments = ['2.6.1-patch', '2.6.1-rc1_patch', '2.6.18-smp-220.0_patch',
- 'UNKNOWN']
-
- def test_is_released_kernel(self):
- for v in self.releases:
- self.assertTrue(kernel_versions.is_released_kernel(v))
- for v in self.candidates + self.experiments:
- self.assertFalse(kernel_versions.is_released_kernel(v))
-
-
- def test_is_release_candidate(self):
- for v in self.releases + self.candidates:
- self.assertTrue(kernel_versions.is_release_candidate(v))
- for v in self.experiments:
- self.assertFalse(kernel_versions.is_release_candidate(v))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/client/bin/temperature.py b/client/bin/temperature.py
deleted file mode 100755
index fad71b6..0000000
--- a/client/bin/temperature.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python2
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import argparse
-
-argparser = argparse.ArgumentParser(
- description="Get the highest reported board temperature (all sensors) in "
- "Celsius.")
-
-group = argparser.add_mutually_exclusive_group()
-group.add_argument("-m", "--maximum",
- action="store_const",
- const='Maximum',
- dest="temperature_type",
- help="Get the highest reported board temperature "
- "from all sensors in Celsius.")
-args = argparser.add_argument("-v", "--verbose",
- action="store_true",
- help="Show temperature type and value.")
-argparser.set_defaults(temperature_type='all')
-args = argparser.parse_args()
-
-import common
-from autotest_lib.client.bin import utils
-
-TEMPERATURE_TYPE = {
- 'Maximum': utils.get_current_temperature_max,
-}
-
-def print_temperature(temperature_type):
- if args.verbose:
- print(temperature_type, end=' ')
- print(TEMPERATURE_TYPE.get(temperature_type)())
-
-if args.temperature_type == 'all':
- for temperature_type in TEMPERATURE_TYPE.keys():
- print_temperature(temperature_type)
-else:
- print_temperature(args.temperature_type)
diff --git a/client/bin/update_intel_pci_ids b/client/bin/update_intel_pci_ids
deleted file mode 100755
index 938c106..0000000
--- a/client/bin/update_intel_pci_ids
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python2
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Create a JSON file containing PCI ID-to-name mappings for Intel GPUs.
-
-This script gets the latest PCI ID list from Mesa.
-The list is used by get_gpu_family() in utils.py.
-This script should be run whenever Mesa is updated
-to keep the list up-to-date.
-"""
-
-import json
-import os
-import shutil
-import subprocess as sp
-from six.moves import range
-
-
-def map_gpu_name(mesa_name):
- """Map Mesa GPU names to autotest names.
- """
- family_name_map = {
- 'Pineview': 'pinetrail',
- 'ILK': 'ironlake',
- 'SNB': 'sandybridge',
- 'IVB': 'ivybridge',
- 'HSW': 'haswell',
- 'BYT': 'baytrail',
- 'BDW': 'broadwell',
- 'CHV': 'braswell',
- 'BSW': 'braswell',
- 'SKL': 'skylake',
- 'APL': 'broxton',
- 'BXT': 'broxton',
- 'KBL': 'kabylake',
- 'GLK': 'geminilake',
- 'CNL': 'cannonlake',
- 'CFL': 'coffeelake',
- 'ICL': 'icelake',
- 'CML': 'cometlake',
- 'WHL': 'whiskeylake',
- 'TGL': 'tigerlake',
- 'JSL': 'jasperlake',
- 'ADL': 'alderlake'
- }
-
- for name in family_name_map:
- if name in mesa_name:
- return family_name_map[name]
- return ''
-
-
-def main():
- """Extract Intel GPU PCI IDs from Mesa and write to JSON file.
- """
-
- in_files = ['i915_pci_ids.h', 'i965_pci_ids.h', 'iris_pci_ids.h']
- script_dir = os.path.dirname(os.path.realpath(__file__))
- out_file = os.path.join(script_dir, 'intel_pci_ids.json')
- local_repo = os.path.join(script_dir, '../../../../mesa')
-
- pci_ids = {}
- chipsets = []
- cmd = 'cd %s; git show HEAD:include/pci_ids/' % local_repo
- for id_file in in_files:
- chipsets.extend(sp.check_output(cmd + id_file,
- shell=True).splitlines())
- for cset in chipsets:
- # Prevent unexpected lines from being parsed
- if not 'CHIPSET(' in cset:
- continue
- cset_attr = cset[len('CHIPSET('):-2].split(',')
-
- # Remove leading and trailing spaces and double quotes.
- for i in range(0, len(cset_attr)):
- cset_attr[i] = cset_attr[i].strip(' "').rstrip(' "')
-
- pci_id = cset_attr[0].lower()
- family_name = map_gpu_name(cset_attr[2])
-
- # Ignore GPU families not in family_name_map.
- if family_name:
- pci_ids[pci_id] = family_name
-
- with open(out_file, 'w') as out_f:
- json.dump(pci_ids, out_f, sort_keys=True, indent=4,
- separators=(',', ': '))
-
-
-if __name__ == '__main__':
- main()
diff --git a/client/common_lib/cros/adb_keepalive.py b/client/common_lib/cros/adb_keepalive.py
deleted file mode 100755
index 582cbf0..0000000
--- a/client/common_lib/cros/adb_keepalive.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/python3
-
-# Copyright 2017 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 argparse
-import logging
-import os
-import pipes
-import re
-import signal
-import sys
-import time
-
-import common
-from autotest_lib.client.bin import utils
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib import logging_config
-
-_ADB_POLLING_INTERVAL_SECONDS = 10
-_ADB_CONNECT_INTERVAL_SECONDS = 1
-_ADB_COMMAND_TIMEOUT_SECONDS = 5
-
-_signum_to_name = {}
-
-
-def _signal_handler(signum, frame):
- logging.info('Received %s, shutting down', _signum_to_name[signum])
- sys.stdout.flush()
- sys.stderr.flush()
- os._exit(0)
-
-
-def _get_adb_options(target, socket):
- """Get adb global options."""
- # ADB 1.0.36 does not support -L adb socket option. Parse the host and port
- # part from the socket instead.
- # https://developer.android.com/studio/command-line/adb.html#issuingcommands
- pattern = r'^[^:]+:([^:]+):(\d+)$'
- match = re.match(pattern, socket)
- if not match:
- raise ValueError('Unrecognized socket format: %s' % socket)
- server_host, server_port = match.groups()
- return '-s %s -H %s -P %s' % (
- pipes.quote(target), pipes.quote(server_host), pipes.quote(server_port))
-
-
-def _run_adb_cmd(cmd, adb_option="", **kwargs):
- """Run adb command.
-
- @param cmd: command to issue with adb. (Ex: connect, devices)
- @param target: Device to connect to.
- @param adb_option: adb global option configuration.
-
- @return: the stdout of the command.
- """
- adb_cmd = 'adb %s %s' % (adb_option, cmd)
- while True:
- try:
- output = utils.system_output(adb_cmd, **kwargs)
- break
- except error.CmdTimeoutError as e:
- logging.warning(e)
- logging.info('Retrying command %s', adb_cmd)
- logging.debug('%s: %s', adb_cmd, output)
- return output
-
-
-def _is_adb_connected(target, adb_option=""):
- """Return true if adb is connected to the container.
-
- @param target: Device to connect to.
- @param adb_option: adb global option configuration.
- """
- output = _run_adb_cmd('get-state', adb_option=adb_option,
- timeout=_ADB_COMMAND_TIMEOUT_SECONDS,
- ignore_status=True)
- return output.strip() == 'device'
-
-
-def _ensure_adb_connected(target, adb_option=""):
- """Ensures adb is connected to the container, reconnects otherwise.
-
- @param target: Device to connect to.
- @param adb_option: adb global options configuration.
- """
- did_reconnect = False
- while not _is_adb_connected(target, adb_option):
- if not did_reconnect:
- logging.info('adb not connected. attempting to reconnect')
- did_reconnect = True
- _run_adb_cmd('connect %s' % pipes.quote(target),
- adb_option=adb_option,
- timeout=_ADB_COMMAND_TIMEOUT_SECONDS, ignore_status=True)
- time.sleep(_ADB_CONNECT_INTERVAL_SECONDS)
- if did_reconnect:
- logging.info('Reconnection succeeded')
-
-
-if __name__ == '__main__':
- logging_config.LoggingConfig().configure_logging()
- parser = argparse.ArgumentParser(description='ensure adb is connected')
- parser.add_argument('target', help='Device to connect to')
- parser.add_argument('--socket', help='ADB server socket.',
- default='tcp:localhost:5037')
- args = parser.parse_args()
- adb_option = _get_adb_options(args.target, args.socket)
-
- # Setup signal handler for logging on exit
- for attr in dir(signal):
- if not attr.startswith('SIG') or attr.startswith('SIG_'):
- continue
- if attr in ('SIGCHLD', 'SIGCLD', 'SIGKILL', 'SIGSTOP'):
- continue
- signum = getattr(signal, attr)
- _signum_to_name[signum] = attr
- signal.signal(signum, _signal_handler)
-
- logging.info('Starting adb_keepalive for target %s on socket %s',
- args.target, args.socket)
- while True:
- time.sleep(_ADB_POLLING_INTERVAL_SECONDS)
- _ensure_adb_connected(args.target, adb_option=adb_option)
diff --git a/client/common_lib/cros/arc.py b/client/common_lib/cros/arc.py
deleted file mode 100644
index 189d365..0000000
--- a/client/common_lib/cros/arc.py
+++ /dev/null
@@ -1,942 +0,0 @@
-# Lint as: python2, python3
-# Copyright 2015 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.
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import collections
-import glob
-import logging
-import os
-import pipes
-import shutil
-import socket
-import sys
-import tempfile
-import time
-
-from autotest_lib.client.bin import test, utils
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib.cros import chrome, arc_common
-from six.moves import range
-
-_ADB_KEYS_PATH = '/tmp/adb_keys'
-_ADB_VENDOR_KEYS = 'ADB_VENDOR_KEYS'
-_ANDROID_CONTAINER_PID_PATH = '/run/containers/android*/container.pid'
-_ANDROID_DATA_ROOT_PATH = '/opt/google/containers/android/rootfs/android-data'
-_ANDROID_CONTAINER_ROOT_PATH = '/opt/google/containers/android/rootfs'
-_SCREENSHOT_DIR_PATH = '/var/log/arc-screenshots'
-_SCREENSHOT_BASENAME = 'arc-screenshot'
-_MAX_SCREENSHOT_NUM = 10
-# This address should match the one present in
-# https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/main/chromeos-base/arc-sslh-init/files/sslh.conf
-_ADBD_ADDRESS = ('100.115.92.2', 5555)
-_ADBD_PID_PATH = '/run/arc/adbd.pid'
-_SDCARD_PID_PATH = '/run/arc/sdcard.pid'
-_ANDROID_ADB_KEYS_PATH = '/data/misc/adb/adb_keys'
-_PROCESS_CHECK_INTERVAL_SECONDS = 1
-_PROPERTY_CHECK_INTERVAL_SECONDS = 1
-_WAIT_FOR_ADB_READY = 60
-_WAIT_FOR_ANDROID_PROCESS_SECONDS = 60
-_PLAY_STORE_PKG = 'com.android.vending'
-_SETTINGS_PKG = 'com.android.settings'
-
-
-def setup_adb_host():
- """Setup ADB host keys.
-
- This sets up the files and environment variables that wait_for_adb_ready()
- needs"""
- if _ADB_VENDOR_KEYS in os.environ:
- return
- if not os.path.exists(_ADB_KEYS_PATH):
- os.mkdir(_ADB_KEYS_PATH)
- # adb expects $HOME to be writable.
- os.environ['HOME'] = _ADB_KEYS_PATH
-
- # Generate and save keys for adb if needed
- key_path = os.path.join(_ADB_KEYS_PATH, 'test_key')
- if not os.path.exists(key_path):
- utils.system('adb keygen ' + pipes.quote(key_path))
- os.environ[_ADB_VENDOR_KEYS] = key_path
-
-
-def restart_adbd(timeout):
- """Restarts the adb daemon.
-
- Follows the same logic as tast.
- """
- logging.debug('restarting adbd')
- config = 'adb'
- _android_shell('setprop persist.sys.usb.config ' + config)
- _android_shell('setprop sys.usb.config ' + config)
-
- def property_check():
- return _android_shell('getprop sys.usb.state') == config
-
- try:
- utils.poll_for_condition(
- condition=property_check,
- desc='Wait for sys.usb.state',
- timeout=timeout,
- sleep_interval=_PROPERTY_CHECK_INTERVAL_SECONDS)
- except utils.TimeoutError:
- raise error.TestFail('Timed out waiting for sys.usb.state change')
-
- _android_shell('setprop ctl.restart adbd')
-
-
-def restart_adb():
- """Restarts adb.
-
- Follows the same logic as in tast, specifically avoiding kill-server
- since it is unreliable (crbug.com/855325).
- """
- logging.debug('killing and restarting adb server')
- utils.system('killall --quiet --wait -KILL adb')
- utils.system('adb start-server')
-
-
-def is_adb_connected():
- """Return true if adb is connected to the container."""
- output = utils.system_output('adb get-state', ignore_status=True)
- logging.debug('adb get-state: %s', output)
- return output.strip() == 'device'
-
-
-def _is_android_data_mounted():
- """Return true if Android's /data is mounted with partial boot enabled."""
- return _android_shell('getprop ro.data_mounted', ignore_status=True) == '1'
-
-
-def get_zygote_type():
- """Return zygote service type."""
- return _android_shell('getprop ro.zygote', ignore_status=True)
-
-
-def get_sdk_version():
- """Return the SDK level version for Android."""
- return _android_shell('getprop ro.build.version.sdk')
-
-
-def get_product():
- """Return the product string used for the Android build."""
- return _android_shell('getprop ro.build.product', ignore_status=True)
-
-
-def _is_tcp_port_reachable(address):
- """Return whether a TCP port described by |address| is reachable."""
- try:
- s = socket.create_connection(address)
- s.close()
- return True
- except socket.error:
- return False
-
-
-def _wait_for_data_mounted(timeout):
- utils.poll_for_condition(
- condition=_is_android_data_mounted,
- desc='Wait for /data mounted',
- timeout=timeout,
- sleep_interval=_PROCESS_CHECK_INTERVAL_SECONDS)
-
-
-def wait_for_adb_ready(timeout=_WAIT_FOR_ADB_READY):
- """Wait for the ADB client to connect to the ARC container.
-
- @param timeout: Timeout in seconds.
- """
- # Although adbd is started at login screen, we still need /data to be
- # mounted to set up key-based authentication. /data should be mounted
- # once the user has logged in.
-
- initial_timeout = timeout
-
- start_time = time.time()
- _wait_for_data_mounted(timeout)
- timeout -= (time.time() - start_time)
- start_time = time.time()
- arc_common.wait_for_android_boot(timeout)
- timeout -= (time.time() - start_time)
-
- setup_adb_host()
- if is_adb_connected():
- return
-
- # Push keys for adb.
- pubkey_path = os.environ[_ADB_VENDOR_KEYS] + '.pub'
- with open(pubkey_path, 'r') as f:
- _write_android_file(_ANDROID_ADB_KEYS_PATH, f.read())
- _android_shell('chown shell ' + pipes.quote(_ANDROID_ADB_KEYS_PATH))
- _android_shell('restorecon ' + pipes.quote(_ANDROID_ADB_KEYS_PATH))
-
- attempt_count = 3
- timeout = timeout / attempt_count
-
- for i in range(attempt_count):
- if _restart_adb_and_wait_for_ready(timeout):
- return
- raise error.TestFail(
- 'Failed to connect to adb in %d seconds.' % initial_timeout)
-
-
-def _restart_adb_and_wait_for_ready(timeout):
- """Restart adb/adbd and wait adb connection is ready.
-
- @param timeout: Timeout in seconds.
- @return True in case adb connection was established or throw an error in
- case persistent error occured.
- """
-
- # Restart adbd and adb.
- start_time = time.time()
- restart_adbd(timeout)
- timeout -= (time.time() - start_time)
- start_time = time.time()
- restart_adb()
- timeout -= (time.time() - start_time)
-
- try:
- utils.poll_for_condition(condition=is_adb_connected,
- timeout=timeout)
- return True
- except (utils.TimeoutError):
- # The operation has failed, but let's try to clarify the failure to
- # avoid shifting blame to adb.
-
- # First, collect some information and log it.
- arc_alive = is_android_container_alive()
- arc_booted = _android_shell('getprop sys.boot_completed',
- ignore_status=True)
- arc_system_events = _android_shell(
- 'logcat -d -b events *:S arc_system_event', ignore_status=True)
- adbd_pid = _android_shell('pidof -s adbd', ignore_status=True)
- adbd_port_reachable = _is_tcp_port_reachable(_ADBD_ADDRESS)
- adb_state = utils.system_output('adb get-state', ignore_status=True)
- logging.debug('ARC alive: %s', arc_alive)
- logging.debug('ARC booted: %s', arc_booted)
- logging.debug('ARC system events: %s', arc_system_events)
- logging.debug('adbd process: %s', adbd_pid)
- logging.debug('adbd port reachable: %s', adbd_port_reachable)
- logging.debug('adb state: %s', adb_state)
-
- # Now go through the usual suspects and raise nicer errors to make the
- # actual failure clearer.
- if not arc_alive:
- raise error.TestFail('ARC is not alive.')
- if arc_booted != '1':
- raise error.TestFail('ARC did not finish booting.')
- return False
-
-
-def grant_permissions(package, permissions):
- """Grants permissions to a package.
-
- @param package: Package name.
- @param permissions: A list of permissions.
-
- """
- for permission in permissions:
- adb_shell('pm grant %s android.permission.%s' % (
- pipes.quote(package), pipes.quote(permission)))
-
-
-def adb_cmd(cmd, **kwargs):
- """Executed cmd using adb. Must wait for adb ready.
-
- @param cmd: Command to run.
- """
- # TODO(b/79122489) - Assert if cmd == 'root'
- wait_for_adb_ready()
- return utils.system_output('adb %s' % cmd, **kwargs)
-
-
-def adb_shell(cmd, **kwargs):
- """Executed shell command with adb.
-
- @param cmd: Command to run.
- """
- output = adb_cmd('shell %s' % pipes.quote(cmd), **kwargs)
- # Some android commands include a trailing CRLF in their output.
- if kwargs.pop('strip_trailing_whitespace', True):
- output = output.rstrip()
- return output
-
-
-def adb_install(apk, auto_grant_permissions=True, ignore_status=False):
- """Install an apk into container. You must connect first.
-
- @param apk: Package to install.
- @param auto_grant_permissions: Set to false to not automatically grant all
- permissions. Most tests should not care.
- @param ignore_status: Set to true to allow the install command to fail,
- for example if you are installing multiple architectures and only need
- one to succeed.
- """
- flags = '-g' if auto_grant_permissions else ''
- return adb_cmd('install -r -t %s %s' % (flags, apk),
- timeout=60*5,
- ignore_status=ignore_status)
-
-
-def adb_uninstall(apk):
- """Remove an apk from container. You must connect first.
-
- @param apk: Package to uninstall.
- """
- return adb_cmd('uninstall %s' % apk)
-
-
-def adb_reboot():
- """Reboots the container and block until container pid is gone.
-
- You must connect first.
- """
- old_pid = get_container_pid()
- logging.info('Trying to reboot PID:%s', old_pid)
- adb_cmd('reboot', ignore_status=True)
- # Ensure that the old container is no longer booted
- utils.poll_for_condition(
- lambda: not utils.pid_is_alive(int(old_pid)), timeout=10)
-
-
-# This adb_root() function is deceiving in that it works just fine on debug
-# builds of ARC (user-debug, eng). However "adb root" does not work on user
-# builds as run by the autotest machines when testing prerelease images. In fact
-# it will silently fail. You will need to find another way to do do what you
-# need to do as root.
-#
-# TODO(b/79122489) - Remove this function.
-def adb_root():
- """Restart adbd with root permission."""
-
- adb_cmd('root')
-
-
-def get_container_root():
- """Returns path to Android container root directory."""
- return _ANDROID_CONTAINER_ROOT_PATH
-
-
-def get_container_pid_path():
- """Returns the container's PID file path.
-
- Raises:
- TestError if no PID file is found, or more than one files are found.
- """
- # Find the PID file rather than the android-XXXXXX/ directory to ignore
- # stale and empty android-XXXXXX/ directories when they exist.
- arc_container_pid_files = glob.glob(_ANDROID_CONTAINER_PID_PATH)
-
- if len(arc_container_pid_files) == 0:
- raise error.TestError('Android container.pid not available')
-
- if len(arc_container_pid_files) > 1:
- raise error.TestError(
- 'Multiple Android container.pid files found: %r. '
- 'Reboot your DUT to recover.' % (arc_container_pid_files))
-
- return arc_container_pid_files[0]
-
-
-def get_android_data_root():
- """Returns path to Chrome OS directory that bind-mounts Android's /data."""
- return _ANDROID_DATA_ROOT_PATH
-
-
-def get_container_pid():
- """Returns the PID of the container."""
- return utils.read_one_line(get_container_pid_path())
-
-
-def get_adbd_pid():
- """Returns the PID of the adbd proxy container."""
- if not os.path.exists(_ADBD_PID_PATH):
- # The adbd proxy does not run on all boards.
- return None
- return utils.read_one_line(_ADBD_PID_PATH)
-
-
-def is_android_process_running(process_name):
- """Return whether Android has completed booting.
-
- @param process_name: Process name.
- """
- output = adb_shell('pgrep -c -f %s' % pipes.quote(process_name),
- ignore_status=True)
- return int(output) > 0
-
-
-def check_android_file_exists(filename):
- """Checks whether the given file exists in the Android filesystem
-
- @param filename: File to check.
- """
- return adb_shell(
- 'test -e {} && echo FileExists'.format(pipes.quote(filename)),
- ignore_status=True).find("FileExists") >= 0
-
-
-def read_android_file(filename):
- """Reads a file in Android filesystem.
-
- @param filename: File to read.
- """
- with tempfile.NamedTemporaryFile() as tmpfile:
- adb_cmd('pull %s %s' % (pipes.quote(filename),
- pipes.quote(tmpfile.name)))
- with open(tmpfile.name) as f:
- return f.read()
-
- return None
-
-
-def write_android_file(filename, data):
- """Writes to a file in Android filesystem.
-
- @param filename: File to write.
- @param data: Data to write.
- """
- with tempfile.NamedTemporaryFile() as tmpfile:
- tmpfile.write(data)
- tmpfile.flush()
-
- adb_cmd('push %s %s' % (pipes.quote(tmpfile.name),
- pipes.quote(filename)))
-
-
-def _write_android_file(filename, data):
- """Writes to a file in Android filesystem.
-
- This is an internal function used to bootstrap adb.
- Tests should use write_android_file instead.
- """
- android_cmd = 'cat > %s' % pipes.quote(filename)
- cros_cmd = 'android-sh -c %s' % pipes.quote(android_cmd)
- utils.run(cros_cmd, stdin=data)
-
-
-def get_android_file_stats(filename):
- """Returns an object of file stats for an Android file.
-
- The returned object supported limited attributes, but can be easily extended
- if needed. Note that the value are all string.
-
- This uses _android_shell to run as root, so that it can access to all files
- inside the container. On non-debuggable build, adb shell is not rootable.
- """
- mapping = {
- '%a': 'mode',
- '%g': 'gid',
- '%h': 'nlink',
- '%u': 'uid',
- }
- output = _android_shell(
- 'stat -c "%s" %s' % (' '.join(mapping.keys()), pipes.quote(filename)),
- ignore_status=True)
- stats = output.split(' ')
- if len(stats) != len(mapping):
- raise error.TestError('Unexpected output from stat: %s' % output)
- _Stats = collections.namedtuple('_Stats', mapping.values())
- return _Stats(*stats)
-
-
-def remove_android_file(filename):
- """Removes a file in Android filesystem.
-
- @param filename: File to remove.
- """
- adb_shell('rm -f %s' % pipes.quote(filename))
-
-
-def wait_for_android_boot(timeout=None):
- """Sleep until Android has completed booting or timeout occurs.
-
- @param timeout: Timeout in seconds.
- """
- arc_common.wait_for_android_boot(timeout)
-
-
-def wait_for_android_process(process_name,
- timeout=_WAIT_FOR_ANDROID_PROCESS_SECONDS):
- """Sleep until an Android process is running or timeout occurs.
-
- @param process_name: Process name.
- @param timeout: Timeout in seconds.
- """
- condition = lambda: is_android_process_running(process_name)
- utils.poll_for_condition(condition=condition,
- desc='%s is running' % process_name,
- timeout=timeout,
- sleep_interval=_PROCESS_CHECK_INTERVAL_SECONDS)
-
-
-def _android_shell(cmd, **kwargs):
- """Execute cmd instead the Android container.
-
- This function is strictly for internal use only, as commands do not run in
- a fully consistent Android environment. Prefer adb_shell instead.
- """
- return utils.system_output('android-sh -c {}'.format(pipes.quote(cmd)),
- **kwargs)
-
-
-def is_android_container_alive():
- """Check if android container is alive."""
- try:
- container_pid = get_container_pid()
- except Exception as e:
- logging.error('is_android_container_alive failed: %r', e)
- return False
- return utils.pid_is_alive(int(container_pid))
-
-
-def _is_in_installed_packages_list(package, option=None):
- """Check if a package is in the list returned by pm list packages.
-
- adb must be ready.
-
- @param package: Package in request.
- @param option: An option for the command adb shell pm list packages.
- Valid values include '-s', '-3', '-d', and '-e'.
- """
- command = 'pm list packages'
- if option:
- command += ' ' + option
- packages = adb_shell(command).splitlines()
- package_entry = 'package:' + package
- ret = package_entry in packages
-
- if not ret:
- logging.info('Could not find "%s" in %s',
- package_entry, str(packages))
- return ret
-
-
-def is_package_installed(package):
- """Check if a package is installed. adb must be ready.
-
- @param package: Package in request.
- """
- return _is_in_installed_packages_list(package)
-
-
-def is_package_disabled(package):
- """Check if an installed package is disabled. adb must be ready.
-
- @param package: Package in request.
- """
- return _is_in_installed_packages_list(package, '-d')
-
-
-def get_package_install_path(package):
- """Returns the apk install location of the given package."""
- output = adb_shell('pm path {}'.format(pipes.quote(package)))
- return output.split(':')[1]
-
-
-def _before_iteration_hook(obj):
- """Executed by parent class before every iteration.
-
- This function resets the run_once_finished flag before every iteration
- so we can detect failure on every single iteration.
-
- Args:
- obj: the test itself
- """
- obj.run_once_finished = False
-
-
-def _after_iteration_hook(obj):
- """Executed by parent class after every iteration.
-
- The parent class will handle exceptions and failures in the run and will
- always call this hook afterwards. Take a screenshot if the run has not
- been marked as finished (i.e. there was a failure/exception).
-
- Args:
- obj: the test itself
- """
- if not obj.run_once_finished:
- if is_adb_connected():
- logging.debug('Recent activities dump:\n%s',
- adb_shell('dumpsys activity recents',
- ignore_status=True))
- if not os.path.exists(_SCREENSHOT_DIR_PATH):
- os.mkdir(_SCREENSHOT_DIR_PATH, 0o755)
- obj.num_screenshots += 1
- if obj.num_screenshots <= _MAX_SCREENSHOT_NUM:
- logging.warning('Iteration %d failed, taking a screenshot.',
- obj.iteration)
- try:
- utils.run('screenshot "{}/{}_iter{}.png"'.format(
- _SCREENSHOT_DIR_PATH, _SCREENSHOT_BASENAME, obj.iteration))
- except Exception as e:
- logging.warning('Unable to capture screenshot. %s', e)
- else:
- logging.warning('Too many failures, no screenshot taken')
-
-
-def send_keycode(keycode):
- """Sends the given keycode to the container
-
- @param keycode: keycode to send.
- """
- adb_shell('input keyevent {}'.format(keycode))
-
-
-def get_android_sdk_version():
- """Returns the Android SDK version.
-
- This function can be called before Android container boots.
- """
- with open('/etc/lsb-release') as f:
- values = dict(line.split('=', 1) for line in f.read().splitlines())
- try:
- return int(values['CHROMEOS_ARC_ANDROID_SDK_VERSION'])
- except (KeyError, ValueError):
- raise error.TestError('Could not determine Android SDK version')
-
-
-def set_device_mode(device_mode, use_fake_sensor_with_lifetime_secs=0):
- """Sets the device in either Clamshell or Tablet mode.
-
- "inject_powerd_input_event" might fail if the DUT does not support Tablet
- mode, and it will raise an |error.CmdError| exception. To prevent that, use
- the |use_fake_sensor_with_lifetime_secs| parameter.
-
- @param device_mode: string with either 'clamshell' or 'tablet'
- @param use_fake_sensor_with_lifetime_secs: if > 0, it will create the
- input device with the given lifetime in seconds
- @raise ValueError: if passed invalid parameters
- @raise error.CmdError: if inject_powerd_input_event fails
- """
- valid_value = ('tablet', 'clamshell')
- if device_mode not in valid_value:
- raise ValueError('Invalid device_mode parameter: %s' % device_mode)
-
- value = 1 if device_mode == 'tablet' else 0
-
- args = ['--code=tablet', '--value=%d' % value]
-
- if use_fake_sensor_with_lifetime_secs > 0:
- args.extend(['--create_dev', '--dev_lifetime=%d' %
- use_fake_sensor_with_lifetime_secs])
-
- try:
- utils.run('inject_powerd_input_event', args=args)
- except error.CmdError as err:
- # TODO: Fragile code ahead. Correct way to do it is to check
- # if device is already in desired mode, and do nothing if so.
- # ATM we don't have a way to check current device mode.
-
- # Assuming that CmdError means that device does not support
- # --code=tablet parameter, meaning that device only supports clamshell
- # mode.
- if device_mode == 'clamshell' and \
- use_fake_sensor_with_lifetime_secs == 0:
- return
- raise err
-
-
-def wait_for_userspace_ready():
- """Waits for userspace apps to be launchable.
-
- Launches and then closes Android settings as a way to ensure all basic
- services are ready. This goes a bit beyond waiting for boot-up to complete,
- as being able to launch an activity requires more of the framework to have
- started. The boot-complete signal happens fairly early, and the framework
- system server is still starting services. By waiting for ActivityManager to
- respond, we automatically wait on more services to be ready.
- """
- output = adb_shell('am start -W -a android.settings.SETTINGS',
- ignore_status=True)
- if not output.endswith('Complete'):
- logging.debug('Output was: %s', output)
- raise error.TestError('Could not launch SETTINGS')
- adb_shell('am force-stop com.android.settings', ignore_status=True)
-
-
-class ArcTest(test.test):
- """ Base class of ARC Test.
-
- This class could be used as super class of an ARC test for saving
- redundant codes for container bringup, autotest-dep package(s) including
- uiautomator setup if required, and apks install/remove during
- arc_setup/arc_teardown, respectively. By default arc_setup() is called in
- initialize() after Android have been brought up. It could also be
- overridden to perform non-default tasks. For example, a simple
- ArcHelloWorldTest can be just implemented with print 'HelloWorld' in its
- run_once() and no other functions are required. We could expect
- ArcHelloWorldTest would bring up browser and wait for container up, then
- print 'Hello World', and shutdown browser after. As a precaution, if you
- overwrite initialize(), arc_setup(), or cleanup() function(s) in ARC test,
- remember to call the corresponding function(s) in this base class as well.
- """
- version = 1
- _PKG_UIAUTOMATOR = 'uiautomator'
- _FULL_PKG_NAME_UIAUTOMATOR = 'com.github.uiautomator'
-
- def __init__(self, *args, **kwargs):
- """Initialize flag setting."""
- super(ArcTest, self).__init__(*args, **kwargs)
- self.initialized = False
- # Set the flag run_once_finished to detect if a test is executed
- # successfully without any exception thrown. Otherwise, generate
- # a screenshot in /var/log for debugging.
- self.run_once_finished = False
- self.logcat_proc = None
- self.dep_package = None
- self.apks = None
- self.full_pkg_names = []
- self.uiautomator = False
- self._should_reenable_play_store = False
- self._chrome = None
- if os.path.exists(_SCREENSHOT_DIR_PATH):
- shutil.rmtree(_SCREENSHOT_DIR_PATH)
- self.register_before_iteration_hook(_before_iteration_hook)
- self.register_after_iteration_hook(_after_iteration_hook)
- # Keep track of the number of debug screenshots taken and keep the
- # total number valid to avoid issues.
- self.num_screenshots = 0
-
- def initialize(self, extension_path=None, username=None, password=None,
- arc_mode=arc_common.ARC_MODE_ENABLED, **chrome_kargs):
- """Log in to a test account."""
- extension_paths = [extension_path] if extension_path else []
- self._chrome = chrome.Chrome(extension_paths=extension_paths,
- username=username,
- password=password,
- arc_mode=arc_mode,
- **chrome_kargs)
- if extension_path:
- self._extension = self._chrome.get_extension(extension_path)
- else:
- self._extension = None
- # With ARC enabled, Chrome will wait until container to boot up
- # before returning here, see chrome.py.
- self.initialized = True
- try:
- if is_android_container_alive():
- self.arc_setup()
- else:
- logging.error('Container is alive?')
- except Exception as err:
- raise error.TestFail(err)
-
- def after_run_once(self):
- """Executed after run_once() only if there were no errors.
-
- This function marks the run as finished with a flag. If there was a
- failure the flag won't be set and the failure can then be detected by
- testing the run_once_finished flag.
- """
- logging.info('After run_once')
- self.run_once_finished = True
-
- def cleanup(self):
- """Log out of Chrome."""
- if not self.initialized:
- logging.info('Skipping ARC cleanup: not initialized')
- return
- logging.info('Starting ARC cleanup')
- try:
- if is_android_container_alive():
- self.arc_teardown()
- except Exception as err:
- raise error.TestFail(err)
- finally:
- try:
- if self.logcat_proc:
- self.logcat_proc.close()
- finally:
- if self._chrome is not None:
- self._chrome.close()
-
- def _install_apks(self, dep_package, apks, full_pkg_names):
- """"Install apks fetched from the specified package folder.
-
- @param dep_package: A dependent package directory
- @param apks: List of apk names to be installed
- @param full_pkg_names: List of packages to be uninstalled at teardown
- """
- apk_path = os.path.join(self.autodir, 'deps', dep_package)
- if apks:
- for apk in apks:
- logging.info('Installing %s', apk)
- out = adb_install('%s/%s' % (apk_path, apk), ignore_status=True)
- logging.info('Install apk output: %s', str(out))
- # Verify if package(s) are installed correctly. We ignored
- # individual install statuses above because some tests list apks for
- # all arches and only need one installed.
- if not full_pkg_names:
- raise error.TestError('Package names of apks expected')
- for pkg in full_pkg_names:
- logging.info('Check if %s is installed', pkg)
- if not is_package_installed(pkg):
- raise error.TestError('Package %s not found' % pkg)
- # Make sure full_pkg_names contains installed packages only
- # so arc_teardown() knows what packages to uninstall.
- self.full_pkg_names.append(pkg)
-
- def _count_nested_array_level(self, array):
- """Count the level of a nested array."""
- if isinstance(array, list):
- return 1 + self._count_nested_array_level(array[0])
- return 0
-
- def _fix_nested_array_level(self, var_name, expected_level, array):
- """Enclose array one level deeper if needed."""
- level = self._count_nested_array_level(array)
- if level == expected_level:
- return array
- if level == expected_level - 1:
- return [array]
-
- logging.error("Variable %s nested level is not fixable: "
- "Expecting %d, seeing %d",
- var_name, expected_level, level)
- raise error.TestError('Format error with variable %s' % var_name)
-
- def arc_setup(self, dep_packages=None, apks=None, full_pkg_names=None,
- uiautomator=False, disable_play_store=False):
- """ARC test setup: Setup dependencies and install apks.
-
- This function disables package verification and enables non-market
- APK installation. Then, it installs specified APK(s) and uiautomator
- package and path if required in a test.
-
- @param dep_packages: Array of package names of autotest_deps APK
- packages.
- @param apks: Array of APK name arrays to be installed in dep_package.
- @param full_pkg_names: Array of full package name arrays to be removed
- in teardown.
- @param uiautomator: uiautomator python package is required or not.
- @param disable_play_store: Set this to True if you want to prevent
- GMS Core from updating.
- """
- if not self.initialized:
- logging.info('Skipping ARC setup: not initialized')
- return
- logging.info('Starting ARC setup')
-
- # Sample parameters for multi-deps setup after fixup (if needed):
- # dep_packages: ['Dep1-apk', 'Dep2-apk']
- # apks: [['com.dep1.arch1.apk', 'com.dep2.arch2.apk'], ['com.dep2.apk']
- # full_pkg_nmes: [['com.dep1.app'], ['com.dep2.app']]
- # TODO(crbug/777787): once the parameters of all callers of arc_setup
- # are refactored, we can delete the safety net here.
- if dep_packages:
- dep_packages = self._fix_nested_array_level(
- 'dep_packages', 1, dep_packages)
- apks = self._fix_nested_array_level('apks', 2, apks)
- full_pkg_names = self._fix_nested_array_level(
- 'full_pkg_names', 2, full_pkg_names)
- if (len(dep_packages) != len(apks) or
- len(apks) != len(full_pkg_names)):
- logging.info('dep_packages length is %d', len(dep_packages))
- logging.info('apks length is %d', len(apks))
- logging.info('full_pkg_names length is %d',
- len(full_pkg_names))
- raise error.TestFail(
- 'dep_packages/apks/full_pkg_names format error')
-
- self.dep_packages = dep_packages
- self.apks = apks
- self.uiautomator = uiautomator or disable_play_store
- # Setup dependent packages if required
- packages = []
- if dep_packages:
- packages = dep_packages[:]
- if self.uiautomator:
- packages.append(self._PKG_UIAUTOMATOR)
- if packages:
- logging.info('Setting up dependent package(s) %s', packages)
- self.job.setup_dep(packages)
-
- self.logcat_proc = arc_common.Logcat()
-
- wait_for_adb_ready()
-
- # Setting verifier_verify_adb_installs to zero suppresses a dialog box
- # that can appear asking for the user to consent to the install.
- adb_shell('settings put global verifier_verify_adb_installs 0')
-
- # Install apks based on dep_packages/apks/full_pkg_names tuples
- if dep_packages:
- for i in range(len(dep_packages)):
- self._install_apks(dep_packages[i], apks[i], full_pkg_names[i])
-
- if self.uiautomator:
- path = os.path.join(self.autodir, 'deps', self._PKG_UIAUTOMATOR)
- sys.path.append(path)
- self._add_ui_object_not_found_handler()
- if disable_play_store and not is_package_disabled(_PLAY_STORE_PKG):
- self._disable_play_store()
- if not is_package_disabled(_PLAY_STORE_PKG):
- raise error.TestFail('Failed to disable Google Play Store.')
- self._should_reenable_play_store = True
-
- def arc_teardown(self):
- """ARC test teardown.
-
- This function removes all installed packages in arc_setup stage
- first. Then, it restores package verification and disables non-market
- APK installation.
-
- """
- if self.full_pkg_names:
- for pkg in self.full_pkg_names:
- logging.info('Uninstalling %s', pkg)
- if not is_package_installed(pkg):
- raise error.TestError('Package %s was not installed' % pkg)
- adb_uninstall(pkg)
- if (self.uiautomator and
- is_package_installed(self._FULL_PKG_NAME_UIAUTOMATOR)):
- logging.info('Uninstalling %s', self._FULL_PKG_NAME_UIAUTOMATOR)
- adb_uninstall(self._FULL_PKG_NAME_UIAUTOMATOR)
- if self._should_reenable_play_store:
- adb_shell('pm enable ' + _PLAY_STORE_PKG)
- adb_shell('settings put secure install_non_market_apps 0')
- adb_shell('settings put global package_verifier_enable 1')
- adb_shell('settings put secure package_verifier_user_consent 0')
-
- # Remove the adb keys without going through adb. This is because the
- # 'rm' tool does not have permissions to remove the keys once they have
- # been restorecon(8)ed.
- utils.system_output('rm -f %s' %
- pipes.quote(os.path.join(
- get_android_data_root(),
- os.path.relpath(_ANDROID_ADB_KEYS_PATH, '/'))))
- utils.system_output('adb kill-server')
-
- def _add_ui_object_not_found_handler(self):
- """Logs the device dump upon uiautomator.UiObjectNotFoundException."""
- from uiautomator import device as d
- d.handlers.on(lambda d: logging.debug('Device window dump:\n%s',
- d.dump()))
-
- def _disable_play_store(self):
- """Disables the Google Play Store app."""
- if is_package_disabled(_PLAY_STORE_PKG):
- return
- adb_shell('am force-stop ' + _PLAY_STORE_PKG)
- adb_shell('am start -a android.settings.APPLICATION_DETAILS_SETTINGS '
- '-d package:' + _PLAY_STORE_PKG)
-
- # Note: the straightforward "pm disable <package>" command would be
- # better, but that requires root permissions, which aren't available on
- # a pre-release image being tested. The only other way is through the
- # Settings UI, but which might change.
- from uiautomator import device as d
- d(textMatches='(?i)DISABLE', packageName=_SETTINGS_PKG).wait.exists()
- d(textMatches='(?i)DISABLE', packageName=_SETTINGS_PKG).click.wait()
- d(textMatches='(?i)DISABLE APP').click.wait()
- ok_button = d(textMatches='(?i)OK')
- if ok_button.exists:
- ok_button.click.wait()
- adb_shell('am force-stop ' + _SETTINGS_PKG)
diff --git a/client/common_lib/cros/arc_common.py b/client/common_lib/cros/arc_common.py
deleted file mode 100644
index b8507c9..0000000
--- a/client/common_lib/cros/arc_common.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2016 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.
-#
-# This file contains things that are shared by arc.py and arc_util.py.
-
-import logging
-import subprocess
-import time
-
-from autotest_lib.client.bin import utils
-from autotest_lib.client.common_lib import error
-
-
-# Ask Chrome to start ARC instance and the script will block until ARC's boot
-# completed event.
-ARC_MODE_ENABLED = "enabled"
-# Similar to "enabled", except that it will not block.
-ARC_MODE_ENABLED_ASYNC = "enabled_async"
-# Ask Chrome to not start ARC instance. This is the default.
-ARC_MODE_DISABLED = "disabled"
-# All available ARC options.
-ARC_MODES = [ARC_MODE_ENABLED, ARC_MODE_ENABLED_ASYNC, ARC_MODE_DISABLED]
-
-_BOOT_CHECK_INTERVAL_SECONDS = 2
-_WAIT_FOR_ANDROID_BOOT_SECONDS = 120
-
-_VAR_LOGCAT_PATH = '/var/log/logcat'
-_VAR_LOGCAT_BOOT_PATH = '/var/log/logcat-boot'
-
-
-class Logcat(object):
- """Saves the output of logcat to a file."""
-
- def __init__(self, path=_VAR_LOGCAT_PATH):
- with open(path, 'w') as f:
- self._proc = subprocess.Popen(
- ['android-sh', '-c', 'logcat'],
- stdout=f,
- stderr=subprocess.STDOUT,
- close_fds=True)
-
- def __enter__(self):
- """Support for context manager."""
- return self
-
- def __exit__(self, *args):
- """Support for context manager.
-
- Calls close().
- """
- self.close()
-
- def close(self):
- """Stop the logcat process gracefully."""
- if not self._proc:
- return
- self._proc.terminate()
-
- class TimeoutException(Exception):
- """Termination timeout timed out."""
-
- try:
- utils.poll_for_condition(
- condition=lambda: self._proc.poll() is not None,
- exception=TimeoutException,
- timeout=10,
- sleep_interval=0.1,
- desc='Waiting for logcat to terminate')
- except TimeoutException:
- logging.info('Killing logcat due to timeout')
- self._proc.kill()
- self._proc.wait()
- finally:
- self._proc = None
-
-
-def wait_for_android_boot(timeout=None):
- """Sleep until Android has completed booting or timeout occurs."""
- if timeout is None:
- timeout = _WAIT_FOR_ANDROID_BOOT_SECONDS
-
- def _is_container_started():
- return utils.system('android-sh -c true', ignore_status=True) == 0
-
- def _is_android_booted():
- output = utils.system_output(
- 'android-sh -c "getprop sys.boot_completed"', ignore_status=True)
- return output.strip() == '1'
-
- logging.info('Waiting for Android to boot completely.')
-
- start_time = time.time()
- utils.poll_for_condition(condition=_is_container_started,
- desc='Container has started',
- timeout=timeout,
- exception=error.TestFail('Android did not boot!'),
- sleep_interval=_BOOT_CHECK_INTERVAL_SECONDS)
- with Logcat(_VAR_LOGCAT_BOOT_PATH):
- boot_timeout = timeout - (time.time() - start_time)
- utils.poll_for_condition(
- condition=_is_android_booted,
- desc='Android has booted',
- timeout=boot_timeout,
- exception=error.TestFail('Android did not boot!'),
- sleep_interval=_BOOT_CHECK_INTERVAL_SECONDS)
- logging.info('Android has booted completely.')
diff --git a/client/common_lib/cros/arc_util.py b/client/common_lib/cros/arc_util.py
deleted file mode 100644
index f16fa03..0000000
--- a/client/common_lib/cros/arc_util.py
+++ /dev/null
@@ -1,369 +0,0 @@
-# Lint as: python2, python3
-# Copyright 2016 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.
-#
-# arc_util.py is supposed to be called from chrome.py for ARC specific logic.
-# It should not import arc.py since it will create a import loop.
-
-import collections
-import logging
-import os
-import tempfile
-
-from autotest_lib.client.bin import utils
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib import file_utils
-from autotest_lib.client.common_lib.cros import arc_common
-from telemetry.core import exceptions
-from telemetry.internal.browser import extension_page
-
-_ARC_SUPPORT_HOST_URL = 'chrome-extension://cnbgggchhmkkdmeppjobngjoejnihlei/'
-_ARC_SUPPORT_HOST_PAGENAME = '_generated_background_page.html'
-_DUMPSTATE_PATH = '/var/log/arc-dumpstate.log'
-_USERNAME = 'crosarcplusplustest@gmail.com'
-_ARCP_URL = 'https://sites.google.com/a/chromium.org/dev/chromium-os' \
- '/testing/arcplusplus-testing/arcp'
-_OPT_IN_BEGIN = 'Initializing ARC opt-in flow.'
-_OPT_IN_SKIP = 'Skip waiting provisioning completed.'
-_OPT_IN_FINISH = 'ARC opt-in flow complete.'
-
-_SIGN_IN_TIMEOUT = 120
-_SIGN_IN_CHECK_INTERVAL = 1
-
-
-# Describes ARC session state.
-# - provisioned is set to True once ARC is provisioned.
-# - tos_needed is set to True in case ARC Terms of Service need to be shown.
-# This depends on ARC Terms of Service acceptance and policy for
-# ARC preferences, such as backup and restore and use of location
-# services.
-ArcSessionState = collections.namedtuple(
- 'ArcSessionState', ['provisioned', 'tos_needed'])
-
-
-def get_arc_session_state(autotest_ext):
- """Returns the runtime state of ARC session.
-
- @param autotest_ext private autotest API.
-
- @raises error.TestFail in case autotest API failure or if ARC is not
- allowed for the device.
-
- @return ArcSessionState that describes the state of current ARC session.
-
- """
- get_arc_state = '''
- new Promise((resolve, reject) => {
- chrome.autotestPrivate.getArcState((state) => {
- if (chrome.runtime.lastError) {
- reject(new Error(chrome.runtime.lastError.message));
- return;
- }
- resolve(state);
- });
- })
- '''
- try:
- state = autotest_ext.EvaluateJavaScript(get_arc_state, promise=True)
- return ArcSessionState(state['provisioned'], state['tosNeeded'])
- except exceptions.EvaluateException as e:
- raise error.TestFail('Could not get ARC session state "%s".' % e)
-
-
-def _wait_arc_provisioned(autotest_ext):
- """Waits until ARC provisioning is completed.
-
- @param autotest_ext private autotest API.
-
- @raises: error.TimeoutException if provisioning is not complete.
-
- """
- utils.poll_for_condition(
- condition=lambda: get_arc_session_state(autotest_ext).provisioned,
- desc='Wait for ARC is provisioned',
- timeout=_SIGN_IN_TIMEOUT,
- sleep_interval=_SIGN_IN_CHECK_INTERVAL)
-
-
-def should_start_arc(arc_mode):
- """
- Determines whether ARC should be started.
-
- @param arc_mode: mode as defined in arc_common.
-
- @returns: True or False.
-
- """
- logging.debug('ARC is enabled in mode %s', arc_mode)
- assert arc_mode is None or arc_mode in arc_common.ARC_MODES
- return arc_mode in [arc_common.ARC_MODE_ENABLED,
- arc_common.ARC_MODE_ENABLED_ASYNC]
-
-
-def post_processing_after_browser(chrome, timeout):
- """
- Called when a new browser instance has been initialized.
-
- Note that this hook function is called regardless of arc_mode.
-
- @param chrome: Chrome object.
-
- """
- # Remove any stale dumpstate files.
- if os.path.isfile(_DUMPSTATE_PATH):
- os.unlink(_DUMPSTATE_PATH)
-
- # Wait for Android container ready if ARC is enabled.
- if chrome.arc_mode == arc_common.ARC_MODE_ENABLED:
- try:
- arc_common.wait_for_android_boot(timeout)
- except Exception:
- # Save dumpstate so that we can figure out why boot does not
- # complete.
- _save_android_dumpstate()
- raise
-
-
-def pre_processing_before_close(chrome):
- """
- Called when the browser instance is being closed.
-
- Note that this hook function is called regardless of arc_mode.
-
- @param chrome: Chrome object.
-
- """
- if not should_start_arc(chrome.arc_mode):
- return
- # TODO(b/29341443): Implement stopping of adb logcat when we start adb
- # logcat for all tests
-
- # Save dumpstate just before logout.
- _save_android_dumpstate()
-
-
-def _save_android_dumpstate():
- """
- Triggers a dumpstate and saves its contents to to /var/log/arc-dumpstate.log
- with logging.
-
- Exception thrown while doing dumpstate will be ignored.
- """
-
- try:
- logging.info('Saving Android dumpstate.')
- with open(_DUMPSTATE_PATH, 'w') as out:
- log = utils.system_output('android-sh -c arc-bugreport')
- out.write(log)
- logging.info('Android dumpstate successfully saved.')
- except Exception:
- # Dumpstate is nice-to-have stuff. Do not make it as a fatal error.
- logging.exception('Failed to save Android dumpstate.')
-
-
-def get_test_account_info():
- """Retrieve test account information."""
- with tempfile.NamedTemporaryFile() as pltp:
- file_utils.download_file(_ARCP_URL, pltp.name)
- password = pltp.read().rstrip()
- return (_USERNAME, password)
-
-
-def set_browser_options_for_opt_in(b_options):
- """
- Setup Chrome for gaia login and opt_in.
-
- @param b_options: browser options object used by chrome.Chrome.
-
- """
- b_options.username, b_options.password = get_test_account_info()
- b_options.disable_default_apps = False
- b_options.disable_component_extensions_with_background_pages = False
- b_options.gaia_login = True
-
-
-def enable_play_store(autotest_ext, enabled, enable_managed_policy=True):
- """
- Enable ARC++ Play Store
-
- Do nothing if the account is managed and enable_managed_policy is set to
- True.
-
- @param autotest_ext: autotest extension object.
-
- @param enabled: if True then perform opt-in, otherwise opt-out.
-
- @param enable_managed_policy: If False then policy check is ignored for
- managed user case and ARC++ is forced enabled or disabled.
-
- @returns: True if the opt-in should continue; else False.
-
- """
-
- if autotest_ext is None:
- raise error.TestFail(
- 'Could not change the Play Store enabled state because '
- 'autotest API does not exist')
-
- # Skip enabling for managed users, since value is policy enforced.
- # Return early if a managed user has ArcEnabled set to false.
- get_play_store_state = '''
- new Promise((resolve, reject) => {
- chrome.autotestPrivate.getPlayStoreState((state) => {
- if (chrome.runtime.lastError) {
- reject(new Error(chrome.runtime.lastError.message));
- return;
- }
- resolve(state);
- });
- })
- '''
- try:
- state = autotest_ext.EvaluateJavaScript(get_play_store_state,
- promise=True)
- if state['managed']:
- # Handle managed case.
- logging.info('Determined that ARC is managed by user policy.')
- if enable_managed_policy:
- if enabled == state['enabled']:
- return True
- logging.info('Returning early since ARC is policy-enforced.')
- return False
- logging.info('Forcing ARC %s, ignore managed state.',
- ('enabled' if enabled else 'disabled'))
-
- autotest_ext.ExecuteJavaScript('''
- chrome.autotestPrivate.setPlayStoreEnabled(
- %s, function(enabled) {});
- ''' % ('true' if enabled else 'false'))
- except exceptions.EvaluateException as e:
- raise error.TestFail('Could not change the Play Store enabled state '
- ' via autotest API. "%s".' % e)
-
- return True
-
-
-def find_opt_in_extension_page(browser):
- """
- Find and verify the opt-in extension extension page.
-
- @param browser: chrome.Chrome broswer object.
-
- @returns: the extension page.
-
- @raises: error.TestFail if extension is not found or is mal-formed.
-
- """
- opt_in_extension_id = extension_page.UrlToExtensionId(_ARC_SUPPORT_HOST_URL)
- try:
- extension_pages = browser.extensions.GetByExtensionId(
- opt_in_extension_id)
- except Exception as e:
- raise error.TestFail('Could not locate extension for arc opt-in. '
- 'Make sure disable_default_apps is False. '
- '"%s".' % e)
-
- extension_main_page = None
- for page in extension_pages:
- url = page.EvaluateJavaScript('location.href;')
- if url.endswith(_ARC_SUPPORT_HOST_PAGENAME):
- extension_main_page = page
- break
- if not extension_main_page:
- raise error.TestError('Found opt-in extension but not correct page!')
- extension_main_page.WaitForDocumentReadyStateToBeComplete()
-
- js_code_did_start_conditions = ['termsPage != null',
- '(termsPage.isManaged_ || termsPage.state_ == LoadState.LOADED)']
- try:
- for condition in js_code_did_start_conditions:
- extension_main_page.WaitForJavaScriptCondition(condition,
- timeout=60)
- except Exception as e:
- raise error.TestError('Error waiting for "%s": "%s".' % (condition, e))
-
- return extension_main_page
-
-
-def opt_in_and_wait_for_completion(extension_main_page):
- """
- Step through the user input of the opt-in extension and wait for completion.
-
- @param extension_main_page: opt-in extension object.
-
- @raises error.TestFail if opt-in doesn't complete after timeout.
-
- """
- extension_main_page.ExecuteJavaScript('termsPage.onAgree()')
-
- try:
- extension_main_page.WaitForJavaScriptCondition('!appWindow',
- timeout=_SIGN_IN_TIMEOUT)
- except Exception as e:
- js_read_error_message = """
- err = appWindow.contentWindow.document.getElementById(
- "error-message");
- if (err) {
- err.innerText;
- }
- """
- err_msg = extension_main_page.EvaluateJavaScript(js_read_error_message)
- err_msg = err_msg.strip()
- logging.error('Error: %r', err_msg)
- if err_msg:
- raise error.TestFail('Opt-in app error: %r' % err_msg)
- else:
- raise error.TestFail('Opt-in app did not finish running after %s '
- 'seconds!' % _SIGN_IN_TIMEOUT)
- # Reset termsPage to be able to reuse OptIn page and wait condition for ToS
- # are loaded.
- extension_main_page.ExecuteJavaScript('termsPage = null')
-
-
-def opt_in(browser,
- autotest_ext,
- enable_managed_policy=True,
- wait_for_provisioning=True):
- """
- Step through opt in and wait for it to complete.
-
- Return early if the arc_setting cannot be set True.
-
- @param browser: chrome.Chrome browser object.
- @param autotest_ext: autotest extension object.
- @param enable_managed_policy: If False then policy check is ignored for
- managed user case and ARC++ is forced enabled.
- @param wait_for_provisioning: True in case we have to wait for provisioning
- to complete.
-
- @raises: error.TestFail if opt in fails.
-
- """
-
- logging.info(_OPT_IN_BEGIN)
-
- # TODO(b/124391451): Enterprise tests have race, when ARC policy appears
- # after profile prefs sync completed. That means they may appear as
- # non-managed first, treated like this but finally turns as managed. This
- # leads to test crash. Solution is to wait until prefs are synced or, if
- # possible tune test accounts to wait sync is completed before starting the
- # Chrome session.
-
- # Enabling Play Store may affect this flag, capture it before.
- tos_needed = get_arc_session_state(autotest_ext).tos_needed
-
- if not enable_play_store(autotest_ext, True, enable_managed_policy):
- return
-
- if not wait_for_provisioning:
- logging.info(_OPT_IN_SKIP)
- return
-
- if tos_needed:
- extension_main_page = find_opt_in_extension_page(browser)
- opt_in_and_wait_for_completion(extension_main_page)
- else:
- _wait_arc_provisioned(autotest_ext)
-
- logging.info(_OPT_IN_FINISH)
diff --git a/client/common_lib/cros/bluetooth/__init__.py b/client/common_lib/cros/bluetooth/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/common_lib/cros/bluetooth/__init__.py
+++ /dev/null
diff --git a/client/common_lib/cros/bluetooth/bluetooth_gatt_server.py b/client/common_lib/cros/bluetooth/bluetooth_gatt_server.py
deleted file mode 100644
index 8203ab2..0000000
--- a/client/common_lib/cros/bluetooth/bluetooth_gatt_server.py
+++ /dev/null
@@ -1,83 +0,0 @@
-import asyncore
-import btsocket
-import struct
-import logging
-
-
-BT_ATT_DEFAULT_LE_MTU = 23
-
-BT_ATT_OP_MTU_REQ = 0x02
-BT_ATT_OP_MTU_RSP = 0x03
-
-
-class BluetoothGATTServerError(Exception):
- """Error raised for GATT-related issues with BluetoothGATTServer."""
- pass
-
-
-class BluetoothGATTServer(asyncore.dispatcher):
- """Bluetooth GATT Server.
-
- This class inherits asyncore.dispatcher to handle I/O on BLE socket.
- It is essentially a socket service server. The class implements
- initialization, read/write requests, notifications and indications.
-
- Before creating an instance of this class, the machine must be set up
- (with appropriate HCI commands) to be at least advertising, be powered,
- and have LE turned on.
-
- """
-
- def __init__(self, mtu=BT_ATT_DEFAULT_LE_MTU):
- self.mtu = max(mtu, BT_ATT_DEFAULT_LE_MTU)
-
- sock, addr = btsocket.create_le_gatt_server_socket()
- logging.debug('incoming connection from address %s', addr)
-
- asyncore.dispatcher.__init__(self, sock=sock)
- asyncore.loop()
-
-
- def exchange_mtu(self, data):
- """Handle exchange MTU request.
-
- Exchange MTU request/response usually initiates client-server
- communication. The method sends exchange MTU response back to client.
- It also sets value for MTU attribute.
-
- @param data: Raw data received from socket (without opcode).
-
- """
- if len(data) != 2:
- raise BluetoothGATTServerError(
- 'Invalid MTU size: expected 2 bytes for Exchange MTU Request')
-
- client_rx_mtu = struct.unpack('<H', data)
- if client_rx_mtu < BT_ATT_DEFAULT_LE_MTU:
- raise BluetoothGATTServerError('Invalid MTU size: %d < %d' %
- client_rx_mtu, BT_ATT_DEFAULT_LE_MTU)
-
- self.mtu = min(client_rx_mtu, self.mtu)
-
- response = struct.pack('<BH', BT_ATT_OP_MTU_RSP, self.mtu)
- self.send(response)
-
-
- def handle_read(self):
- """Receive and handle a single message from the socket.
-
- This method gets called when the asynchronous loop detects that a read()
- call on the channel's socket will succeed. It overrides handle_read()
- from asyncore.dispatcher class.
-
- """
- data = self.recv(self.mtu)
-
- opcode = ord(data[0])
- data = data[1:]
-
- func_map = {BT_ATT_OP_MTU_REQ: self.exchange_mtu}
- if opcode not in func_map:
- raise BluetoothGATTServerError('Invalid Opcode: %d' % opcode)
-
- func_map[opcode](data)
diff --git a/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py b/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py
deleted file mode 100644
index 0de577f..0000000
--- a/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py
+++ /dev/null
@@ -1,582 +0,0 @@
-# Copyright (c) 2013 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 logging
-import socket
-import struct
-
-import btsocket
-
-SDP_HDR_FORMAT = '>BHH'
-SDP_HDR_SIZE = struct.calcsize(SDP_HDR_FORMAT)
-SDP_TID_CNT = 1 << 16
-SDP_MAX_UUIDS_CNT = 12
-SDP_BODY_CNT_FORMAT = '>HH'
-SDP_BODY_CNT_SIZE = struct.calcsize(SDP_BODY_CNT_FORMAT)
-BLUETOOTH_BASE_UUID = 0x0000000000001000800000805F9B34FB
-
-# Constants are taken from lib/sdp.h in BlueZ source.
-SDP_RESPONSE_TIMEOUT = 20
-SDP_REQ_BUFFER_SIZE = 2048
-SDP_RSP_BUFFER_SIZE = 65535
-SDP_PDU_CHUNK_SIZE = 1024
-
-SDP_PSM = 0x0001
-
-SDP_UUID = 0x0001
-
-SDP_DATA_NIL = 0x00
-SDP_UINT8 = 0x08
-SDP_UINT16 = 0x09
-SDP_UINT32 = 0x0A
-SDP_UINT64 = 0x0B
-SDP_UINT128 = 0x0C
-SDP_INT8 = 0x10
-SDP_INT16 = 0x11
-SDP_INT32 = 0x12
-SDP_INT64 = 0x13
-SDP_INT128 = 0x14
-SDP_UUID_UNSPEC = 0x18
-SDP_UUID16 = 0x19
-SDP_UUID32 = 0x1A
-SDP_UUID128 = 0x1C
-SDP_TEXT_STR_UNSPEC = 0x20
-SDP_TEXT_STR8 = 0x25
-SDP_TEXT_STR16 = 0x26
-SDP_TEXT_STR32 = 0x27
-SDP_BOOL = 0x28
-SDP_SEQ_UNSPEC = 0x30
-SDP_SEQ8 = 0x35
-SDP_SEQ16 = 0x36
-SDP_SEQ32 = 0x37
-SDP_ALT_UNSPEC = 0x38
-SDP_ALT8 = 0x3D
-SDP_ALT16 = 0x3E
-SDP_ALT32 = 0x3F
-SDP_URL_STR_UNSPEC = 0x40
-SDP_URL_STR8 = 0x45
-SDP_URL_STR16 = 0x46
-SDP_URL_STR32 = 0x47
-
-SDP_ERROR_RSP = 0x01
-SDP_SVC_SEARCH_REQ = 0x02
-SDP_SVC_SEARCH_RSP = 0x03
-SDP_SVC_ATTR_REQ = 0x04
-SDP_SVC_ATTR_RSP = 0x05
-SDP_SVC_SEARCH_ATTR_REQ = 0x06
-SDP_SVC_SEARCH_ATTR_RSP = 0x07
-
-
-class BluetoothSDPSocketError(Exception):
- """Error raised for SDP-related issues with BluetoothSDPSocket."""
- pass
-
-
-class BluetoothSDPSocket(btsocket.socket):
- """Bluetooth SDP Socket.
-
- BluetoothSDPSocket wraps the btsocket.socket() class to implement
- the necessary send and receive methods for the SDP protocol.
-
- """
-
- def __init__(self):
- super(BluetoothSDPSocket, self).__init__(family=btsocket.AF_BLUETOOTH,
- type=socket.SOCK_SEQPACKET,
- proto=btsocket.BTPROTO_L2CAP)
- self.tid = 0
-
-
- def gen_tid(self):
- """Generate new Transaction ID
-
- @return Transaction ID
-
- """
- self.tid = (self.tid + 1) % SDP_TID_CNT
- return self.tid
-
-
- def connect(self, address):
- """Connect to device with the given address
-
- @param address: Bluetooth address.
-
- """
- try:
- super(BluetoothSDPSocket, self).connect((address, SDP_PSM))
- except btsocket.error as e:
- logging.error('Error connecting to %s: %s', address, e)
- raise BluetoothSDPSocketError('Error connecting to host: %s' % e)
- except btsocket.timeout as e:
- logging.error('Timeout connecting to %s: %s', address, e)
- raise BluetoothSDPSocketError('Timeout connecting to host: %s' % e)
-
- def send_request(self, code, tid, data, forced_pdu_size=None):
- """Send a request to the socket.
-
- @param code: Request code.
- @param tid: Transaction ID.
- @param data: Parameters as bytearray or str.
- @param forced_pdu_size: Use certain PDU size parameter instead of
- calculating actual length of sequence.
-
- @raise BluetoothSDPSocketError: if 'send' to the socket didn't succeed.
-
- """
- size = len(data)
- if forced_pdu_size != None:
- size = forced_pdu_size
- msg = struct.pack(SDP_HDR_FORMAT, code, tid, size) + data
-
- length = self.send(msg)
- if length != len(msg):
- raise BluetoothSDPSocketError('Short write on socket')
-
-
- def recv_response(self):
- """Receive a single response from the socket.
-
- The response data is not parsed.
-
- Use settimeout() to set whether this method will block if there is no
- reply, return immediately or wait for a specific length of time before
- timing out and raising TimeoutError.
-
- @return tuple of (code, tid, data)
- @raise BluetoothSDPSocketError: if the received packet is too small or
- if size of the packet differs from size written in header
-
- """
- # Read the response from the socket.
- response = self.recv(SDP_RSP_BUFFER_SIZE)
-
- if len(response) < SDP_HDR_SIZE:
- raise BluetoothSDPSocketError('Short read on socket')
-
- code, tid, length = struct.unpack_from(SDP_HDR_FORMAT, response)
- data = response[SDP_HDR_SIZE:]
-
- if length != len(data):
- raise BluetoothSDPSocketError('Short read on socket')
-
- return code, tid, data
-
-
- def send_request_and_wait(self, req_code, req_data, forced_pdu_size=None):
- """Send a request to the socket and wait for the response.
-
- The response data is not parsed.
-
- @param req_code: Request code.
- @param req_data: Parameters as bytearray or str.
- @param forced_pdu_size: Use certain PDU size parameter instead of
- calculating actual length of sequence.
-
- Use settimeout() to set whether this method will block if there is no
- reply, return immediately or wait for a specific length of time before
- timing out and raising TimeoutError.
-
- @return tuple of (rsp_code, data)
- @raise BluetoothSDPSocketError: if Transaction ID of the response
- doesn't match to Transaction ID sent in request
-
- """
- req_tid = self.gen_tid()
- self.send_request(req_code, req_tid, req_data, forced_pdu_size)
- rsp_code, rsp_tid, rsp_data = self.recv_response()
-
- if req_tid != rsp_tid:
- raise BluetoothSDPSocketError("Transaction IDs for request and "
- "response don't match")
-
- return rsp_code, rsp_data
-
-
- def _pack_list(self, data_element_list):
- """Preappend a list with required header.
-
- Size of the header is chosen to be minimal possible.
-
- @param data_element_list: List to be packed.
-
- @return packed list as a str
- @raise BluetoothSDPSocketError: if size of the list is larger than or
- equal to 2^32 bytes, which is not supported in SDP transactions
-
- """
- size = len(data_element_list)
- if size < (1 << 8):
- header = struct.pack('>BB', SDP_SEQ8, size)
- elif size < (1 << 16):
- header = struct.pack('>BH', SDP_SEQ16, size)
- elif size < (1 << 32):
- header = struct.pack('>BI', SDP_SEQ32, size)
- else:
- raise BluetoothSDPSocketError('List is too long')
- return header + data_element_list
-
-
- def _pack_uuids(self, uuids, preferred_size):
- """Pack a list of UUIDs to a binary sequence
-
- @param uuids: List of UUIDs (as integers).
- @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
-
- @return packed list as a str
- @raise BluetoothSDPSocketError: the given preferred size is not
- supported by SDP
-
- """
- if preferred_size not in (16, 32, 128):
- raise BluetoothSDPSocketError('Unsupported UUID size: %d; '
- 'Supported values are: 16, 32, 128'
- % preferred_size)
-
- res = ''
- for uuid in uuids:
- # Fall back to 128 bits if the UUID doesn't fit into preferred_size.
- if uuid >= (1 << preferred_size) or preferred_size == 128:
- uuid128 = uuid
- if uuid < (1 << 32):
- uuid128 = (uuid128 << 96) + BLUETOOTH_BASE_UUID
- packed_uuid = struct.pack('>BQQ', SDP_UUID128, uuid128 >> 64,
- uuid128 & ((1 << 64) - 1))
- elif preferred_size == 16:
- packed_uuid = struct.pack('>BH', SDP_UUID16, uuid)
- elif preferred_size == 32:
- packed_uuid = struct.pack('>BI', SDP_UUID32, uuid)
-
- res += packed_uuid
-
- res = self._pack_list(res)
-
- return res
-
-
- def _unpack_uuids(self, response):
- """Unpack SDP response
-
- @param response: body of raw SDP response.
-
- @return tuple of (uuids, cont_state)
-
- """
- total_cnt, cur_cnt = struct.unpack_from(SDP_BODY_CNT_FORMAT, response)
- scanned = SDP_BODY_CNT_SIZE
- uuids = []
- for i in range(cur_cnt):
- uuid, = struct.unpack_from('>I', response, scanned)
- uuids.append(uuid)
- scanned += 4
-
- cont_state = response[scanned:]
- return uuids, cont_state
-
-
- def _unpack_error_code(self, response):
- """Unpack Error Code from SDP error response
-
- @param response: Body of raw SDP response.
-
- @return Error Code as int
-
- """
- error_code, = struct.unpack_from('>H', response)
- return error_code
-
-
- def service_search_request(self, uuids, max_rec_cnt, preferred_size=32,
- forced_pdu_size=None, invalid_request=False):
- """Send a Service Search Request
-
- @param uuids: List of UUIDs (as integers) to look for.
- @param max_rec_cnt: Maximum count of returned service records.
- @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
- @param forced_pdu_size: Use certain PDU size parameter instead of
- calculating actual length of sequence.
- @param invalid_request: Whether to send request with intentionally
- invalid syntax for testing purposes (bool flag).
-
- @return list of found services' service record handles or Error Code
- @raise BluetoothSDPSocketError: arguments do not match the SDP
- restrictions or if the response has an incorrect code
-
- """
- if max_rec_cnt < 1 or max_rec_cnt > 65535:
- raise BluetoothSDPSocketError('MaximumServiceRecordCount must be '
- 'between 1 and 65535, inclusive')
-
- if len(uuids) > SDP_MAX_UUIDS_CNT:
- raise BluetoothSDPSocketError('Too many UUIDs')
-
- pattern = self._pack_uuids(uuids, preferred_size) + struct.pack(
- '>H', max_rec_cnt)
- cont_state = '\0'
- handles = []
-
- while True:
- request = pattern + cont_state
-
- # Request without any continuation state is an example of invalid
- # request syntax.
- if invalid_request:
- request = pattern
-
- code, response = self.send_request_and_wait(
- SDP_SVC_SEARCH_REQ, request, forced_pdu_size)
-
- if code == SDP_ERROR_RSP:
- return self._unpack_error_code(response)
-
- if code != SDP_SVC_SEARCH_RSP:
- raise BluetoothSDPSocketError('Incorrect response code')
-
- cur_list, cont_state = self._unpack_uuids(response)
- handles.extend(cur_list)
- if cont_state == '\0':
- break
-
- return handles
-
-
- def _pack_attr_ids(self, attr_ids):
- """Pack a list of Attribute IDs to a binary sequence
-
- @param attr_ids: List of Attribute IDs.
-
- @return packed list as a str
- @raise BluetoothSDPSocketError: if list of UUIDs after packing is larger
- than or equal to 2^32 bytes
-
- """
- attr_ids.sort()
- res = ''
- for attr_id in attr_ids:
- # Each element could be either a single Attribute ID or
- # a range of IDs.
- if isinstance(attr_id, list):
- packed_attr_id = struct.pack('>BHH', SDP_UINT32,
- attr_id[0], attr_id[1])
- else:
- packed_attr_id = struct.pack('>BH', SDP_UINT16, attr_id)
-
- res += packed_attr_id
-
- res = self._pack_list(res)
-
- return res
-
-
- def _unpack_int(self, data, cnt):
- """Unpack an unsigned integer of cnt bytes
-
- @param data: raw data to be parsed
- @param cnt: size of integer
-
- @return unsigned integer
-
- """
- res = 0
- for i in range(cnt):
- res = (res << 8) | ord(data[i])
- return res
-
-
- def _unpack_sdp_data_element(self, data):
- """Unpack a data element from a raw response
-
- @param data: raw data to be parsed
-
- @return tuple (result, scanned bytes)
-
- """
- header, = struct.unpack_from('>B', data)
- data_type = header >> 3
- data_size = header & 7
- scanned = 1
- data = data[1:]
- if data_type == 0:
- if data_size != 0:
- raise BluetoothSDPSocketError('Invalid size descriptor')
- return None, scanned
- elif data_type <= 3 or data_type == 5:
- if (data_size > 4 or
- data_type == 3 and (data_size == 0 or data_size == 3) or
- data_type == 5 and data_size != 0):
- raise BluetoothSDPSocketError('Invalid size descriptor')
-
- int_size = 1 << data_size
- res = self._unpack_int(data, int_size)
-
- # Consider negative integers.
- if data_type == 2 and (ord(data[0]) & 128) != 0:
- res = res - (1 << (int_size * 8))
-
- # Consider booleans.
- if data_type == 5:
- res = res != 0
-
- scanned += int_size
- return res, scanned
- elif data_type == 4 or data_type == 8:
- if data_size < 5 or data_size > 7:
- raise BluetoothSDPSocketError('Invalid size descriptor')
-
- int_size = 1 << (data_size - 5)
- str_size = self._unpack_int(data, int_size)
-
- res = data[int_size : int_size + str_size]
- scanned += int_size + str_size
- return res, scanned
- elif data_type == 6 or data_type == 7:
- if data_size < 5 or data_size > 7:
- raise BluetoothSDPSocketError('Invalid size descriptor')
-
- int_size = 1 << (data_size - 5)
- total_size = self._unpack_int(data, int_size)
-
- data = data[int_size:]
- scanned += int_size + total_size
-
- res = []
- cur_size = 0
- while cur_size < total_size:
- elem, elem_size = self._unpack_sdp_data_element(data)
- res.append(elem)
- data = data[elem_size:]
- cur_size += elem_size
-
- return res, scanned
- else:
- raise BluetoothSDPSocketError('Invalid size descriptor')
-
-
- def service_attribute_request(self, handle, max_attr_byte_count, attr_ids,
- forced_pdu_size=None, invalid_request=None):
- """Send a Service Attribute Request
-
- @param handle: service record from which attribute values are to be
- retrieved.
- @param max_attr_byte_count: maximum number of bytes of attribute data to
- be returned in the response to this request.
- @param attr_ids: a list, where each element is either an attribute ID
- or a range of attribute IDs.
- @param forced_pdu_size: Use certain PDU size parameter instead of
- calculating actual length of sequence.
- @param invalid_request: Whether to send request with intentionally
- invalid syntax for testing purposes (string with raw request).
-
- @return list of found attributes IDs and their values or Error Code
- @raise BluetoothSDPSocketError: arguments do not match the SDP
- restrictions or if the response has an incorrect code
-
- """
- if max_attr_byte_count < 7 or max_attr_byte_count > 65535:
- raise BluetoothSDPSocketError('MaximumAttributeByteCount must be '
- 'between 7 and 65535, inclusive')
-
- pattern = (struct.pack('>I', handle) +
- struct.pack('>H', max_attr_byte_count) +
- self._pack_attr_ids(attr_ids))
- cont_state = '\0'
- complete_response = ''
-
- while True:
- request = (invalid_request if invalid_request
- else pattern + cont_state)
-
- code, response = self.send_request_and_wait(
- SDP_SVC_ATTR_REQ, request, forced_pdu_size)
-
- if code == SDP_ERROR_RSP:
- return self._unpack_error_code(response)
-
- if code != SDP_SVC_ATTR_RSP:
- raise BluetoothSDPSocketError('Incorrect response code')
-
- response_byte_count, = struct.unpack_from('>H', response)
- if response_byte_count > max_attr_byte_count:
- raise BluetoothSDPSocketError('AttributeListByteCount exceeds'
- 'MaximumAttributeByteCount')
-
- response = response[2:]
- complete_response += response[:response_byte_count]
- cont_state = response[response_byte_count:]
-
- if cont_state == '\0':
- break
-
- id_values_list = self._unpack_sdp_data_element(complete_response)[0]
- if len(id_values_list) % 2 == 1:
- raise BluetoothSDPSocketError('Length of returned list is odd')
-
- return id_values_list
-
-
- def service_search_attribute_request(self, uuids, max_attr_byte_count,
- attr_ids, preferred_size=32,
- forced_pdu_size=None,
- invalid_request=None):
- """Send a Service Search Attribute Request
-
- @param uuids: list of UUIDs (as integers) to look for.
- @param max_attr_byte_count: maximum number of bytes of attribute data to
- be returned in the response to this request.
- @param attr_ids: a list, where each element is either an attribute ID
- or a range of attribute IDs.
- @param preferred_size: Preffered size of UUIDs in bits (16, 32, or 128).
- @param forced_pdu_size: Use certain PDU size parameter instead of
- calculating actual length of sequence.
- @param invalid_request: Whether to send request with intentionally
- invalid syntax for testing purposes (string to be prepended
- to correct request).
-
- @return list of found attributes IDs and their values or Error Code
- @raise BluetoothSDPSocketError: arguments do not match the SDP
- restrictions or if the response has an incorrect code
-
- """
- if len(uuids) > SDP_MAX_UUIDS_CNT:
- raise BluetoothSDPSocketError('Too many UUIDs')
-
- if max_attr_byte_count < 7 or max_attr_byte_count > 65535:
- raise BluetoothSDPSocketError('MaximumAttributeByteCount must be '
- 'between 7 and 65535, inclusive')
-
- pattern = (self._pack_uuids(uuids, preferred_size) +
- struct.pack('>H', max_attr_byte_count) +
- self._pack_attr_ids(attr_ids))
- cont_state = '\0'
- complete_response = ''
-
- while True:
- request = pattern + cont_state
- if invalid_request:
- request = invalid_request + request
-
- code, response = self.send_request_and_wait(
- SDP_SVC_SEARCH_ATTR_REQ, request, forced_pdu_size)
-
- if code == SDP_ERROR_RSP:
- return self._unpack_error_code(response)
-
- if code != SDP_SVC_SEARCH_ATTR_RSP:
- raise BluetoothSDPSocketError('Incorrect response code')
-
- response_byte_count, = struct.unpack_from('>H', response)
- if response_byte_count > max_attr_byte_count:
- raise BluetoothSDPSocketError('AttributeListByteCount exceeds'
- 'MaximumAttributeByteCount')
-
- response = response[2:]
- complete_response += response[:response_byte_count]
- cont_state = response[response_byte_count:]
-
- if cont_state == '\0':
- break
-
- id_values_list = self._unpack_sdp_data_element(complete_response)[0]
-
- return id_values_list
diff --git a/client/common_lib/cros/bluetooth/bluetooth_socket.py b/client/common_lib/cros/bluetooth/bluetooth_socket.py
deleted file mode 100644
index 7e02d68..0000000
--- a/client/common_lib/cros/bluetooth/bluetooth_socket.py
+++ /dev/null
@@ -1,1224 +0,0 @@
-# Copyright (c) 2013 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 array
-import btsocket
-import fcntl
-import logging
-import socket
-import struct
-
-
-# Constants from lib/mgmt.h in BlueZ source
-MGMT_INDEX_NONE = 0xFFFF
-
-MGMT_HDR_SIZE = 6
-
-MGMT_STATUS_SUCCESS = 0x00
-MGMT_STATUS_UNKNOWN_COMMAND = 0x01
-MGMT_STATUS_NOT_CONNECTED = 0x02
-MGMT_STATUS_FAILED = 0x03
-MGMT_STATUS_CONNECT_FAILED = 0x04
-MGMT_STATUS_AUTH_FAILED = 0x05
-MGMT_STATUS_NOT_PAIRED = 0x06
-MGMT_STATUS_NO_RESOURCES = 0x07
-MGMT_STATUS_TIMEOUT = 0x08
-MGMT_STATUS_ALREADY_CONNECTED = 0x09
-MGMT_STATUS_BUSY = 0x0a
-MGMT_STATUS_REJECTED = 0x0b
-MGMT_STATUS_NOT_SUPPORTED = 0x0c
-MGMT_STATUS_INVALID_PARAMS = 0x0d
-MGMT_STATUS_DISCONNECTED = 0x0e
-MGMT_STATUS_NOT_POWERED = 0x0f
-MGMT_STATUS_CANCELLED = 0x10
-MGMT_STATUS_INVALID_INDEX = 0x11
-MGMT_STATUS_RFKILLED = 0x12
-
-MGMT_OP_READ_VERSION = 0x0001
-MGMT_OP_READ_COMMANDS = 0x0002
-MGMT_OP_READ_INDEX_LIST = 0x0003
-MGMT_OP_READ_INFO = 0x0004
-MGMT_OP_SET_POWERED = 0x0005
-MGMT_OP_SET_DISCOVERABLE = 0x0006
-MGMT_OP_SET_CONNECTABLE = 0x0007
-MGMT_OP_SET_FAST_CONNECTABLE = 0x0008
-MGMT_OP_SET_PAIRABLE = 0x0009
-MGMT_OP_SET_LINK_SECURITY = 0x000A
-MGMT_OP_SET_SSP = 0x000B
-MGMT_OP_SET_HS = 0x000C
-MGMT_OP_SET_LE = 0x000D
-MGMT_OP_SET_DEV_CLASS = 0x000E
-MGMT_OP_SET_LOCAL_NAME = 0x000F
-MGMT_OP_ADD_UUID = 0x0010
-MGMT_OP_REMOVE_UUID = 0x0011
-MGMT_OP_LOAD_LINK_KEYS = 0x0012
-MGMT_OP_LOAD_LONG_TERM_KEYS = 0x0013
-MGMT_OP_DISCONNECT = 0x0014
-MGMT_OP_GET_CONNECTIONS = 0x0015
-MGMT_OP_PIN_CODE_REPLY = 0x0016
-MGMT_OP_PIN_CODE_NEG_REPLY = 0x0017
-MGMT_OP_SET_IO_CAPABILITY = 0x0018
-MGMT_OP_PAIR_DEVICE = 0x0019
-MGMT_OP_CANCEL_PAIR_DEVICE = 0x001A
-MGMT_OP_UNPAIR_DEVICE = 0x001B
-MGMT_OP_USER_CONFIRM_REPLY = 0x001C
-MGMT_OP_USER_CONFIRM_NEG_REPLY = 0x001D
-MGMT_OP_USER_PASSKEY_REPLY = 0x001E
-MGMT_OP_USER_PASSKEY_NEG_REPLY = 0x001F
-MGMT_OP_READ_LOCAL_OOB_DATA = 0x0020
-MGMT_OP_ADD_REMOTE_OOB_DATA = 0x0021
-MGMT_OP_REMOVE_REMOTE_OOB_DATA = 0x0022
-MGMT_OP_START_DISCOVERY = 0x0023
-MGMT_OP_STOP_DISCOVERY = 0x0024
-MGMT_OP_CONFIRM_NAME = 0x0025
-MGMT_OP_BLOCK_DEVICE = 0x0026
-MGMT_OP_UNBLOCK_DEVICE = 0x0027
-MGMT_OP_SET_DEVICE_ID = 0x0028
-MGMT_OP_SET_ADVERTISING = 0x0029
-MGMT_OP_SET_BREDR = 0x002A
-MGMT_OP_SET_STATIC_ADDRESS = 0x002B
-MGMT_OP_SET_SCAN_PARAMS = 0x002C
-MGMT_OP_SET_SECURE_CONN = 0x002D
-MGMT_OP_SET_DEBUG_KEYS = 0x002E
-MGMT_OP_SET_PRIVACY = 0x002F
-MGMT_OP_LOAD_IRKS = 0x0030
-MGMT_OP_GET_CONN_INFO = 0x0031
-MGMT_OP_GET_CLOCK_INFO = 0x0032
-MGMT_OP_ADD_DEVICE = 0x0033
-MGMT_OP_REMOVE_DEVICE = 0x0034
-MGMT_OP_LOAD_CONN_PARAM = 0x0035
-MGMT_OP_READ_UNCONF_INDEX_LIST = 0x0036
-MGMT_OP_READ_CONFIG_INFO = 0x0037
-MGMT_OP_SET_EXTERNAL_CONFIG = 0x0038
-MGMT_OP_SET_PUBLIC_ADDRESS = 0x0039
-
-MGMT_EV_CMD_COMPLETE = 0x0001
-MGMT_EV_CMD_STATUS = 0x0002
-MGMT_EV_CONTROLLER_ERROR = 0x0003
-MGMT_EV_INDEX_ADDED = 0x0004
-MGMT_EV_INDEX_REMOVED = 0x0005
-MGMT_EV_NEW_SETTINGS = 0x0006
-MGMT_EV_CLASS_OF_DEV_CHANGED = 0x0007
-MGMT_EV_LOCAL_NAME_CHANGED = 0x0008
-MGMT_EV_NEW_LINK_KEY = 0x0009
-MGMT_EV_NEW_LONG_TERM_KEY = 0x000A
-MGMT_EV_DEVICE_CONNECTED = 0x000B
-MGMT_EV_DEVICE_DISCONNECTED = 0x000C
-MGMT_EV_CONNECT_FAILED = 0x000D
-MGMT_EV_PIN_CODE_REQUEST = 0x000E
-MGMT_EV_USER_CONFIRM_REQUEST = 0x000F
-MGMT_EV_USER_PASSKEY_REQUEST = 0x0010
-MGMT_EV_AUTH_FAILED = 0x0011
-MGMT_EV_DEVICE_FOUND = 0x0012
-MGMT_EV_DISCOVERING = 0x0013
-MGMT_EV_DEVICE_BLOCKED = 0x0014
-MGMT_EV_DEVICE_UNBLOCKED = 0x0015
-MGMT_EV_DEVICE_UNPAIRED = 0x0016
-MGMT_EV_PASSKEY_NOTIFY = 0x0017
-MGMT_EV_NEW_IRK = 0x0018
-MGMT_EV_NEW_CSRK = 0x0019
-MGMT_EV_DEVICE_ADDED = 0x001a
-MGMT_EV_DEVICE_REMOVED = 0x001b
-MGMT_EV_NEW_CONN_PARAM = 0x001c
-MGMT_EV_UNCONF_INDEX_ADDED = 0x001d
-MGMT_EV_UNCONF_INDEX_REMOVED = 0x001e
-MGMT_EV_NEW_CONFIG_OPTIONS = 0x001f
-
-# Settings returned by MGMT_OP_READ_INFO
-MGMT_SETTING_POWERED = 0x00000001
-MGMT_SETTING_CONNECTABLE = 0x00000002
-MGMT_SETTING_FAST_CONNECTABLE = 0x00000004
-MGMT_SETTING_DISCOVERABLE = 0x00000008
-MGMT_SETTING_PAIRABLE = 0x00000010
-MGMT_SETTING_LINK_SECURITY = 0x00000020
-MGMT_SETTING_SSP = 0x00000040
-MGMT_SETTING_BREDR = 0x00000080
-MGMT_SETTING_HS = 0x00000100
-MGMT_SETTING_LE = 0x00000200
-MGMT_SETTING_ADVERTISING = 0x00000400
-MGMT_SETTING_SECURE_CONNECTIONS = 0x00000800
-MGMT_SETTING_DEBUG_KEYS = 0x00001000
-MGMT_SETTING_PRIVACY = 0x00002000
-MGMT_SETTING_CONTROLLER_CONFIG = 0x00004000
-
-# Options returned by MGMT_OP_READ_CONFIG_INFO
-MGMT_OPTION_EXTERNAL_CONFIG = 0x00000001
-MGMT_OPTION_PUBLIC_ADDRESS = 0x00000002
-
-# Disconnect reason returned in MGMT_EV_DEVICE_DISCONNECTED
-MGMT_DEV_DISCONN_UNKNOWN = 0x00
-MGMT_DEV_DISCONN_TIMEOUT = 0x01
-MGMT_DEV_DISCONN_LOCAL_HOST = 0x02
-MGMT_DEV_DISCONN_REMOTE = 0x03
-
-# Flags returned in MGMT_EV_DEVICE_FOUND
-MGMT_DEV_FOUND_CONFIRM_NAME = 0x01
-MGMT_DEV_FOUND_LEGACY_PAIRING = 0x02
-
-
-# EIR Data field types
-EIR_FLAGS = 0x01
-EIR_UUID16_SOME = 0x02
-EIR_UUID16_ALL = 0x03
-EIR_UUID32_SOME = 0x04
-EIR_UUID32_ALL = 0x05
-EIR_UUID128_SOME = 0x06
-EIR_UUID128_ALL = 0x07
-EIR_NAME_SHORT = 0x08
-EIR_NAME_COMPLETE = 0x09
-EIR_TX_POWER = 0x0A
-EIR_CLASS_OF_DEV = 0x0D
-EIR_SSP_HASH = 0x0E
-EIR_SSP_RANDOMIZER = 0x0F
-EIR_DEVICE_ID = 0x10
-EIR_GAP_APPEARANCE = 0x19
-
-
-# Derived from lib/hci.h
-HCIGETDEVLIST = 0x800448d2
-HCIGETDEVINFO = 0x800448d3
-
-HCI_UP = 1 << 0
-HCI_INIT = 1 << 1
-HCI_RUNNING = 1 << 2
-HCI_PSCAN = 1 << 3
-HCI_ISCAN = 1 << 4
-HCI_AUTH = 1 << 5
-HCI_ENCRYPT = 1 << 6
-HCI_INQUIRY = 1 << 7
-HCI_RAW = 1 << 8
-
-
-def parse_eir(eirdata):
- """Parse Bluetooth Extended Inquiry Result (EIR) data structuree.
-
- @param eirdata: Encoded eir data structure.
-
- @return Dictionary equivalent to the expanded structure keyed by EIR_*
- fields, with any data members parsed to useful formats.
-
- """
- fields = {}
- pos = 0
- while pos < len(eirdata):
- # Byte at the current position is the field length, which should be
- # zero at the end of the structure.
- (field_len,) = struct.unpack('B', buffer(eirdata, pos, 1))
- if field_len == 0:
- break
- # Next byte is the field type, and the rest of the field is the data.
- # Note that the length field doesn't include itself so that's why the
- # offsets and lengths look a little odd.
- (field_type,) = struct.unpack('B', buffer(eirdata, pos + 1, 1))
- data = eirdata[pos+2:pos+field_len+1]
- pos += field_len + 1
- # Parse the individual fields to make the data meaningful.
- if field_type == EIR_NAME_SHORT or field_type == EIR_NAME_COMPLETE:
- data = data.rstrip('\0')
- # Place in the dictionary keyed by type.
- fields[field_type] = data
-
- return fields
-
-
-
-class BluetoothSocketError(Exception):
- """Error raised for general issues with BluetoothSocket."""
- pass
-
-class BluetoothInvalidPacketError(Exception):
- """Error raised when an invalid packet is received from the socket."""
- pass
-
-class BluetoothControllerError(Exception):
- """Error raised when the Controller Error event is received."""
- pass
-
-
-class BluetoothSocket(btsocket.socket):
- """Bluetooth Socket.
-
- BluetoothSocket wraps the btsocket.socket() class, and thus the system
- socket.socket() class, to implement the necessary send and receive methods
- for the HCI Control and Monitor protocols (aka mgmt_ops) of the
- Linux Kernel.
-
- Instantiate either BluetoothControlSocket or BluetoothRawSocket rather
- than this class directly.
-
- See bluez/doc/mgmt_api.txt for details.
-
- """
-
- def __init__(self):
- super(BluetoothSocket, self).__init__(family=btsocket.AF_BLUETOOTH,
- type=socket.SOCK_RAW,
- proto=btsocket.BTPROTO_HCI)
- self.events = []
-
-
- def send_command(self, code, index, data=''):
- """Send a command to the socket.
-
- To send a command, wait for the reply event, and parse it use
- send_command_and_wait() instead.
-
- @param code: Command Code.
- @param index: Controller index, may be MGMT_INDEX_NONE.
- @param data: Parameters as bytearray or str (optional).
-
- """
- # Send the command to the kernel
- msg = struct.pack('<HHH', code, index, len(data)) + data
-
- length = self.send(msg)
- if length != len(msg):
- raise BluetoothSocketError('Short write on socket')
-
-
- def recv_event(self):
- """Receive a single event from the socket.
-
- The event data is not parsed; in the case of command complete events
- this means it includes both the data for the event and the response
- for the command.
-
- Use settimeout() to set whether this method will block if there is no
- data, return immediately or wait for a specific length of time before
- timing out and raising TimeoutError.
-
- @return tuple of (event, index, data)
-
- """
- # Read the message from the socket
- hdr = bytearray(MGMT_HDR_SIZE)
- data = bytearray(512)
- try:
- (nbytes, ancdata, msg_flags, address) = self.recvmsg_into(
- (hdr, data))
- except btsocket.timeout as e:
- raise BluetoothSocketError('Error receiving event: %s' % e)
- if nbytes < MGMT_HDR_SIZE:
- raise BluetoothInvalidPacketError('Packet shorter than header')
-
- # Parse the header
- (event, index, length) = struct.unpack_from('<HHH', buffer(hdr))
- if nbytes < MGMT_HDR_SIZE + length:
- raise BluetoothInvalidPacketError('Packet shorter than length')
-
- return (event, index, data[:length])
-
-
- def send_command_and_wait(self, cmd_code, cmd_index, cmd_data='',
- expected_length=None):
- """Send a command to the socket and wait for the reply.
-
- Additional events are appended to the events list of the socket object.
-
- @param cmd_code: Command Code.
- @param cmd_index: Controller index, may be btsocket.HCI_DEV_NONE.
- @param cmd_data: Parameters as bytearray or str.
- @param expected_length: May be set to verify the length of the data.
-
- Use settimeout() to set whether this method will block if there is no
- reply, return immediately or wait for a specific length of time before
- timing out and raising TimeoutError.
-
- @return tuple of (status, data)
-
- """
- self.send_command(cmd_code, cmd_index, cmd_data)
-
- while True:
- (event, index, data) = self.recv_event()
-
- if event == MGMT_EV_CMD_COMPLETE:
- if index != cmd_index:
- raise BluetoothInvalidPacketError(
- ('Response for wrong controller index received: ' +
- '0x%04d (expected 0x%04d)' % (index, cmd_index)))
- if len(data) < 3:
- raise BluetoothInvalidPacketError(
- ('Incorrect command complete event data length: ' +
- '%d (expected at least 3)' % len(data)))
-
- (code, status) = struct.unpack_from('<HB', buffer(data, 0, 3))
- logging.debug('[0x%04x] command 0x%04x complete: 0x%02x',
- index, code, status)
-
- if code != cmd_code:
- raise BluetoothInvalidPacketError(
- ('Response for wrong command code received: ' +
- '0x%04d (expected 0x%04d)' % (code, cmd_code)))
-
- response_length = len(data) - 3
- if (expected_length is not None and
- response_length != expected_length):
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected %d)' % (response_length,
- expected_length)))
-
- return (status, data[3:])
-
- elif event == MGMT_EV_CMD_STATUS:
- if index != cmd_index:
- raise BluetoothInvalidPacketError(
- ('Response for wrong controller index received: ' +
- '0x%04d (expected 0x%04d)' % (index, cmd_index)))
- if len(data) != 3:
- raise BluetoothInvalidPacketError(
- ('Incorrect command status event data length: ' +
- '%d (expected 3)' % len(data)))
-
- (code, status) = struct.unpack_from('<HB', buffer(data, 0, 3))
- logging.debug('[0x%04x] command 0x%02x status: 0x%02x',
- index, code, status)
-
- if code != cmd_code:
- raise BluetoothInvalidPacketError(
- ('Response for wrong command code received: ' +
- '0x%04d (expected 0x%04d)' % (code, cmd_code)))
-
- return (status, None)
-
- elif event == MGMT_EV_CONTROLLER_ERROR:
- if len(data) != 1:
- raise BluetoothInvalidPacketError(
- ('Incorrect controller error event data length: ' +
- '%d (expected 1)' % len(data)))
-
- (error_code) = struct.unpack_from('<B', buffer(data, 0, 1))
-
- raise BluetoothControllerError('Controller error: %d' %
- error_code)
-
- else:
- logging.debug('[0x%04x] event 0x%02x length: %d',
- index, event, len(data))
- self.events.append((event, index, data))
-
-
- def wait_for_events(self, index, events):
- """Wait for and return the first of a set of events specified.
-
- @param index: Controller index of event, may be btsocket.HCI_DEV_NONE.
- @param events: List of event codes to wait for.
-
- Use settimeout() to set whether this method will block if there is no
- event received, return immediately or wait for a specific length of
- time before timing out and raising TimeoutError.
-
- @return Tuple of (event, data)
-
- """
- while True:
- for idx, (event, event_index, data) in enumerate(self.events):
- if event_index == index and event in events:
- self.events.pop(idx)
- return (event, data)
-
- (event, event_index, data) = self.recv_event()
- if event_index == index and event in events:
- return (event, data)
- elif event == MGMT_EV_CMD_COMPLETE:
- if len(data) < 3:
- raise BluetoothInvalidPacketError(
- ('Incorrect command complete event data length: ' +
- '%d (expected at least 3)' % len(data)))
-
- (code, status) = struct.unpack_from('<HB', buffer(data, 0, 3))
- logging.debug('[0x%04x] command 0x%04x complete: 0x%02x '
- '(Ignored)', index, code, status)
-
- elif event == MGMT_EV_CMD_STATUS:
- if len(data) != 3:
- raise BluetoothInvalidPacketError(
- ('Incorrect command status event data length: ' +
- '%d (expected 3)' % len(data)))
-
- (code, status) = struct.unpack_from('<HB', buffer(data, 0, 3))
- logging.debug('[0x%04x] command 0x%02x status: 0x%02x '
- '(Ignored)', index, code, status)
-
- elif event == MGMT_EV_CONTROLLER_ERROR:
- if len(data) != 1:
- raise BluetoothInvalidPacketError(
- ('Incorrect controller error event data length: ' +
- '%d (expected 1)' % len(data)))
-
- (error_code) = struct.unpack_from('<B', buffer(data, 0, 1))
- logging.debug('[0x%04x] controller error: %d (Ignored)',
- index, error_code)
-
- else:
- self.events.append((event, index, data))
-
-
-class BluetoothControlSocket(BluetoothSocket):
- """Bluetooth Control Socket.
-
- BluetoothControlSocket provides convenient methods mapping to each mgmt_ops
- command that send an appropriately formatted command and parse the response.
-
- """
-
- DEFAULT_TIMEOUT = 15
-
- def __init__(self):
- super(BluetoothControlSocket, self).__init__()
- self.bind((btsocket.HCI_DEV_NONE, btsocket.HCI_CHANNEL_CONTROL))
- self.settimeout(self.DEFAULT_TIMEOUT)
-
- # Certain features will depend on the management version and revision,
- # so check those now.
- (version, revision) = self.read_version()
- logging.debug('MGMT API %d.%d', version, revision)
- self._kernel_confirms_name = (
- (version > 1) or ((version == 1) and (revision >= 5)))
-
- def read_version(self):
- """Read the version of the management interface.
-
- @return tuple (version, revision) on success, None on failure.
-
- """
- (status, data) = self.send_command_and_wait(
- MGMT_OP_READ_VERSION,
- MGMT_INDEX_NONE,
- expected_length=3)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (version, revision) = struct.unpack_from('<BH', buffer(data))
- return (version, revision)
-
-
- def read_supported_commands(self):
- """Read the supported management commands and events.
-
- @return tuple (commands, events) on success, None on failure.
-
- """
- (status, data) = self.send_command_and_wait(
- MGMT_OP_READ_COMMANDS,
- MGMT_INDEX_NONE)
- if status != MGMT_STATUS_SUCCESS:
- return None
- if len(data) < 4:
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected at least 4)' % len(data)))
-
- (ncommands, nevents) = struct.unpack_from('<HH', buffer(data, 0, 4))
- offset = 4
- expected_length = offset + (ncommands * 2) + (nevents * 2)
- if len(data) != expected_length:
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected %d)' % (len(data), expected_length)))
-
- commands = []
- while len(commands) < ncommands:
- commands.extend(struct.unpack_from('<H', buffer(data, offset, 2)))
- offset += 2
-
- events = []
- while len(events) < nevents:
- events.extend(struct.unpack_from('<H', buffer(data, offset, 2)))
- offset += 2
-
- return (commands, events)
-
-
- def read_index_list(self):
- """Read the list of currently known controllers.
-
- @return array of controller indexes on success, None on failure.
-
- """
- (status, data) = self.send_command_and_wait(
- MGMT_OP_READ_INDEX_LIST,
- MGMT_INDEX_NONE)
- if status != MGMT_STATUS_SUCCESS:
- return None
- if len(data) < 2:
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected at least 2)' % len(data)))
-
- (nindexes,) = struct.unpack_from('<H', buffer(data, 0, 2))
- offset = 2
- expected_length = offset + (nindexes * 2)
- if len(data) != expected_length:
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected %d)' % (len(data), expected_length)))
-
- indexes = []
- while len(indexes) < nindexes:
- indexes.extend(struct.unpack_from('<H', buffer(data, offset, 2)))
- offset += 2
-
- return indexes
-
-
- def read_info(self, index):
- """Read the state and basic information of a controller.
-
- Address is returned as a string in upper-case hex to match the
- BlueZ property.
-
- @param index: Controller index.
-
- @return tuple (address, bluetooth_version, manufacturer,
- supported_settings, current_settings,
- class_of_device, name, short_name) on success,
- None on failure.
-
- """
- (status, data) = self.send_command_and_wait(
- MGMT_OP_READ_INFO,
- index,
- expected_length=280)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (address, bluetooth_version, manufacturer,
- supported_settings, current_settings,
- class_of_device_lo, class_of_device_mid, class_of_device_hi,
- name, short_name) = struct.unpack_from(
- '<6sBHLL3B249s11s',
- buffer(data))
-
- return (
- ':'.join('%02X' % x
- for x in reversed(struct.unpack('6B', address))),
- bluetooth_version,
- manufacturer,
- supported_settings,
- current_settings,
- (class_of_device_lo |(class_of_device_mid << 8) |
- (class_of_device_hi << 16)),
- name.rstrip('\0'),
- short_name.rstrip('\0'))
-
-
- def set_powered(self, index, powered):
- """Set the powered state of a controller.
-
- @param index: Controller index.
- @param powered: Whether controller radio should be powered.
-
- @return New controller settings on success, None on failure.
-
- """
- msg_data = struct.pack('<B', bool(powered))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_POWERED,
- index,
- msg_data,
- expected_length=4)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_discoverable(self, index, discoverable, timeout=0):
- """Set the discoverable state of a controller.
-
- @param index: Controller index.
- @param discoverable: Whether controller should be discoverable.
- @param timeout: Timeout in seconds before disabling discovery again,
- ignored when discoverable is False, must not be zero when
- discoverable is True.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<BH', bool(discoverable), timeout)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_DISCOVERABLE,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not discoverable:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_connectable(self, index, connectable):
- """Set the connectable state of a controller.
-
- @param index: Controller index.
- @param connectable: Whether controller should be connectable.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(connectable))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_CONNECTABLE,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not connectable:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_fast_connectable(self, index, connectable):
- """Set the fast connectable state of a controller.
-
- Fast Connectable is a state where page scan parameters are set to favor
- faster connect times at the expense of higher power consumption.
-
- Unlike most other set_* commands, this may only be used when the
- controller is powered.
-
- @param index: Controller index.
- @param connectable: Whether controller should be fast connectable.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False or the controller is
- powered down, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(connectable))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_FAST_CONNECTABLE,
- index,
- msg_data)
- if status == MGMT_STATUS_NOT_SUPPORTED and not connectable:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
- # This is documented as returning current settings, but doesn't in
- # our kernel version (probably a bug), so if no data is returned,
- # pretend that was success.
- if len(data) == 0:
- return 0
- elif len(data) != 4:
- raise BluetoothInvalidPacketError(
- ('Incorrect length of data for response: ' +
- '%d (expected 4)' % len(data)))
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_pairable(self, index, pairable):
- """Set the pairable state of a controller.
-
- @param index: Controller index.
- @param pairable: Whether controller should be pairable.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(pairable))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_PAIRABLE,
- index,
- msg_data,
- expected_length=4)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_link_security(self, index, link_security):
- """Set the link security state of a controller.
-
- Toggles the use of link level security (aka Security Mode 3) for a
- controller.
-
- @param index: Controller index.
- @param link_security: Whether controller should be link_security.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(link_security))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_LINK_SECURITY,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not link_security:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_ssp(self, index, ssp):
- """Set the whether a controller supports Simple Secure Pairing.
-
- @param index: Controller index.
- @param ssp: Whether controller should support SSP.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(ssp))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_SSP,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not ssp:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_hs(self, index, hs):
- """Set the whether a controller supports Bluetooth High Speed.
-
- @param index: Controller index.
- @param hs: Whether controller should support High Speed.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(hs))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_HS,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not hs:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_le(self, index, le):
- """Set the whether a controller supports Bluetooth Low Energy.
-
- @param index: Controller index.
- @param le: Whether controller should support Low Energy.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(le))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_LE,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not le:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_device_class(self, index, major, minor):
- """Set the device class of the controller.
-
- Consult the Bluetooth Baseband Assigned Numbers specification for valid
- values, in general both values are bit fields defined by that
- specification.
-
- If the device class is set while the controller is powered off, 0 will
- be returned, but the new class will be set by the host subsystem after
- the controller is powered on.
-
- @param index: Controller index.
- @param major: Major device class.
- @param minor: Minor device class.
-
- @return New three-octet device class on success, None on failure.
-
- """
- msg_data = struct.pack('<BB', major, minor)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_DEV_CLASS,
- index,
- msg_data,
- expected_length=3)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (class_of_device_lo, class_of_device_mid,
- class_of_device_hi) = struct.unpack_from('<3B', buffer(data))
- return (class_of_device_lo |(class_of_device_mid << 8) |
- (class_of_device_hi << 16))
-
-
- def set_local_name(self, index, name, short_name):
- """Set the local name of the controller.
-
- @param index: Controller index.
- @param name: Full length name, up to 248 characters.
- @param short_name: Short name, up to 10 characters.
-
- @return Tuple of (name, short_name) on success, None on failure.
-
- """
- # Truncate the provided parameters and then zero-pad using struct
- # so we pass a fixed-length null-terminated string to the kernel.
- msg_data = struct.pack('<249s11s', name[:248], short_name[:10])
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_LOCAL_NAME,
- index,
- msg_data,
- expected_length=260)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (name, short_name) = struct.unpack_from('<249s11s', buffer(data))
- return (name.rstrip('\0'), short_name.rstrip('\0'))
-
-
- def start_discovery(self, index, address_type):
- """Start discovering remote devices.
-
- Call get_discovered_devices() to retrieve the list of devices found.
-
- @param index: Controller index.
- @param address_type: Address types to discover.
-
- @return Address types discovery was started for on success,
- None on failure.
-
- """
- msg_data = struct.pack('<B', address_type)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_START_DISCOVERY,
- index,
- msg_data,
- expected_length=1)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (address_type,) = struct.unpack_from('<B', buffer(data))
- return address_type
-
-
- def stop_discovery(self, index, address_type):
- """Stop discovering remote devices.
-
- There is usually no need to call this method explicitly as discovery
- is automatically stopped once it has iterated through the necessary
- channels.
-
- @param index: Controller index.
- @param address_type: Address types to stop discovering.
-
- @return Address types discovery was stopped for on success,
- None on failure.
-
- """
- msg_data = struct.pack('<B', address_type)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_STOP_DISCOVERY,
- index,
- msg_data,
- expected_length=1)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (address_type,) = struct.unpack_from('<B', buffer(data))
- return address_type
-
-
- def get_discovered_devices(self, index):
- """Return list of discovered remote devices.
-
- This method may be called any time after start_discovery() and will
- wait until the full list of devices has been returned, there is usually
- no need to call stop_discovery() explicitly.
-
- Use settimeout() to set whether this method will block if there are no
- events, return immediately or wait for a specific length of time before
- timing out and raising TimeoutError.
-
- @param index: Controller index.
-
- @return List of devices found as tuples with the format
- (address, address_type, rssi, flags, eirdata)
-
- """
- devices = []
- discovering = True
- while discovering:
- (event, data) = self.wait_for_events(
- index,
- ( MGMT_EV_DISCOVERING, MGMT_EV_DEVICE_FOUND ))
-
- if event == MGMT_EV_DISCOVERING:
- if len(data) != 2:
- raise BluetoothInvalidPacketError(
- ('Incorrect discovering event data length: ' +
- '%d (expected 2)' % len(data)))
-
- (address_type,
- discovering) = struct.unpack_from('<BB', buffer(data))
-
- elif event == MGMT_EV_DEVICE_FOUND:
- if len(data) < 14:
- raise BluetoothInvalidPacketError(
- ('Incorrect device found event data length: ' +
- '%d (expected at least 14)' % len(data)))
-
- (address, address_type, rssi,
- flags, eir_len) = struct.unpack_from('<6sBbLH',
- buffer(data, 0, 14))
-
- if len(data) != 14 + eir_len:
- raise BluetoothInvalidPacketError(
- ('Incorrect device found event data length: ' +
- '%d (expected %d)' % (len(data), 14 + eir_len)))
-
- devices.append((
- ':'.join('%02X' % x
- for x in reversed(
- struct.unpack('6B', address))),
- address_type,
- rssi,
- flags,
- bytes(data[14:])
- ))
-
- # The kernel might want us to confirm whether or not we
- # know the name of the device. We don't really care whether
- # or not this works, we just have to do it to get the EIR
- # Request.
- if flags & MGMT_DEV_FOUND_CONFIRM_NAME:
- msg_data = struct.pack('<6sBB',
- address, address_type, False)
- if self._kernel_confirms_name:
- self.send_command_and_wait(
- MGMT_OP_CONFIRM_NAME,
- index,
- msg_data)
- else:
- self.send_command(
- MGMT_OP_CONFIRM_NAME,
- index,
- msg_data)
-
-
- return devices
-
-
- def set_advertising(self, index, advertising):
- """Set the whether a controller is advertising via LE.
-
- @param index: Controller index.
- @param advertising: Whether controller should advertise via LE.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(advertising))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_ADVERTISING,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not advertising:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_bredr(self, index, bredr):
- """Set the whether a controller supports Bluetooth BR/EDR (classic).
-
- @param index: Controller index.
- @param bredr: Whether controller should support BR/EDR.
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(bredr))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_BREDR,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not bredr:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def set_secure_connections(self, index, secure_conn):
- """Set whether a controller supports secure connections.
-
- @param index: Controller index.
- @param secure_conn: Whether controller should support secure connections
-
- @return New controller settings on success, 0 if the feature is not
- supported and the parameter was False, None otherwise.
-
- """
- msg_data = struct.pack('<B', bool(secure_conn))
- (status, data) = self.send_command_and_wait(
- MGMT_OP_SET_SECURE_CONN,
- index,
- msg_data,
- expected_length=4)
- if status == MGMT_STATUS_NOT_SUPPORTED and not secure_conn:
- return 0
- elif status != MGMT_STATUS_SUCCESS:
- return None
-
- (current_settings, ) = struct.unpack_from('<L', buffer(data))
- return current_settings
-
-
- def add_device(self, index, address, address_type, action):
- """Add a device to the action list.
-
- @param index: Controller index.
- @param address: Address of the device to add.
- @param address_type: Type of device in @address.
- @param action: Action to take.
-
- @return Tuple of ( address, address_type ) on success,
- None on failure.
-
- """
- msg_data = struct.pack('<6sBB', address, address_type, action)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_ADD_DEVICE,
- index,
- msg_data,
- expected_length=7)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (address, address_type,) = struct.unpack_from('<6sB', buffer(data))
- return (address, address_type)
-
-
- def remove_device(self, index, address, address_type):
- """Remove a device from the action list.
-
- @param index: Controller index.
- @param address: Address of the device to remove.
- @param address_type: Type of device in @address.
-
- @return Tuple of ( address, address_type ) on success,
- None on failure.
-
- """
- msg_data = struct.pack('<6sB', address, address_type)
- (status, data) = self.send_command_and_wait(
- MGMT_OP_REMOVE_DEVICE,
- index,
- msg_data,
- expected_length=7)
- if status != MGMT_STATUS_SUCCESS:
- return None
-
- (address, address_type,) = struct.unpack_from('<6sB', buffer(data))
- return (address, address_type)
-
-
-class BluetoothRawSocket(BluetoothSocket):
- """Bluetooth Raw HCI Socket.
-
- BluetoothRawSocket is a subclass of BluetoothSocket representing raw access
- to the HCI controller and providing commands corresponding to ioctls that
- can be made on that kind of socket.
-
- """
-
- def get_dev_info(self, index):
- """Read HCI device information.
-
- This method uses the same underlying ioctl as the hciconfig tool.
-
- Address is returned as a string in upper-case hex to match the
- BlueZ property.
-
- @param index: Device index.
-
- @return tuple (index, name, address, flags, device_type, bus_type,
- features, pkt_type, link_policy, link_mode,
- acl_mtu, acl_pkts, sco_mtu, sco_pkts,
- err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx,
- sco_tx, sco_rx, byte_rx, byte_tx) on success,
- None on failure.
-
- """
- buf = array.array('B', [0] * 96)
- fcntl.ioctl(self.fileno(), HCIGETDEVINFO, buf, 1)
-
- ( dev_id, name, address, flags, dev_type, features, pkt_type,
- link_policy, link_mode, acl_mtu, acl_pkts, sco_mtu, sco_pkts,
- err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx, sco_tx, sco_rx,
- byte_rx, byte_tx ) = struct.unpack_from(
- '@H8s6sIBQIIIHHHHIIIIIIIIII', buf)
-
- return (
- dev_id,
- name.rstrip('\0'),
- ':'.join('%02X' % x
- for x in reversed(struct.unpack('6B', address))),
- flags,
- (dev_type & 0x30) >> 4,
- dev_type & 0x0f,
- features,
- pkt_type,
- link_policy,
- link_mode,
- acl_mtu,
- acl_pkts,
- sco_mtu,
- sco_pkts,
- err_rx,
- err_tx,
- cmd_tx,
- evt_rx,
- acl_tx,
- acl_rx,
- sco_tx,
- sco_rx,
- byte_rx,
- byte_tx)
diff --git a/client/common_lib/cros/bluetooth/common.py b/client/common_lib/cros/bluetooth/common.py
deleted file mode 100644
index 849be4d..0000000
--- a/client/common_lib/cros/bluetooth/common.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import os, sys
-dirname = os.path.dirname(sys.modules[__name__].__file__)
-client_dir = os.path.abspath(os.path.join(dirname, "..", "..", ".."))
-sys.path.insert(0, client_dir)
-import setup_modules
-sys.path.pop(0)
-setup_modules.setup(base_path=client_dir,
- root_module_name="autotest_lib.client")
diff --git a/client/common_lib/cros/cfm/__init__.py b/client/common_lib/cros/cfm/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/client/common_lib/cros/cfm/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/client/common_lib/cros/cfm/apollo/__init__.py b/client/common_lib/cros/cfm/apollo/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/client/common_lib/cros/cfm/apollo/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/client/common_lib/cros/cfm/apollo/apollo_utils.py b/client/common_lib/cros/cfm/apollo/apollo_utils.py
deleted file mode 100644
index 9751acc..0000000
--- a/client/common_lib/cros/cfm/apollo/apollo_utils.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2020 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.
-"""
-Test utilities for the Apollo kit Chromebox and IP peripherals
-"""
-
-import logging
-
-from autotest_lib.client.bin import utils
-
-
-def ectool_pse_status(port):
- result = utils.run('ectool pse {0}'.format(port)).stdout.strip()
- logging.debug("ectool pse output for port {0}: {1}".format(port, result))
-
- # Strip stdout to return only the status
- prefix = 'Port {0}: '.format(port)
- if not result.startswith(prefix):
- return error
-
- return result[len(prefix):]
-
-
-def ectool_pse_enable(port):
- utils.run('ectool pse {port} enable'.format(port=port))
-
-
-def ectool_pse_disable(port):
- utils.run('ectool pse {port} disable'.format(port=port))
diff --git a/client/common_lib/cros/cfm/atrus/__init__.py b/client/common_lib/cros/cfm/atrus/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/common_lib/cros/cfm/atrus/__init__.py
+++ /dev/null
diff --git a/client/common_lib/cros/cfm/atrus/atrus_utils.py b/client/common_lib/cros/cfm/atrus/atrus_utils.py
deleted file mode 100644
index eebf665..0000000
--- a/client/common_lib/cros/cfm/atrus/atrus_utils.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2017 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 dbus
-
-from autotest_lib.client.common_lib import utils
-from autotest_lib.client.common_lib.cros import dbus_send
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_collector
-from autotest_lib.client.common_lib.cros.cfm.usb import cfm_usb_devices
-
-ATRUS = cfm_usb_devices.ATRUS
-
-def check_dbus_available():
- """
- Checks if Atrusd with dbus support is available.
-
- @returns True if dbus is supported in atrusd. False otherwise.
- """
- result = dbus_send.dbus_send(
- 'org.freedesktop.DBus',
- 'org.freedesktop.DBus',
- '/org/freedesktop/DBus',
- 'ListNames',
- args=None,
- timeout_seconds=2,
- tolerate_failures=False)
-
- return 'org.chromium.Atrusctl' in result.response
-
-def force_upgrade_atrus():
- """
- Executes a forced upgrade of the Atrus device.
-
- @returns True if the upgrade succeeded. False otherwise.
- """
- args = [dbus.String('/lib/firmware/google/atrus-fw-bundle-latest.bin')]
- result = dbus_send.dbus_send(
- 'org.chromium.Atrusctl',
- 'org.chromium.Atrusctl',
- '/org/chromium/Atrusctl',
- 'ForceFirmwareUpgrade',
- args=args,
- timeout_seconds=90,
- tolerate_failures=True)
-
- return result.response
-
-def wait_for_atrus_enumeration(timeout_seconds=30):
- """
- Wait for an Atrus device to enumerate.
-
- @param timeout_seconds: Maximum number of seconds to wait.
- """
- device_manager = usb_device_collector.UsbDeviceCollector()
- utils.poll_for_condition(
- lambda: len(device_manager.get_devices_by_spec(ATRUS)) >= 1,
- timeout=timeout_seconds,
- sleep_interval=1.0,
- desc='No atrus device enumerated')
\ No newline at end of file
diff --git a/client/common_lib/cros/cfm/cras_input_node.py b/client/common_lib/cros/cfm/cras_input_node.py
deleted file mode 100644
index 49c026f..0000000
--- a/client/common_lib/cros/cfm/cras_input_node.py
+++ /dev/null
@@ -1,19 +0,0 @@
-class CrasInputNode(object):
- """Class representing an input node from ChromeOS Audio Server data.
-
- An input node is a node that can pick up audio, e.g. a microphone jack.
- """
-
- def __init__(self, node_id, node_name, gain, node_type, device_id,
- device_name):
- self.node_id = node_id
- self.node_name = node_name
- self.gain = int(gain)
- self.node_type = node_type
- self.device_id = device_id
- self.device_name = device_name
-
- def __str__(self):
- return ('Node id: %s, Node name: %s, Device id: %s, Device name: %s '
- 'Gain: %d' % (self.node_id, self.node_name, self.device_id,
- self.device_name, self.gain))
diff --git a/client/common_lib/cros/cfm/cras_node_collector.py b/client/common_lib/cros/cfm/cras_node_collector.py
deleted file mode 100644
index 83367be..0000000
--- a/client/common_lib/cros/cfm/cras_node_collector.py
+++ /dev/null
@@ -1,146 +0,0 @@
-from autotest_lib.client.common_lib.cros.cfm import cras_input_node
-from autotest_lib.client.common_lib.cros.cfm import cras_output_node
-
-class CrasNodeCollector(object):
- """Utility class for obtaining node data from cras_test_client."""
-
- DEVICE_COLUMN_COUNT = 2
- NODE_COLUMN_COUNT = 8
- DEVICE_HEADERS = ['ID', 'Name']
- OUTPUT_NODE_HEADERS = ['Stable Id', 'ID', 'Vol', 'Plugged', 'L/R swapped',
- 'Time Hotword', 'Type', 'Name']
- INPUT_NODE_HEADERS = ['Stable Id', 'ID', 'Gain', 'Plugged', 'L/Rswapped',
- 'Time Hotword', 'Type', 'Name']
-
- def __init__(self, host):
- """
- Constructor
- @param host the device under test (CrOS).
- """
- self._host = host
-
- def _replace_multiple_whitespace_with_one(self, string):
- """
- Replace multiple sequential whitespaces with a single whitespace.
- @returns a string
- """
- return ' '.join(string.split())
-
- def _construct_columns(self, columns_str, columns_count):
- """
- Constructs a list of strings from a single string.
-
- @param columns_str A whitespace separated list of values.
- @param columns_count number of columns to create
- @returns a list with strings.
- """
- # 1) Replace multiple whitespaces with one
- # 2) Split on whitespace, create nof_columns columns
- columns_str = self._replace_multiple_whitespace_with_one(columns_str)
- return columns_str.split(None, columns_count-1)
-
- def _collect_input_device_data(self):
- cmd = ("cras_test_client --dump_server_info "
- " | awk '/Input Devices:/,/Input Nodes:/'")
- lines = self._host.run_output(cmd).split('\n')
- # Ignore the first two lines ("Input Devices" and headers) and the
- # last line ("Input Nodes")
- lines = lines[2:-1]
- rows = [self._construct_columns(line, self.DEVICE_COLUMN_COUNT)
- for line in lines]
- return [dict(zip(self.DEVICE_HEADERS, row)) for row in rows]
-
- def _collect_output_device_data(self):
- cmd = ("cras_test_client --dump_server_info "
- " | awk '/Output Devices:/,/Output Nodes:/'")
- lines = self._host.run_output(cmd).split('\n')
- # Ignore the first two lines ("Output Devices" and headers) and the
- # last line ("Output Nodes")
- lines = lines[2:-1]
- rows = [self._construct_columns(line, self.DEVICE_COLUMN_COUNT)
- for line in lines]
- return [dict(zip(self.DEVICE_HEADERS, row)) for row in rows]
-
- def _collect_output_node_cras_data(self):
- """
- Collects output nodes data using cras_test_client.
-
- @returns a list of dictionaries where keys are in OUTPUT_NODE_HEADERS
- """
- # It's a bit hacky to use awk; we should probably do the parsing
- # in Python instead using textfsm or some other lib.
- cmd = ("cras_test_client --dump_server_info"
- "| awk '/Output Nodes:/,/Input Devices:/'")
- lines = self._host.run_output(cmd).split('\n')
- # Ignore the first two lines ("Output Nodes:" and headers) and the
- # last line ("Input Devices:")
- lines = lines[2:-1]
- rows = [self._construct_columns(line, self.NODE_COLUMN_COUNT)
- for line in lines]
- return [dict(zip(self.OUTPUT_NODE_HEADERS, row)) for row in rows]
-
- def _collect_input_node_cras_data(self):
- """
- Collects input nodes data using cras_test_client.
-
- @returns a list of dictionaries where keys are in INPUT_NODE_HEADERS
- """
- cmd = ("cras_test_client --dump_server_info "
- " | awk '/Input Nodes:/,/Attached clients:/'")
- lines = self._host.run_output(cmd).split('\n')
- # Ignore the first two lines ("Input Nodes:" and headers) and the
- # last line ("Attached clients:")
- lines = lines[2:-1]
- rows = [self._construct_columns(line, self.NODE_COLUMN_COUNT)
- for line in lines]
- return [dict(zip(self.INPUT_NODE_HEADERS, row)) for row in rows]
-
- def _get_device_name(self, device_data, device_id):
- for device in device_data:
- if device['ID'] == device_id:
- return device['Name']
- return None
-
- def _create_input_node(self, node_data, device_data):
- """
- Create a CrasInputNode.
- @param node_data Input Node data
- @param device_data Input Device data
- @return CrasInputNode
- """
- device_id = node_data['ID'].split(':')[0]
- device_name = self._get_device_name(device_data, device_id)
- return cras_input_node.CrasInputNode(
- node_id=node_data['ID'],
- node_name=node_data['Name'],
- gain=node_data['Gain'],
- node_type=node_data['Type'],
- device_id=device_id,
- device_name=device_name)
-
- def _create_output_node(self, node_data, device_data):
- """
- Create a CrasOutputNode.
- @param node_data Output Node data
- @param device_data Output Device data
- @return CrasOutputNode
- """
- device_id = node_data['ID'].split(':')[0]
- device_name = self._get_device_name(device_data, device_id)
- return cras_output_node.CrasOutputNode(
- node_id=node_data['ID'],
- node_type=node_data['Type'],
- node_name=node_data['Name'],
- volume=node_data['Vol'],
- device_id=device_id,
- device_name=device_name)
-
- def get_input_nodes(self):
- device_data = self._collect_input_device_data()
- node_data = self._collect_input_node_cras_data()
- return [self._create_input_node(d, device_data) for d in node_data]
-
- def get_output_nodes(self):
- device_data = self._collect_output_device_data()
- node_data = self._collect_output_node_cras_data()
- return [self._create_output_node(d, device_data) for d in node_data]
diff --git a/client/common_lib/cros/cfm/cras_node_collector_unittest.py b/client/common_lib/cros/cfm/cras_node_collector_unittest.py
deleted file mode 100644
index 91c88c2..0000000
--- a/client/common_lib/cros/cfm/cras_node_collector_unittest.py
+++ /dev/null
@@ -1,105 +0,0 @@
-import unittest
-import mock
-
-from autotest_lib.client.common_lib.cros.cfm import cras_node_collector
-
-# pylint: disable=missing-docstring
-
-class CrasNodeCollectorTest(unittest.TestCase):
- """Unit tests for cras_node_collector."""
-
- def test_collect_output(self):
- output_devices = (
- 'Output Devices:\n'
- 'ID Name\n'
- '13 HDA Intel PCH: ALC283 Analog:3,0\n'
- '12 HDA Intel HDMI: HDMI 2:2,8\n'
- '11 HDA Intel HDMI: HDMI 1:2,7\n'
- '10 HDA Intel HDMI: HDMI 0:2,3\n'
- '8 Jabra SPEAK 410 USB: USB Audio:1,0\n'
- '6 Jabra SPEAK 410 USB: USB Audio:0,0\n'
- 'Output Nodes:')
-
- output_nodes = (
- 'Output Nodes:\n'
- 'Stable Id ID Vol Plugged L/R swapped Time Hotword '
- 'Type Name\n'
- '(d5da8553) 13:0 100 no no 0 '
- 'HEADPHONE Headphone Jack\n'
- '(5280b26d) 12:0 100 no no 0 '
- 'HDMI HDMI/DP,pcm=8 Jack\n'
- '(78297d51) 11:0 100 no no 0 '
- 'HDMI HDMI/DP,pcm=7 Jack\n'
- '(f2070728) 10:0 100 no no 1511264933 '
- 'HDMI HDMI/DP,pcm=3 Jack\n'
- '(2fb77ef4) 10:1 100 no no 0 '
- 'HDMI HDMI\n'
- '(051d1a79) 8:0 75 yes no 1511264933 '
- 'USB *(default)\n'
- '(051d1a79) 6:0 100 yes no 1511264933 '
- 'USB (default)\n'
- 'Input Devices:')
-
- mock_host = mock.Mock()
- mock_host.run_output.side_effect = [output_devices, output_nodes]
- collector = cras_node_collector.CrasNodeCollector(mock_host)
-
- nodes = collector.get_output_nodes()
- self.assertEquals(7, len(nodes))
- node_ids = set([node.node_id for node in nodes])
- node_types = set([node.node_type for node in nodes])
- device_names = set([node.device_name for node in nodes])
- self.assertEquals(node_ids, set(
- ['13:0', '12:0', '11:0', '10:0', '10:1', '8:0', '6:0']))
- self.assertEquals(node_types, set(['HEADPHONE', 'USB', 'HDMI' ]))
-
- def test_collect_input(self):
- input_devices = (
- 'Input Devices:\n'
- 'ID Name\n'
- '14 HDA Intel PCH: ALC283 Analog:3,0\n'
- '9 Jabra SPEAK 410 USB: USB Audio:1,0\n'
- '7 Jabra SPEAK 410 USB: USB Audio:0,0\n'
- '5 Post DSP Loopback\n'
- '4 Post Mix Pre DSP Loopback\n'
- 'Input Nodes:'
- )
- input_nodes = (
- 'Input Nodes:\n'
- 'Stable Id ID Gain Plugged L/R swapped Time Hotword '
- 'Type Name\n'
- '(ca711b33) 14:0 0 no no 0 '
- 'MIC Mic Jack\n'
- '(4b5d44d7) 9:0 0 yes no 1511264933 '
- 'USB Jabra SPEAK 410 USB: USB Audio:1,0: Mic\n'
- '(ca24f0a3) 7:0 0 yes no 1511264933 '
- 'USB *Jabra SPEAK 410 USB: USB Audio:0,0: Mic\n'
- '(8c74f766) 5:0 0 yes no 0 '
- 'POST_DSP_LOOPBACK Post DSP Loopback\n'
- '(8a04af91) 4:0 0 yes no 0 '
- 'POST_MIX_LOOPBACK Post Mix Pre DSP Loopback\n'
- 'Attached clients:'
- )
-
- mock_host = mock.Mock()
- mock_host.run_output.side_effect = [input_devices, input_nodes]
- collector = cras_node_collector.CrasNodeCollector(mock_host)
-
- nodes = collector.get_input_nodes()
- self.assertEquals(5, len(nodes))
- node_ids = set([node.node_id for node in nodes])
- node_types = set([node.node_type for node in nodes])
- device_names = set([node.device_name for node in nodes])
- self.assertEquals(node_ids, set(
- ['4:0', '5:0', '7:0', '9:0', '14:0']))
- self.assertEquals(node_types, set(
- ['MIC', 'USB', 'POST_DSP_LOOPBACK', 'POST_MIX_LOOPBACK']))
- self.assertEquals(device_names, set(
- ['HDA Intel PCH: ALC283 Analog:3,0',
- 'Jabra SPEAK 410 USB: USB Audio:1,0',
- 'Jabra SPEAK 410 USB: USB Audio:0,0',
- 'Post DSP Loopback',
- 'Post Mix Pre DSP Loopback',]))
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/client/common_lib/cros/cfm/cras_output_node.py b/client/common_lib/cros/cfm/cras_output_node.py
deleted file mode 100644
index 96c7e42..0000000
--- a/client/common_lib/cros/cfm/cras_output_node.py
+++ /dev/null
@@ -1,19 +0,0 @@
-class CrasOutputNode(object):
- """Class representing an output node from ChromeOS Audio Server data.
-
- An output node is a node that can play out audio, e.g. a headphone jack.
- """
-
- def __init__(self, node_id, node_type, node_name, volume, device_id,
- device_name):
- self.node_id = node_id
- self.node_type = node_type
- self.node_name = node_name
- self.volume = int(volume)
- self.device_id = device_id
- self.device_name = device_name
-
- def __str__(self):
- return ('Node id %s, Node name: %s, Device id: %s, Device name: %s '
- 'Volume: %d' % (self.node_id, self.node_name, self.device_id,
- self.device_name, self.volume))
diff --git a/client/common_lib/cros/cfm/metrics/__init__.py b/client/common_lib/cros/cfm/metrics/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/common_lib/cros/cfm/metrics/__init__.py
+++ /dev/null
diff --git a/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor.py b/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor.py
deleted file mode 100644
index cfb6d31..0000000
--- a/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor.py
+++ /dev/null
@@ -1,125 +0,0 @@
-"""Extracts media info metrics from media info data points."""
-
-import collections
-import enum
-
-
-# Direction and type numbers map to constants in the DataPoint group in
-# callstats.proto
-class Direction(enum.Enum):
- """
- Possible directions for media entries of a data point.
- """
- SENDER = 0
- RECEIVER = 1
- BANDWIDTH_ESTIMATION = 2
-
-
-class MediaType(enum.Enum):
- """
- Possible media types for media entries of a data point.
- """
- AUDIO = 1
- VIDEO = 2
- DATA = 3
-
-
-TimestampedValues = collections.namedtuple('TimestampedValues',
- ['TimestampEpochSeconds',
- 'ValueList'])
-
-
-class MediaInfoMetricsExtractor(object):
- """
- Extracts media metrics from a list of raw media info data points.
-
- Media info datapoints are expected to be dictionaries in the format returned
- by cfm_facade.get_media_info_data_points.
- """
-
- def __init__(self, data_points):
- """
- Initializes with a set of data points.
-
- @param data_points Data points as a list of dictionaries. Dictionaries
- should be in the format returned by
- cfm_facade.get_media_info_data_points. I.e., as returned when
- querying the Browser Window for datapoints when the ExportMediaInfo
- mod is active.
- """
- self._data_points = data_points
-
- def get_top_level_metric(self, name):
- """
- Gets top level metrics.
-
- Gets metrics that are global for one datapoint. I.e., metrics that
- are not in the media list, such as CPU usage.
-
- @param name Name of the metric. Names map to the names in the DataPoint
- group in callstats.proto.
-
- @returns A list with TimestampedValues. The ValueList is guaranteed to
- not contain any None values.
- """
- metrics = []
- for data_point in self._data_points:
- value = data_point.get(name)
- if value is not None:
- timestamp = data_point['timestamp']
- metrics.append(TimestampedValues(timestamp, [value]))
- return metrics
-
- def get_media_metric(self,
- name,
- direction=None,
- media_type=None,
- post_process_func=lambda x: x):
- """
- Gets media metrics.
-
- Gets metrics that are in the media part of the datapoint. A DataPoint
- often contains many media entries, why there are multiple values for a
- specific name.
-
- @param name Name of the metric. Names map to the names in the DataPoint
- group in callstats.proto.
- @param direction: Only include metrics with this direction in the media
- stream. See the Direction constants in this module. If None, all
- directions are included.
- @param media_type: Only include metrics with this media type in the
- media stream. See the MediaType constants in this module. If None,
- all media types are included.
- @param post_process_func: Function that takes a list of values and
- optionally transforms it, returning the updated list or a scalar
- value. Default is to return the unmodified list. This method is
- called for the list of values in the same datapoint. Example usage
- is to sum the received audio bytes for all streams for one logged
- line.
-
- @returns A list with TimestampedValues. The ValueList is guaranteed to
- not contain any None values.
- """
- metrics = []
- for data_point in self._data_points:
- timestamp = data_point['timestamp']
- values = [
- media[name] for media in data_point['media']
- if name in media
- and _media_matches(media, direction, media_type)
- ]
- # Filter None values and only add the metric if there is at least
- # one value left.
- values = [x for x in values if x is not None]
- if values:
- values = post_process_func(values)
- values = values if isinstance(values, list) else [values]
- metrics.append(TimestampedValues(timestamp, values))
- return metrics
-
-def _media_matches(media, direction, media_type):
- direction_match = (True if direction is None
- else media['direction'] == direction.value)
- type_match = (True if media_type is None
- else media['mediatype'] == media_type.value)
- return direction_match and type_match
diff --git a/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor_unittest.py b/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor_unittest.py
deleted file mode 100644
index 7536ab2..0000000
--- a/client/common_lib/cros/cfm/metrics/media_info_metrics_extractor_unittest.py
+++ /dev/null
@@ -1,251 +0,0 @@
-import unittest
-
-from autotest_lib.client.common_lib.cros.cfm.metrics import (
- media_info_metrics_extractor)
-
-MEDIA_TYPE = media_info_metrics_extractor.MediaType
-DIRECTION = media_info_metrics_extractor.Direction
-
-
-# pylint: disable=missing-docstring
-class MediaInfoMetricsExtractorTest(unittest.TestCase):
-
- def setUp(self):
- self.extractor = media_info_metrics_extractor.MediaInfoMetricsExtractor(
- TEST_DATA_POINTS)
-
- def testGlobalMetric(self):
- metric = self.extractor.get_top_level_metric('processcpuusage')
- self.assertEqual(metric, [(1, [105]), (2, [95])])
-
- def testMediaMetric(self):
- metric = self.extractor.get_media_metric(
- 'fps', media_type=MEDIA_TYPE.VIDEO,
- direction=DIRECTION.RECEIVER)
- self.assertEqual(metric, [(1, [8, 23]), (2, [25, 12])])
-
- def testPostProcessReturnsScalar(self):
- metric = self.extractor.get_media_metric(
- 'fps',
- media_type=MEDIA_TYPE.VIDEO,
- direction=DIRECTION.RECEIVER,
- post_process_func=sum)
- self.assertEqual(metric, [(1, [31]), (2, [37])])
-
- def testPostProcessReturnsList(self):
- metric = self.extractor.get_media_metric(
- 'fps',
- media_type=MEDIA_TYPE.VIDEO,
- direction=DIRECTION.RECEIVER,
- post_process_func=lambda values: [x + 1 for x in values])
- self.assertEqual(metric, [(1, [9, 24]), (2, [26, 13])])
-
- def testMetricNameDoesNotExist(self):
- metric = self.extractor.get_top_level_metric('does_not_exist')
- self.assertEqual([], metric)
-
- def testWildcardMediaType(self):
- metric = self.extractor.get_media_metric(
- 'bytessent', direction=DIRECTION.SENDER)
- self.assertEqual(
- metric, [(1.0, [58978, 3826779]), (2.0, [59206, 3986136])])
-
- def testNoneValueMediaMetricsSkipped(self):
- metric = self.extractor.get_media_metric(
- 'fps',
- media_type=MEDIA_TYPE.VIDEO,
- direction=DIRECTION.BANDWIDTH_ESTIMATION)
- self.assertEquals(0, len(metric))
-
- def testNoneValueTopLevelMetricsSkipped(self):
- metric = self.extractor.get_top_level_metric('gpuProcessCpuUsage')
- self.assertEqual(metric, [(2.0, [0])])
-
-
-# Two data points extracted from a real call. Somewhat post processed to make
-# numbers easier to use in tests.
-TEST_DATA_POINTS = [{
- u'gpuProcessCpuUsage':
- None,
- u'processcpuusage':
- 105,
- u'timestamp': 1,
- u'systemcpuusage':
- 615,
- u'media': [{
- u'leakybucketdelay': 0,
- u'availablerecvbitrate': 0,
- u'ssrc': None,
- u'availablesendbitrate': 2187820,
- u'direction': 2,
- u'height': None,
- u'fractionlost': -1,
- u'fpsnetwork': None,
- u'width': None,
- u'fps': None,
- u'mediatype': 2
- }, {
- u'bytessent': 58978,
- u'direction': 0,
- u'ssrc': 511990786,
- u'fractionlost': 0,
- u'transmissionbitrate': 1212,
- u'packetssent': 946,
- u'mediatype': 1
- }, {
- u'bytessent': 3826779,
- u'fps': 21,
- u'ssrc': 4134692703,
- u'direction': 0,
- u'height': 720,
- u'mediatype': 2,
- u'encodeUsagePercent': 19,
- u'fpsnetwork': 20,
- u'transmissionbitrate': 1246604,
- u'packetssent': 5166,
- u'fractionlost': 0,
- u'width': 1280,
- u'avgEncodeMs': 7
- }, {
- u'speechExpandRate': 0,
- u'fractionlost': 0,
- u'ssrc': 6666,
- u'packetsreceived': 1129,
- u'recvbitrate': 41523,
- u'direction': 1,
- u'bytesreceived': 111317,
- u'mediatype': 1
- }, {
- u'speechExpandRate': 0,
- u'fractionlost': 0,
- u'ssrc': 6667,
- u'packetsreceived': 1016,
- u'recvbitrate': 41866,
- u'direction': 1,
- u'bytesreceived': 100225,
- u'mediatype': 1
- }, {
- u'frameSpacingMaxMs': 524,
- u'fps': 8,
- u'ssrc': 1491110400,
- u'direction': 1,
- u'packetsreceived': 3475,
- u'recvbitrate': 449595,
- u'fractionlost': 0,
- u'height': 720,
- u'bytesreceived': 3863701,
- u'fpsnetwork': 8,
- u'width': 1280,
- u'mediatype': 2,
- u'fpsdecoded': 8
- }, {
- u'frameSpacingMaxMs': 363,
- u'fps': 23,
- u'ssrc': 2738775122,
- u'direction': 1,
- u'packetsreceived': 3419,
- u'recvbitrate': 2228961,
- u'fractionlost': 0,
- u'height': 180,
- u'bytesreceived': 3829959,
- u'fpsnetwork': 22,
- u'width': 320,
- u'mediatype': 2,
- u'fpsdecoded': 23
- }],
- u'browserProcessCpuUsage':
- 46
-}, {
- u'gpuProcessCpuUsage':
- 0,
- u'processcpuusage':
- 95,
- u'timestamp': 2,
- u'systemcpuusage':
- 580,
- u'media': [{
- u'leakybucketdelay': 0,
- u'availablerecvbitrate': 0,
- u'ssrc': None,
- u'availablesendbitrate': 2187820,
- u'direction': 2,
- u'height': None,
- u'fractionlost': -1,
- u'fpsnetwork': None,
- u'width': None,
- u'fps': None,
- u'mediatype': 2
- }, {
- u'bytessent': 59206,
- u'direction': 0,
- u'ssrc': 511990786,
- u'fractionlost': 0,
- u'transmissionbitrate': 1820,
- u'packetssent': 952,
- u'mediatype': 1
- }, {
- u'bytessent': 3986136,
- u'fps': 21,
- u'ssrc': 4134692703,
- u'direction': 0,
- u'height': 720,
- u'mediatype': 2,
- u'encodeUsagePercent': 19,
- u'fpsnetwork': 20,
- u'transmissionbitrate': 1272311,
- u'packetssent': 5325,
- u'fractionlost': 0,
- u'width': 1280,
- u'avgEncodeMs': 8
- }, {
- u'speechExpandRate': 0,
- u'fractionlost': 0,
- u'ssrc': 6666,
- u'packetsreceived': 1147,
- u'recvbitrate': 8527,
- u'direction': 1,
- u'bytesreceived': 112385,
- u'mediatype': 1
- }, {
- u'speechExpandRate': 0,
- u'fractionlost': 0,
- u'ssrc': 6667,
- u'packetsreceived': 1062,
- u'recvbitrate': 35321,
- u'direction': 1,
- u'bytesreceived': 104649,
- u'mediatype': 1
- }, {
- u'frameSpacingMaxMs': 330,
- u'fps': 25,
- u'ssrc': 1491110400,
- u'direction': 1,
- u'packetsreceived': 3694,
- u'recvbitrate': 1963721,
- u'fractionlost': 0,
- u'height': 720,
- u'bytesreceived': 4109657,
- u'fpsnetwork': 26,
- u'width': 1280,
- u'mediatype': 2,
- u'fpsdecoded': 25
- }, {
- u'frameSpacingMaxMs': 363,
- u'fps': 12,
- u'ssrc': 2738775122,
- u'direction': 1,
- u'packetsreceived': 3440,
- u'recvbitrate': 147018,
- u'fractionlost': 0,
- u'height': 180,
- u'bytesreceived': 3848373,
- u'fpsnetwork': 13,
- u'width': 320,
- u'mediatype': 2,
- u'fpsdecoded': 12
- }],
- u'browserProcessCpuUsage':
- 38
-}]
-
-
diff --git a/client/common_lib/cros/cfm/metrics/media_metrics_collector.py b/client/common_lib/cros/cfm/metrics/media_metrics_collector.py
deleted file mode 100644
index 12af999..0000000
--- a/client/common_lib/cros/cfm/metrics/media_metrics_collector.py
+++ /dev/null
@@ -1,196 +0,0 @@
-from __future__ import division
-
-from autotest_lib.client.common_lib.cros.cfm.metrics import (
- media_info_metrics_extractor)
-
-MEDIA_TYPE = media_info_metrics_extractor.MediaType
-DIRECTION = media_info_metrics_extractor.Direction
-
-# Delta used to determine if floating point values are equal.
-FLOATING_POINT_COMPARISON_DELTA = 0.00001
-
-
-def _avg(l):
- """
- Returns the average of the list or 0 if the list is empty.
- """
- return sum(l)/len(l) if l else 0
-
-
-def _get_number_of_incoming_active_video_streams(extractor):
- """
- Calculates the number of incoming video streams.
-
- @param extractor media_info_metrics_extractor.MediaInfoMetricsExtractor.
-
- @returns List with (timestamp, number of incoming video streams) tuples.
- """
- # Get metrics of a kind we know exists and count the nuber of values
- # for each data point.
- fps_metrics = extractor.get_media_metric(
- 'fps', direction=DIRECTION.RECEIVER, media_type=MEDIA_TYPE.VIDEO)
- return [(x, [len(y)]) for x, y in fps_metrics]
-
-
-ADAPTATION_CHANGES = 'adaptation_changes'
-ADAPTATION_REASON = 'adaptation_reason'
-AVG_ENCODE_MS = 'avg_encode_ms'
-BROWSER_CPU_PERCENT_OF_TOTAL = 'browser_cpu_percent'
-CPU_PERCENT_OF_TOTAL = 'cpu_percent'
-FRAMERATE_CAPTURED = 'framerate_catured'
-FRAMERATE_DECODED = 'framerate_decoded'
-FRAMERATE_ENCODED = 'framerate_encoded'
-FRAMERATE_TO_RENDERER = 'framerate_to_renderer'
-FRAMERATE_NETWORK_RECEIVED = 'framerate_network_received'
-GPU_PERCENT_OF_TOTAL = 'gpu_cpu_percent'
-NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS = 'num_active_vid_in_streams'
-PROCESS_JS_MEMORY_USED = 'process_js_memory_used'
-RENDERER_CPU_PERCENT_OF_TOTAL = 'renderer_cpu_percent'
-VIDEO_RECEIVED_FRAME_HEIGHT = 'video_received_frame_height'
-VIDEO_RECEIVED_FRAME_WIDTH = 'video_received_frame_width'
-VIDEO_SENT_FRAME_HEIGHT = 'video_sent_frame_height'
-VIDEO_SENT_FRAME_WIDTH = 'video_sent_frame_width'
-VIDEO_SENT_PACKETS = 'video_sent_packets'
-
-
-# Mapping between metric names and how to extract the named metric using the
-# MediaInfoMetricsExtractor.
-METRIC_NAME_TO_EXTRACTOR_FUNC_DICT = {
- ADAPTATION_CHANGES:
- lambda x: x.get_media_metric('adaptationChanges',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- ADAPTATION_REASON:
- lambda x: x.get_media_metric('adaptationReason',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- AVG_ENCODE_MS:
- lambda x: x.get_media_metric('avgEncodeMs',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- BROWSER_CPU_PERCENT_OF_TOTAL:
- lambda x: x.get_top_level_metric('browserProcessCpuUsage'),
- CPU_PERCENT_OF_TOTAL:
- lambda x: x.get_top_level_metric('systemcpuusage'),
- FRAMERATE_CAPTURED:
- lambda x: x.get_media_metric('fps',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- FRAMERATE_DECODED:
- lambda x: x.get_media_metric('fpsdecoded',
- direction=DIRECTION.RECEIVER,
- media_type=MEDIA_TYPE.VIDEO,
- post_process_func=_avg),
- FRAMERATE_ENCODED:
- lambda x: x.get_media_metric('fpsnetwork',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- FRAMERATE_NETWORK_RECEIVED:
- lambda x: x.get_media_metric('fpsnetwork',
- direction=DIRECTION.RECEIVER,
- media_type=MEDIA_TYPE.VIDEO),
- FRAMERATE_TO_RENDERER:
- lambda x: x.get_media_metric('fps',
- direction=DIRECTION.RECEIVER,
- media_type=MEDIA_TYPE.VIDEO,
- post_process_func=_avg),
- GPU_PERCENT_OF_TOTAL:
- lambda x: x.get_top_level_metric('gpuProcessCpuUsage'),
- NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS:
- _get_number_of_incoming_active_video_streams,
- PROCESS_JS_MEMORY_USED:
- lambda x: x.get_top_level_metric('processJsMemoryUsed'),
- RENDERER_CPU_PERCENT_OF_TOTAL:
- lambda x: x.get_top_level_metric('processcpuusage'),
- VIDEO_RECEIVED_FRAME_WIDTH:
- lambda x: x.get_media_metric('width',
- direction=DIRECTION.RECEIVER,
- media_type=MEDIA_TYPE.VIDEO,
- post_process_func=_avg),
- VIDEO_RECEIVED_FRAME_HEIGHT:
- lambda x: x.get_media_metric('height',
- direction=DIRECTION.RECEIVER,
- media_type=MEDIA_TYPE.VIDEO,
- post_process_func=_avg),
- VIDEO_SENT_FRAME_HEIGHT:
- lambda x: x.get_media_metric('height',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- VIDEO_SENT_FRAME_WIDTH:
- lambda x: x.get_media_metric('width',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
- VIDEO_SENT_PACKETS:
- lambda x: x.get_media_metric('packetssent',
- direction=DIRECTION.SENDER,
- media_type=MEDIA_TYPE.VIDEO),
-}
-
-class MetricsCollector(object):
- """Collects metrics for a test run."""
-
- def __init__(self, data_point_collector):
- """
- Initializes.
-
- @param data_point_collector
- """
- self._data_point_collector = data_point_collector
- self._extractor = None
-
- def collect_snapshot(self):
- """
- Stores new merics since the last call.
-
- Metrics can then be retrieved by calling get_metric.
- """
- self._data_point_collector.collect_snapshot()
- data_points = self._data_point_collector.get_data_points()
- # Replace the extractor on each snapshot to always support
- # getting metrics
- self._extractor = (media_info_metrics_extractor
- .MediaInfoMetricsExtractor(data_points))
-
- def get_metric(self, name):
- """
- Gets the metric with the specified name.
-
- @param name The name of the metric
- @returns a list with (timestamp, value_list) tuples
- """
- if self._extractor is None:
- raise RuntimeError(
- 'collect_snapshot() must be called at least once.')
- return METRIC_NAME_TO_EXTRACTOR_FUNC_DICT[name](
- self._extractor)
-
-
-class DataPointCollector(object):
- """Collects data points."""
-
- def __init__(self, cfm_facade):
- """
- Initializes.
-
- @param cfm_facade The cfm facade to use for getting data points.
- """
- self._cfm_facade = cfm_facade
- self._data_points = []
-
- def collect_snapshot(self):
- """
- Collects any new datapoints since the last collection.
- """
- data_points = self._cfm_facade.get_media_info_data_points()
- last_timestamp = (self._data_points[-1]['timestamp']
- if self._data_points else 0)
- for data_point in data_points:
- if (data_point['timestamp'] >
- last_timestamp + FLOATING_POINT_COMPARISON_DELTA):
- self._data_points.append(data_point)
-
- def get_data_points(self):
- """
- Gets all collected data points.
- """
- return self._data_points
diff --git a/client/common_lib/cros/cfm/metrics/media_metrics_collector_test.py b/client/common_lib/cros/cfm/metrics/media_metrics_collector_test.py
deleted file mode 100644
index a11c1a3..0000000
--- a/client/common_lib/cros/cfm/metrics/media_metrics_collector_test.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from autotest_lib.client.common_lib.cros.cfm.metrics import (
- media_metrics_collector)
-
-import mock
-import unittest
-
-# pylint: disable=missing-docstring
-class MediaMetricsCollectorTest(unittest.TestCase):
-
- def test_data_point_collector_same_timestamp_one_entry(self):
- cfm_facade = mock.MagicMock()
- cfm_facade.get_media_info_data_points = mock.Mock(
- return_value = [{'timestamp': 123.1}])
- data_point_collector = media_metrics_collector.DataPointCollector(
- cfm_facade)
- data_point_collector.collect_snapshot()
- data_point_collector.collect_snapshot()
- self.assertEqual(1, len(data_point_collector.get_data_points()))
-
- def test_data_point_collector_different_timestamps_many_entries(self):
- cfm_facade = mock.MagicMock()
- cfm_facade.get_media_info_data_points = mock.Mock(
- side_effect=[[{'timestamp': 123.1}],
- [{'timestamp': 124.1}],
- [{'timestamp': 125.1}]
- ])
- data_point_collector = media_metrics_collector.DataPointCollector(
- cfm_facade)
- data_point_collector.collect_snapshot()
- data_point_collector.collect_snapshot()
- data_point_collector.collect_snapshot()
- self.assertEqual(3, len(data_point_collector.get_data_points()))
-
-
-
-
-
-
diff --git a/client/common_lib/cros/cfm/usb/__init__.py b/client/common_lib/cros/cfm/usb/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/common_lib/cros/cfm/usb/__init__.py
+++ /dev/null
diff --git a/client/common_lib/cros/cfm/usb/cfm_usb_devices.py b/client/common_lib/cros/cfm/usb/cfm_usb_devices.py
deleted file mode 100644
index 6d1d268..0000000
--- a/client/common_lib/cros/cfm/usb/cfm_usb_devices.py
+++ /dev/null
@@ -1,140 +0,0 @@
-"""CfM USB device constants.
-
-This module contains constants for known USB device specs.
-
-A UsbDeviceSpec instance represents a known USB device and its spec;
- - VendorID
- - ProdID
- - interfaces
-
-This is different from a UsbDevice instance which represents a device actually
-connected to the CfM and found by the usb-device command.
-
-A UsbDevice instance found connected to a CfM is expected to match a known
-UsbDeviceSpec (mapping is done using vid:pid), but due to bugs that might
-not be the case (list of interfaces might be different for example).
-"""
-
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_spec
-
-# Cameras
-AVER_CAM520_CAMERA = usb_device_spec.UsbDeviceSpec(
- vid='2574',
- pid='0910',
- product='CAM520',
- interfaces=['uvcvideo', 'uvcvideo', 'usbhid'],
-)
-
-AVER_VC520_CAMERA = usb_device_spec.UsbDeviceSpec(
- vid='2574',
- pid='0901',
- product='VC520+',
- interfaces=['uvcvideo', 'uvcvideo', 'snd-usb-audio',
- 'snd-usb-audio', 'snd-usb-audio', 'usbhid'],
-)
-
-HUDDLY_GO = usb_device_spec.UsbDeviceSpec(
- vid='2bd9',
- pid='0011',
- product='Huddly GO',
- interfaces=['uvcvideo', 'uvcvideo', 'uvcvideo', 'uvcvideo'],
-)
-
-LOGITECH_WEBCAM_C930E = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='0843',
- product='Logitech Webcam C930e',
- interfaces=['uvcvideo', 'uvcvideo', 'snd-usb-audio', 'snd-usb-audio']
-)
-
-HD_PRO_WEBCAM_C920 = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='082d',
- product='HD Pro Webcam C920',
- interfaces=['uvcvideo', 'uvcvideo', 'snd-usb-audio', 'snd-usb-audio'],
-)
-
-PTZ_PRO_CAMERA = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='0853',
- product='PTZ Pro Camera',
- interfaces=['uvcvideo', 'uvcvideo', 'usbhid'],
-)
-
-PTZ_PRO_2_CAMERA = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='085f',
- product='PTZ Pro 2 Camera',
- interfaces=['uvcvideo', 'uvcvideo', 'usbhid'],
-)
-
-# Devices with Camera and Audio
-
-# Camera in Logitech MeetUp Device
-LOGITECH_MEETUP = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='0866',
- product='Logitech MeetUp',
- interfaces=['uvcvideo', 'uvcvideo', 'usbhid'],
-)
-
-# Audio peripheral in Logitech MeetUp Device
-LOGITECH_MEETUP_SPEAKERPHONE = usb_device_spec.UsbDeviceSpec(
- vid='046d',
- pid='0867',
- product='Logitech MeetUp Speakerphone',
- interfaces=['snd-usb-audio', 'snd-usb-audio', 'snd-usb-audio', 'usbhid'],
-)
-
-# Audio peripherals
-ATRUS = usb_device_spec.UsbDeviceSpec(
- vid='18d1',
- pid='8001',
- product='Hangouts Meet speakermic',
- interfaces=['snd-usb-audio', 'snd-usb-audio', 'snd-usb-audio', 'usbhid'],
-)
-
-JABRA_SPEAK_410 = usb_device_spec.UsbDeviceSpec(
- vid='0b0e',
- pid='0412',
- product='Jabra SPEAK 410',
- interfaces=['snd-usb-audio', 'snd-usb-audio', 'snd-usb-audio'],
-)
-
-# MiMOs
-MIMO_VUE_HD_DISPLAY = usb_device_spec.UsbDeviceSpec(
- vid='17e9',
- pid='016b',
- product='MIMO VUE HD',
- interfaces=['udl'],
-)
-
-# The MiMO's firmware is tied to the Chrome OS version. The firmware was updated
-# in Chrome OS 65.0.3319.0. This resulted in the PID being changed from 016b to
-# 416d. The following device is the device with the new PID. We need to support
-# both versions since we want to support tests at the ToT revision running
-# against older Chrome OS versions.
-MIMO_VUE_HD_DISPLAY_PLANKTON = usb_device_spec.UsbDeviceSpec(
- vid='17e9',
- pid='416d',
- product='MIMO VUE HD',
- interfaces=['udl'],
-)
-
-# Tuple with all known MIMO display specs that we support.
-ALL_MIMO_DISPLAYS = (MIMO_VUE_HD_DISPLAY, MIMO_VUE_HD_DISPLAY_PLANKTON)
-
-MIMO_VUE_HID_TOUCH_CONTROLLER = usb_device_spec.UsbDeviceSpec(
- vid='266e',
- pid='0110',
- product='SiS HID Touch Controller',
- interfaces=['usbhid'],
-)
-
-# Utility methods
-def get_usb_device_spec(vid_pid):
- """
- Look up UsbDeviceSpec based on vid_pid.
- @return UsbDeviceSpec with matching vid_pid or None if no match.
- """
- return usb_device_spec.UsbDeviceSpec.get_usb_device_spec(vid_pid)
diff --git a/client/common_lib/cros/cfm/usb/cfm_usb_devices_unittest.py b/client/common_lib/cros/cfm/usb/cfm_usb_devices_unittest.py
deleted file mode 100644
index a157109..0000000
--- a/client/common_lib/cros/cfm/usb/cfm_usb_devices_unittest.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import unittest
-
-from autotest_lib.client.common_lib.cros.cfm.usb import cfm_usb_devices
-
-# pylint: disable=missing-docstring
-
-class CfmUsbDevicesTest(unittest.TestCase):
- """Unit tests for cfm_usb_devices."""
-
- def test_get_usb_device(self):
- device_spec = cfm_usb_devices.HUDDLY_GO
- self.assertEqual(cfm_usb_devices.get_usb_device_spec(device_spec.vid_pid),
- device_spec)
diff --git a/client/common_lib/cros/cfm/usb/usb_device.py b/client/common_lib/cros/cfm/usb/usb_device.py
deleted file mode 100644
index cdeedfc..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device.py
+++ /dev/null
@@ -1,150 +0,0 @@
-"""Utility class representing a CfM USB device.
-
-This class represents actual data found by running the usb-device command.
-"""
-
-class UsbDevice(object):
- """Utility class representing a CfM USB device."""
-
- def __init__(self,
- vid,
- pid,
- product,
- interfaces,
- bus,
- port,
- level,
- parent=None):
- """
- Constructor.
-
- @param vid: Vendor ID. String.
- @param pid: Product ID. String.
- @param product: Product description. String
- @param interfaces: List of strings.
- @param bus: The bus this device is connected to. Number.
- @param port: The port number as specified in /sys/bus/usb/devices/usb*.
- Number.
- @param level: The level in the device hierarchy this device is connected
- at. A device connected directly to a port is typically at level 1.
- @param parent: Optional parent UsbDevice. A parent device is a device that
- this device is connected to, typically a USB Hub.
- """
- self._vid = vid
- self._pid = pid
- self._product = product
- self._interfaces = interfaces
- self._bus = bus
- self._port = port
- self._level = level
- self._parent = parent
-
- @property
- def vendor_id(self):
- """Returns the vendor id for this USB device."""
- return self._vid
-
- @property
- def product_id(self):
- """Returns the product id for this USB device."""
- return self._pid
-
- @property
- def vid_pid(self):
- """Return the <vendor_id>:<product_id> as a string."""
- return '%s:%s' % (self._vid, self._pid)
-
- @property
- def product(self):
- """Returns the product name."""
- return self._product
-
- @property
- def interfaces(self):
- """Returns the list of interfaces."""
- return self._interfaces
-
- @property
- def port(self):
- """Returns the port this USB device is connected to."""
- return self._port
-
- @property
- def bus(self):
- """Returns the bus this USB device is connected to."""
- return self._bus
-
- @property
- def level(self):
- """Returns the level of this USB Device."""
- return self._level
-
- @property
- def parent(self):
- """
- Returns the parent device of this device.
-
- Or None if this is the top level device.
- @returns the parent or None.
- """
- return self._parent
-
- @parent.setter
- def parent(self, value):
- """
- Sets the parent device of this device.
-
- We allow setting parents to make it easier to create the device tree.
- @param value the new parent.
- """
- self._parent = value
-
- def interfaces_match_spec(self, usb_device_spec):
- """
- Checks that the interfaces of this device matches those of the given spec.
-
- @param usb_device_spec an instance of UsbDeviceSpec
- @returns True or False
- """
- # List of expected interfaces. This might be a sublist of the actual
- # list of interfaces. Note: we have to use lists and not sets since
- # the list of interfaces might contain duplicates.
- expected_interfaces = sorted(usb_device_spec.interfaces)
- length = len(expected_interfaces)
- actual_interfaces = sorted(self.interfaces)
- return actual_interfaces[0:length] == expected_interfaces
-
- def get_parent(self, level):
- """
- Gets the parent device at the specified level.
-
- Devices are connected in a hierarchy. Typically like this:
- Level 0: Machine's internal USB hub
- |
- +--+ Level 1: Device connected to the machine's physical ports.
- |
- +--+ Level 2: If level 1 is a Hub, this is a device connected to
- that Hub.
-
- A typical application of this method is when power cycling. Then we get a
- device's parent at level 1 to locate the port that should be power cycled.
-
- @param level the level of the parent to return.
- @returns A UsbDevice instance of the parent at the specified level.
- @raises ValueError if we did not find a device at the specified level.
- """
- device = self
- while device != None:
- if device.level < level:
- raise ValueError(
- 'Reached lower level without finding level %d', level)
- if device.level == level:
- return device
- device = device.parent
-
- def __str__(self):
- return "%s (%s)" % (self._product, self.vid_pid)
-
- def __repr__(self):
- return "%s (%s), bus=%s, port=%s, parent=%s" % (
- self._product, self.vid_pid, self._bus, self._port, self.parent)
diff --git a/client/common_lib/cros/cfm/usb/usb_device_collector.py b/client/common_lib/cros/cfm/usb/usb_device_collector.py
deleted file mode 100644
index 78f3c7a..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device_collector.py
+++ /dev/null
@@ -1,133 +0,0 @@
-import six
-
-from autotest_lib.client.bin import utils
-from autotest_lib.client.common_lib.cros import textfsm
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device
-
-
-class UsbDeviceCollector(object):
- """Utility class for obtaining info about connected USB devices."""
-
- USB_DEVICES_TEMPLATE = (
- 'Value Required Vendor ([0-9a-fA-F]+)\n'
- 'Value Required ProdID ([0-9A-Fa-f]+)\n'
- 'Value Required prev ([0-9a-fA-Z.]+)\n'
- 'Value Required Bus ([0-9.]+)\n'
- 'Value Required Port ([0-9.]+)\n'
- 'Value Required Lev ([0-9.]+)\n'
- 'Value Required Dev ([0-9.]+)\n'
- 'Value Required Prnt ([0-9.]+)\n'
- 'Value Manufacturer (.+)\n'
- 'Value Product (.+)\n'
- 'Value serialnumber ([0-9a-fA-Z\:\-]+)\n'
- 'Value cinterfaces (\d)\n'
- 'Value List intindex ([0-9])\n'
- 'Value List intdriver ([A-Za-z-\(\)]+)\n\n'
- 'Start\n'
- ' ^USB-Device -> Continue.Record\n'
- ' ^T:\s+Bus=${Bus}\s+Lev=${Lev}\s+Prnt=${Prnt}'
- '\s+Port=${Port}.*Dev#=\s*${Dev}.*\n'
- ' ^P:\s+Vendor=${Vendor}\s+ProdID=${ProdID}\sRev=${prev}\n'
- ' ^S:\s+Manufacturer=${Manufacturer}\n'
- ' ^S:\s+Product=${Product}\n'
- ' ^S:\s+SerialNumber=${serialnumber}\n'
- ' ^C:\s+\#Ifs=\s+${cinterfaces}\n'
- ' ^I:\s+If\#=\s+${intindex}.*Driver=${intdriver}\n'
- )
-
- def __init__(self, host=None):
- """
- Constructor
- @param host: An optional host object if running against a remote host.
- """
- self._host = host
-
- def _extract_usb_data(self, rawdata):
- """
- Populate usb data into a list of dictionaries.
- @param rawdata The output of "usb-devices" on CfM.
- @returns list of dictionary, example dictionary:
- {'Manufacturer': 'USBest Technology',
- 'Product': 'SiS HID Touch Controller',
- 'Vendor': '266e',
- 'intindex': ['0'],
- 'tport': '00',
- 'tcnt': '01',
- 'serialnumber': '',
- 'tlev': '03',
- 'tdev': '18',
- 'dver': '',
- 'intdriver': ['usbhid'],
- 'tbus': '01',
- 'prev': '03.00',
- 'cinterfaces': '1',
- 'ProdID': '0110',
- 'tprnt': '14'}
- """
- usbdata = []
- rawdata += '\n'
- re_table = textfsm.TextFSM(six.StringIO(self.USB_DEVICES_TEMPLATE))
- fsm_results = re_table.ParseText(rawdata)
- usbdata = [dict(zip(re_table.header, row)) for row in fsm_results]
- return usbdata
-
- def _collect_usb_device_data(self):
- """Collecting usb device data."""
- run = utils.run if self._host is None else self._host.run
- usb_devices = (run('usb-devices', ignore_status=True).
- stdout.strip().split('\n\n'))
- return self._extract_usb_data(
- '\nUSB-Device\n'+'\nUSB-Device\n'.join(usb_devices))
-
-
- def _create_usb_device(self, usbdata):
- return usb_device.UsbDevice(
- vid=usbdata['Vendor'],
- pid=usbdata['ProdID'],
- product=usbdata.get('Product', 'Not available'),
- interfaces=usbdata['intdriver'],
- bus=int(usbdata['Bus']),
- level=int(usbdata['Lev']),
- # We increment here by 1 because usb-devices reports 0-indexed port
- # numbers where as lsusb reports 1-indexed. We opted to follow the
- # the lsusb standard.
- port=int(usbdata['Port']) + 1)
-
- def get_usb_devices(self):
- """
- Returns the list of UsbDevices connected to the DUT.
- @returns A list of UsbDevice instances.
- """
- usbdata = self._collect_usb_device_data()
- data_and_devices = []
- for data in usbdata:
- usb_device = self._create_usb_device(data)
- data_and_devices.append((data, usb_device))
- # Make a pass to populate parents of the UsbDevices.
- # We need parent ID and Device ID from the raw data since we do not
- # care about storing those in a UsbDevice. That's why we bother
- # iterating through the (data,UsbDevice) pairs.
- for data, usb_device in data_and_devices:
- parent_id = int(data['Prnt'])
- bus = usb_device.bus
- # Device IDs are not unique across busses. When finding a device's
- # parent we look for a device with the parent ID on the same bus.
- usb_device.parent = self._find_device_on_same_bus(
- data_and_devices, parent_id, bus)
- return [x[1] for x in data_and_devices]
-
- def _find_device_on_same_bus(self, data_and_devices, device_id, bus):
- for data, usb_device in data_and_devices:
- if int(data['Dev']) == device_id and usb_device.bus == bus:
- return usb_device
- return None
-
- def get_devices_by_spec(self, *specs):
- """
- Returns all UsbDevices that match the any of the given specs.
- @param specs instances of UsbDeviceSpec.
- @returns a list UsbDevice instances.
- """
- spec_vid_pids = [spec.vid_pid for spec in specs]
- return [d for d in self.get_usb_devices()
- if d.vid_pid in spec_vid_pids]
diff --git a/client/common_lib/cros/cfm/usb/usb_device_collector_unittest.py b/client/common_lib/cros/cfm/usb/usb_device_collector_unittest.py
deleted file mode 100644
index 22c5e50..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device_collector_unittest.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import mock
-import unittest
-
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_collector
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_spec
-
-
-# pylint: disable=missing-docstring
-class UsbDeviceCollectorTest(unittest.TestCase):
- """Unit test for the class UsbDeviceCollector."""
-
- def setUp(self):
- # Sample stdout from `usb-devices`.
- usb_devices = (
- '\n'
- 'T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 8 Spd=12 '
- 'MxCh= 0\n'
- 'D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1\n'
- 'P: Vendor=0000 ProdID=aaaa Rev=01.01\n'
- 'S: Manufacturer=Google Inc.\n'
- 'S: Product=FOO\n'
- 'S: SerialNumber=GATRW17340078\n'
- 'C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA\n'
- 'I: If#= 0 Alt= 0 #EPs= 0 Cls=0e(video) Sub=01 Prot=00 '
- 'Driver=int-a\n'
- 'I: If#= 1 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 '
- 'Driver=(none)\n'
- '\n'
- 'T: Bus=01 Lev=02 Prnt=08 Port=03 Cnt=01 Dev#= 4 Spd=5000 '
- 'MxCh= 0\n'
- 'D: Ver= 3.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS= 9 #Cfgs= 1\n'
- 'P: Vendor=0a0a ProdID=9f9f Rev=06.00\n'
- 'S: Manufacturer=Huddly\n'
- 'S: Product=BAR\n'
- 'S: SerialNumber=43F00190\n'
- 'C: #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=752mA\n'
- 'I: If#= 0 Alt= 0 #EPs= 0 Cls=0e(video) Sub=01 Prot=00 '
- 'Driver=int-a\n'
- 'I: If#= 1 Alt= 0 #EPs= 1 Cls=0e(video) Sub=02 Prot=00 '
- 'Driver=int-a\n'
- 'I: If#= 2 Alt= 0 #EPs= 0 Cls=0e(video) Sub=01 Prot=00 '
- 'Driver=int-b\n')
-
- mock_host = mock.Mock()
- mock_host.run.return_value.stdout = usb_devices
- self.collector = usb_device_collector.UsbDeviceCollector(mock_host)
-
- def test_get_usb_devices(self):
- """Unit test for get_usb_devices."""
- usb_data = self.collector.get_usb_devices()
- self.assertEqual(2, len(usb_data))
-
- foo_device = usb_data[0]
- self.assertEqual(foo_device.vendor_id, '0000')
- self.assertEqual(foo_device.product_id, 'aaaa')
- self.assertEqual(foo_device.product, 'FOO')
- self.assertEqual(foo_device.interfaces, ['int-a', '(none)'])
- self.assertEqual(foo_device.bus, 1)
- self.assertEqual(foo_device.port, 2)
- self.assertIsNone(foo_device.parent)
-
- bar_device = usb_data[1]
- self.assertEqual(bar_device.vendor_id, '0a0a')
- self.assertEqual(bar_device.product_id, '9f9f')
- self.assertEqual(bar_device.product, 'BAR')
- self.assertEqual(bar_device.interfaces, ['int-a', 'int-a', 'int-b'])
- self.assertEqual(bar_device.bus, 1)
- self.assertEqual(bar_device.port, 4)
-
- self.assertEqual(bar_device.parent, foo_device)
-
- def test_get_devices_by_spec(self):
- spec = usb_device_spec.UsbDeviceSpec('0a0a', '9f9f', 'PRODUCT', [])
- devices = self.collector.get_devices_by_spec(spec)
- self.assertEquals(len(devices), 1)
-
- def test_get_devices_by_specs(self):
- specs = (usb_device_spec.UsbDeviceSpec('0a0a', '9f9f', 'PRODUCT', []),
- usb_device_spec.UsbDeviceSpec('0000', 'aaaa', 'PRODUCT', []))
- devices = self.collector.get_devices_by_spec(*specs)
- self.assertEquals(len(devices), 2)
-
- def test_get_devices_by_not_matching_specs(self):
- specs = (usb_device_spec.UsbDeviceSpec('no', 'match', 'PRODUCT', []),
- usb_device_spec.UsbDeviceSpec('nono', 'match', 'PRODUCT', []))
- devices = self.collector.get_devices_by_spec(*specs)
- self.assertEquals(devices, [])
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/client/common_lib/cros/cfm/usb/usb_device_spec.py b/client/common_lib/cros/cfm/usb/usb_device_spec.py
deleted file mode 100644
index dd2f89c..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device_spec.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""Utility class representing the spec for a USB device.
-
-The file cfm_usb_devices.py lists all known USB device specs.
-"""
-
-class UsbDeviceSpec(object):
- """Utility class representing the spec for a CfM USB device."""
-
- # Dictionary of all UsbDeviceSpec instance that have been created.
- # Mapping from vid_pid to UsbDeviceSpec instance.
- _all_specs = {}
-
- def __init__(self, vid, pid, product, interfaces):
- """
- Constructor.
-
- @param vid: Vendor ID. String.
- @param pid: Product ID. String.
- @param product: Product description. String
- @param interfaces: List of strings
- """
- self._vid = vid
- self._pid = pid
- self._product = product
- self._interfaces = interfaces
- self.__class__._all_specs[self.vid_pid] = self
-
- @classmethod
- def get_usb_device_spec(cls, vid_pid):
- """Looks up UsbDeviceSpec by vid_pid."""
- return cls._all_specs.get(vid_pid)
-
- @property
- def vendor_id(self):
- """Returns the vendor id for this USB device."""
- return self._vid
-
- @property
- def product_id(self):
- """Returns the product id for this USB device."""
- return self._pid
-
- @property
- def vid_pid(self):
- """Return the <vendor_id>:<product_id> as a string."""
- return '%s:%s' % (self._vid, self._pid)
-
- @property
- def product(self):
- """Returns the product name."""
- return self._product
-
- @property
- def interfaces(self):
- """Returns the list of interfaces."""
- return self._interfaces
-
- def __str__(self):
- return self.__repr__()
-
- def __repr__(self):
- return "%s (%s)" % (self._product, self.vid_pid)
diff --git a/client/common_lib/cros/cfm/usb/usb_device_spec_unittest.py b/client/common_lib/cros/cfm/usb/usb_device_spec_unittest.py
deleted file mode 100644
index 2dfe79a..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device_spec_unittest.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import unittest
-
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_spec
-
-# pylint: disable=missing-docstring
-
-class UsbDeviceSpecTest(unittest.TestCase):
- """Unit tests for UsbDeviceSpec."""
-
- def setUp(self):
- self._spec = usb_device_spec.UsbDeviceSpec(
- vid='vid',
- pid='pid',
- product='product',
- interfaces=['a', 'b'])
-
- def test_vendor_id(self):
- self.assertEqual(self._spec.vendor_id, 'vid')
-
- def test_product_id(self):
- self.assertEqual(self._spec.product_id, 'pid')
-
- def test_product(self):
- self.assertEqual(self._spec.product, 'product')
-
- def test_vid_pid(self):
- self.assertEqual(self._spec.vid_pid, 'vid:pid')
-
- def test_get_usb_device_spec(self):
- self.assertEqual(self._spec,
- usb_device_spec.UsbDeviceSpec.get_usb_device_spec(
- self._spec.vid_pid))
diff --git a/client/common_lib/cros/cfm/usb/usb_device_unittest.py b/client/common_lib/cros/cfm/usb/usb_device_unittest.py
deleted file mode 100644
index d5addf4..0000000
--- a/client/common_lib/cros/cfm/usb/usb_device_unittest.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import unittest
-
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_device_spec
-
-# pylint: disable=missing-docstring
-
-class UsbDeviceTest(unittest.TestCase):
- """Unit tests for UsbDevice."""
-
- def setUp(self):
- self._usb_device = usb_device.UsbDevice(
- vid='vid',
- pid='pid',
- product='product',
- interfaces=['a', 'b'],
- bus=1,
- level=1,
- port=2)
-
- def test_vendor_id(self):
- self.assertEqual(self._usb_device.vendor_id, 'vid')
-
- def test_product_id(self):
- self.assertEqual(self._usb_device.product_id, 'pid')
-
- def test_product(self):
- self.assertEqual(self._usb_device.product, 'product')
-
- def test_vid_pid(self):
- self.assertEqual(self._usb_device.vid_pid, 'vid:pid')
-
- def test_bus(self):
- self.assertEqual(self._usb_device.bus, 1)
-
- def test_port(self):
- self.assertEqual(self._usb_device.port, 2)
-
- def test_level(self):
- self.assertEqual(self._usb_device.level, 1)
-
- def test_get_parent(self):
- child = usb_device.UsbDevice(
- vid='vid1',
- pid='pid1',
- product='product',
- interfaces=['a', 'b'],
- bus=1,
- level=2,
- port=2,
- parent=self._usb_device)
- self.assertEquals(child.get_parent(1).vid_pid, 'vid:pid')
-
- def test_get_parent_error(self):
- self.assertRaises(ValueError, lambda: self._usb_device.get_parent(2))
-
- def test_interfaces_matches_spec(self):
- device_spec = usb_device_spec.UsbDeviceSpec(
- vid='vid',
- pid='pid',
- product='product',
- interfaces=['a', 'b'])
- self.assertTrue(self._usb_device.interfaces_match_spec(device_spec))
diff --git a/client/common_lib/cros/cfm/usb/usb_port_manager.py b/client/common_lib/cros/cfm/usb/usb_port_manager.py
deleted file mode 100644
index 4b443ae..0000000
--- a/client/common_lib/cros/cfm/usb/usb_port_manager.py
+++ /dev/null
@@ -1,197 +0,0 @@
-import collections
-import logging
-import os.path
-
-
-PortId = collections.namedtuple('PortId', ['bus', 'port_number'])
-
-GPIO_PATH = '/sys/class/gpio'
-GUADO_CONTROLLER = 'INT3437:00'
-
-# Mapping from bus ID and port number to the GPIO index.
-_PORT_ID_TO_GPIO_INDEX_DICT = {
- # On Guado, there are three gpios that control usb port power.
- # These are offsets used to calculate GPIO index.
- 'guado': {
- # Front ports
- PortId(bus=1, port_number=2): 56, # Front left USB 2
- PortId(bus=2, port_number=1): 56, # Front left USB 3
- PortId(bus=1, port_number=3): 57, # Front right USB 2
- PortId(bus=2, port_number=2): 57, # Front right USB 3
- # Back ports (same GPIO is used for both ports)
- PortId(bus=1, port_number=5): 47, # Back upper USB 2
- PortId(bus=2, port_number=3): 47, # Back upper USB 3
- PortId(bus=1, port_number=6): 47, # Back lower USB 2
- PortId(bus=2, port_number=4): 47, # Back lower USB 3
- },
- 'guado-cfm': {
- # Front ports
- PortId(bus=1, port_number=2): 56, # Front left USB 2
- PortId(bus=2, port_number=1): 56, # Front left USB 3
- PortId(bus=1, port_number=3): 57, # Front right USB 2
- PortId(bus=2, port_number=2): 57, # Front right USB 3
- # Back ports (same GPIO is used for both ports)
- PortId(bus=1, port_number=5): 47, # Back upper USB 2
- PortId(bus=2, port_number=3): 47, # Back upper USB 3
- PortId(bus=1, port_number=6): 47, # Back lower USB 2
- PortId(bus=2, port_number=4): 47, # Back lower USB 3
- },
- # On Fizz, there are in total 5 usb ports and per port usb power
- # is controlled by EC with user space command:
- # ectool gpioset USBx_ENABLE 0/1 (x from 1 to 5).
- 'fizz': {
- # USB 2 bus.
- PortId(bus=1, port_number=3): 4, # Front right USB 2
- PortId(bus=1, port_number=4): 5, # Front left USB 2
- PortId(bus=1, port_number=5): 1, # Back left USB 2
- PortId(bus=1, port_number=6): 2, # Back middle USB 2
- PortId(bus=1, port_number=2): 3, # Back right USB 2
- # USB 3 bus.
- PortId(bus=2, port_number=3): 4, # Front right USB 3
- PortId(bus=2, port_number=4): 5, # Front left USB 3
- PortId(bus=2, port_number=5): 1, # Back left USB 3
- PortId(bus=2, port_number=6): 2, # Back middle USB 3
- PortId(bus=2, port_number=2): 3, # Back right USB 3
- },
- 'fizz-cfm': {
- # USB 2 bus.
- PortId(bus=1, port_number=3): 4, # Front right USB 2
- PortId(bus=1, port_number=4): 5, # Front left USB 2
- PortId(bus=1, port_number=5): 1, # Back left USB 2
- PortId(bus=1, port_number=6): 2, # Back middle USB 2
- PortId(bus=1, port_number=2): 3, # Back right USB 2
- # USB 3 bus.
- PortId(bus=2, port_number=3): 4, # Front right USB 3
- PortId(bus=2, port_number=4): 5, # Front left USB 3
- PortId(bus=2, port_number=5): 1, # Back left USB 3
- PortId(bus=2, port_number=6): 2, # Back middle USB 3
- PortId(bus=2, port_number=2): 3, # Back right USB 3
- }
-}
-
-
-def _get_gpio_index(board, port_id):
- return _PORT_ID_TO_GPIO_INDEX_DICT[board][port_id]
-
-
-class UsbPortManager(object):
- """
- Manages USB ports.
-
- Can for example power cycle them.
- """
- def __init__(self, host):
- """
- Initializes with a host.
-
- @param host a Host object.
- """
- self._host = host
-
- def set_port_power(self, port_ids, power_on):
- """
- Turns on or off power to the USB port for peripheral devices.
-
- @param port_ids Iterable of PortId instances (i.e. bus, port_number
- tuples) to set power for.
- @param power_on If true, turns power on. If false, turns power off.
- """
- for port_id in port_ids:
- gpio_index = _get_gpio_index(self._get_board(), port_id)
- self._set_gpio_power(self._get_board(), gpio_index, power_on)
-
- def _find_gpio_base_index(self, expected_controller):
- """
- Finds the gpiochip* base index using the expected controller.
-
- If `cat /sys/class/gpio/gpiochip<N>/label` has the expected controller, return <N>
-
- @param expected_controller The controller to match to return gpiochip<N>/base
- """
- gpiochips = self._run(
- 'ls -d /sys/class/gpio/gpiochip*').stdout.strip().split('\n')
- if not gpiochips:
- raise ValueError('No gpiochips found')
-
- for gpiochip in gpiochips:
- logging.debug('Checking gpiochip path "%s" for controller %s',
- gpiochip, expected_controller)
- gpiochip_label = os.path.join(gpiochip, 'label')
- gpiochip_controller = self._run(
- 'cat {}'.format(gpiochip_label)).stdout.strip()
-
- if gpiochip_controller == expected_controller:
- gpiochip_base = os.path.join(gpiochip, 'base')
- gpiochip_base_index = self._run(
- 'cat {}'.format(gpiochip_base)).stdout.strip()
- return int(gpiochip_base_index)
-
- raise ValueError('Expected controller not found')
-
- def _get_board(self):
- # host.get_board() adds 'board: ' in front of the board name
- return self._host.get_board().split(':')[1].strip()
-
- def _set_gpio_power_guado(self, gpio_idx, power_on):
- """
- Turns on or off the power for a specific GPIO on board Guado.
-
- @param gpio_idx The *offset* of the gpio to set the power for, added to the base.
- @param power_on If True, powers on the GPIO. If False, powers it off.
- """
-
- # First, we need to find the gpio base
- gpio_base_index = self._find_gpio_base_index(GUADO_CONTROLLER)
-
- # Once base is found, calculate index
- gpio_index = gpio_base_index + gpio_idx
- logging.debug('Using gpio index: "%s"', gpio_index)
-
- gpio_path = '/sys/class/gpio/gpio{}'.format(gpio_index)
- did_export = False
- if not self._host.path_exists(gpio_path):
- did_export = True
- self._run('echo {} > /sys/class/gpio/export'.format(
- gpio_index))
- try:
- self._run('echo out > {}/direction'.format(gpio_path))
- value_string = '1' if power_on else '0'
- self._run('echo {} > {}/value'.format(
- value_string, gpio_path))
- finally:
- if did_export:
- self._run('echo {} > /sys/class/gpio/unexport'.format(
- gpio_index))
-
- def _set_gpio_power_fizz(self, gpio_idx, power_on):
- """
- Turns on or off the power for a specific GPIO on board Fizz.
-
- @param gpio_idx The index of the gpio to set the power for.
- @param power_on If True, powers on the GPIO. If False, powers it off.
- """
- value_string = '1' if power_on else '0'
- cmd = 'ectool gpioset USB{}_ENABLE {}'.format(gpio_idx,
- value_string)
- self._run(cmd)
-
- def _set_gpio_power(self, board, gpio_index, power_on):
- """
- Turns on or off the power for a specific GPIO.
-
- @param board Board type. Currently support: Guado, Fizz.
- @param gpio_idx The index of the gpio to set the power for.
- @param power_on If True, powers on the GPIO. If False, powers it off.
- """
- if board == 'guado' or board == 'guado-cfm':
- self._set_gpio_power_guado(gpio_index, power_on)
- elif board == 'fizz' or board == 'fizz-cfm':
- self._set_gpio_power_fizz(gpio_index, power_on)
- else:
- raise ValueError('Unsupported board type {}.'.format(board))
-
- def _run(self, command):
- logging.debug('Running: "%s"', command)
- res = self._host.run(command)
- logging.debug('Result: "%s"', res)
- return res
diff --git a/client/common_lib/cros/cfm/usb/usb_port_manager_unittest.py b/client/common_lib/cros/cfm/usb/usb_port_manager_unittest.py
deleted file mode 100644
index c57d5d6..0000000
--- a/client/common_lib/cros/cfm/usb/usb_port_manager_unittest.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import mock
-import unittest
-import os.path
-
-from autotest_lib.client.common_lib.cros.cfm.usb import usb_port_manager
-
-# Fake GPIO value for testing.
-GUADO_GPIO_BASE = '100'
-# GPIO offset for the port on bus 1, port 2.
-GUADO_GPIO_OFFSET = '56'
-# Expected index -- base + offset
-GUADO_GPIO_INDEX = '156'
-GUADO_GPIO_PATH = '/sys/class/gpio'
-GUADO_CONTROLLER = 'INT3437:00'
-
-FIZZ_GPIO = 3
-
-
-def host_run_expected_guado(command):
- """
- Defines mock values to return from host.run(). This covers expected calls
- from usb_port_manager._find_gpio_base_index().
- """
- ret = mock.Mock()
-
- if command == 'ls -d /sys/class/gpio/gpiochip*':
- ret.stdout = os.path.join(GUADO_GPIO_PATH,
- 'gpiochip%s' % GUADO_GPIO_BASE)
- elif command.startswith('cat') and command.endswith('/label'):
- ret.stdout = GUADO_CONTROLLER
- elif command.startswith('cat') and command.endswith('/base'):
- ret.stdout = GUADO_GPIO_BASE
-
- return ret
-
-# pylint: disable=missing-docstring
-class UsbPortManagerTest(unittest.TestCase):
-
- def test_power_off_gpio_unexported_guado(self):
- host = mock.Mock()
- host.get_board = mock.Mock(return_value='board: guado')
-
- host.run = mock.Mock(side_effect=host_run_expected_guado)
- host.path_exists = mock.Mock(return_value=False)
- port_manager = usb_port_manager.UsbPortManager(host)
- port_manager.set_port_power([(1, 2)], False)
- expected_runs = [
- mock.call('ls -d /sys/class/gpio/gpiochip*'),
- mock.call('cat /sys/class/gpio/gpiochip%s/label' % GUADO_GPIO_BASE),
- mock.call('cat /sys/class/gpio/gpiochip%s/base' % GUADO_GPIO_BASE),
- mock.call('echo %s > /sys/class/gpio/export' % GUADO_GPIO_INDEX),
- mock.call('echo out > {path}/gpio{index}/direction'.format(
- path=GUADO_GPIO_PATH, index=GUADO_GPIO_INDEX)),
- mock.call('echo 0 > {path}/gpio{index}/value'.format(
- path=GUADO_GPIO_PATH, index=GUADO_GPIO_INDEX)),
- mock.call('echo %s > /sys/class/gpio/unexport' % GUADO_GPIO_INDEX),
- ]
- host.run.assert_has_calls(expected_runs)
-
- def test_power_on_gpio_exported_guado(self):
- host = mock.Mock()
- host.get_board = mock.Mock(return_value='board: guado')
-
- host.run = mock.Mock(side_effect=host_run_expected_guado)
- host.path_exists = mock.Mock(return_value=True)
- port_manager = usb_port_manager.UsbPortManager(host)
- port_manager.set_port_power([(1, 2)], True)
- expected_runs = [
- mock.call('ls -d /sys/class/gpio/gpiochip*'),
- mock.call('cat /sys/class/gpio/gpiochip%s/label' % GUADO_GPIO_BASE),
- mock.call('cat /sys/class/gpio/gpiochip%s/base' % GUADO_GPIO_BASE),
- mock.call('echo out > {path}/gpio{index}/direction'.format(
- path=GUADO_GPIO_PATH, index=GUADO_GPIO_INDEX)),
- mock.call('echo 1 > {path}/gpio{index}/value'.format(
- path=GUADO_GPIO_PATH, index=GUADO_GPIO_INDEX)),
- ]
- host.run.assert_has_calls(expected_runs)
-
- def test_power_off_gpio_fizz(self):
- host = mock.Mock()
- host.get_board = mock.Mock(return_value='board: fizz')
- host.run = mock.Mock()
- port_manager = usb_port_manager.UsbPortManager(host)
- port_manager.set_port_power([(1, 2)], False)
- expected_runs = [
- mock.call('ectool gpioset USB%s_ENABLE 0' % FIZZ_GPIO)
- ]
- host.run.assert_has_calls(expected_runs)
-
- def test_power_on_gpio_fizz(self):
- host = mock.Mock()
- host.get_board = mock.Mock(return_value='board: fizz')
- host.run = mock.Mock()
- port_manager = usb_port_manager.UsbPortManager(host)
- port_manager.set_port_power([(1, 2)], True)
- expected_runs = [
- mock.call('ectool gpioset USB%s_ENABLE 1' % FIZZ_GPIO)
- ]
- host.run.assert_has_calls(expected_runs)
diff --git a/client/common_lib/cros/manual/__init__.py b/client/common_lib/cros/manual/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/client/common_lib/cros/manual/__init__.py
+++ /dev/null
diff --git a/client/common_lib/cros/manual/audio_helper.py b/client/common_lib/cros/manual/audio_helper.py
deleted file mode 100644
index c861043..0000000
--- a/client/common_lib/cros/manual/audio_helper.py
+++ /dev/null
@@ -1,444 +0,0 @@
-# Copyrigh 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.
-
-"""Get speaker/microphone status from cras_client_test, /proc/asound and
- atrus.log.
-"""
-
-from __future__ import print_function
-
-import logging
-import re
-
-
-NUM_AUDIO_STREAM_IN_MEETING = 3
-
-def get_soundcard_by_name(dut, name):
- """
- Returns the soundcard number of specified soundcard by name.
- @param dut: The handle of the device under test.
- @param name: The name of Speaker
- For example: 'Hangouts Meet speakermic'
- @returns the soundcard, if no device found returns None.
- """
- soundcard = None
- cmd = "cat /proc/asound/cards | grep \"{}\" | grep USB".format(name)
- logging.info('---cmd: %s', cmd)
- try:
- soundcard = dut.run(cmd, ignore_status=True).stdout.strip().split()[0]
- except Exception as e:
- soundcard = None
- logging.exception('Fail to execute %s.', cmd)
- if soundcard:
- soundcard = "card{}".format(soundcard)
- logging.info('---audio card %s', soundcard)
- else:
- logging.exception('Fail to get sound card, cli=%s.', cmd)
- return soundcard
-
-def check_soundcard_by_name(dut, name):
- """
- check soundcard by name exists
- @param dut: The handle of the device under test.
- @param name: The name of Speaker
- For example: 'Hangouts Meet speakermic'
- @returns: True, None if test passes,
- False, errMsg if test fails
- """
- if get_soundcard_by_name(dut, name):
- return True, None
- else:
- return False, 'Soundcard is not found under /proc/asound/cards.'
-
-def check_audio_stream(dut, is_in_meeting):
- """
- Verify speaker is streaming or not streaming as expected.
- @param dut: The handle of the device under test.
- @is_in_meeting: True if CfM is in meeting, False, if not
- @returns: True, None if test passes,
- False, errMsg if test fails
- """
- number_stream = get_number_of_active_streams(dut)
- if is_in_meeting:
- if number_stream >= NUM_AUDIO_STREAM_IN_MEETING:
- return True, None
- else:
- return False, 'Number of Audio streams is not expected.'
- else:
- if number_stream <= NUM_AUDIO_STREAM_IN_MEETING:
- return True, None
- else:
- return False, 'Number of Audio streams is not expected.'
-
-def get_audio_stream_state(dut, soundcard):
- """
- Returns the state of stream0 for specified soundcard.
-
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @param soundcard: soundcard
- For example: 'card0'
-
- @returns the list of state of steam0, "Running" or "Stop"
-
- """
- stream_state = []
- try:
- cmd = ("cat /proc/asound/%s/stream0 | grep Status | "
- "awk -v N=2 '{print $N}'" % soundcard)
- stream_state = dut.run(cmd, ignore_status=True).stdout.split()
- except Exception as e:
- logging.exception('Fail to run cli: %s.', cmd)
- return stream_state
-
-
-def check_default_speaker_volume(dut, cfm_facade):
- """Check volume of speaker is the same as expected.
- @param dut: The handle of the device under test.
- @param cfm_facade: the handle of cfm facade
- @returns True, None if default speakers have same volume as one read
- from hotrod,
- False, errMsg, otherwise
- """
- try:
- expected_volume = int(cfm_facade.get_speaker_volume())
- except Exception as e:
- errmsg = 'Fail to run telemetry api to get speaker volume.'
- logging.exception(errmsg)
- return False, errmsg
- if expected_volume < 1:
- return False, 'Fail to get speaker volume from Hotrod.'
- nodes = get_nodes_for_default_speakers_cras(dut)
- if not nodes:
- logging.info('---Fail to get node for default speaker.')
- return False, 'Fail to get node for default speaker.'
- for node in nodes:
- cras_volume = get_speaker_volume_cras(dut, node)
- logging.info('---Volume for default speaker are sync for '
- 'node %s? cfm: %d, cras: %d.'
- 'format(node, expected_volume, cras_volume)')
- if not expected_volume == cras_volume:
- logging.info('---Volume Check Fail for default speaker: '
- 'expected_volume:%d, actual_volume:%d.'
- 'format(expected_volume, cras_volume)')
- return False, ('Volume Check fails for default speaker: '
- 'expected_volume:%d, actual_volume:%d',
- '% expected_volume, cras_volume')
- logging.info('---Expected volume: %d, actual: %d',
- expected_volume, cras_volume)
- return True, None
-
-def get_number_of_active_streams(dut):
- """
- Returns the number of active stream.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @returns the number of active streams.
- """
- cmd = ("cras_test_client --dump_server_info "
- "| grep 'Num active streams:' "
- "| awk -v N=4 '{print $N}'")
-
- try:
- number_of_streams = int(dut.run(cmd, ignore_status=True).stdout.strip())
- except Exception as e:
- logging.exception('Fail to execute cli to get number of streams: %s.',
- cmd)
- return None
- logging.info('---number of audio streaming: %d', number_of_streams)
- return number_of_streams
-
-
-def get_nodes_for_default_speakers_cras(dut):
- """get node for default speakers from cras_test_client.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @returns the list of nodes for default speakers. If device not found,
- returns [].
- """
- nodes = []
- cmd = ("cras_test_client --dump_server_info | awk '/Output Nodes:/,"
- "/Input Devices:/'")
- try:
- lines = dut.run(cmd, ignore_status=True).stdout.splitlines()
- except Exception as e:
- logging.exception('Fail to execute cli to get nodes for default'
- 'speaker: %s', cmd)
- return nodes
- for _line in lines:
- match = re.findall(r"(\d+):\d+.*USB\s+\*.*", _line)
- if match:
- nodes.append(match[0])
- logging.info('---found nodes for default speaker %s', nodes)
- return nodes
-
-
-def get_speaker_for_node_cras(dut, node):
- """get node for default speakers from cras_test_client.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
-
- @returns the list of nodes for default speakers. If device not found,
- returns [].
- """
- cmd = ("cras_test_client --dump_server_info | awk '/Output Devices:/,"
- "/Output Nodes:/' | grep '%s'" % node)
-
- try:
- line = dut.run(cmd, ignore_status=True).stdout.stripe()
- speaker = re.findall(r"^[0-9]+\s*(.*):\s+USB\s+Audio:", line)[0]
- except Exception as e:
- logging.exception('Fail to execute cli to get nodes for default'
- 'speaker: %s.', cmd)
-
- logging.info('---speaker for %s is %s', node, speaker)
- return speaker
-
-
-def get_nodes_for_default_microphone_cras(dut):
- """get node for default microphones from cras_test_client.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
-
- @returns the list of nodes for default microphone. If device not found,
- returns [].
- """
- nodes = None
- cmd = ("cras_test_client --dump_server_info | awk '/Input Nodes:/,"
- "/Attached clients:/'")
- try:
- lines = dut.run(cmd, ignore_status=True).stdout.splitlines()
- for _line in lines:
- nodes.append(re.findall(r"(\d+):\d+.*USB\s+\*.*", _line)[0])
- except Exception as e:
- logging.exception('Fail to execute cli to get nodes for default'
- ' speaker: %s.', cmd)
- return nodes
-
-
-def get_microphone_for_node_cras(dut, node):
- """get node for default speakers from cras_test_client.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
-
- @returns the list of nodes for default speakers. If device not found,
- returns [].
- """
- cmd = ("cras_test_client --dump_server_info | awk '/Input Devices:/,"
- "/Input Nodes:/' | grep '%s' " % node)
-
- try:
- line = dut.run(cmd, ignore_status=True).stdout
- microphone = re.findall(r"10\t(.*):\s+USB\s+Audio:", line)[0]
- except Exception as e:
- logging.exception('Fail to execute cli to get nodes for default'
- ' speaker: %s.', cmd)
- logging.info('---mic for %s is %s', node, microphone)
- return microphone
-
-
-def get_speaker_volume_cras(dut, node):
- """get volume for speaker from cras_test_client based on node
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @param node: The node of Speaker
- Example cli:
- cras_test_client --dump_server_info | awk
- '/Output Nodes:/,/Input Devices:/' | grep 9:0 |
- awk -v N=3 '{print $N}'
-
- @returns the volume of speaker. If device not found, returns None.
- """
- cmd = ("cras_test_client --dump_server_info | awk '/Output Nodes:/,"
- "/Input Devices:/' | grep -E 'USB' | grep '%s':0 "
- "| awk -v N=3 '{print $N}'" % node)
- try:
- volume = int(dut.run(cmd, ignore_status=True).stdout.strip())
- except Exception as e:
- logging.exception('Fail to execute cli %s to get volume for node %d',
- cmd, node)
- return None
- return volume
-
-
-def check_cras_mic_mute(dut, cfm_facade):
- """
- check microphone is muted or unmuted as expected/.
- @param dut: The handle of the device under test.
- @param cfm_facade: facade of CfM
- @param is_mic_muted: True if muted, False otherwise
- @returns True, none if test passes
- False, errMsg if test fails
- """
- try:
- is_mic_muted = cfm_facade.is_mic_muted()
- except Exception as e:
- errmsg = 'Fail to run telemetry api to check mute state for mic.'
- logging.exception(errmsg)
- return False, errmsg
- actual_muted = get_mic_muted_cras(dut)
- if is_mic_muted == actual_muted:
- return True, None
- else:
- if is_mic_muted:
- logging.info('Hotrod setting: microphone is muted')
- else:
- logging.info('Hotrod setting: microphone is not muted')
- if actual_muted:
- logging.info('cras setting: microphone is muted')
- else:
- logging.info('cras setting: microphone is not muted')
- return False, 'Microphone is not muted/unmuted as shown in Hotrod.'
-
-def check_is_preferred_speaker(dut, name):
- """
- check preferred speaker is speaker to be tested.
- @param dut: The handle of the device under test.
- @param cfm_facade: facade of CfM
- @param name: name of speaker
- @returns True, none if test passes
- False, errMsg if test fails
- """
- node = None
- cmd = ("cras_test_client --dump_server_info | awk "
- "'/Output Devices:/,/Output Nodes:/' "
- "| grep '%s' " % name)
- try:
- output = dut.run(cmd, ignore_status=True).stdout.strip()
- except Exception as e:
- logging.exception('Fail to run cli %s to find %s in cras_test_client.',
- cmd, node)
- return False, 'Fail to run cli {}:, reason: {}'.format(cmd, str(e))
- logging.info('---output = %s', output)
- if output:
- node = output.split()[0]
- logging.info('---found node for %s is %s', name, node)
- else:
- return False, 'Fail in get node for speaker in cras.'
- default_nodes = get_nodes_for_default_speakers_cras(dut)
- logging.info('---default speaker node is %s', default_nodes)
- if node in default_nodes:
- return True, None
- return False, '{} is not set to preferred speaker.'.format(name)
-
-
-def check_is_preferred_mic(dut, name):
- """check preferred mic is set to speaker to be tested."""
- cmd = ("cras_test_client --dump_server_info | "
- "awk '/Input Devices/,/Input Nodes/' | grep '%s' | "
- "awk -v N=1 '{print $N}'" % name)
- logging.info('---cmd = %s',cmd)
- try:
- mic_node = dut.run(cmd, ignore_status=True).stdout.strip()
- logging.info('---mic_node : %s', mic_node)
- except Exception as e:
- logging.exception('Fail to execute: %s to check preferred mic.', cmd)
- return False, 'Fail to run cli.'
- try:
- cmd = ("cras_test_client --dump_server_info | awk '/Input Nodes:/,"
- "/Attached clients:/' | grep default "
- "| awk -v N=2 '{print $N}'")
- mic_node_default = dut.run(cmd, ignore_status=True).stdout.strip()
- if not mic_node_default:
- cmd = ("cras_test_client --dump_server_info | awk '/Input Nodes:/,"
- "/Attached clients:/' | grep '%s' "
- "| awk -v N=2 '{print $N}'" %name)
- mic_node_default = dut.run(cmd,ignore_status=True).stdout.strip()
- logging.info('---%s',cmd)
- logging.info('---%s', mic_node_default)
- except Exception as e:
- msg = 'Fail to execute: {} to check preferred mic'.format(cmd)
- logging.exception(msg)
- return False, msg
- logging.info('---mic node:%s, default node:%s',
- mic_node, mic_node_default)
- if mic_node == mic_node_default.split(':')[0]:
- return True, None
- return False, '{} is not preferred microphone.'.format(name)
-
-
-def get_mic_muted_cras(dut):
- """
- Get the status of mute or unmute for microphone
- @param dut: the handle of CfM under test
- @returns True if mic is muted
- False if mic not not muted
- """
- cmd = 'cras_test_client --dump_server_info | grep "Capture Gain"'
- try:
- microphone_muted = dut.run(cmd, ignore_status=True).stdout.strip()
- except Exception as e:
- logging.exception('Fail to execute: %s.', cmd)
- return False, 'Fail to execute: {}.'.format(cmd)
- logging.info('---%s', microphone_muted)
- if "Muted" in microphone_muted:
- return True
- else:
- return False
-
-
-def check_speaker_exist_cras(dut, name):
- """
- Check speaker exists in cras.
- @param dut: The handle of the device under test.
- @param name: name of speaker
- @returns: True, None if test passes,
- False, errMsg if test fails
- """
- cmd = ("cras_test_client --dump_server_info | awk "
- "'/Output Devices:/, /Output Nodes:/' "
- "| grep '%s'" % name)
- try:
- speaker = dut.run(cmd, ignore_status=True).stdout.splitlines()[0]
- except Exception as e:
- logging.exception('Fail to find %s in cras_test_client running %s.',
- name, cmd)
- speaker = None
- logging.info('---cmd: %s\n---output = %s', cmd, speaker)
- if speaker:
- return True, None
- return False, 'Fail to execute cli {}: Reason: {}'.format(cmd, str(e))
-
-
-def check_microphone_exist_cras(dut, name):
- """
- Check microphone exists in cras.
- @param dut: The handle of the device under test.
- @param name: name of speaker
- @returns: True, None if test passes,
- False, errMsg if test fails
- """
- microphone = None
- cmd = ("cras_test_client --dump_server_info | awk "
- "'/Input Devices:/, /Input Nodes:/' "
- "| grep '%s'" % name )
- try:
- microphone = dut.run(cmd, ignore_status=True).stdout.splitlines()[0]
- except Exception as e:
- logging.exception('Fail to execute cli %s.', cmd)
- logging.info('---cmd: %s\n---output = %s', cmd, microphone)
- if microphone:
- return True, None
- return False, 'Fail to find microphone {}.'.format(name)
-
-def check_audio_stream(dut, is_in_meet):
- """
- Verify speaker is streaming or not streaming as expected.
- @param dut: The handle of the device under test.
- @is_in_meeting: True if CfM is in meeting, False, if not
- @returns: True, None if test passes,
- False, errMsg if test fails
- """
- number_stream = get_number_of_active_streams(dut)
- if is_in_meet:
- if number_stream >= NUM_AUDIO_STREAM_IN_MEETING:
- return True, None
- else:
- return False, 'Number of Audio streams is not expected.'
- else:
- if number_stream <= NUM_AUDIO_STREAM_IN_MEETING:
- return True, None
- else:
- return False, 'Number of Audio streams is not expected.'
-
diff --git a/client/common_lib/cros/manual/cfm_helper.py b/client/common_lib/cros/manual/cfm_helper.py
deleted file mode 100644
index 28bd1dc..0000000
--- a/client/common_lib/cros/manual/cfm_helper.py
+++ /dev/null
@@ -1,383 +0,0 @@
-# Copyright 2017 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.
-
-"""Check USB device by running linux command on CfM"""
-
-from __future__ import print_function
-
-import logging
-import re
-import six
-import time
-import common
-from autotest_lib.client.common_lib.cros.manual import get_usb_devices
-from autotest_lib.client.common_lib.cros import cros_config
-from autotest_lib.client.common_lib.cros import power_cycle_usb_util
-
-CORE_DIR_LINES = 3
-ATRUS = '18d1:8001'
-
-def check_chrome_logfile(dut):
- """
- Get the latest chrome log file.
- @param dut: The handle of the device under test.
- @returns: the latest chrome log file
- """
- output = None
- logging.info('---Get the latest chrome log file')
- cmd = 'ls -latr /var/log/chrome/chrome'
- try:
- output = dut.run(cmd, ignore_status=True).stdout
- except Exception as e:
- logging.exception('Fail to run command %s.', cmd)
- return None
- logging.info('---cmd: %s', cmd)
- logging.info('---output: %s', output.lower().strip())
- return output
-
-def check_last_reboot(dut):
- """
- Get the last line of eventlog.txt
- @param dut: The handle of the device under test.
- @returns: the last line in eventlog.txt
- """
- output = None
- cmd = 'tail -1 /var/log/eventlog.txt'
- logging.info('---Get the latest reboot log')
- try:
- output = dut.run(cmd, ignore_status=True).stdout
- except Exception as e:
- logging.exception('Fail to run command %s.', cmd)
- return None
- logging.info('---cmd: %s', cmd)
- logging.info('---output: %s', output.lower().strip())
- return output
-
-def check_is_platform(dut, name):
- """
- Check whether CfM is expected platform.
- @param dut: The handle of the device under test.
- @param name: The name of platform
- @returns: True, if CfM's platform is same as expected.
- False, if not.
- """
- cros_config_args = '/identity platform-name'
- output = cros_config.call_cros_config_get_output(cros_config_args,
- dut.run, ignore_status=True)
- logging.info('---cmd: cros_config %s', cros_config_args)
- logging.info('---output: %s', output.lower())
- return output.lower() == name
-
-
-def get_mgmt_ipv4(dut):
- """
- Get mgmt ipv4 address
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @return: ipv4 address for mgmt interface.
- """
- cmd = 'ifconfig -a | grep eth0 -A 2 | grep netmask'
- try:
- output = dut.run(cmd, ignore_status=True).stdout
- except Exception as e:
- logging.exception('Fail to run command %s.', cmd)
- return None
- ipv4 = re.findall(r"inet\s*([0-9.]+)\s*netmask.*", output)[0]
- return ipv4
-
-
-def retrieve_usb_devices(dut):
- """
- Populate output of usb-devices on CfM.
- @param dut: handle of CfM under test
- @returns dict of all usb devices detected on CfM.
- """
- usb_devices = (dut.run('usb-devices', ignore_status=True).
- stdout.strip().split('\n\n'))
- usb_data = get_usb_devices.extract_usb_data(
- '\nUSB-Device\n'+'\nUSB-Device\n'.join(usb_devices))
- return usb_data
-
-
-def extract_peripherals_for_cfm(usb_data):
- """
- Check CfM has camera, speaker and Mimo connected.
- @param usb_data: dict extracted from output of "usb-devices"
- """
- peripheral_map = {}
- get_devices_funcs = (get_usb_devices.get_speakers,
- get_usb_devices.get_cameras, get_usb_devices.get_display_mimo,
- get_usb_devices.get_controller_mimo)
- for get_devices in get_devices_funcs:
- device_list = get_devices(usb_data)
- for pid_vid, device_count in six.iteritems(device_list):
- if device_count > 0:
- peripheral_map[pid_vid] = device_count
-
- for pid_vid, device_count in six.iteritems(peripheral_map):
- logging.info('---device: %s (%s), count: %d',
- pid_vid, get_usb_devices.get_device_prod(pid_vid),
- device_count)
-
- return peripheral_map
-
-
-def check_peripherals_for_cfm(peripheral_map):
- """
- Check CfM has one and only one camera,
- one and only one speaker,
- or one and only one mimo.
- @param peripheral_map: dict for connected camera, speaker, or mimo.
- @returns: True if check passes,
- False if check fails.
- """
- peripherals = peripheral_map.keys()
-
- type_camera = set(peripherals).intersection(get_usb_devices.CAMERA_LIST)
- type_speaker = set(peripherals).intersection(get_usb_devices.SPEAKER_LIST)
- type_controller = set(peripherals).intersection(\
- get_usb_devices.TOUCH_CONTROLLER_LIST)
- type_panel = set(peripherals).intersection(\
- get_usb_devices.TOUCH_DISPLAY_LIST)
-
- # check CfM have one, and only one type camera, huddly and mimo
- if len(type_camera) == 0:
- logging.info('No camera is found on CfM.')
- return False
-
- if not len(type_camera) == 1:
- logging.info('More than one type of cameras are found on CfM.')
- return False
-
- if len(type_speaker) == 0:
- logging.info('No speaker is found on CfM.')
- return False
-
- if not len(type_speaker) == 1:
- logging.info('More than one type of speakers are found on CfM.')
- return False
-
- if len(type_controller) == 0:
- logging.info('No controller is found on CfM.')
- return False
-
-
- if not len(type_controller) == 1:
- logging.info('More than one type of controller are found on CfM.')
- return False
-
- if len(type_panel) == 0:
- logging.info('No Display is found on CfM.')
- return False
-
- if not len(type_panel) == 1:
- logging.info('More than one type of displays are found on CfM.')
- return False
-
- # check CfM have only one camera, huddly and mimo
- for pid_vid, device_count in six.iteritems(peripheral_map):
- if device_count > 1:
- logging.info('Number of device %s connected to CfM : %d',
- get_usb_devices.get_device_prod(pid_vid),
- device_count)
- return False
-
- return True
-
-
-def check_usb_enumeration(dut, puts):
- """
- Check USB enumeration for devices
- @param dut: the handle of CfM under test
- @param puts: the list of peripherals under test
- @returns True, none if test passes
- False, errMsg if test test fails
- """
- usb_data = retrieve_usb_devices(dut)
- if not usb_data:
- logging.warning('No usb devices found on DUT')
- return False, 'No usb device found on DUT.'
- else:
- usb_device_list = extract_peripherals_for_cfm(usb_data)
- logging.info('---usb device = %s', usb_device_list)
- if not set(puts).issubset(set(usb_device_list.keys())):
- logging.info('Detect device fails for usb enumeration')
- logging.info('Expect enumerated devices: %s', puts)
- logging.info('Actual enumerated devices: %s',
- usb_device_list.keys())
- return False, 'Some usb devices are not found.'
- return True, None
-
-
-def check_usb_interface_initializion(dut, puts):
- """
- Check CfM shows valid interface for all peripherals connected.
- @param dut: the handle of CfM under test
- @param puts: the list of peripherals under test
- @returns True, none if test passes
- False, errMsg if test test fails
- """
- usb_data = retrieve_usb_devices(dut)
- for put in puts:
- number, health = get_usb_devices.is_usb_device_ok(usb_data, put)
- logging.info('---device interface = %d, %s for %s',
- number, health, get_usb_devices.get_device_prod(put))
- if '0' in health:
- logging.warning('Device %s has invalid interface', put)
- return False, 'Device {} has invalid interface.'.format(put)
- return True, None
-
-
-def clear_core_file(dut):
- """clear core files"""
- cmd = "rm -rf /var/spool/crash/*.*"
- try:
- dut.run_output(cmd)
- except Exception as e:
- logging.exception('Fail to clean core files under '
- '/var/spool/crash')
- logging.exception('Fail to execute %s :', cmd)
-
-
-def check_process_crash(dut, cdlines):
- """Check whether there is core file."""
- cmd = 'ls -latr /var/spool/crash'
- try:
- core_files_output = dut.run_output(cmd).splitlines()
- except Exception as e:
- logging.exception('Can not find file under /var/spool/crash.')
- logging.exception('Fail to execute %s:', cmd)
- return True, CORE_DIR_LINES
- logging.info('---%s\n---%s', cmd, core_files_output)
- if len(core_files_output) - cdlines <= 0:
- logging.info('---length of files: %d', len(core_files_output))
- return True, len(core_files_output)
- else:
- return False, len(core_files_output)
-
-
-def gpio_usb_test(dut, gpio_list, device_list, pause, board):
- """
- Run GPIO test to powercycle usb port.
- @parama dut: handler of CfM,
- @param gpio_list: the list of gpio ports,
- @param device_list: the list of usb devices,
- @param pause: time needs to wait before restoring power to usb port,
- in seconds
- @param board: board name for CfM
- @returns True
- """
- for device in device_list:
- vid, pid = device.split(':')
- logging.info('---going to powercyle device %s:%s', vid, pid)
- try:
- power_cycle_usb_util.power_cycle_usb_vidpid(dut, board,
- vid, pid, pause)
- except Exception as e:
- errmsg = 'Fail to power cycle device.'
- logging.exception('%s.', errmsg)
- return False, errmsg
-
- return True, None
-
-
-def reboot_test(dut, pause):
- """
- Reboot CfM.
- @parama dut: handler of CfM,
- @param pause: time needs to wait after issuing reboot command, in seconds,
-
- """
- try:
- dut.reboot()
- except Exception as e:
- logging.exception('Fail to reboot CfM.')
- return False
- logging.info('---reboot done')
- time.sleep(pause)
- return True
-
-
-
-def find_last_log(dut, speaker):
- """
- Get the lastlast_lines line for log files.
- @param dut: handler of CfM
- @param speaker: vidpid if speaker.
- @returns: the list of string of the last line of logs.
- """
- last_lines = {
- 'messages':[],
- 'chrome':[],
- 'ui': [],
- 'atrus': []
- }
- logging.debug('Get the last line of log file, speaker %s', speaker)
- try:
- cmd = "tail -1 /var/log/messages | awk -v N=1 '{print $N}'"
- last_lines['messages'] = dut.run_output(cmd).strip().split()[0]
- cmd = "tail -1 /var/log/chrome/chrome | awk -v N=1 '{print $N}'"
- last_lines['chrome'] = dut.run_output(cmd).strip().split()[0]
- cmd = "tail -1 /var/log/ui/ui.LATEST | awk -v N=1 '{print $N}'"
- last_lines['ui']= dut.run_output(cmd)
- if speaker == ATRUS and check_is_platform(dut, 'guado'):
- logging.info('---atrus speaker %s connected to CfM', speaker)
- cmd = 'tail -1 /var/log/atrus.log | awk -v N=1 "{print $N}"'
- last_lines['atrus'] = dut.run_output(cmd).strip().split()[0]
- except Exception as e:
- logging.exception('Fail to get the last line from log files.')
- for item, timestamp in six.iteritems(last_lines):
- logging.debug('---%s: %s', item, timestamp)
- return last_lines
-
-
-def collect_log_since_last_check(dut, lastlines, logfile):
- """Collect log file since last check."""
- output = None
- if logfile == "messages":
- cmd ='awk \'/{}/,0\' /var/log/messages'.format(lastlines[logfile])
- if logfile == "chrome":
- cmd ='awk \'/{}/,0\' /var/log/chrome/chrome'.format(lastlines[logfile])
- if logfile == "ui":
- cmd ='awk \'/{}/,0\' /var/log/ui/ui.LATEST'.format(lastlines[logfile])
- if logfile == 'atrus':
- cmd ='awk \'/{}/,0\' /var/log/atrus.log'.format(lastlines[logfile])
- logging.info('---cmd = %s', cmd)
- try:
- output = dut.run_output(cmd).split('\n')
- except Exception as e:
- logging.exception('Fail to get output from log files.')
- logging.info('---length of log: %d', len(output))
- if not output:
- logging.info('--fail to find match log, check the latest log.')
-
- if not output:
- if logfile == "messages":
- cmd ='cat /var/log/messages'
- if logfile == "chrome":
- cmd ='cat /var/log/chrome/chrome'
- if logfile == "ui":
- cmd ='cat /var/log/ui/ui.LATEST'
- if logfile == 'atrus':
- cmd ='cat /var/log/atrus.log'
- output = dut.run_output(cmd).split('\n')
- logging.info('---length of log: %d', len(output))
- return output
-
-def check_log(dut, timestamp, error_list, checkitem, logfile):
- """
- Check logfile does not contain any element in error_list[checkitem].
- """
- error_log_list = []
- logging.info('---now check log %s in file %s', checkitem, logfile)
- output = collect_log_since_last_check(dut, timestamp, logfile)
- for _error in error_list[checkitem]:
- error_log_list.extend([s for s in output if _error in str(s)])
- if not error_log_list:
- return True, None
- else:
- tempmsg = '\n'.join(error_log_list)
- errmsg = 'Error_Found:in_log_file:{}:{}.'.format(logfile, tempmsg)
- logging.info('---%s', errmsg)
- return False, errmsg
diff --git a/client/common_lib/cros/manual/cfm_helper_unittest.py b/client/common_lib/cros/manual/cfm_helper_unittest.py
deleted file mode 100644
index 4e50e6b..0000000
--- a/client/common_lib/cros/manual/cfm_helper_unittest.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2019 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
-"""Tests for cfm_helper.py."""
-
-import unittest
-
-from autotest_lib.client.common_lib.cros.manual import cfm_helper
-from autotest_lib.client.common_lib.cros.manual import get_usb_devices
-
-SPEAKERS = 'speakers'
-CAMERAS = 'cameras'
-DISPLAY_MIMO = 'display_mimo'
-CONTROLLER_MIMO = 'controller_mimo'
-DEVICE_TYPES = (SPEAKERS, CAMERAS, DISPLAY_MIMO, CONTROLLER_MIMO)
-
-
-class TestExtractPeripherals(unittest.TestCase):
- """Test cfm_helper.extract_peripherals()"""
-
- def create_mock_device_getter(self, device_list):
- """Mock a function to take usb_data and return device_list"""
-
- def mock_device_getter(usb_data):
- """Return the specified device_list, ignoring usb_data."""
- return device_list
-
- return mock_device_getter
-
- def setUp(self):
- """
- Mock the various get_devices functions so that each one returns a
- key-value pair.
- In extract_peripherals(), the key represents the pid_vid, and the value
- represents the device_count.
- For these testing purposes, we use the device_type ('cameras', etc.)
- as the key, and a number 1-4 as the device_count.
- (If we used a device_count of 0 it would be ignored; hence, 1-4.)
-
- """
- self.original_funcs = {}
- for i in range(len(DEVICE_TYPES)):
- device_type = DEVICE_TYPES[i]
- mock = self.create_mock_device_getter({device_type: i + 1})
- setattr(cfm_helper.get_usb_devices, 'get_%s' % device_type, mock)
-
- def runTest(self):
- """Verify that all 4 peripheral-types are extracted."""
- peripherals = cfm_helper.extract_peripherals_for_cfm(None)
- self.assertEqual(len(peripherals), 4)
- for i in range(len(DEVICE_TYPES)):
- device_type = DEVICE_TYPES[i]
- self.assertEqual(peripherals[device_type], i + 1)
-
- def tearDown(self):
- """Restore the original functions, for the sake of other tests."""
- for device_type in DEVICE_TYPES:
- original_func = getattr(get_usb_devices, 'get_%s' % device_type)
- setattr(cfm_helper.get_usb_devices, 'get_%s' % device_type,
- original_func)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/client/common_lib/cros/manual/common.py b/client/common_lib/cros/manual/common.py
deleted file mode 100644
index 849be4d..0000000
--- a/client/common_lib/cros/manual/common.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import os, sys
-dirname = os.path.dirname(sys.modules[__name__].__file__)
-client_dir = os.path.abspath(os.path.join(dirname, "..", "..", ".."))
-sys.path.insert(0, client_dir)
-import setup_modules
-sys.path.pop(0)
-setup_modules.setup(base_path=client_dir,
- root_module_name="autotest_lib.client")
diff --git a/client/common_lib/cros/manual/get_usb_devices.py b/client/common_lib/cros/manual/get_usb_devices.py
deleted file mode 100644
index b2479f3..0000000
--- a/client/common_lib/cros/manual/get_usb_devices.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# Copyright 2017 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.
-#
-# """extract data from output of use-devices on linux box"""
-# The parser takes output of "usb-devices" as rawdata, and has capablities to
-# 1. Populate usb data into dictionary
-# 3. Extract defined peripheral devices based on CAMERA_LIST, SPEAKER_LIST.
-# 4. As of now only one type touch panel is defined here, which is Mimo.
-# 5. Check usb devices's interface.
-# 6. Retrieve usb device based on product and manufacture.
-#
-
-from six import StringIO
-from autotest_lib.client.common_lib.cros import textfsm
-
-USB_DEVICES_TPLT = (
- 'Value Required Vendor ([0-9a-fA-F]+)\n'
- 'Value Required ProdID ([0-9A-Fa-f]+)\n'
- 'Value Required prev ([0-9a-fA-Z.]+)\n'
- 'Value Manufacturer (.+)\n'
- 'Value Product (.+)\n'
- 'Value serialnumber ([0-9a-fA-Z\:\-]+)\n'
- 'Value cinterfaces (\d)\n'
- 'Value List intindex ([0-9])\n'
- 'Value List intdriver ([A-Za-z-\(\)]+)\n\n'
- 'Start\n'
- ' ^USB-Device -> Continue.Record\n'
- ' ^P:\s+Vendor=${Vendor}\s+ProdID=${ProdID}\sRev=${prev}\n'
- ' ^S:\s+Manufacturer=${Manufacturer}\n'
- ' ^S:\s+Product=${Product}\n'
- ' ^S:\s+SerialNumber=${serialnumber}\n'
- ' ^C:\s+\#Ifs=\s+${cinterfaces}\n'
- ' ^I:\s+If\#=\s+${intindex}.*Driver=${intdriver}\n'
-)
-
-# As of now there are certain types of cameras, speakers and touch-panel.
-# New devices can be added to these global variables.
-CAMERA_LIST = ['2bd9:0011', '046d:0843', '046d:082d', '046d:0853', '064e:9405',
- '046d:085f']
-CAMERA_MAP = {'2bd9:0011':'Huddly GO',
- '046d:0843':'Logitech Webcam C930e',
- '046d:082d':'HD Pro Webcam C920',
- '046d:0853':'PTZ Pro Camera',
- '046d:085f':'PTZ Pro 2',
- '064e:9405':'HD WebCam'}
-
-SPEAKER_LIST = ['18d1:8001', '0b0e:0412', '2abf:0505']
-SPEAKER_MAP = {'18d1:8001':'Hangouts Meet speakermic',
- '0b0e:0412':'Jabra SPEAK 410',
- '2abf:0505':'FLX UC 500'}
-
-TOUCH_DISPLAY_LIST = ['17e9:016b','17e9:416d']
-TOUCH_CONTROLLER_LIST = ['266e:0110']
-
-DISPLAY_PANEL_MAP = {'17e9:016b':'DisplayLink',
- '17e9:416d':'DisplayLink'}
-
-TOUCH_PANEL_MAP = {'266e:0110':'SiS HID Touch Controller'}
-
-
-INTERFACES_LIST = {'2bd9:0011':['uvcvideo', 'uvcvideo',
- 'uvcvideo', 'uvcvideo'],
- '046d:0843':['uvcvideo', 'uvcvideo',
- 'snd-usb-audio', 'snd-usb-audio'],
- '046d:082d':['uvcvideo', 'uvcvideo',
- 'snd-usb-audio', 'snd-usb-audio'],
- '046d:085f': ['uvcvideo', 'uvcvideo','usbhid'],
- '0b0e:0412':['snd-usb-audio', 'snd-usb-audio',
- 'snd-usb-audio'],
- '18d1:8001':['snd-usb-audio', 'snd-usb-audio',
- 'snd-usb-audio', 'usbhid'],
- '17e9:016b':['udl'],
- '17e9:416d':['udl'],
- '266e:0110':['usbhid'],
- '046d:0853':['uvcvideo', 'uvcvideo','usbhid'],
- '064e:9405':['uvcvideo', 'uvcvideo'],
- '2abf:0505':['snd-usb-audio', 'snd-usb-audio',
- 'snd-usb-audio', 'usbhid']
- }
-
-
-def extract_usb_data(rawdata):
- """populate usb data into list dictionary
- @param rawdata: The output of "usb-devices" on CfM.
- @returns list of dictionary, examples:
- {'Manufacturer': 'USBest Technology', 'Product': 'SiS HID Touch Controller',
- 'Vendor': '266e', 'intindex': ['0'], 'tport': '00', 'tcnt': '01',
- 'serialnumber': '', 'tlev': '03', 'tdev': '18', 'dver': '',
- 'intdriver': ['usbhid'], 'tbus': '01', 'prev': '03.00',
- 'cinterfaces': '1', 'ProdID': '0110', 'tprnt': '14'}
- """
- usbdata = []
- rawdata += '\n'
- re_table = textfsm.TextFSM(StringIO.StringIO(USB_DEVICES_TPLT))
- fsm_results = re_table.ParseText(rawdata)
- usbdata = [dict(zip(re_table.header, row)) for row in fsm_results]
- return usbdata
-
-
-def extract_peri_device(usbdata, vid_pid):
- """retrive the list of dictionary for certain types of VID_PID
- @param usbdata: list of dictionary for usb devices
- @param vid_pid: list of vid_pid combination
- @returns the list of dictionary for certain types of VID_PID
- """
- vid_pid_usb_list = []
- for _vid_pid in vid_pid:
- vid = _vid_pid.split(':')[0]
- pid = _vid_pid.split(':')[1]
- for _data in usbdata:
- if vid == _data['Vendor'] and pid == _data['ProdID']:
- vid_pid_usb_list.append(_data)
- return vid_pid_usb_list
-
-
-def get_list_audio_device(usbdata):
- """retrive the list of dictionary for all audio devices
- @param usbdata: list of dictionary for usb devices
- @returns the list of dictionary for all audio devices
- """
- audio_device_list = []
- for _data in usbdata:
- if "snd-usb-audio" in _data['intdriver']:
- audio_device_list.append(_data)
- return audio_device_list
-
-
-def get_list_video_device(usbdata):
- """retrive the list of dictionary for all video devices
- @param usbdata: list of dictionary for usb devices
- @returns the list of dictionary for all video devices
- """
- video_device_list = []
- for _data in usbdata:
- if "uvcvideo" in _data['intdriver']:
- video_device_list.append(_data)
- return video_device_list
-
-
-def get_list_mimo_device(usbdata):
- """retrive the list of dictionary for all touch panel devices
- @param usbdata: list of dictionary for usb devices
- @returns the lists of dictionary
- one for displaylink, the other for touch controller
- """
- displaylink_list = []
- touchcontroller_list = []
- for _data in usbdata:
- if "udl" in _data['intdriver']:
- displaylink_list.append(_data)
- if "SiS HID Touch Controller" == _data['Product']:
- touchcontroller_list.append(_data)
- return displaylink_list, touchcontroller_list
-
-
-def get_list_by_product(usbdata, product_name):
- """retrive the list of dictionary based on product_name
- @param usbdata: list of dictionary for usb devices
- @returns the list of dictionary
- """
- usb_list_by_product = []
- for _data in usbdata:
- if product_name == _data['Product']:
- usb_list_by_product.append(_data)
- return usb_list_by_product
-
-
-def get_list_by_manufacturer(usbdata, manufacturer_name):
- """retrive the list of dictionary based on manufacturer_name
- @param usbdata: list of dictionary for usb devices
- @returns the list of dictionary
- """
- usb_list_by_manufacturer = []
- for _data in usbdata:
- if manufacturer_name == _data['Manufacturer']:
- usb_list_by_manufacturer.append(_data)
- return usb_list_by_manufacturer
-
-
-def is_usb_device_ok(usbdata, vid_pid):
- """check usb device has expected usb interface
- @param usbdata: list of dictionary for usb devices
- @vid_pid: VID, PID combination for each type of USB device
- @returns:
- int: number of device
- boolean: usb interfaces expected or not?
- """
- number_of_device = 0
- device_health = []
- vid = vid_pid[0:4]
- pid = vid_pid[-4:]
- for _data in usbdata:
- if vid == _data['Vendor'] and pid == _data['ProdID']:
- number_of_device += 1
- compare_list = _data['intdriver'][0:len(INTERFACES_LIST[vid_pid])]
- if cmp(compare_list, INTERFACES_LIST[vid_pid]) == 0:
- device_health.append('1')
- else:
- device_health.append('0')
- return number_of_device, device_health
-
-
-def get_speakers(usbdata):
- """get number of speaker for each type
- @param usbdata: list of dictionary for usb devices
- @returns: list of dictionary, key is VID_PID, value is number of speakers
- """
- number_speaker = {}
- for _speaker in SPEAKER_LIST:
- vid = _speaker.split(':')[0]
- pid = _speaker.split(':')[1]
- _number = 0
- for _data in usbdata:
- if _data['Vendor'] == vid and _data['ProdID'] == pid:
- _number += 1
- number_speaker[_speaker] = _number
- return number_speaker
-
-
-def get_dual_speaker(usbdata):
- """check whether dual speakers are present
- @param usbdata: list of dictionary for usb devices
- @returns: True or False
- """
- dual_speaker = None
- speaker_dict = get_speakers(usbdata)
- for _key in speaker_dict.keys():
- if speaker_dict[_key] == 2:
- dual_speaker = _key
- break
- return dual_speaker
-
-
-def get_cameras(usbdata):
- """get number of camera for each type
- @param usbdata: list of dictionary for usb devices
- @returns: list of dictionary, key is VID_PID, value is number of cameras
- """
- number_camera = {}
- for _camera in CAMERA_LIST:
- vid = _camera.split(':')[0]
- pid = _camera.split(':')[1]
- _number = 0
- for _data in usbdata:
- if _data['Vendor'] == vid and _data['ProdID'] == pid:
- _number += 1
- number_camera[_camera] = _number
- return number_camera
-
-def get_display_mimo(usbdata):
- """get number of displaylink in Mimo for each type
- @param usbdata: list of dictionary for usb devices
- @returns: list of dictionary, key is VID_PID, value
- is number of displaylink
- """
- number_display = {}
- for _display in TOUCH_DISPLAY_LIST:
- vid = _display.split(':')[0]
- pid = _display.split(':')[1]
- _number = 0
- for _data in usbdata:
- if _data['Vendor'] == vid and _data['ProdID'] == pid:
- _number += 1
- number_display[_display] = _number
- return number_display
-
-def get_controller_mimo(usbdata):
- """get number of touch controller Mimo for each type
- @param usbdata: list of dictionary for usb devices
- @returns: list of dictionary, key is VID_PID, value
- is number of touch controller
- """
- number_controller = {}
- for _controller in TOUCH_CONTROLLER_LIST:
- vid = _controller.split(':')[0]
- pid = _controller.split(':')[1]
- _number = 0
- for _data in usbdata:
- if _data['Vendor'] == vid and _data['ProdID'] == pid:
- _number += 1
- number_controller[_controller] = _number
- return number_controller
-
-def get_preferred_speaker(peripheral):
- """get string for the 1st speakers in the device list
- @param peripheral: of dictionary for usb devices
- @returns: string for name of preferred speake
- """
- for _key in peripheral:
- if _key in SPEAKER_LIST:
- speaker_name = SPEAKER_MAP[_key]+' ('+_key+')'
- return speaker_name
-
-def get_preferred_camera(peripheral):
- """get string for the 1st cameras in the device list
- @param peripheral: of dictionary for usb devices
- @returns: string for name of preferred camera
- """
- for _key in peripheral:
- if _key in CAMERA_LIST:
- camera_name = CAMERA_MAP[_key]+' ('+_key+')'
- return camera_name
-
-def get_device_prod(vid_pid):
- """get product for vid_pid
- @param vid_pid: vid and pid combo for device
- @returns: product
- """
- for _key in SPEAKER_MAP.keys():
- if _key == vid_pid:
- return SPEAKER_MAP[_key]
- for _key in CAMERA_MAP.keys():
- if _key == vid_pid:
- return CAMERA_MAP[_key]
- for _key in DISPLAY_PANEL_MAP.keys():
- if _key == vid_pid:
- return DISPLAY_PANEL_MAP[_key]
- for _key in TOUCH_PANEL_MAP.keys():
- if _key == vid_pid:
- return TOUCH_PANEL_MAP[_key]
- return None
diff --git a/client/common_lib/cros/manual/meet_helper.py b/client/common_lib/cros/manual/meet_helper.py
deleted file mode 100644
index 86c6ba1..0000000
--- a/client/common_lib/cros/manual/meet_helper.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright 2017 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.
-
-"""Meeting related operations"""
-
-from __future__ import print_function
-
-import logging
-import random
-
-MIN_VOL = 1
-MAX_VOL = 100
-
-def restart_chrome(handle, is_meeting, recovery):
- """
- Restart chrome and wait for telemetry commands to be ready.
- @param handle: CfM telemetry remote facade,
- @param is_meeting: True, None if CfM running MEET mode,
- False if CfM running hangout mode
- @returns: True, None if success,
- False otherwise.
- """
- try:
- if recovery:
- logging.info('+++Restart chrome')
- handle.restart_chrome_for_cfm()
- handle.wait_for_telemetry_commands()
- except Exception as e:
- errmsg = 'Fail to run telemetry api restart_chrome_for_cfm.'
- logging.exception(errmsg)
- return False, errmsg
- return True, None
-
-def join_meeting(handle, is_meeting, meet_code):
- """
- Join meeting.
- @param handle: CfM telemetry remote facade,
- @param is_meeting: True, None if CfM running MEET mode,
- False if CfM running hangout mode
- @param meeting_code: meeting code
- @returns: True, None if CfM joins meeting successfully,
- False otherwise.
- """
- try:
- if is_meeting:
- logging.info('+++Start meet meeting')
- if meet_code:
- handle.join_meeting_session(meet_code)
- else:
- handle.start_meeting_session()
- else:
- logging.info('+++start hangout meeting')
- if meet_code:
- handle.start_new_hangout_session(meet_code)
- else:
- errmsg = 'Meeting code is required for hangout meet.'
- logging.exception(errmsg)
- return False, errmsg
- logging.info('+++Meeting %s joined.', meet_code)
- return True, None
- except Exception as e:
- errmsg = 'Fail to run telemetry api to join meeting.'
- logging.exception(errmsg)
- return False, errmsg
-
-def leave_meeting(handle, is_meeting):
- """
- Leave meeting.
- @param handle: CfM telemetry remote facade,
- @param is_meeting: True, None if CfM running MEET mode,
- False if CfM running hangout mode
- @returns: True, None if CfM leaves meeting successfully,
- False otherwise.
-
- """
- try:
- if is_meeting:
- handle.end_meeting_session()
- else:
- handle.end_hangout_session()
- except Exception as e:
- errmsg = 'Fail to run telemetry api to leave meeting.'
- logging.exception(errmsg)
- return False, errmsg
- logging.info('+++meet ended')
- return True, None
-
-
-def mute_unmute_camera(handle, is_muted):
- """
- @param handle: CfM telemetry remote facade,
- @param is_muted: True, None if camera is muted,
- False otherwise.
- @returns: True, None if camera is muted/unmuted successfully,
- False otherwise.
- """
- try:
- if is_muted:
- logging.info('+++unmute camera')
- handle.unmute_camera()
- else:
- logging.info('+++mute camera')
- handle.mute_camera()
- except Exception as e:
- errmsg = 'Fail to run telemetry api to mute/unmute camera.'
- logging.exception(errmsg)
- return False, errmsg
- return True, None
-
-
-def mute_unmute_mic(handle, is_muted):
- """
- @param handle: CfM telemetry remote facade,
- @param is_muted: True, None if mic is muted,
- False otherwise.
- @returns: True, None if camera is muted/unmuted successfully,
- False otherwise.
- """
- try:
- if is_muted:
- logging.info('+++unmute mic')
- handle.unmute_mic()
- else:
- logging.info('+++mute mic')
- handle.mute_mic()
- except Exception as e:
- errmsg = 'Fail to run telemetry api to mute/unmute mic.'
- logging.exception(errmsg)
- return False, errmsg
- return True, None
-
-
-def set_speaker_volume(handle, volume):
- """
- Change speaker's volume.
- @param handle: CfM telemetry remote facade
- @param volume: volume for speaker
- """
- try:
- handle.set_speaker_volume(volume)
- except Exception as e:
- errmsg = 'Fail to run telemetry api to set speaker volume.'
- logging.exception(errmsg)
- return False, errmsg
- return True, str(volume)
-
-
-def speaker_volume_test(handle, step, mode, randommode):
- """
- Change speaker's volume.
- @param handle: CfM telemetry remote facade,
- @param step: volume to be increased or decreased in one call
- @param mode: if it equal to 1, update volume directly to
- targeted value,
- else, update volume in multiple calls.
- @param randommode: if True, None, the value of volume to be change in
- each call is randomly set,
- else, the value is fixed defined by step.
- """
- test_volume = random.randrange(MIN_VOL, MAX_VOL)
- if mode == 1:
- return set_speaker_volume(handle, test_volume)
- step = max(2, step)
- try:
- current = int(handle.get_speaker_volume())
- except Exception as e:
- errmsg = 'Fail to run telemetry api to set speaker volume.'
- logging.exception(errmsg)
- return False, errmsg
-
- if test_volume > current:
- while test_volume > current:
- if randommode:
- transit_volume = current + random.randrange(1, step)
- else:
- transit_volume = current + step
-
- if transit_volume > test_volume:
- transit_volume = test_volume
-
- handle.set_speaker_volume(transit_volume)
- try:
- current = int(handle.get_speaker_volume())
- except Exception as e:
- errmsg = 'Fail to run telemetry api to set speaker volume.'
- logging.exception(errmsg)
- return False, errmsg
-
- logging.info('+++set vol %d, current %d, target %d',
- transit_volume, current, test_volume)
- else:
- while test_volume < current:
- if randommode:
- transit_volume = current - random.randrange(1, step)
- else:
- transit_volume = current - step
- if transit_volume < test_volume:
- transit_volume = test_volume
- handle.set_speaker_volume(transit_volume)
- try:
- current = int(handle.get_speaker_volume())
- except Exception as e:
- errmsg = 'Fail to run telemetry api to set speaker volume.'
- logging.exception(errmsg)
- return False, errmsg
-
- logging.info('+++set vol %d, current %d, target %d',
- transit_volume, current, test_volume)
- return True, str(current)
diff --git a/client/common_lib/cros/manual/video_helper.py b/client/common_lib/cros/manual/video_helper.py
deleted file mode 100644
index d2e09e6..0000000
--- a/client/common_lib/cros/manual/video_helper.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2017 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.
-
-"""Get v4l2 interface, and chrome processes which access the video interface"""
-
-from __future__ import print_function
-
-import logging
-
-
-LSOF_CHROME_VIDEO = {
- '2bd9:0011': 3,
- '046d:0843': 2,
- '046d:082d': 2,
- '046d:0853': 2,
- '064e:9405': 2,
- '046d:0853': 2
- }
-
-
-def get_video_by_name(dut, name):
- """
- Get v4l2 interface based on WebCamera
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @param name: The name of web camera
- For example: 'Huddly GO'
- 'Logitech Webcam C930e'
- @returns: if video device v4l2 found, return True,
- else return False.
- """
- cmd = 'ls /sys/class/video4linux/'
- video4linux_list = dut.run(cmd, ignore_status=True).stdout.split()
- for video_dev in video4linux_list:
- cmd = 'cat /sys/class/video4linux/{}/name'.format(video_dev)
- video_dev_name = dut.run(cmd, ignore_status=True).stdout.strip()
- logging.info('---%s', cmd)
- logging.info('---%s', video_dev_name)
- if name in video_dev_name and not 'overview' in video_dev_name:
- logging.info('---found interface for %s', name)
- return video_dev
- return None
-
-
-def get_lsof4_video(dut, video):
- """
- Get output of chrome processes which attach to video device.
- @param dut: The handle of the device under test. Should be initialized in
- autotest.
- @param video: video device name for camera.
- @returns: output of lsof /dev/videox.
- """
- cmd = 'lsof /dev/{} | grep chrome'.format(video)
- lsof_output = dut.run(cmd, ignore_status=True).stdout.strip().split('\n')
- logging.info('---%s', cmd)
- logging.info('---%s', lsof_output)
- return lsof_output
-
-
-def get_video_streams(dut, name):
- """
- Get output of chrome processes which attach to video device.
- @param dut: The handle of the device under test.
- @param name: name of camera.
- @returns: output of lsof for v4l2 device.
- """
- video_dev = get_video_by_name(dut, name)
- lsof_output = get_lsof4_video(dut, video_dev)
- return lsof_output
-
-
-def check_v4l2_interface(dut, vidpid, camera):
- """
- Check v4l2 interface exists for camera.
- @param dut: The handle of the device under test.
- @param vidpid: vidpid of camera.
- @param camera: name of camera
- @returns: True if v4l2 interface found for camera,
- False if not found.
- """
- logging.info('---check v4l2 interface for %s', camera)
- if get_video_by_name(dut, camera):
- return True, None
- return False, '{} have no v4l2 interface.'.format(camera)
-
-
-def check_video_stream(dut, is_muted, vidpid, camera):
- """
- Check camera is streaming as expected.
- @param dut: The handle of the device under test.
- @is_streaming: True if camera is expected to be streaming,
- False if not.
- @param vidpid: vidpid of camera
- @param camera: name of camera.
- @returns: True if camera is streaming or not based on
- expectation,
- False, errMsg if not found.
- """
- process_camera = get_video_streams(dut, camera)
- if is_muted:
- if len(process_camera) >= LSOF_CHROME_VIDEO[vidpid]:
- return False, '{} fails to stop video streaming.'.format(camera)
- else:
- if not len(process_camera) >= LSOF_CHROME_VIDEO[vidpid]:
- return False, '{} fails to start video streaming.'.format(camera)
- return True, None
diff --git a/client/common_lib/kernel_versions.py b/client/common_lib/kernel_versions.py
deleted file mode 100644
index 605fb9b..0000000
--- a/client/common_lib/kernel_versions.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Lint as: python2, python3
-#
-# kernel_versions.py -- linux kernel version comparisons
-#
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-__author__ = """Copyright Andy Whitcroft 2007"""
-
-import sys,re
-
-from six.moves import range
-
-#
-# Sort key for ordering versions chronologically. The key ordering
-# problem is between that introduced by -rcN. These come _before_
-# their accompanying version.
-#
-# 2.6.0 -> 2.6.1-rc1 -> 2.6.1
-#
-# In order to sort them we convert all non-rc releases to a pseudo
-# -rc99 release. We also convert all numbers to two digits. The
-# result is then sortable textually.
-#
-# 02.06.00-rc99 -> 02.06.01-rc01 -> 02.06.01-rc99
-#
-encode_sep = re.compile(r'(\D+)')
-
-def version_encode(version):
- bits = encode_sep.split(version)
- n = 9
- if len(bits[0]) == 0:
- n += 2
- if len(bits) == n or (len(bits) > n and bits[n] != '_rc'):
- # Insert missing _rc99 after 2 . 6 . 18 -smp- 220 . 0
- bits.insert(n, '_rc')
- bits.insert(n+1, '99')
- n = 5
- if len(bits[0]) == 0:
- n += 2
- if len(bits) <= n or bits[n] != '-rc':
- bits.insert(n, '-rc')
- bits.insert(n+1, '99')
- for n in range(0, len(bits), 2):
- if len(bits[n]) == 1:
- bits[n] = '0' + bits[n]
-
- return ''.join(bits)
-
-
-def version_limit(version, n):
- bits = encode_sep.split(version)
- return ''.join(bits[0:n])
-
-
-def version_len(version):
- return len(encode_sep.split(version))
-
-#
-# Given a list of versions find the nearest version which is deemed
-# less than or equal to the target. Versions are in linux order
-# as follows:
-#
-# 2.6.0 -> 2.6.1 -> 2.6.2-rc1 -> 2.6.2-rc2 -> 2.6.2 -> 2.6.3-rc1
-# | |\
-# | | 2.6.2-rc1-mm1 -> 2.6.2-rc1-mm2
-# | \
-# | 2.6.2-rc1-ac1 -> 2.6.2-rc1-ac2
-# \
-# 2.6.1-mm1 -> 2.6.1-mm2
-#
-# Note that a 2.6.1-mm1 is not a predecessor of 2.6.2-rc1-mm1.
-#
-def version_choose_config(version, candidates):
- # Check if we have an exact match ... if so magic
- if version in candidates:
- return version
-
- # Sort the search key into the list ordered by 'age'
- deco = [ (version_encode(v), i, v) for i, v in
- enumerate(candidates + [ version ]) ]
- deco.sort()
- versions = [ v for _, _, v in deco ]
-
- # Everything sorted below us is of interst.
- for n in range(len(versions) - 1, -1, -1):
- if versions[n] == version:
- break
- n -= 1
-
- # Try ever shorter 'prefixes' 2.6.20-rc3-mm, 2.6.20-rc, 2.6. etc
- # to match against the ordered list newest to oldest.
- length = version_len(version) - 1
- version = version_limit(version, length)
- while length > 1:
- for o in range(n, -1, -1):
- if version_len(versions[o]) == (length + 1) and \
- version_limit(versions[o], length) == version:
- return versions[o]
- length -= 2
- version = version_limit(version, length)
-
- return None
-
-
-def is_released_kernel(version):
- # True if version name suggests a released kernel,
- # not some release candidate or experimental kernel name
- # e.g. 2.6.18-smp-200.0 includes no other text, underscores, etc
- version = version.strip('01234567890.-')
- return version in ['', 'smp', 'smpx', 'pae']
-
-
-def is_release_candidate(version):
- # True if version names a released kernel or release candidate,
- # not some experimental name containing arbitrary text
- # e.g. 2.6.18-smp-220.0_rc3 but not 2.6.18_patched
- version = re.sub(r'[_-]rc\d+', '', version)
- return is_released_kernel(version)
diff --git a/client/common_lib/powerplay_util.py b/client/common_lib/powerplay_util.py
deleted file mode 100644
index 75298ed..0000000
--- a/client/common_lib/powerplay_util.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Lint as: python2, python3
-# Copyright 2015 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 error, logging, os, serial, shutil, threading, time
-
-_power_play_data_file = '/tmp/power_play_data'
-
-class PowerPlay(object):
- """Class to record serial over USB data from Power Play (go/powerplay).
-
- It detects if powerplay is connected to the DUT over USB and opens the
- serial port to start receiving powerplay data. It also opens a text file to
- save this data after some formatting.
- """
-
- version = 1
-
- def __init__(self, test_obj, record_interval=0):
- """Initialize PowerPlay.
-
- @param test_obj: test object.
- @param record_interval: Power play data recording interval in seconds.
- """
- self.test = test_obj
- self.ser = None
- self.recording_interval = record_interval
- self.momentary_curr_list = list()
- self.record_thread = None
-
- def extract_current(self, pp_data):
- """Extract momentary current value from each line of powerplay data.
-
- @param pp_data: Single line of powerplay data with eight comma separated
- values.
- @return list containing momentary current values.
- """
- if pp_data[0].isdigit():
- self.momentary_curr_list.append(float(pp_data[pp_data.index(',')+1:]
- [:pp_data[pp_data.index(',')+1:].index(',')]))
- return self.momentary_curr_list
-
- def start_recording_power_play_data(self):
- """Starts a new thread to record power play data."""
- self.record_thread = threading.Thread(target=self.start_record_thread)
- self.record_thread.daemon = True
- self.record_thread.start()
-
- def start_record_thread(self):
- """Start recording power play data.
-
- Get a list of connected USB devices and try to establish a serial
- connection. Once the connection is established, open a text file and
- start reading serial data and write it to the text file after some
- formatting.
- """
- devices = [x for x in os.listdir('/dev/') if x.startswith('ttyUSB')]
-
- for device in devices:
- device_link = '/dev/' + device
- try:
- if self.ser == None:
- logging.info('Trying ... %s', device_link)
- self.ser = serial.Serial(device_link, 115200)
- logging.info('Successfully connected to %s', device_link)
- break
- except serial.SerialException as e:
- raise error.TestError('Failed to connect to %s becuase of %s' %
- (device_link, str(e)))
-
- self.text_file = open(_power_play_data_file, 'w')
-
- if self.ser != None:
- title_row = ('time,powerplay_timestamp,momentary_current (A),' +
- 'momentary_charge (AH),average_current (A),' +
- 'total_standby_time,total_wake_time,num_wakes,is_awake?\n')
- self.text_file.write(title_row)
- start_time = time.time()
- while self.ser.readline():
- current_timestamp = (('{:>10.3f}'.
- format(time.time() - start_time)).replace(' ', ''))
- pp_data = (self.ser.readline().replace('\00', '').
- replace(' ', ',').replace('\r', ''))
- if (not pp_data.startswith('#') and (len(pp_data) > 30) and
- not self.text_file.closed):
- self.text_file.write(current_timestamp + ',' + pp_data)
- self.momentary_curr_list = self.extract_current(pp_data)
- time.sleep(self.recording_interval)
- self.ser.flushInput()
- else:
- self.text_file.write('No data from powerplay. Check connection.')
-
- def stop_recording_power_play_data(self):
- """Stop recording power play data.
-
- Close the text file and copy it to the test log results directory. Also
- report current data to the performance dashboard.
- """
- if not self.text_file.closed:
- self.text_file.close()
- shutil.copy(_power_play_data_file, self.test.resultsdir)
- self.test.output_perf_value(description='momentary_current_draw',
- value=self.momentary_curr_list,
- units='Amps', higher_is_better=False)
diff --git a/client/common_lib/smogcheck_ina219.py b/client/common_lib/smogcheck_ina219.py
deleted file mode 100644
index c7ac526..0000000
--- a/client/common_lib/smogcheck_ina219.py
+++ /dev/null
@@ -1,208 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2011 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.
-
-"""A Python library to interact with INA219 module for TPM testing.
-
-Background
- - INA219 is one of two modules on TTCI board
- - This library provides methods to interact with INA219 programmatically
-
-Dependency
- - This library depends on a new C shared library called "libsmogcheck.so".
- - In order to run test cases built using this API, one needs a TTCI board
-
-Notes:
- - An exception is raised if it doesn't make logical sense to continue program
- flow (e.g. I/O error prevents test case from executing)
- - An exception is caught and then converted to an error code if the caller
- expects to check for error code per API definition
-"""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import logging, re
-from autotest_lib.client.common_lib import i2c_node
-import six
-
-
-# INA219 registers
-INA_REG = {
- 'CONF': 0, # Configuration Register
- 'SHUNT_VOLT': 1, # Shunt Voltage
- 'BUS_VOLT': 2, # Bus Voltage
- 'POWER': 3, # Power
- 'CURRENT': 4, # Current
- 'CALIB': 5, # Calibration
- }
-
-# Regex pattern for measurement value
-HEX_STR_PATTERN = re.compile('^0x([0-9a-f]{2})([0-9a-f]{2})$')
-
-# Constants used to initialize INA219 registers
-# TODO(tgao): add docstring for these values after stevenh replies
-INA_CONF_INIT_VAL = 0x9f31
-INA_CALIB_INIT_VAL = 0xc90e
-
-# Default values used to calculate/interpret voltage and current measurements.
-DEFAULT_MEAS_RANGE_VALUE = {
- 'current': {'max': 0.1, 'min': 0.0, 'denom': 10000.0,
- 'reg': INA_REG['CURRENT']},
- 'voltage': {'max': 3.35, 'min': 3.25, 'denom': 2000.0,
- 'reg': INA_REG['BUS_VOLT']},
- }
-
-
-class InaError(Exception):
- """Base class for all errors in this module."""
-
-
-class InaController(i2c_node.I2cNode):
- """Object to control INA219 module on TTCI board."""
-
- def __init__(self, node_addr=None, range_dict=None):
- """Constructor.
-
- Mandatory params:
- node_addr: node address to set. Default: None.
-
- Optional param:
- range_dict: desired max/min thresholds for measurement values.
- Default: DEFAULT_MEAS_RANGE_VALUE.
-
- Args:
- node_addr: an integer, address of main or backup power.
- range_dict: desired max/min thresholds for measurement values.
-
- Raises:
- InaError: if error initializing INA219 module or invalid range_dict.
- """
- super(InaController, self).__init__()
- if node_addr is None:
- raise InaError('Error node_addr expected')
-
- try:
- if range_dict is None:
- range_dict = DEFAULT_MEAS_RANGE_VALUE
- else:
- self._validateRangeDict(DEFAULT_MEAS_RANGE_VALUE, range_dict)
- self.range_dict = range_dict
-
- self.setNodeAddress(node_addr)
- self.writeWord(INA_REG['CONF'], INA_CONF_INIT_VAL)
- self.writeWord(INA_REG['CALIB'], INA_CALIB_INIT_VAL)
- except InaError as e:
- raise InaError('Error initializing INA219: %s' % e)
-
- def _validateRangeDict(self, d_ref, d_in):
- """Validates keys and types of value in range_dict.
-
- Iterate over d_ref to make sure all keys exist in d_in and
- values are of the correct type.
-
- Args:
- d_ref: a dictionary, used as reference.
- d_in: a dictionary, to be validated against reference.
-
- Raises:
- InaError: if range_dict is invalid.
- """
- for k, v in six.iteritems(d_ref):
- if k not in d_in:
- raise InaError('Key %s not present in dict %r' % (k, d_in))
- if type(v) != type(d_in[k]):
- raise InaError(
- 'Value type mismatch for key %s. Expected: %s; actual = %s'
- % (k, type(v), type(d_in[k])))
- if type(v) is dict:
- self._validateRangeDict(v, d_in[k])
-
- def readMeasure(self, measure):
- """Reads requested measurement.
-
- Args:
- measure: a string, 'current' or 'voltage'.
-
- Returns:
- a float, measurement in units. Or None if error.
-
- Raises:
- InaError: if error reading requested measurement.
- """
- try:
- hex_str = '0x%.4x' % self.readWord(self.range_dict[measure]['reg'])
- logging.debug('Word read = %r', hex_str)
- return self._checkMeasureRange(hex_str, measure)
- except InaError as e:
- logging.error('Error reading %s: %s', measure, e)
-
- def getPowerMetrics(self):
- """Get measurement metrics for Main Power.
-
- Returns:
- an integer, 0 for success and -1 for error.
- a float, voltage value in Volts. Or None if error.
- a float, current value in Amps. Or None if error.
- """
- logging.info('Attempt to get power metrics')
- try:
- return (0, self.readMeasure('voltage'),
- self.readMeasure('current'))
- except InaError as e:
- logging.error('getPowerMetrics(): %s', e)
- return (-1, None, None)
-
- def _checkMeasureRange(self, hex_str, measure):
- """Checks if measurement value falls within a pre-specified range.
-
- Args:
- hex_str: a string (hex value).
- measure: a string, 'current' or 'voltage'.
-
- Returns:
- measure_float: a float, measurement value.
-
- Raises:
- InaError: if value doesn't fall in range.
- """
- measure_float = self._convertHexToFloat(
- hex_str, self.range_dict[measure]['denom'])
- measure_msg = '%s value %.2f' % (measure, measure_float)
- range_msg = '[%(min).2f, %(max).2f]' % self.range_dict[measure]
- if (measure_float < self.range_dict[measure]['min'] or
- measure_float > self.range_dict[measure]['max']):
- raise InaError('%s is out of range %s' % measure_msg, range_msg)
- logging.info('%s is in range %s', measure_msg, range_msg)
- return measure_float
-
- def _convertHexToFloat(self, hex_str, denom):
- """Performs measurement calculation.
-
- The measurement reading from INA219 module is a 2-byte hex string.
- To convert this hex string to a float, we need to swap these two bytes
- and perform a division. An example:
- response = 0xca19
- swap bytes to get '0x19ca'
- convert to decimal value = 6602
- divide decimal by 2000.0 = 3.301 (volts)
-
- Args:
- hex_str: a string (raw hex value).
- denom: a float, denominator used for hex-to-float conversion.
-
- Returns:
- a float, measurement value.
-
- Raises:
- InaError: if error converting measurement to float.
- """
- match = HEX_STR_PATTERN.match(hex_str)
- if not match:
- raise InaError('Error: hex string %s does not match '
- 'expected pattern' % hex_str)
-
- decimal = int('0x%s%s' % (match.group(2), match.group(1)), 16)
- return decimal/denom
diff --git a/client/common_lib/smogcheck_pca9555.py b/client/common_lib/smogcheck_pca9555.py
deleted file mode 100644
index c1fd40b..0000000
--- a/client/common_lib/smogcheck_pca9555.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2011 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.
-
-"""A Python library to interact with PCA9555 module for TPM testing.
-
-Background
- - PCA9555 is one of two modules on TTCI board
- - This library provides methods to interact with PCA9555 programmatically
-
-Dependency
- - This library depends on a new C shared library called "libsmogcheck.so".
- - In order to run test cases built using this API, one needs a TTCI board
-
-Notes:
- - An exception is raised if it doesn't make logical sense to continue program
- flow (e.g. I/O error prevents test case from executing)
- - An exception is caught and then converted to an error code if the caller
- expects to check for error code per API definition
-"""
-
-import logging
-from autotest_lib.client.common_lib import i2c_node
-
-
-# I2C constants
-PCA9555_SLV = 0x27 # I2C node address of PCA9555
-
-# PCA9555 registers
-PCA_REG = {
- 'IN0': 0, # Input Port 0
- 'IN1': 1, # Input Port 1
- 'OUT0': 2, # Output Port 0
- 'OUT1': 3, # Output Port 1
- 'PI0': 4, # Polarity Inversion 0
- 'PI1': 5, # Polarity Inversion 1
- 'CONF0': 6, # Configuration 0
- 'CONF1': 7, # Configuration 1
- }
-
-# Each '1' represents turning on corresponding LED via writing to PCA9555
-# Output Port Registers
-PCA_BIT_ONE = {
- 'unalloc_0': 0x01,
- 'unalloc_1': 0x02,
- 'unalloc_2': 0x04,
- 'tpm_i2c': 0x08,
- 'yellow_led': 0x10,
- 'main_power': 0x10,
- 'red_led': 0x20,
- 'backup_power': 0x20,
- 'reset': 0x40,
- 'pp': 0x80,
- }
-
-# Constants used to initialize PCA registers
-# TODO(tgao): document these bits after stevenh replies
-PCA_OUT0_INIT_VAL = 0xff7f
-PCA_CONF0_INIT_VAL = 0xc007
-
-
-class PcaError(Exception):
- """Base class for all errors in this module."""
-
-
-class PcaController(i2c_node.I2cNode):
- """Object to control PCA9555 module on TTCI board."""
-
- def __init__(self):
- """Initialize PCA9555 module on the TTCI board.
-
- Raises:
- PcaError: if error initializing PCA9555 module.
- """
- super(PcaController, self).__init__()
- logging.info('Attempt to initialize PCA9555 module')
- try:
- self.setNodeAddress(PCA9555_SLV)
- self.writeWord(PCA_REG['OUT0'], PCA_OUT0_INIT_VAL)
- self.writeWord(PCA_REG['PI0'], 0)
- self.writeWord(PCA_REG['CONF0'], PCA_CONF0_INIT_VAL)
- except PcaError as e:
- raise PcaError('Error initializing PCA9555: %s' % e)
-
- def setPCAcontrol(self, key, turn_on):
- """Sets specific bit value in Output Port 0 of PCA9555.
-
- Args:
- key: a string, valid dict keys in PCA_BIT_ONE.
- turn_on: a boolean, true = set bit value to 1.
-
- Returns:
- an integer, 0 for success and -1 for error.
- """
- logging.info('Attempt to set %r bit to %r', key, turn_on)
- try:
- byte_read = self.readByte(PCA_REG['OUT0'])
- if turn_on:
- write_byte = byte_read | PCA_BIT_ONE[key]
- else:
- write_byte = byte_read & ~PCA_BIT_ONE[key]
- self.writeByte(PCA_REG['OUT0'], write_byte)
- return 0
- except PcaError as e:
- logging.error('Error setting PCA9555 Output Port 0: %s', e)
- return -1
-
- def _computeLEDmask(self, bit_value, failure, warning):
- """Computes proper bit mask to set LED values.
-
- Args:
- <see docstring for TTCI_Set_LEDs()>
-
- Returns:
- an integer, 8-bit mask.
-
- Raises:
- PcaError: if bit value is out of range.
- """
- bit_mask = 0
- if bit_value < 0 or bit_value > 15:
- raise PcaError('Error: bit_value out of range [0, 15]')
-
- bit_mask = bit_value
- if failure:
- bit_mask |= 0x20
- if warning:
- bit_mask |= 0x10
-
- return bit_mask
-
- def getPCAbitStatus(self, key):
- """Gets specific bit value from Output Port 0 of PCA9555.
-
- Args:
- key: a string, valid dict keys in PCA_BIT_ONE.
-
- Returns:
- an integer, 0 for success and -1 for error.
- status: a boolean, True if bit value is '1' and False if bit value
- is '0'.
- """
- status = False
- try:
- if PCA_BIT_ONE[key] & self.readByte(PCA_REG['OUT0']):
- status = True
- return (0, status)
- except PcaError as e:
- logging.error('Error reading from PCA9555 Output Port 0: %s', e)
- return (-1, status)
-
- def setLEDs(self, bit_value, failure, warning):
- """De/activate PCA9555 LEDs.
-
- Mapping of LED to bit values in Output Port 1 (register 3)
- (default bit value = 1 <--> LED OFF)
- LED 0 (GREEN): O1.0 (mask = 0x01)
- LED 1 (GREEN): O1.1 (mask = 0x02)
- LED 2 (GREEN): O1.2 (mask = 0x04)
- LED 3 (GREEN): O1.3 (mask = 0x08)
- LED 4 (YELLOW): O1.4 (mask = 0x10)
- LED 5 (RED): O1.5 (mask = 0x20)
-
- To change LED bit values:
- 1) read byte value from register 3
- 2) set all 6 lower bits to 1 (LED OFF) by logical OR with 0x3f
- 3) set appropriate bits to 0 (LED ON) by logical XOR with proper mask
- 4) write updated byte value to register 3
-
- An example: bit_value=9, failure=False, warning=True
- 1) read back, say, 0x96, or 1001 0110 (LEDs 0, 3, 5 ON)
- 2) 0x96 | 0x3f = 0xbf (all LEDs OFF)
- 3) bit_value=9 -> turn on LEDs 1, 2
- failure=False -> keep LED 5 off
- warning=True -> turn on LED 4
- proper mask = 0001 0110, or 0x16
- 0xbf ^ 0x16 = 0xa9, or 1010 1001 (LEDs 1, 2, 4 ON)
- 4) write 0xa9 to register 3
-
- Args:
- bit_value: an integer between 0 and 15, representing 4-bit binary
- value for green LEDs (i.e. 0~3).
- failure: a boolean, true = set red LED value to 0.
- warning: a boolean, true = set yellow LED value to 0.
-
- Returns:
- an integer, 0 for success and -1 for error.
- """
- logging.info('Attempt to set LED values: bit_value=%r, failure=%r, '
- 'warning=%r', bit_value, failure, warning)
- try:
- byte_read = self.readByte(PCA_REG['OUT1'])
- reset_low6 = byte_read | 0x3f
- bit_mask = self._computeLEDmask(bit_value, failure, warning)
- write_byte = reset_low6 ^ bit_mask
- logging.debug('byte_read = 0x%x, reset_low6 = 0x%x, '
- 'bit_mask = 0x%x, write_byte = 0x%x',
- byte_read, reset_low6, bit_mask, write_byte)
- self.writeByte(PCA_REG['OUT1'], write_byte)
- return 0
- except PcaError as e:
- logging.error('Error setting PCA9555 Output Port 0: %s', e)
- return -1
-
- def getSwitchStatus(self):
- """Checks status of DIP Switches (2-bit).
-
- Returns:
- ret: an integer, error code. 0 = no error.
- status: an integer, valid value in range [0, 3].
- """
- logging.info('Attempt to read DIP switch status')
- ret = -1
- status = -1
- try:
- byte_read = self.readByte(PCA_REG['IN1'])
- # Right shift 6-bit to get 2 high-order bits
- status = byte_read >> 6
- logging.info('DIP switch status = 0x%x', status)
- ret = 0
- except PcaError as e:
- logging.error('No byte read from PCA9555 Input Port 1: %s', e)
-
- return (ret, status)
-
- def getLEDstatus(self):
- """Checks LED status.
-
- Returns:
- ret: an integer, 0 for success and -1 for error.
- bit_value: an integer between 0 and 15, representing 4-bit binary
- value for green LEDs (i.e. 0~3). Default: -1.
- failure: a boolean, true = red LED has value 0. Default: False.
- warning: a boolean, true = yellow LED has value 0. Default: False.
- """
- ret = -1
- bit_value = -1
- failure = False
- warning = False
-
- try:
- byte_read = self.readByte(PCA_REG['OUT1'])
- if not (byte_read | PCA_BIT_ONE['red_led']):
- failure = True
- if not (byte_read | PCA_BIT_ONE['yellow_led']):
- warning = True
- bit_value = byte_read & 0xf # Get lower 4-bit value
- logging.info('LED bit_value = %r, failure = %r, warning = %r',
- bit_value, failure, warning)
- ret = 0
- except PcaError as e:
- logging.error('No byte read from PCA9555 Output Port 1: %s', e)
-
- return (ret, bit_value, failure, warning)
diff --git a/client/common_lib/smogcheck_tpm.py b/client/common_lib/smogcheck_tpm.py
deleted file mode 100644
index a40db6a..0000000
--- a/client/common_lib/smogcheck_tpm.py
+++ /dev/null
@@ -1,605 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2011 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.
-
-"""A Python library to interact with TPM module for testing.
-
-Background
- - TPM stands for Trusted Platform Module, a piece of security device
- - TPM specification is the work of Trusted Computing Group
- - As of September 2011, the current TPM specification is version 1.2
-
-Dependency
- - This library depends on a C shared library called "libtspi.so", which
- contains a set of APIs for interacting with TPM module
-
-Notes:
- - An exception is raised if it doesn't make logical sense to continue program
- flow (e.g. I/O error prevents test case from executing)
- - An exception is caught and then converted to an error code if the caller
- expects to check for error code per API definition
-"""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import datetime, logging
-from six.moves import range
-
-from autotest_lib.client.common_lib import smogcheck_ttci
-# Use explicit import to make code more readable
-from ctypes import c_uint, c_uint32, cdll, c_bool, Structure, POINTER, \
- c_ubyte, c_byte, byref, c_uint16, cast, create_string_buffer, c_uint64, \
- c_char_p, addressof, c_char, pointer
-
-
-# TPM flags
-# TODO(tgao): possible to import from trousers/src/include/tss/tss_defines.h?
-TSS_KEY_AUTHORIZATION = c_uint32(0x00000001)
-TSS_KEY_TSP_SRK = c_uint32(0x04000000)
-TSS_POLICY_USAGE = c_uint32(0x00000001)
-TSS_OBJECT_TYPE_RSAKEY = c_uint(0x02)
-TSS_SECRET_MODE_SHA1 = c_uint32(0x00001000)
-TSS_SECRET_MODE_PLAIN = c_uint32(0x00001800)
-TSS_TPMCAP_PROP_MANUFACTURER = c_uint(0x12)
-TSS_TPMCAP_PROPERTY = c_uint(0x13)
-TSS_TPMCAP_VERSION = c_uint(0x14)
-TSS_TPMCAP_VERSION_VAL = c_uint32(0x15)
-TSS_TPMSTATUS_DISABLEOWNERCLEAR = c_uint32(0x00000001)
-TSS_TPMSTATUS_DISABLEFORCECLEAR = c_uint32(0x00000002)
-TSS_TPMSTATUS_PHYSICALSETDEACTIVATED = c_uint32(0x00000010)
-TSS_TPMSTATUS_SETTEMPDEACTIVATED = c_uint32(0x00000011)
-
-# TODO(tgao): possible to import from trousers/src/include/tss/tpm.h?
-TPM_SHA1_160_HASH_LEN = c_uint(0x14)
-
-# Path to TSPI shared library.
-TSPI_C_LIB = "/usr/lib/libtspi.so.1"
-
-# Valid operation of tpmSetActive(). Equivalent CLI commands:
-# 'status' = tpm_setactive --well-known --status
-# 'activate' = tpm_setactive --well-known --active
-# 'deactivate' = tpm_setactive --well-known --inactive
-# 'temp' = tpm_setactive --well-known --temp
-TPM_SETACTIVE_OP = ['status', 'activate', 'deactivate', 'temp']
-
-# Valid operation of tpmSetClearable(). Equivalent CLI commands:
-# 'status' = tpm_setclearable --well-known --status
-# 'owner' = tpm_setclearable --well-known --owner
-# 'force' = tpm_setclearable --well-known --force
-TPM_SETCLEARABLE_OP = ['status', 'owner', 'force']
-
-# Secret mode for setPolicySecret()
-TSS_SECRET_MODE = dict(sha1=TSS_SECRET_MODE_SHA1,
- plain=TSS_SECRET_MODE_PLAIN)
-
-
-class SmogcheckError(Exception):
- """Base class for all smogcheck API errors."""
-
-
-class TpmVersion(Structure):
- """Defines TPM version string struct.
-
- Declared in tss/tpm.h and named TPM_VERSION.
- """
- _fields_ = [('major', c_ubyte),
- ('minor', c_ubyte),
- ('revMajor', c_ubyte),
- ('revMinor', c_ubyte)]
-
-
-class TpmCapVersionInfo(Structure):
- """Defines TPM version info struct.
-
- Declared in tss/tpm.h and named TPM_CAP_VERSION_INFO.
- """
- _fields_ = [('tag', c_uint16),
- ('version', TpmVersion),
- ('specLevel', c_uint16),
- ('errataRev', c_ubyte),
- ('tpmVendorID', c_char*4),
- ('vendorSpecific', POINTER(c_ubyte))]
-
-
-def InitVersionInfo(vi):
- """Utility method to allocate memory for TPM version info.
-
- Args:
- vi: a TpmCapVerisonInfo object, just created.
- """
- vi.tpmVendorId = create_string_buffer(4) # Allocate 4 bytes
- vendorDetail = create_string_buffer(64) # Allocate 64 bytes
- vi.vendorSpecific = cast(pointer(vendorDetail), POINTER(c_ubyte))
-
-
-def PrintVersionInfo(vi):
- """Utility method to print TPM version info.
-
- Args:
- vi: a TpmCapVerisonInfo object.
- """
- logging.info(' TPM 1.2 Version Info:\n')
- logging.info(' Chip Version: %d.%d.%d.%d.', vi.version.major,
- vi.version.minor, vi.version.revMajor, vi.version.revMinor)
- logging.info(' Spec Level: %d', vi.specLevel)
- logging.info(' Errata Revision: %d', vi.errataRev)
- vendorId = [i for i in vi.tpmVendorID if i]
- logging.info(' TPM Vendor ID: %s', ''.join(vendorId))
- # TODO(tgao): handle the case when there's no vendor specific data.
- logging.info(' Vendor Specific data (first 4 bytes in Hex): '
- '%.2x %.2x %.2x %.2x', vi.vendorSpecific[0],
- vi.vendorSpecific[1], vi.vendorSpecific[2],
- vi.vendorSpecific[3])
-
-
-def PrintSelfTestResult(str_len, pResult):
- """Utility method to print TPM self test result.
-
- Args:
- str_len: an integer, length of string pointed to by pResult.
- pResult: a c_char_p, pointer to result.
- """
- out = []
- for i in range(str_len):
- if i and not i % 32:
- out.append('\t')
- if not i % 4:
- out.append(' ')
- b = pResult.value[i]
- out.append('%02x' % ord(b))
- logging.info(' TPM Test Results: %s', ''.join(out))
-
-
-class TpmController(object):
- """Object to interact with TPM module for testing."""
-
- def __init__(self):
- """Constructor.
-
- Mandatory params:
- hContext: a c_uint32, context object handle.
- _contextSet: a boolean, True if TPM context is set.
- hTpm: a c_uint32, TPM object handle.
- hTpmPolicy: a c_uint32, TPM policy object handle.
- tspi_lib: a shared library object (libtspi.so).
-
- Raises:
- SmogcheckError: if error initializing TpmController.
- """
- self.hContext = c_uint32(0)
- self._contextSet = False
- self.hTpm = c_uint32(0)
- self.hTpmPolicy = c_uint32(0)
-
- logging.info('Attempt to load shared library %s', TSPI_C_LIB)
- try:
- self.tspi_lib = cdll.LoadLibrary(TSPI_C_LIB)
- except OSError as e:
- raise SmogcheckError('Error loading C library %s: %r' %
- (TSPI_C_LIB, e))
- logging.info('Successfully loaded shared library %s', TSPI_C_LIB)
-
- def closeContext(self):
- """Closes TPM context and cleans up.
-
- Returns:
- an integer, 0 for success and -1 for error.
- """
- if not self._contextSet:
- logging.debug('TPM context NOT set.')
- return 0
-
- ret = -1
- # Calling the pointer type without an argument creates a NULL pointer
- if self.tspi_lib.Tspi_Context_FreeMemory(self.hContext,
- POINTER(c_byte)()) != 0:
- logging.error('Error freeing memory when closing TPM context')
- else:
- logging.debug('Tspi_Context_FreeMemory() success')
-
- if self.tspi_lib.Tspi_Context_Close(self.hContext) != 0:
- logging.error('Error closing TPM context')
- else:
- logging.debug('Tspi_Context_Close() success')
- ret = 0
- self._contextSet = False
-
- return ret
-
- def _closeContextObject(self, hObject):
- """Closes TPM context object.
-
- Args:
- hObject: an integer, basic object handle.
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- if self.tspi_lib.Tspi_Context_CloseObject(self.hContext, hObject) != 0:
- raise SmogcheckError('Error closing TPM context object')
-
- logging.debug('Tspi_Context_CloseObject() success')
-
- def setupContext(self):
- """Sets up tspi context for TPM access.
-
- TPM context cannot be reused. Therefore, each new Tspi_* command would
- require a new context to be set up before execution and closing that
- context after execution (or error).
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- if self._contextSet:
- logging.debug('TPM context already set.')
- return
-
- if self.tspi_lib.Tspi_Context_Create(byref(self.hContext)) != 0:
- raise SmogcheckError('Error creating tspi context')
-
- logging.info('Created tspi context = 0x%x', self.hContext.value)
-
- if self.tspi_lib.Tspi_Context_Connect(self.hContext,
- POINTER(c_uint16)()) != 0:
- raise SmogcheckError('Error connecting to tspi context')
-
- logging.info('Connected to tspi context')
-
- if self.tspi_lib.Tspi_Context_GetTpmObject(self.hContext,
- byref(self.hTpm)) != 0:
- raise SmogcheckError('Error getting TPM object from tspi context')
-
- logging.info('Got tpm object from tspi context = 0x%x', self.hTpm.value)
- self._contextSet = True
-
- def _getTpmStatus(self, flag, bValue):
- """Wrapper function to call Tspi_TPM_GetStatus().
-
- Args:
- flag: a c_uint, TPM status info flag, values defined in C header file
- "tss/tss_defines.h".
- bValue: a c_bool, place holder for specific TPM flag bit value (0/1).
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- result = self.tspi_lib.Tspi_TPM_GetStatus(self.hTpm, flag,
- byref(bValue))
- if result != 0:
- msg = ('Error (0x%x) getting status for flag 0x%x' %
- (result, flag.value))
- raise SmogcheckError(msg)
-
- logging.info('Tspi_TPM_GetStatus(): success for flag 0x%x',
- flag.value)
-
- def _setTpmStatus(self, flag, bValue):
- """Wrapper function to call Tspi_TPM_GetStatus().
-
- Args:
- flag: a c_uint, TPM status info flag.
- bValue: a c_bool, place holder for specific TPM flag bit value (0/1).
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- result = self.tspi_lib.Tspi_TPM_SetStatus(self.hTpm, flag, bValue)
- if result != 0:
- msg = ('Error (0x%x) setting status for flag 0x%x' %
- (result, flag.value))
- raise SmogcheckError(msg)
-
- logging.info('Tspi_TPM_SetStatus(): success for flag 0x%x',
- flag.value)
-
- def getPolicyObject(self, hTpm=None, hPolicy=None):
- """Get TPM policy object.
-
- Args:
- hTpm: a c_uint, TPM object handle.
- hPolicy: a c_uint, TPM policy object handle.
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- if hTpm is None:
- hTpm = self.hTpm
-
- if hPolicy is None:
- hPolicy = self.hTpmPolicy
-
- logging.debug('Tspi_GetPolicyObject(): hTpm = 0x%x, hPolicy = 0x%x',
- hTpm.value, hPolicy.value)
- result = self.tspi_lib.Tspi_GetPolicyObject(hTpm, TSS_POLICY_USAGE,
- byref(hPolicy))
- if result != 0:
- msg = 'Error (0x%x) getting TPM policy object' % result
- raise SmogcheckError(msg)
-
- logging.debug('Tspi_GetPolicyObject() success hTpm = 0x%x, '
- 'hPolicy = 0x%x', hTpm.value, hPolicy.value)
-
- def setPolicySecret(self, hPolicy=None, pSecret=None, secret_mode=None):
- """Sets TPM policy secret.
-
- Args:
- hPolicy: a c_uint, TPM policy object handle.
- pSecret: a pointer to a byte array, which holds the TSS secret.
- secret_mode: a string, valid values are keys of TSS_SECRET_MODE.
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- if hPolicy is None:
- hPolicy = self.hTpmPolicy
-
- if pSecret is None:
- raise SmogcheckError('setPolicySecret(): pSecret cannot be None')
-
- if secret_mode is None or secret_mode not in TSS_SECRET_MODE:
- raise SmogcheckError('setPolicySecret(): invalid secret_mode')
-
- logging.debug('Tspi_Policy_SetSecret(): hPolicy = 0x%x, secret_mode '
- '(%r) = %r', hPolicy.value, secret_mode,
- TSS_SECRET_MODE[secret_mode])
-
- result = self.tspi_lib.Tspi_Policy_SetSecret(
- hPolicy, TSS_SECRET_MODE[secret_mode], TPM_SHA1_160_HASH_LEN,
- pSecret)
- if result != 0:
- msg = 'Error (0x%x) setting TPM policy secret' % result
- raise SmogcheckError(msg)
-
- logging.debug('Tspi_Policy_SetSecret() success, hPolicy = 0x%x',
- hPolicy.value)
-
- def getTpmVersion(self):
- """Gets TPM version info.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_version.c
- Downloaded from:
- http://sourceforge.net/projects/trousers/files/tpm-tools/1.3.4/\
- tpm-tools-1.3.4.tar.gz
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- uiResultLen = c_uint32(0)
- pResult = c_char_p()
- offset = c_uint64(0)
- versionInfo = TpmCapVersionInfo()
- InitVersionInfo(versionInfo)
-
- logging.debug('Successfully set up tspi context: hTpm = %r', self.hTpm)
-
- result = self.tspi_lib.Tspi_TPM_GetCapability(
- self.hTpm, TSS_TPMCAP_VERSION_VAL, 0, POINTER(c_byte)(),
- byref(uiResultLen), byref(pResult))
- if result != 0:
- msg = 'Error (0x%x) getting TPM capability, pResult = %r' % (
- result, pResult.value)
- raise SmogcheckError(msg)
-
- logging.info('Successfully received TPM capability: '
- 'uiResultLen = %d, pResult=%r', uiResultLen.value,
- pResult.value)
- result = self.tspi_lib.Trspi_UnloadBlob_CAP_VERSION_INFO(
- byref(offset), pResult, cast(byref(versionInfo),
- POINTER(c_byte)))
- if result != 0:
- msg = 'Error (0x%x) unloading TPM CAP version info' % result
- raise SmogcheckError(msg)
-
- PrintVersionInfo(versionInfo)
-
- def runTpmSelfTest(self):
- """Executes TPM self test.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_selftest.c
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- uiResultLen = c_uint32(0)
- pResult = c_char_p()
- self.setupContext()
-
- logging.debug('Successfully set up tspi context: hTpm = 0x%x',
- self.hTpm.value)
-
- result = self.tspi_lib.Tspi_TPM_SelfTestFull(self.hTpm)
- if result != 0:
- self.closeContext()
- raise SmogcheckError('Error (0x%x) with TPM self test' % result)
-
- logging.info('Successfully executed TPM self test: hTpm = 0x%x',
- self.hTpm.value)
- result = self.tspi_lib.Tspi_TPM_GetTestResult(
- self.hTpm, byref(uiResultLen), byref(pResult))
- if result != 0:
- self.closeContext()
- raise SmogcheckError('Error (0x%x) getting test results' % result)
-
- logging.info('TPM self test results: uiResultLen = %d, pResult=%r',
- uiResultLen.value, pResult.value)
- PrintSelfTestResult(uiResultLen.value, pResult)
- self.closeContext()
-
- def takeTpmOwnership(self):
- """Take TPM ownership.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_takeownership.c
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- hSrk = c_uint32(0) # TPM Storage Root Key
- hSrkPolicy = c_uint32(0)
- # Defaults each byte value to 0x00
- well_known_secret = create_string_buffer(20)
- pSecret = c_char_p(addressof(well_known_secret))
-
- self.setupContext()
- logging.debug('Successfully set up tspi context: hTpm = 0x%x',
- self.hTpm.value)
-
- try:
- self.getPolicyObject()
- self.setPolicySecret(pSecret=pSecret, secret_mode='sha1')
- except SmogcheckError:
- if hSrk != 0:
- self._closeContextObject(hSrk)
- self.closeContext()
- raise # re-raise
-
- flag = TSS_KEY_TSP_SRK.value | TSS_KEY_AUTHORIZATION.value
- result = self.tspi_lib.Tspi_Context_CreateObject(
- self.hContext, TSS_OBJECT_TYPE_RSAKEY, flag, byref(hSrk))
- if result != 0:
- raise SmogcheckError('Error (0x%x) creating context object' %
- result)
- logging.debug('hTpm = 0x%x, flag = 0x%x, hSrk = 0x%x',
- self.hTpm.value, flag, hSrk.value) # DEBUG
-
- try:
- self.getPolicyObject(hTpm=hSrk, hPolicy=hSrkPolicy)
- self.setPolicySecret(hPolicy=hSrkPolicy, pSecret=pSecret,
- secret_mode='sha1')
- except SmogcheckError:
- if hSrk != 0:
- self._closeContextObject(hSrk)
- self.closeContext()
- raise # re-raise
-
- logging.debug('Successfully set up SRK policy: secret = %r, '
- 'hSrk = 0x%x, hSrkPolicy = 0x%x',
- well_known_secret.value, hSrk.value, hSrkPolicy.value)
-
- start_time = datetime.datetime.now()
- result = self.tspi_lib.Tspi_TPM_TakeOwnership(self.hTpm, hSrk,
- c_uint(0))
- end_time = datetime.datetime.now()
- if result != 0:
- logging.info('Tspi_TPM_TakeOwnership error')
- self._closeContextObject(hSrk)
- self.closeContext()
- raise SmogcheckError('Error (0x%x) taking TPM ownership' % result)
-
- logging.info('Successfully took TPM ownership')
- self._closeContextObject(hSrk)
- self.closeContext()
- return smogcheck_ttci.computeTimeElapsed(end_time, start_time)
-
- def clearTpm(self):
- """Return TPM to default state.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_clear.c
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- logging.debug('Successfully set up tspi context: hTpm = %r', self.hTpm)
-
- result = self.tspi_lib.Tspi_TPM_ClearOwner(self.hTpm, True)
- if result != 0:
- raise SmogcheckError('Error (0x%x) clearing TPM' % result)
-
- logging.info('Successfully cleared TPM')
-
- def setTpmActive(self, op):
- """Change TPM active state.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_activate.c
-
- Args:
- op: a string, desired operation. Valid values are defined in
- TPM_SETACTIVE_OP.
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- bValue = c_bool()
- # Defaults each byte value to 0x00
- well_known_secret = create_string_buffer(20)
- pSecret = c_char_p(addressof(well_known_secret))
-
- if op not in TPM_SETACTIVE_OP:
- msg = ('Invalid op (%s) for tpmSetActive(). Valid values are %r' %
- (op, TPM_SETACTIVE_OP))
- raise SmogcheckError(msg)
-
- logging.debug('Successfully set up tspi context: hTpm = %r', self.hTpm)
-
- if op == 'status':
- self.getPolicyObject()
- self.setPolicySecret(pSecret=pSecret, secret_mode='sha1')
-
- self._getTpmStatus(
- TSS_TPMSTATUS_PHYSICALSETDEACTIVATED, bValue)
- logging.info('Persistent Deactivated Status: %s', bValue.value)
-
- self._getTpmStatus(
- TSS_TPMSTATUS_SETTEMPDEACTIVATED, bValue)
- logging.info('Volatile Deactivated Status: %s', bValue.value)
- elif op == 'activate':
- self._setTpmStatus(
- TSS_TPMSTATUS_PHYSICALSETDEACTIVATED, False)
- logging.info('Successfully activated TPM')
- elif op == 'deactivate':
- self._setTpmStatus(
- TSS_TPMSTATUS_PHYSICALSETDEACTIVATED, True)
- logging.info('Successfully deactivated TPM')
- elif op == 'temp':
- self._setTpmStatus(
- TSS_TPMSTATUS_SETTEMPDEACTIVATED, True)
- logging.info('Successfully deactivated TPM for current boot')
-
- def setTpmClearable(self, op):
- """Disable TPM clear operations.
-
- Implementation based on tpm-tools-1.3.4/src/tpm_mgmt/tpm_clearable.c
-
- Args:
- op: a string, desired operation. Valid values are defined in
- TPM_SETCLEARABLE_OP.
-
- Raises:
- SmogcheckError: if an error is encountered.
- """
- bValue = c_bool()
- # Defaults each byte value to 0x00
- well_known_secret = create_string_buffer(20)
- pSecret = c_char_p(addressof(well_known_secret))
-
- if op not in TPM_SETCLEARABLE_OP:
- msg = ('Invalid op (%s) for tpmSetClearable(). Valid values are %r'
- % (op, TPM_SETCLEARABLE_OP))
- raise SmogcheckError(msg)
-
- logging.debug('Successfully set up tspi context: hTpm = %r', self.hTpm)
-
- if op == 'status':
- self.getPolicyObject()
- self.setPolicySecret(pSecret=pSecret, secret_mode='sha1')
-
- self._getTpmStatus(
- TSS_TPMSTATUS_DISABLEOWNERCLEAR, bValue)
- logging.info('Owner Clear Disabled: %s', bValue.value)
-
- self._getTpmStatus(
- TSS_TPMSTATUS_DISABLEFORCECLEAR, bValue)
- logging.info('Force Clear Disabled: %s', bValue.value)
- elif op == 'owner':
- self.getPolicyObject()
- self.setPolicySecret(pSecret=pSecret, secret_mode='sha1')
-
- self._setTpmStatus(
- TSS_TPMSTATUS_DISABLEOWNERCLEAR, False)
- logging.info('Successfully disabled Owner Clear')
- elif op == 'force':
- self._setTpmStatus(
- TSS_TPMSTATUS_DISABLEFORCECLEAR, True)
- logging.info('Successfully disabled Force Clear')
diff --git a/client/common_lib/smogcheck_ttci.py b/client/common_lib/smogcheck_ttci.py
deleted file mode 100644
index c7dfe56..0000000
--- a/client/common_lib/smogcheck_ttci.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# Lint as: python2, python3
-# Copyright (c) 2011 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.
-
-"""A Python library to interact with TTCI module for TPM testing.
-
-Background
- - TTCI stands for TPM Test Controller Interface
- - TTCI is a custom-designed hardware board that can be used to test TPM module
- - TTCI board contains two modules: PCA9555 and INA219. This library provides
- methods to interact with these modules programmatically
-
-Dependency
- - This library depends on a new C shared library called "libsmogcheck.so".
- - In order to run test cases built using this API, one needs a TTCI board
-
-Notes:
- - An exception is raised if it doesn't make logical sense to continue program
- flow (e.g. I/O error prevents test case from executing)
- - An exception is caught and then converted to an error code if the caller
- expects to check for error code per API definition
-"""
-
-import logging
-from autotest_lib.client.common_lib import smogcheck_ina219, smogcheck_pca9555
-
-
-# I2C follower addresses of INA219 module
-INA219_BPWR_SLV = 0x40 # Backup Power
-INA219_MPWR_SLV = 0x44 # Main Power
-
-
-class TtciError(Exception):
- """Base class for all errors in this module."""
-
-
-class TtciController(object):
- """Object to control TTCI board used for TPM module testing."""
-
- def __init__(self):
- """Constructor.
-
- Mandatory params:
- err: error string.
- ina_backup_obj: an instance of InaController (for Backup Power port
- of INA219 module).
- ina_main_obj: an instance of InaController (for Main Power port
- of INA219 module).
- pca_obj: an instance of PcaController.
-
- Raises:
- TtciError: if error initializing TTCI controller.
- """
- self.err = None
- try:
- # Initialize PCA9555 module.
- self.pca_obj = smogcheck_pca9555.PcaController()
-
- # Initialize INA219 module.
- self.ina_main_obj = smogcheck_ina219.InaController(
- node_addr=INA219_MPWR_SLV)
- self.ina_backup_obj = smogcheck_ina219.InaController(
- node_addr=INA219_BPWR_SLV)
- except smogcheck_pca9555.PcaError as e:
- raise TtciError('Error initialize PCA9555 module: %s' % e)
- except smogcheck_ina219.InaError as e:
- raise TtciError('Error initialize INA219 module: %s' % e)
-
- def TTCI_Get_Main_Power_Metrics(self):
- """Gets voltage and current measurements from INA219 Main Power.
-
- See docstring of getPowerMetrics() in smogcheck_ina219.py.
- """
- return self.ina_main_obj.getPowerMetrics()
-
- def TTCI_Get_Backup_Power_Metrics(self):
- """Gets voltage and current measurements from INA219 Backup Power.
-
- See docstring of getPowerMetrics() in smogcheck_ina219.py.
- """
- return self.ina_backup_obj.getPowerMetrics()
-
- def TTCI_Set_Main_Power_Control(self, turn_on):
- """De/activated TPM Main Power.
-
- Args:
- turn_on: a boolean, on (true) = set bit to 1.
-
- See docstring of setPCAcontrol() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setPCAcontrol('main_power', turn_on=turn_on)
-
- def TTCI_Set_Backup_Power_Control(self, turn_on):
- """De/activated TPM Backup Power.
-
- Args:
- turn_on: a boolean, on (true) = set bit to 1.
-
- See docstring of setPCAcontrol() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setPCAcontrol('backup_power', turn_on=turn_on)
-
- def TTCI_Set_Reset_Control(self, turn_on):
- """De/activated TPM Reset.
-
- Exception note:
- for TPM Reset, true means setting bit value to 0 (not 1).
-
- Args:
- turn_on: a boolean, on (true) = set bit to 0.
-
- See docstring of setPCAcontrol() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setPCAcontrol('reset', turn_on=not(turn_on))
-
- def TTCI_Set_PP_Control(self, turn_on):
- """De/activated TPM Physical Presence.
-
- Args:
- turn_on: a boolean, on (true) = set bit to 1.
-
- See docstring of setPCAcontrol() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setPCAcontrol('pp', turn_on=turn_on)
-
- def TTCI_Set_TPM_I2C_Control(self, turn_on):
- """Enable/Disable I2C communication with TPM.
-
- Args:
- turn_on: a boolean, on (true) = set bit to 1.
-
- See docstring of setPCAcontrol() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setPCAcontrol('tpm_i2c', turn_on=turn_on)
-
- def TTCI_Get_Main_Power_Status(self):
- """Checks bit value of Main Power.
-
- See docstring of getPCAbitStatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getPCAbitStatus('main_power')
-
- def TTCI_Get_Backup_Power_Status(self):
- """Checks bit value of Backup Power.
-
- See docstring of getPCAbitStatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getPCAbitStatus('backup_power')
-
- def TTCI_Get_PP_Status(self):
- """Checks bit value of Physical Presence.
-
- See docstring of getPCAbitStatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getPCAbitStatus('pp')
-
- def TTCI_Get_TPM_I2C_Status(self):
- """Checks bit value of TPM I2C.
-
- See docstring of getPCAbitStatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getPCAbitStatus('tpm_i2c')
-
- def TTCI_Set_LEDs(self, bit_value, failure, warning):
- """De/activates PCA9555 LEDs.
-
- See docstring of setLEDs() in smogcheck_pca9555.py.
- """
- return self.pca_obj.setLEDs(bit_value, failure, warning)
-
- def TTCI_Get_Switch_Status(self):
- """Checks status of DIP Switches (2-bit).
-
- See docstring of getSwitchStatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getSwitchStatus()
-
- def TTCI_Get_LED_Status(self):
- """Checks LED status.
-
- See docstring of getLEDstatus() in smogcheck_pca9555.py.
- """
- return self.pca_obj.getLEDstatus()
-
-
-def computeTimeElapsed(end, start):
- """Computes time difference in microseconds.
-
- Args:
- end: a datetime.datetime() object, end timestamp.
- start: a datetime.datetime() object, start timestamp.
-
- Returns:
- usec: an integer.
- """
- t = end - start
- usec = 1000000 * t.seconds + t.microseconds
- logging.info('Elapsed time = %d usec', usec)
- return usec
diff --git a/client/common_lib/smogcheck_util.py b/client/common_lib/smogcheck_util.py
deleted file mode 100644
index 61da951..0000000
--- a/client/common_lib/smogcheck_util.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""A Python utility library for TPM module testing."""
-
-import logging, subprocess, time
-from autotest_lib.client.common_lib import error
-
-
-def runInSubprocess(args, rc_list=None):
- """Run a command in subprocess and return stdout.
-
- Args:
- args: a list of string, command to run.
- rc_list: a list of int, acceptable return code values.
-
- Returns:
- out: a string, stdout of the command executed.
- err: a string, stderr of the command executed, or None.
-
- Raises:
- RuntimeError: if subprocess return code is non-zero and not in rc_list.
- """
- if rc_list is None:
- rc_list = []
-
- # Sleep for 1 second so we don't overwhelm I2C bus with too many commands
- time.sleep(1)
- logging.debug('runInSubprocess args = %r; rc_list = %r', args, rc_list)
- proc = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = proc.communicate()
- logging.error('runInSubprocess %s: out=%r, err=%r', args[0], out, err)
- if proc.returncode and proc.returncode not in rc_list:
- raise RuntimeError('runInSubprocess %s failed with returncode %d: %s' %
- (args[0], proc.returncode, out))
- return str(out), str(err)
-
-
-def enableI2C():
- """Enable i2c-dev so i2c-tools can be used.
-
- Dependency: 'i2cdetect' is a command from 'i2c-tools' package, which comes
- with Chrom* OS image and is available from inside chroot.
-
- Raises:
- TestFail: if i2c-dev can't be enabled.
- """
- args = ['i2cdetect', '-l']
- out, _ = runInSubprocess(args)
- if not out:
- logging.info('i2c-dev disabled. Enabling it with modprobe')
- out, _ = runInSubprocess(['modprobe', 'i2c-dev'])
- if out:
- raise error.TestFail('Error enable i2c-dev: %s' % out)
- out, _ = runInSubprocess(args)
- logging.info('i2c-dev ready to go:\n%s', out)
-
-
-def computeTimeElapsed(end, start):
- """Computes time difference in microseconds.
-
- Args:
- end: a datetime.datetime() object, end timestamp.
- start: a datetime.datetime() object, start timestamp.
-
- Returns:
- usec: an int, difference between end and start in microseconds.
- """
- t = end - start
- usec = 1000000 * t.seconds + t.microseconds
- logging.info('Elapsed time = %d usec', usec)
- return usec
diff --git a/client/common_lib/ui_utils.py b/client/common_lib/ui_utils.py
deleted file mode 100644
index 5bc6b4f..0000000
--- a/client/common_lib/ui_utils.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# Lint as: python2, python3
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import logging
-import os
-from six.moves import range
-import time
-
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib import utils
-
-
-class UIScreenshoter(object):
- """Simple class to take screenshots within the ui_utils framework."""
-
- _SCREENSHOT_DIR_PATH = '/var/log/ui_utils'
- _SCREENSHOT_BASENAME = 'ui-screenshot'
-
- def __init__(self):
- if not os.path.exists(self._SCREENSHOT_DIR_PATH):
- os.mkdir(self._SCREENSHOT_DIR_PATH, 0o755)
- self.screenshot_num = 0
-
- def take_ss(self):
- try:
- utils.run('screenshot "{}/{}_iter{}.png"'.format(
- self._SCREENSHOT_DIR_PATH, self._SCREENSHOT_BASENAME,
- self.screenshot_num))
- self.screenshot_num += 1
- except Exception as e:
- logging.warning('Unable to capture screenshot. %s', e)
-
-class UI_Handler(object):
-
- REGEX_ALL = '/(.*?)/'
-
- PROMISE_TEMPLATE = \
- '''new Promise(function(resolve, reject) {
- chrome.automation.getDesktop(function(root) {
- resolve(%s);
- })
- })'''
-
- _GET_ON_SCREEN_ITEMS = "findAll({attributes:{role: 'staticText'},state:{" \
- "offscreen: false}}).map(node => node.name)"
-
- def __init__(self):
- self.screenshoter = UIScreenshoter()
-
- def start_ui_root(self, cr):
- """Start the UI root object for testing."""
- self.ext = cr.autotest_ext
-
- def is_obj_restricted(self, name, isRegex=False, role=None):
- """
- Return True if the object restriction is 'disabled'.
- This usually means the button is either greyed out, locked, etc.
-
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the item is a regex.
- @param role: Parameter to provide to the 'role' attribute.
-
- """
- FindParams = self._get_FindParams_str(name=name,
- role=role,
- isRegex=isRegex)
- try:
- restriction = self.ext.EvaluateJavaScript(
- self.PROMISE_TEMPLATE % ("%s.restriction" % FindParams),
- promise=True)
- except Exception:
- raise error.TestError(
- 'Could not find object {}.'.format(name))
- if restriction == 'disabled':
- return True
- return False
-
- def item_present(self, name, isRegex=False, flip=False, role=None):
- """
- Determines if an object is present on the screen
-
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the 'name' is a regex.
- @param flip: Flips the return status.
- @param role: Parameter to provide to the 'role' attribute.
-
- @returns:
- True if object is present and flip is False.
- False if object is present and flip is True.
- False if object is not present and flip is False.
- True if object is not present and flip is True.
-
- """
- FindParams = self._get_FindParams_str(name=name,
- role=role,
- isRegex=isRegex)
-
- if flip is True:
- return not self._is_item_present(FindParams)
- return self._is_item_present(FindParams)
-
- def wait_for_ui_obj(self,
- name,
- isRegex=False,
- remove=False,
- role=None,
- timeout=10):
- """
- Waits for the UI object specified.
-
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the 'name' is a regex.
- @param remove: bool, if you are waiting for the item to be removed.
- @param role: Parameter to provide to the 'role' attribute.
- @param timeout: int, time to wait for the item.
-
- @raises error.TestError if the element is not loaded (or removed).
-
- """
- try:
- utils.poll_for_condition(
- condition=lambda: self.item_present(name=name,
- isRegex=isRegex,
- flip=remove,
- role=role),
- timeout=timeout,
- exception=error.TestError('{} did not load'
- .format(name)))
- except error.TestError:
- self.screenshoter.take_ss()
- logging.debug("CURRENT UI ITEMS VISIBLE {}".format(
- self.list_screen_items()))
- raise error.TestError('{} did not load'.format(name))
-
- def did_obj_not_load(self, name, isRegex=False, timeout=5):
- """
- Specifically used to wait and see if an item appears on the UI.
-
- NOTE: This is different from wait_for_ui_obj because that returns as
- soon as the object is either loaded or not loaded. This function will
- wait to ensure over the timeout period the object never loads.
- Additionally it will return as soon as it does load. Basically a fancy
- time.sleep()
-
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the item is a regex.
- @param timeout: Time in seconds to wait for the object to appear.
-
- @returns: True if object never loaded within the timeout period,
- else False.
-
- """
- t1 = time.time()
- while time.time() - t1 < timeout:
- if self.item_present(name=name, isRegex=isRegex):
- return False
- time.sleep(1)
- return True
-
- def doDefault_on_obj(self, name, isRegex=False, role=None):
- """Runs the .doDefault() js command on the element."""
- FindParams = self._get_FindParams_str(name=name,
- role=role,
- isRegex=isRegex)
- try:
- self.ext.EvaluateJavaScript(
- self.PROMISE_TEMPLATE % ("%s.doDefault()" % FindParams),
- promise=True)
- except:
- logging.info('Unable to .doDefault() on {}. All items: {}'
- .format(FindParams, self.list_screen_items()))
- raise error.TestError("doDefault failed on {}".format(FindParams))
-
- def doCommand_on_obj(self, name, cmd, isRegex=False, role=None):
- """Run the specified command on the element."""
- FindParams = self._get_FindParams_str(name=name,
- role=role,
- isRegex=isRegex)
- return self.ext.EvaluateJavaScript(self.PROMISE_TEMPLATE % """
- %s.%s""" % (FindParams, cmd), promise=True)
-
- def list_screen_items(self,
- role=None,
- name=None,
- isRegex=False,
- attr='name'):
-
- """
- List all the items currently visable on the screen.
-
- If no paramters are given, it will return the name of each item,
- including items with empty names.
-
- @param role: The role of the items to use (ie button).
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the obj is a regex.
- @param attr: Str, the attribute you want returned in the list
- (eg 'name').
-
- """
-
- if isRegex:
- if name is None:
- raise error.TestError('If regex is True name must be given')
- name = self._format_obj(name, isRegex)
- elif name is not None:
- name = self._format_obj(name, isRegex)
- name = self.REGEX_ALL if name is None else name
- role = self.REGEX_ALL if role is None else self._format_obj(role,
- False)
-
- new_promise = self.PROMISE_TEMPLATE % """root.findAll({attributes:
- {name: %s, role: %s}}).map(node => node.%s)""" % (name, role, attr)
- return self.ext.EvaluateJavaScript(new_promise, promise=True)
-
- def get_name_role_list(self, name=None, role=None):
- """
- Return [{}, {}] containing the name/role of everything on screen.
-
- """
- name = self.REGEX_ALL if name is None else name
- role = self.REGEX_ALL if role is None else self._format_obj(role,
- False)
-
- new_promise = self.PROMISE_TEMPLATE % """root.findAll({attributes:
- {name: %s, role: %s}}).map(node =>
- {return {name: node.name, role: node.role} })""" % (name, role)
-
- return self.ext.EvaluateJavaScript(new_promise, promise=True)
-
- def _format_obj(self, name, isRegex):
- """
- Formats the object for use in the javascript name attribute.
-
- When searching for an element on the UI, a regex expression or string
- can be used. If the search is using a string, the obj will need to be
- wrapped in quotes. A Regex is not.
-
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: if True, the object will be returned as is, if False
- the obj will be returned wrapped in quotes.
-
- @returns: The formatted string for regex/name.
- """
- if isRegex:
- return name
- else:
- return '"{}"'.format(name)
-
- def _get_FindParams_str(self, name, role, isRegex):
- """Returns the FindParms string, so that automation node functions
- can be run on it
-
- @param role: The role of the items to use (ie button).
- @param name: Parameter to provide to the 'name' attribute.
- @param isRegex: bool, if the obj is a regex.
-
- @returns: The ".find($FindParams)" string, which can be used to run
- automation node commands, such as .doDefault()
-
- """
- FINDPARAMS_BASE = """
- root.find({attributes:
- {name: %s,
- role: %s}}
- )"""
-
- name = self._format_obj(name, isRegex)
- if role is None:
- role = self.REGEX_ALL
- else:
- role = self._format_obj(role, False)
- return (FINDPARAMS_BASE % (name, role))
-
- def _is_item_present(self, findParams):
- """Return False if tempVar is None, else True."""
- item_present = self.ext.EvaluateJavaScript(
- self.PROMISE_TEMPLATE % findParams,
- promise=True)
- if item_present is None:
- return False
- return True
-
- def click_and_wait_for_item_with_retries(self,
- item_to_click,
- item_to_wait_for,
- isRegex_click=False,
- isRegex_wait=False,
- click_role=None,
- wait_role=None):
- """
- Click on an item, and wait for a subsequent item to load. If the new
- item does not load, we attempt to click the button again.
-
- This being done to remove the corner case of button being visually
- loaded, but not fully ready to be clicked yet. In simple terms:
- Click button --> Check for next button to appear
- IF button does not appear, its likely the original button click did
- not work, thus reclick that button --> recheck for the next button.
-
- If button did appear, stop clicking.
-
- """
- self.doDefault_on_obj(item_to_click,
- role=click_role,
- isRegex=isRegex_click)
- for retry in range(3):
- try:
- self.wait_for_ui_obj(item_to_wait_for,
- role=wait_role,
- isRegex=isRegex_wait,
- timeout=6)
- break
- except error.TestError:
- self.doDefault_on_obj(item_to_click,
- role=click_role,
- isRegex=isRegex_click)
- else:
- raise error.TestError('Item {} did not load after 2 tries'.format(
- item_to_wait_for))
diff --git a/client/common_lib/ui_utils_helpers.py b/client/common_lib/ui_utils_helpers.py
deleted file mode 100644
index 7d9745a..0000000
--- a/client/common_lib/ui_utils_helpers.py
+++ /dev/null
@@ -1,146 +0,0 @@
-from autotest_lib.client.common_lib import error
-from autotest_lib.client.common_lib import ui_utils
-from autotest_lib.client.cros.input_playback import keyboard
-import logging
-import time
-
-
-class UIPrinterHelper(object):
- """Helper lib for ChromeOS UI automation."""
-
- def __init__(self, ui_handler=None, chrome=None):
- """ui_handler or chrome must be provided. ui_handler is an already
- existing ui object."""
- if not ui_handler and chrome:
- self.ui = ui_utils.UI_Handler()
- self.ui.start_ui_root(chrome)
- elif not chrome and ui_handler:
- self.ui = ui_handler
- else:
- raise error.TestError(
- "Either the chrome object or ui_handler must be provided.")
- self._keyboard = None
-
- def print_to_custom_printer(self, printer_name, isPDF=False):
- """Open the printer menu, select the printer given and click print."""
- self.open_printer_menu()
- self.open_see_more_print_sub_menu()
- self.select_printer_from_see_more_menu(printer_name)
- if not self.check_print_window_open():
- raise error.TestError("Print not open after setting printer.")
- self.click_print(isPDF)
- if self._keyboard:
- self._keyboard.close()
-
- def check_print_window_open(self):
- """Check if the print window is still open."""
- start_time = time.time()
-
- # Giving up to 5 seconds for the window to load.
- while time.time() - start_time < 5:
- if (self.ui.item_present('Destination', role='inlineTextBox') and
- self.ui.item_present('Cancel', role='button')) and not (
- self.ui.item_present('Loading preview')):
- return True
-
- logging.info("Print Window was not open {}"
- .format(self.ui.get_name_role_list()))
- self.ui.screenshoter.take_ss()
- return False
-
- def open_printer_menu(self, retry=0):
- """Open the printer menu via the Chrome Dropdown."""
- if not self._is_chrome_menu_open():
- self.ui.doDefault_on_obj('Chrome')
- self.ui.wait_for_ui_obj('/Print/', role='menuItem', isRegex=True)
- self.ui.doDefault_on_obj('/Print/', isRegex=True)
- if retry == 0:
- try:
- self.wait_for_print_ready()
- except error.TestError:
- self.open_printer_menu(retry=1)
- else:
- self.wait_for_print_ready()
-
- def wait_for_print_ready(self):
- """Wait for the print page to fully load."""
- try:
- self.ui.wait_for_ui_obj('Fit to width', role='button', timeout=30)
- except:
- logging.info("Missing {} in {}".format("Fit to width",
- self.ui.get_name_role_list()))
- raise error.TestError("Fit to width no load")
- self.ui.wait_for_ui_obj('Loading preview', remove=True)
-
- def open_see_more_print_sub_menu(self):
- """Open see more sub menu via the clicking it in the dropdown."""
- if not self._keyboard:
- self._keyboard = keyboard.Keyboard()
-
- # Some tests have a notification which causes the chrome menu
- # to remain open, and loose focus on the print page.
- if self._is_chrome_menu_open():
- self._keyboard.press_key("escape")
- self.verify_print_menu_open()
-
- self.ui.wait_for_ui_obj('Destination Save as PDF')
- self.ui.doDefault_on_obj("Destination Save as PDF", role='popUpButton')
-
- self.ui.wait_for_ui_obj("See more destinations", role='menuItem')
- self.ui.doDefault_on_obj("See more destinations", role='menuItem')
- self.is_see_more_menu_open()
-
- def _is_chrome_menu_open(self):
- """Return True if the chrome dropdown menu is still open."""
- return self.ui.item_present("/Print/", role="menuItem", isRegex=True)
-
- def select_printer_from_see_more_menu(self, printer_name):
- """Click a printer from the "see more" sub menu within print page."""
- if not self.is_see_more_menu_open():
- raise error.TestError(
- "Cannot select printer from sub menu as its not open.")
- # Easier to find via regex since the actual cell has the name twice.
- if not self.is_str_regex(printer_name):
- printer_name = self.make_str_regex(printer_name)
- self.ui.wait_for_ui_obj(printer_name, isRegex=True, role='cell')
- self.ui.doDefault_on_obj(printer_name, isRegex=True, role='cell')
- self.ui.wait_for_ui_obj(printer_name, role='cell', remove=True, isRegex=True)
- # Wait for the "Setting up " loading icon to finish
- self.ui.wait_for_ui_obj('Setting up ', remove=True)
-
- def click_print(self, isPDF=False):
- """Click the print button. Click save if PDF."""
- self.verify_print_menu_open()
- self.ui.doDefault_on_obj('Save' if isPDF else 'Print', role='button')
- if isPDF:
- pass # TODO implement the save menu
-
- def is_see_more_menu_open(self):
- """Return True if the print menu is open."""
- try:
- self.ui.wait_for_ui_obj("Select a destination")
- except error.TestError:
- return False
- return True
-
- def is_print_menu_open(self):
- """Return True if the print menu is open."""
- return self.ui.item_present("Print", role="window")
-
- def verify_print_menu_open(self):
- """Verify print menu is open. If not raise TestError."""
- if not self.is_print_menu_open():
- raise error.TestError(
- "Cannot open See more print menu when print screen not open")
-
- def is_str_regex(self, var):
- """Return True if the given var starts and ends with "/"."""
- if len(var) < 1:
- return False
- if var[0] == "/" and var[-1] == "/":
- return True
- return False
-
- def make_str_regex(self, var):
- """Return the provided var with a leading and ending "/"."""
- return ("/" + var + "/")