blob: 3db8b2d677c587b8061d5306ea5d583819911650 [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
Kevin Chenga2619dc2016-03-28 11:42:08 -070098class LightSensorLabel(base_label.BaseLabel):
99 """Label indicating if a light sensor is detected."""
100
101 _NAME = 'lightsensor'
102 _LIGHTSENSOR_SEARCH_DIR = '/sys/bus/iio/devices'
103 _LIGHTSENSOR_FILES = [
104 "in_illuminance0_input",
105 "in_illuminance_input",
106 "in_illuminance0_raw",
107 "in_illuminance_raw",
108 "illuminance0_input",
109 ]
110
111 def exists(self, host):
112 search_cmd = "find -L %s -maxdepth 4 | egrep '%s'" % (
113 self._LIGHTSENSOR_SEARCH_DIR, '|'.join(self._LIGHTSENSOR_FILES))
114 # Run the search cmd following the symlinks. Stderr_tee is set to
115 # None as there can be a symlink loop, but the command will still
116 # execute correctly with a few messages printed to stderr.
117 result = host.run(search_cmd, stdout_tee=None, stderr_tee=None,
118 ignore_status=True)
119
120 return result.exit_status == 0
121
122
123class BluetoothLabel(base_label.BaseLabel):
124 """Label indicating if bluetooth is detected."""
125
126 _NAME = 'bluetooth'
127
128 def exists(self, host):
C Shapirobcd9c862019-05-22 17:42:08 -0600129 # Based on crbug.com/966219, the label is flipping sometimes.
130 # Potentially this is caused by testing itself.
131 # Making this label permanently sticky.
132 info = host.host_info_store.get()
133 for label in info.labels:
134 if label.startswith(self._NAME):
135 return True
136
Kevin Chenga2619dc2016-03-28 11:42:08 -0700137 result = host.run('test -d /sys/class/bluetooth/hci0',
138 ignore_status=True)
139
140 return result.exit_status == 0
141
142
143class ECLabel(base_label.BaseLabel):
144 """Label to determine the type of EC on this host."""
145
146 _NAME = 'ec:cros'
147
148 def exists(self, host):
149 cmd = 'mosys ec info'
150 # The output should look like these, so that the last field should
151 # match our EC version scheme:
152 #
153 # stm | stm32f100 | snow_v1.3.139-375eb9f
154 # ti | Unknown-10de | peppy_v1.5.114-5d52788
155 #
156 # Non-Chrome OS ECs will look like these:
157 #
158 # ENE | KB932 | 00BE107A00
159 # ite | it8518 | 3.08
160 #
161 # And some systems don't have ECs at all (Lumpy, for example).
162 regexp = r'^.*\|\s*(\S+_v\d+\.\d+\.\d+-[0-9a-f]+)\s*$'
163
164 ecinfo = host.run(command=cmd, ignore_status=True)
165 if ecinfo.exit_status == 0:
166 res = re.search(regexp, ecinfo.stdout)
167 if res:
168 logging.info("EC version is %s", res.groups()[0])
169 return True
170 logging.info("%s got: %s", cmd, ecinfo.stdout)
171 # Has an EC, but it's not a Chrome OS EC
172 logging.info("%s exited with status %d", cmd, ecinfo.exit_status)
173 return False
174
175
Mary Ruthven935ebad2018-06-13 16:13:20 -0700176class Cr50Label(base_label.StringPrefixLabel):
177 """Label indicating the cr50 version."""
178
179 _NAME = 'cr50'
180
181 def __init__(self):
182 self.ver = None
183
184
185 def exists(self, host):
186 # Make sure the gsctool version command runs ok
187 self.ver = host.run('gsctool -a -f', ignore_status=True)
188 return self.ver.exit_status == 0
189
190
191 def generate_labels(self, host):
192 # Check the major version to determine prePVT vs PVT
Mary Ruthven35207022019-04-15 11:57:29 -0700193 version_info = re.search('RW (\d+\.(\d+)\.\d+)$', self.ver.stdout)
194 full_version = version_info.group(1)
195 major_version = int(version_info.group(2))
Mary Ruthven935ebad2018-06-13 16:13:20 -0700196 # PVT images have a odd major version prePVT have even
Mary Ruthven35207022019-04-15 11:57:29 -0700197 return [full_version, 'pvt' if (major_version % 2) else 'prepvt']
Mary Ruthven935ebad2018-06-13 16:13:20 -0700198
199
Kevin Chenga2619dc2016-03-28 11:42:08 -0700200class AccelsLabel(base_label.BaseLabel):
201 """Determine the type of accelerometers on this host."""
202
203 _NAME = 'accel:cros-ec'
204
205 def exists(self, host):
206 # Check to make sure we have ectool
207 rv = host.run('which ectool', ignore_status=True)
208 if rv.exit_status:
209 logging.info("No ectool cmd found; assuming no EC accelerometers")
210 return False
211
212 # Check that the EC supports the motionsense command
Kevin Cheng856f8a32016-03-31 16:08:08 -0700213 rv = host.run('ectool motionsense', ignore_status=True)
Kevin Chenga2619dc2016-03-28 11:42:08 -0700214 if rv.exit_status:
215 logging.info("EC does not support motionsense command; "
216 "assuming no EC accelerometers")
217 return False
218
219 # Check that EC motion sensors are active
Kevin Cheng17e2f002016-05-04 08:48:03 -0700220 active = host.run('ectool motionsense active').stdout.split('\n')
Kevin Chenga2619dc2016-03-28 11:42:08 -0700221 if active[0] == "0":
222 logging.info("Motion sense inactive; assuming no EC accelerometers")
223 return False
224
225 logging.info("EC accelerometers found")
226 return True
227
228
229class ChameleonLabel(base_label.BaseLabel):
230 """Determine if a Chameleon is connected to this host."""
231
232 _NAME = 'chameleon'
233
234 def exists(self, host):
235 return host._chameleon_host is not None
236
237
238class ChameleonConnectionLabel(base_label.StringPrefixLabel):
239 """Return the Chameleon connection label."""
240
241 _NAME = 'chameleon'
242
243 def exists(self, host):
244 return host._chameleon_host is not None
245
Joseph Hwangeac44312016-08-31 12:08:38 +0800246
Kevin Chenga2619dc2016-03-28 11:42:08 -0700247 def generate_labels(self, host):
248 return [host.chameleon.get_label()]
249
250
Joseph Hwangeac44312016-08-31 12:08:38 +0800251class ChameleonPeripheralsLabel(base_label.StringPrefixLabel):
252 """Return the Chameleon peripherals labels.
253
254 The 'chameleon:bt_hid' label is applied if the bluetooth
255 classic hid device, i.e, RN-42 emulation kit, is detected.
256
257 Any peripherals plugged into the chameleon board would be
258 detected and applied proper labels in this class.
259 """
260
261 _NAME = 'chameleon'
262
263 def exists(self, host):
264 return host._chameleon_host is not None
265
266
267 def generate_labels(self, host):
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700268 labels = []
Joseph Hwangbf6b0752018-08-10 08:18:10 +0800269 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700270 if bt_hid_device.CheckSerialConnection():
271 labels.append('bt_hid')
272 ble_hid_device = host.chameleon.get_ble_mouse()
273 if ble_hid_device.CheckSerialConnection():
274 labels.append('bt_ble_hid')
275 bt_a2dp_sink = host.chameleon.get_bluetooth_a2dp_sink()
276 if bt_a2dp_sink.CheckSerialConnection():
277 labels.append('bt_a2dp_sink')
278 return labels
279
280
Joseph Hwangeac44312016-08-31 12:08:38 +0800281
282
Kevin Chenga2619dc2016-03-28 11:42:08 -0700283class AudioLoopbackDongleLabel(base_label.BaseLabel):
284 """Return the label if an audio loopback dongle is plugged in."""
285
286 _NAME = 'audio_loopback_dongle'
287
288 def exists(self, host):
289 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
290 ignore_status=True).stdout
291 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
292 cras_utils.node_type_is_plugged('MIC', nodes_info)):
293 return True
294 return False
295
296
297class PowerSupplyLabel(base_label.StringPrefixLabel):
298 """
299 Return the label describing the power supply type.
300
301 Labels representing this host's power supply.
302 * `power:battery` when the device has a battery intended for
303 extended use
304 * `power:AC_primary` when the device has a battery not intended
305 for extended use (for moving the machine, etc)
306 * `power:AC_only` when the device has no battery at all.
307 """
308
309 _NAME = 'power'
310
311 def __init__(self):
312 self.psu_cmd_result = None
313
314
315 def exists(self, host):
316 self.psu_cmd_result = host.run(command='mosys psu type',
317 ignore_status=True)
318 return self.psu_cmd_result.stdout.strip() != 'unknown'
319
320
321 def generate_labels(self, host):
322 if self.psu_cmd_result.exit_status:
323 # The psu command for mosys is not included for all platforms. The
324 # assumption is that the device will have a battery if the command
325 # is not found.
326 return ['battery']
327 return [self.psu_cmd_result.stdout.strip()]
328
329
330class StorageLabel(base_label.StringPrefixLabel):
331 """
332 Return the label describing the storage type.
333
334 Determine if the internal device is SCSI or dw_mmc device.
335 Then check that it is SSD or HDD or eMMC or something else.
336
337 Labels representing this host's internal device type:
338 * `storage:ssd` when internal device is solid state drive
339 * `storage:hdd` when internal device is hard disk drive
340 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700341 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700342 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700343 * None When internal device is something else or
344 when we are unable to determine the type
345 """
346
347 _NAME = 'storage'
348
349 def __init__(self):
350 self.type_str = ''
351
352
353 def exists(self, host):
354 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
355 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
356 '. /usr/share/misc/chromeos-common.sh;',
357 'load_base_vars;',
358 'get_fixed_dst_drive'])
359 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
360 if rootdev.exit_status:
361 logging.info("Fail to run %s", rootdev_cmd)
362 return False
363 rootdev_str = rootdev.stdout.strip()
364
365 if not rootdev_str:
366 return False
367
368 rootdev_base = os.path.basename(rootdev_str)
369
370 mmc_pattern = '/dev/mmcblk[0-9]'
371 if re.match(mmc_pattern, rootdev_str):
372 # Use type to determine if the internal device is eMMC or somthing
373 # else. We can assume that MMC is always an internal device.
374 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
375 type = host.run(command=type_cmd, ignore_status=True)
376 if type.exit_status:
377 logging.info("Fail to run %s", type_cmd)
378 return False
379 type_str = type.stdout.strip()
380
381 if type_str == 'MMC':
382 self.type_str = 'mmc'
383 return True
384
385 scsi_pattern = '/dev/sd[a-z]+'
386 if re.match(scsi_pattern, rootdev.stdout):
387 # Read symlink for /sys/block/sd* to determine if the internal
388 # device is connected via ata or usb.
389 link_cmd = 'readlink /sys/block/%s' % rootdev_base
390 link = host.run(command=link_cmd, ignore_status=True)
391 if link.exit_status:
392 logging.info("Fail to run %s", link_cmd)
393 return False
394 link_str = link.stdout.strip()
395 if 'usb' in link_str:
396 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700397 elif 'ufs' in link_str:
398 self.type_str = 'ufs'
399 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700400
401 # Read rotation to determine if the internal device is ssd or hdd.
402 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
403 % rootdev_base)
404 rotate = host.run(command=rotate_cmd, ignore_status=True)
405 if rotate.exit_status:
406 logging.info("Fail to run %s", rotate_cmd)
407 return False
408 rotate_str = rotate.stdout.strip()
409
410 rotate_dict = {'0':'ssd', '1':'hdd'}
411 self.type_str = rotate_dict.get(rotate_str)
412 return True
413
Gwendal Grignou327fec62017-07-26 15:25:43 -0700414 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
415 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800416 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700417 return True
418
Kevin Chenga2619dc2016-03-28 11:42:08 -0700419 # All other internal device / error case will always fall here
420 return False
421
422
423 def generate_labels(self, host):
424 return [self.type_str]
425
426
427class ServoLabel(base_label.BaseLabel):
428 """Label to apply if a servo is present."""
429
430 _NAME = 'servo'
431
432 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700433 """
434 Check if the servo label should apply to the host or not.
435
436 @returns True if a servo host is detected, False otherwise.
437 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700438 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700439 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700440 if servo_args:
441 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700442 return (servo_host_hostname is not None
443 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700444
445
Ilja H. Friedel50290642017-12-01 19:39:53 -0800446class ArcLabel(base_label.BaseLabel):
447 """Label indicates if host has ARC support."""
448
449 _NAME = 'arc'
450
451 @base_label.forever_exists_decorate
452 def exists(self, host):
453 return 0 == host.run(
454 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
455 ignore_status=True).exit_status
456
457
458class CtsArchLabel(base_label.StringLabel):
459 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700460
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700461 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700462
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700463 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700464 """Return supported CTS ABIs.
465
466 @return List of supported CTS bundle ABIs.
467 """
468 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700469 return cts_abis.get(arch, [])
470
471 def _get_cts_cpus(self, arch):
472 """Return supported CTS native CPUs.
473
474 This is needed for CTS_Instant scheduling.
475 @return List of supported CTS native CPUs.
476 """
477 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
478 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700479
Rohit Makasana5a153502016-06-13 15:50:09 -0700480 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700481 cpu_arch = host.get_cpu_arch()
482 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
483 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
484 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700485
486
Kevin Chenga2619dc2016-03-28 11:42:08 -0700487class VideoGlitchLabel(base_label.BaseLabel):
488 """Label indicates if host supports video glitch detection tests."""
489
490 _NAME = 'video_glitch_detection'
491
492 def exists(self, host):
493 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
494
495 return board in video_test_constants.SUPPORTED_BOARDS
496
497
Kevin Chenga2619dc2016-03-28 11:42:08 -0700498class InternalDisplayLabel(base_label.StringLabel):
499 """Label that determines if the device has an internal display."""
500
501 _NAME = 'internal_display'
502
503 def generate_labels(self, host):
504 from autotest_lib.client.cros.graphics import graphics_utils
505 from autotest_lib.client.common_lib import utils as common_utils
506
507 def __system_output(cmd):
508 return host.run(cmd).stdout
509
510 def __read_file(remote_path):
511 return host.run('cat %s' % remote_path).stdout
512
513 # Hijack the necessary client functions so that we can take advantage
514 # of the client lib here.
515 # FIXME: find a less hacky way than this
516 original_system_output = utils.system_output
517 original_read_file = common_utils.read_file
518 utils.system_output = __system_output
519 common_utils.read_file = __read_file
520 try:
521 return ([self._NAME]
522 if graphics_utils.has_internal_display()
523 else [])
524 finally:
525 utils.system_output = original_system_output
526 common_utils.read_file = original_read_file
527
528
529class LucidSleepLabel(base_label.BaseLabel):
530 """Label that determines if device has support for lucid sleep."""
531
532 # TODO(kevcheng): See if we can determine if this label is applicable a
533 # better way (crbug.com/592146).
534 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700535 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700536
537 def exists(self, host):
538 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
539 return board in self.LUCID_SLEEP_BOARDS
540
541
Kevin Cheng80ad5732016-03-31 16:01:56 -0700542class HWIDLabel(base_label.StringLabel):
543 """Return all the labels generated from the hwid."""
544
545 # We leave out _NAME because hwid_lib will generate everything for us.
546
547 def __init__(self):
548 # Grab the key file needed to access the hwid service.
549 self.key_file = global_config.global_config.get_config_value(
550 'CROS', 'HWID_KEY', type=str)
551
552
553 def generate_labels(self, host):
554 hwid_labels = []
555 hwid = host.run_output('crossystem hwid').strip()
556 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
557 self.key_file).get('labels', [])
558
559 for hwid_info in hwid_info_list:
560 # If it's a prefix, we'll have:
561 # {'name': prefix_label, 'value': postfix_label} and create
562 # 'prefix_label:postfix_label'; otherwise it'll just be
563 # {'name': label} which should just be 'label'.
564 value = hwid_info.get('value', '')
565 name = hwid_info.get('name', '')
566 # There should always be a name but just in case there is not.
567 if name:
568 hwid_labels.append(name if not value else
569 '%s:%s' % (name, value))
570 return hwid_labels
571
572
573 def get_all_labels(self):
574 """We need to try all labels as a prefix and as standalone.
575
576 We don't know for sure which labels are prefix labels and which are
577 standalone so we try all of them as both.
578 """
579 all_hwid_labels = []
580 try:
581 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
582 self.key_file)
583 except IOError:
584 logging.error('Can not open key file: %s', self.key_file)
585 except hwid_lib.HwIdException as e:
586 logging.error('hwid service: %s', e)
587 return all_hwid_labels, all_hwid_labels
588
589
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800590class DetachableBaseLabel(base_label.BaseLabel):
591 """Label indicating if device has detachable keyboard."""
592
593 _NAME = 'detachablebase'
594
595 def exists(self, host):
596 return host.run('which hammerd', ignore_status=True).exit_status == 0
597
598
Tom Hughese9552342018-12-18 14:29:25 -0800599class FingerprintLabel(base_label.BaseLabel):
600 """Label indicating whether device has fingerprint sensor."""
601
602 _NAME = 'fingerprint'
603
604 def exists(self, host):
605 return host.run('test -c /dev/cros_fp',
606 ignore_status=True).exit_status == 0
607
608
Garry Wang17a829e2019-03-20 12:03:18 -0700609class ReferenceDesignLabel(base_label.StringPrefixLabel):
610 """Determine the correct reference design label for the device. """
611
612 _NAME = 'reference_design'
613
614 def __init__(self):
615 self.response = None
616
617 def exists(self, host):
618 self.response = host.run('mosys platform family', ignore_status=True)
619 return self.response.exit_status == 0
620
621 def generate_labels(self, host):
622 if self.exists(host):
623 return [self.response.stdout.strip()]
624
625
Kevin Chenga2619dc2016-03-28 11:42:08 -0700626CROS_LABELS = [
627 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700628 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700629 AudioLoopbackDongleLabel(),
630 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000631 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600632 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700633 ChameleonConnectionLabel(),
634 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800635 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700636 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700637 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800638 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800639 DetachableBaseLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700640 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800641 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700642 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700643 InternalDisplayLabel(),
644 LightSensorLabel(),
645 LucidSleepLabel(),
646 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700647 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700648 ServoLabel(),
649 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700650 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700651]