blob: 3a6930f6882caeaa7ab8f602f5d1e722de91f33a [file] [log] [blame]
Kevin Chenga2619dc2016-03-28 11:42:08 -07001# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This class defines the CrosHost Label class."""
6
C Shapiro05dd3222017-09-22 10:42:33 -06007import collections
Kevin Chenga2619dc2016-03-28 11:42:08 -07008import logging
9import os
10import re
11
12import common
13
14from autotest_lib.client.bin import utils
Kevin Cheng80ad5732016-03-31 16:01:56 -070015from autotest_lib.client.common_lib import global_config
Kevin Chenga2619dc2016-03-28 11:42:08 -070016from autotest_lib.client.cros.audio import cras_utils
Kevin Chenga2619dc2016-03-28 11:42:08 -070017from autotest_lib.client.cros.video import constants as video_test_constants
18from autotest_lib.server.cros.dynamic_suite import constants as ds_constants
19from autotest_lib.server.hosts import base_label
20from autotest_lib.server.hosts import common_label
Kevin Chengd9dfa582016-05-04 09:37:34 -070021from autotest_lib.server.hosts import servo_host
Kevin Cheng80ad5732016-03-31 16:01:56 -070022from autotest_lib.site_utils import hwid_lib
Kevin Chenga2619dc2016-03-28 11:42:08 -070023
24# pylint: disable=missing-docstring
C Shapiro05dd3222017-09-22 10:42:33 -060025LsbOutput = collections.namedtuple('LsbOutput', ['unibuild', 'board'])
26
27def _parse_lsb_output(host):
Allen Lia0c7afc2019-02-26 15:50:06 -080028 """Parses the LSB output and returns key data points for labeling.
C Shapiro05dd3222017-09-22 10:42:33 -060029
Allen Lia0c7afc2019-02-26 15:50:06 -080030 @param host: Host that the command will be executed against
31 @returns: LsbOutput with the result of parsing the /etc/lsb-release output
32 """
33 release_info = utils.parse_cmd_output('cat /etc/lsb-release',
34 run_method=host.run)
C Shapiro05dd3222017-09-22 10:42:33 -060035
Allen Lia0c7afc2019-02-26 15:50:06 -080036 unibuild = release_info.get('CHROMEOS_RELEASE_UNIBUILD') == '1'
37 return LsbOutput(unibuild, release_info['CHROMEOS_RELEASE_BOARD'])
C Shapiro05dd3222017-09-22 10:42:33 -060038
Kevin Chenga2619dc2016-03-28 11:42:08 -070039
Kevin Chenga8455302016-08-31 20:54:41 +000040class BoardLabel(base_label.StringPrefixLabel):
41 """Determine the correct board label for the device."""
42
43 _NAME = ds_constants.BOARD_PREFIX.rstrip(':')
44
45 def generate_labels(self, host):
46 # We only want to apply the board labels once, which is when they get
47 # added to the AFE. That way we don't have to worry about the board
48 # label switching on us if the wrong builds get put on the devices.
49 # crbug.com/624207 records one event of the board label switching
50 # unexpectedly on us.
Allen Lia0c7afc2019-02-26 15:50:06 -080051 board = host.host_info_store.get().board
52 if board:
53 return [board]
Kevin Chenga8455302016-08-31 20:54:41 +000054 for label in host._afe_host.labels:
55 if label.startswith(self._NAME + ':'):
56 return [label.split(':')[-1]]
57
C Shapiro10970222017-10-24 08:55:55 -060058 return [_parse_lsb_output(host).board]
Kevin Chenga8455302016-08-31 20:54:41 +000059
60
C Shapirob05c00b2017-07-18 15:06:49 -060061class ModelLabel(base_label.StringPrefixLabel):
62 """Determine the correct model label for the device."""
63
64 _NAME = ds_constants.MODEL_LABEL
65
66 def generate_labels(self, host):
C Shapirod7ba4a72018-01-16 17:04:35 -070067 # Based on the issue explained in BoardLabel, return the existing
68 # label if it has already been set once.
Allen Lia0c7afc2019-02-26 15:50:06 -080069 model = host.host_info_store.get().model
70 if model:
71 return [model]
C Shapirod7ba4a72018-01-16 17:04:35 -070072 for label in host._afe_host.labels:
73 if label.startswith(self._NAME + ':'):
74 return [label.split(':')[-1]]
C Shapirob05c00b2017-07-18 15:06:49 -060075
C Shapiro32700032017-11-03 12:46:55 -060076 lsb_output = _parse_lsb_output(host)
77 model = None
78
79 if lsb_output.unibuild:
C Shapiro26fb1012017-12-14 16:38:03 -070080 test_label_cmd = 'cros_config / test-label'
81 result = host.run(command=test_label_cmd, ignore_status=True)
C Shapiro32700032017-11-03 12:46:55 -060082 if result.exit_status == 0:
83 model = result.stdout.strip()
C Shapiro26fb1012017-12-14 16:38:03 -070084 if not model:
85 mosys_cmd = 'mosys platform model'
86 result = host.run(command=mosys_cmd, ignore_status=True)
87 if result.exit_status == 0:
88 model = result.stdout.strip()
C Shapiro32700032017-11-03 12:46:55 -060089
90 # We need some sort of backwards compatibility for boards that
91 # are not yet supported with mosys and unified builds.
92 # This is necessary so that we can begin changing cbuildbot to take
93 # advantage of the model/board label differentiations for
94 # scheduling, while still retaining backwards compatibility.
95 return [model or lsb_output.board]
C Shapirob05c00b2017-07-18 15:06:49 -060096
97
C Shapirobe0ff8d2019-06-14 10:41:43 -060098class DeviceSkuLabel(base_label.StringPrefixLabel):
99 """Determine the correct device_sku label for the device."""
100
101 _NAME = ds_constants.DEVICE_SKU_LABEL
102
103 def generate_labels(self, host):
104 device_sku = host.host_info_store.get().device_sku
105 if device_sku:
106 return [device_sku]
107
108 mosys_cmd = 'mosys platform sku'
109 result = host.run(command=mosys_cmd, ignore_status=True)
110 if result.exit_status == 0:
111 return [result.stdout.strip()]
112
113 return []
114
115
Kevin Chenga2619dc2016-03-28 11:42:08 -0700116class LightSensorLabel(base_label.BaseLabel):
117 """Label indicating if a light sensor is detected."""
118
119 _NAME = 'lightsensor'
120 _LIGHTSENSOR_SEARCH_DIR = '/sys/bus/iio/devices'
121 _LIGHTSENSOR_FILES = [
122 "in_illuminance0_input",
123 "in_illuminance_input",
124 "in_illuminance0_raw",
125 "in_illuminance_raw",
126 "illuminance0_input",
127 ]
128
129 def exists(self, host):
130 search_cmd = "find -L %s -maxdepth 4 | egrep '%s'" % (
131 self._LIGHTSENSOR_SEARCH_DIR, '|'.join(self._LIGHTSENSOR_FILES))
132 # Run the search cmd following the symlinks. Stderr_tee is set to
133 # None as there can be a symlink loop, but the command will still
134 # execute correctly with a few messages printed to stderr.
135 result = host.run(search_cmd, stdout_tee=None, stderr_tee=None,
136 ignore_status=True)
137
138 return result.exit_status == 0
139
140
141class BluetoothLabel(base_label.BaseLabel):
142 """Label indicating if bluetooth is detected."""
143
144 _NAME = 'bluetooth'
145
146 def exists(self, host):
C Shapirobcd9c862019-05-22 17:42:08 -0600147 # Based on crbug.com/966219, the label is flipping sometimes.
148 # Potentially this is caused by testing itself.
149 # Making this label permanently sticky.
150 info = host.host_info_store.get()
151 for label in info.labels:
152 if label.startswith(self._NAME):
153 return True
154
Kevin Chenga2619dc2016-03-28 11:42:08 -0700155 result = host.run('test -d /sys/class/bluetooth/hci0',
156 ignore_status=True)
157
158 return result.exit_status == 0
159
160
161class ECLabel(base_label.BaseLabel):
162 """Label to determine the type of EC on this host."""
163
164 _NAME = 'ec:cros'
165
166 def exists(self, host):
167 cmd = 'mosys ec info'
168 # The output should look like these, so that the last field should
169 # match our EC version scheme:
170 #
171 # stm | stm32f100 | snow_v1.3.139-375eb9f
172 # ti | Unknown-10de | peppy_v1.5.114-5d52788
173 #
174 # Non-Chrome OS ECs will look like these:
175 #
176 # ENE | KB932 | 00BE107A00
177 # ite | it8518 | 3.08
178 #
179 # And some systems don't have ECs at all (Lumpy, for example).
180 regexp = r'^.*\|\s*(\S+_v\d+\.\d+\.\d+-[0-9a-f]+)\s*$'
181
182 ecinfo = host.run(command=cmd, ignore_status=True)
183 if ecinfo.exit_status == 0:
184 res = re.search(regexp, ecinfo.stdout)
185 if res:
186 logging.info("EC version is %s", res.groups()[0])
187 return True
188 logging.info("%s got: %s", cmd, ecinfo.stdout)
189 # Has an EC, but it's not a Chrome OS EC
190 logging.info("%s exited with status %d", cmd, ecinfo.exit_status)
191 return False
192
193
Mary Ruthven935ebad2018-06-13 16:13:20 -0700194class Cr50Label(base_label.StringPrefixLabel):
195 """Label indicating the cr50 version."""
196
197 _NAME = 'cr50'
198
199 def __init__(self):
200 self.ver = None
201
202
203 def exists(self, host):
204 # Make sure the gsctool version command runs ok
205 self.ver = host.run('gsctool -a -f', ignore_status=True)
206 return self.ver.exit_status == 0
207
208
209 def generate_labels(self, host):
210 # Check the major version to determine prePVT vs PVT
Mary Ruthven35207022019-04-15 11:57:29 -0700211 version_info = re.search('RW (\d+\.(\d+)\.\d+)$', self.ver.stdout)
212 full_version = version_info.group(1)
213 major_version = int(version_info.group(2))
Mary Ruthven935ebad2018-06-13 16:13:20 -0700214 # PVT images have a odd major version prePVT have even
Mary Ruthven35207022019-04-15 11:57:29 -0700215 return [full_version, 'pvt' if (major_version % 2) else 'prepvt']
Mary Ruthven935ebad2018-06-13 16:13:20 -0700216
217
Kevin Chenga2619dc2016-03-28 11:42:08 -0700218class AccelsLabel(base_label.BaseLabel):
219 """Determine the type of accelerometers on this host."""
220
221 _NAME = 'accel:cros-ec'
222
223 def exists(self, host):
224 # Check to make sure we have ectool
225 rv = host.run('which ectool', ignore_status=True)
226 if rv.exit_status:
227 logging.info("No ectool cmd found; assuming no EC accelerometers")
228 return False
229
230 # Check that the EC supports the motionsense command
Kevin Cheng856f8a32016-03-31 16:08:08 -0700231 rv = host.run('ectool motionsense', ignore_status=True)
Kevin Chenga2619dc2016-03-28 11:42:08 -0700232 if rv.exit_status:
233 logging.info("EC does not support motionsense command; "
234 "assuming no EC accelerometers")
235 return False
236
237 # Check that EC motion sensors are active
Kevin Cheng17e2f002016-05-04 08:48:03 -0700238 active = host.run('ectool motionsense active').stdout.split('\n')
Kevin Chenga2619dc2016-03-28 11:42:08 -0700239 if active[0] == "0":
240 logging.info("Motion sense inactive; assuming no EC accelerometers")
241 return False
242
243 logging.info("EC accelerometers found")
244 return True
245
246
247class ChameleonLabel(base_label.BaseLabel):
248 """Determine if a Chameleon is connected to this host."""
249
250 _NAME = 'chameleon'
251
252 def exists(self, host):
253 return host._chameleon_host is not None
254
255
256class ChameleonConnectionLabel(base_label.StringPrefixLabel):
257 """Return the Chameleon connection label."""
258
259 _NAME = 'chameleon'
260
261 def exists(self, host):
262 return host._chameleon_host is not None
263
Joseph Hwangeac44312016-08-31 12:08:38 +0800264
Kevin Chenga2619dc2016-03-28 11:42:08 -0700265 def generate_labels(self, host):
266 return [host.chameleon.get_label()]
267
268
Joseph Hwangeac44312016-08-31 12:08:38 +0800269class ChameleonPeripheralsLabel(base_label.StringPrefixLabel):
270 """Return the Chameleon peripherals labels.
271
272 The 'chameleon:bt_hid' label is applied if the bluetooth
273 classic hid device, i.e, RN-42 emulation kit, is detected.
274
275 Any peripherals plugged into the chameleon board would be
276 detected and applied proper labels in this class.
277 """
278
279 _NAME = 'chameleon'
280
281 def exists(self, host):
282 return host._chameleon_host is not None
283
284
285 def generate_labels(self, host):
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700286 labels = []
Joseph Hwangbf6b0752018-08-10 08:18:10 +0800287 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700288 if bt_hid_device.CheckSerialConnection():
289 labels.append('bt_hid')
290 ble_hid_device = host.chameleon.get_ble_mouse()
291 if ble_hid_device.CheckSerialConnection():
292 labels.append('bt_ble_hid')
293 bt_a2dp_sink = host.chameleon.get_bluetooth_a2dp_sink()
294 if bt_a2dp_sink.CheckSerialConnection():
295 labels.append('bt_a2dp_sink')
296 return labels
297
298
Joseph Hwangeac44312016-08-31 12:08:38 +0800299
300
Kevin Chenga2619dc2016-03-28 11:42:08 -0700301class AudioLoopbackDongleLabel(base_label.BaseLabel):
302 """Return the label if an audio loopback dongle is plugged in."""
303
304 _NAME = 'audio_loopback_dongle'
305
306 def exists(self, host):
307 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
308 ignore_status=True).stdout
309 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
310 cras_utils.node_type_is_plugged('MIC', nodes_info)):
311 return True
312 return False
313
314
315class PowerSupplyLabel(base_label.StringPrefixLabel):
316 """
317 Return the label describing the power supply type.
318
319 Labels representing this host's power supply.
320 * `power:battery` when the device has a battery intended for
321 extended use
322 * `power:AC_primary` when the device has a battery not intended
323 for extended use (for moving the machine, etc)
324 * `power:AC_only` when the device has no battery at all.
325 """
326
327 _NAME = 'power'
328
329 def __init__(self):
330 self.psu_cmd_result = None
331
332
333 def exists(self, host):
334 self.psu_cmd_result = host.run(command='mosys psu type',
335 ignore_status=True)
336 return self.psu_cmd_result.stdout.strip() != 'unknown'
337
338
339 def generate_labels(self, host):
340 if self.psu_cmd_result.exit_status:
341 # The psu command for mosys is not included for all platforms. The
342 # assumption is that the device will have a battery if the command
343 # is not found.
344 return ['battery']
345 return [self.psu_cmd_result.stdout.strip()]
346
347
348class StorageLabel(base_label.StringPrefixLabel):
349 """
350 Return the label describing the storage type.
351
352 Determine if the internal device is SCSI or dw_mmc device.
353 Then check that it is SSD or HDD or eMMC or something else.
354
355 Labels representing this host's internal device type:
356 * `storage:ssd` when internal device is solid state drive
357 * `storage:hdd` when internal device is hard disk drive
358 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700359 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700360 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700361 * None When internal device is something else or
362 when we are unable to determine the type
363 """
364
365 _NAME = 'storage'
366
367 def __init__(self):
368 self.type_str = ''
369
370
371 def exists(self, host):
372 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
373 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
374 '. /usr/share/misc/chromeos-common.sh;',
375 'load_base_vars;',
376 'get_fixed_dst_drive'])
377 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
378 if rootdev.exit_status:
379 logging.info("Fail to run %s", rootdev_cmd)
380 return False
381 rootdev_str = rootdev.stdout.strip()
382
383 if not rootdev_str:
384 return False
385
386 rootdev_base = os.path.basename(rootdev_str)
387
388 mmc_pattern = '/dev/mmcblk[0-9]'
389 if re.match(mmc_pattern, rootdev_str):
390 # Use type to determine if the internal device is eMMC or somthing
391 # else. We can assume that MMC is always an internal device.
392 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
393 type = host.run(command=type_cmd, ignore_status=True)
394 if type.exit_status:
395 logging.info("Fail to run %s", type_cmd)
396 return False
397 type_str = type.stdout.strip()
398
399 if type_str == 'MMC':
400 self.type_str = 'mmc'
401 return True
402
403 scsi_pattern = '/dev/sd[a-z]+'
404 if re.match(scsi_pattern, rootdev.stdout):
405 # Read symlink for /sys/block/sd* to determine if the internal
406 # device is connected via ata or usb.
407 link_cmd = 'readlink /sys/block/%s' % rootdev_base
408 link = host.run(command=link_cmd, ignore_status=True)
409 if link.exit_status:
410 logging.info("Fail to run %s", link_cmd)
411 return False
412 link_str = link.stdout.strip()
413 if 'usb' in link_str:
414 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700415 elif 'ufs' in link_str:
416 self.type_str = 'ufs'
417 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700418
419 # Read rotation to determine if the internal device is ssd or hdd.
420 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
421 % rootdev_base)
422 rotate = host.run(command=rotate_cmd, ignore_status=True)
423 if rotate.exit_status:
424 logging.info("Fail to run %s", rotate_cmd)
425 return False
426 rotate_str = rotate.stdout.strip()
427
428 rotate_dict = {'0':'ssd', '1':'hdd'}
429 self.type_str = rotate_dict.get(rotate_str)
430 return True
431
Gwendal Grignou327fec62017-07-26 15:25:43 -0700432 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
433 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800434 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700435 return True
436
Kevin Chenga2619dc2016-03-28 11:42:08 -0700437 # All other internal device / error case will always fall here
438 return False
439
440
441 def generate_labels(self, host):
442 return [self.type_str]
443
444
445class ServoLabel(base_label.BaseLabel):
446 """Label to apply if a servo is present."""
447
448 _NAME = 'servo'
449
450 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700451 """
452 Check if the servo label should apply to the host or not.
453
454 @returns True if a servo host is detected, False otherwise.
455 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700456 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700457 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700458 if servo_args:
459 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700460 return (servo_host_hostname is not None
461 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700462
463
Ilja H. Friedel50290642017-12-01 19:39:53 -0800464class ArcLabel(base_label.BaseLabel):
465 """Label indicates if host has ARC support."""
466
467 _NAME = 'arc'
468
469 @base_label.forever_exists_decorate
470 def exists(self, host):
471 return 0 == host.run(
472 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
473 ignore_status=True).exit_status
474
475
476class CtsArchLabel(base_label.StringLabel):
477 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700478
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700479 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700480
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700481 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700482 """Return supported CTS ABIs.
483
484 @return List of supported CTS bundle ABIs.
485 """
486 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700487 return cts_abis.get(arch, [])
488
489 def _get_cts_cpus(self, arch):
490 """Return supported CTS native CPUs.
491
492 This is needed for CTS_Instant scheduling.
493 @return List of supported CTS native CPUs.
494 """
495 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
496 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700497
Rohit Makasana5a153502016-06-13 15:50:09 -0700498 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700499 cpu_arch = host.get_cpu_arch()
500 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
501 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
502 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700503
504
Kevin Chenga2619dc2016-03-28 11:42:08 -0700505class VideoGlitchLabel(base_label.BaseLabel):
506 """Label indicates if host supports video glitch detection tests."""
507
508 _NAME = 'video_glitch_detection'
509
510 def exists(self, host):
511 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
512
513 return board in video_test_constants.SUPPORTED_BOARDS
514
515
Kevin Chenga2619dc2016-03-28 11:42:08 -0700516class InternalDisplayLabel(base_label.StringLabel):
517 """Label that determines if the device has an internal display."""
518
519 _NAME = 'internal_display'
520
521 def generate_labels(self, host):
522 from autotest_lib.client.cros.graphics import graphics_utils
523 from autotest_lib.client.common_lib import utils as common_utils
524
525 def __system_output(cmd):
526 return host.run(cmd).stdout
527
528 def __read_file(remote_path):
529 return host.run('cat %s' % remote_path).stdout
530
531 # Hijack the necessary client functions so that we can take advantage
532 # of the client lib here.
533 # FIXME: find a less hacky way than this
534 original_system_output = utils.system_output
535 original_read_file = common_utils.read_file
536 utils.system_output = __system_output
537 common_utils.read_file = __read_file
538 try:
539 return ([self._NAME]
540 if graphics_utils.has_internal_display()
541 else [])
542 finally:
543 utils.system_output = original_system_output
544 common_utils.read_file = original_read_file
545
546
547class LucidSleepLabel(base_label.BaseLabel):
548 """Label that determines if device has support for lucid sleep."""
549
550 # TODO(kevcheng): See if we can determine if this label is applicable a
551 # better way (crbug.com/592146).
552 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700553 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700554
555 def exists(self, host):
556 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
557 return board in self.LUCID_SLEEP_BOARDS
558
559
Kevin Cheng80ad5732016-03-31 16:01:56 -0700560class HWIDLabel(base_label.StringLabel):
561 """Return all the labels generated from the hwid."""
562
563 # We leave out _NAME because hwid_lib will generate everything for us.
564
565 def __init__(self):
566 # Grab the key file needed to access the hwid service.
567 self.key_file = global_config.global_config.get_config_value(
568 'CROS', 'HWID_KEY', type=str)
569
570
571 def generate_labels(self, host):
572 hwid_labels = []
573 hwid = host.run_output('crossystem hwid').strip()
574 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
575 self.key_file).get('labels', [])
576
577 for hwid_info in hwid_info_list:
578 # If it's a prefix, we'll have:
579 # {'name': prefix_label, 'value': postfix_label} and create
580 # 'prefix_label:postfix_label'; otherwise it'll just be
581 # {'name': label} which should just be 'label'.
582 value = hwid_info.get('value', '')
583 name = hwid_info.get('name', '')
584 # There should always be a name but just in case there is not.
585 if name:
586 hwid_labels.append(name if not value else
587 '%s:%s' % (name, value))
588 return hwid_labels
589
590
591 def get_all_labels(self):
592 """We need to try all labels as a prefix and as standalone.
593
594 We don't know for sure which labels are prefix labels and which are
595 standalone so we try all of them as both.
596 """
597 all_hwid_labels = []
598 try:
599 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
600 self.key_file)
601 except IOError:
602 logging.error('Can not open key file: %s', self.key_file)
603 except hwid_lib.HwIdException as e:
604 logging.error('hwid service: %s', e)
605 return all_hwid_labels, all_hwid_labels
606
607
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800608class DetachableBaseLabel(base_label.BaseLabel):
609 """Label indicating if device has detachable keyboard."""
610
611 _NAME = 'detachablebase'
612
613 def exists(self, host):
614 return host.run('which hammerd', ignore_status=True).exit_status == 0
615
616
Tom Hughese9552342018-12-18 14:29:25 -0800617class FingerprintLabel(base_label.BaseLabel):
618 """Label indicating whether device has fingerprint sensor."""
619
620 _NAME = 'fingerprint'
621
622 def exists(self, host):
623 return host.run('test -c /dev/cros_fp',
624 ignore_status=True).exit_status == 0
625
626
Garry Wang17a829e2019-03-20 12:03:18 -0700627class ReferenceDesignLabel(base_label.StringPrefixLabel):
628 """Determine the correct reference design label for the device. """
629
630 _NAME = 'reference_design'
631
632 def __init__(self):
633 self.response = None
634
635 def exists(self, host):
636 self.response = host.run('mosys platform family', ignore_status=True)
637 return self.response.exit_status == 0
638
639 def generate_labels(self, host):
640 if self.exists(host):
641 return [self.response.stdout.strip()]
642
643
Kevin Chenga2619dc2016-03-28 11:42:08 -0700644CROS_LABELS = [
645 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700646 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700647 AudioLoopbackDongleLabel(),
648 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000649 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600650 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700651 ChameleonConnectionLabel(),
652 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800653 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700654 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700655 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800656 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800657 DetachableBaseLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700658 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800659 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700660 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700661 InternalDisplayLabel(),
662 LightSensorLabel(),
663 LucidSleepLabel(),
664 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700665 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700666 ServoLabel(),
667 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700668 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700669]