blob: b448036d58ed0df241d0be6c0d2559145803ab25 [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):
Joseph Hwangbf6b0752018-08-10 08:18:10 +0800268 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
Joseph Hwangeac44312016-08-31 12:08:38 +0800269 return ['bt_hid'] if bt_hid_device.CheckSerialConnection() else []
270
271
Kevin Chenga2619dc2016-03-28 11:42:08 -0700272class AudioLoopbackDongleLabel(base_label.BaseLabel):
273 """Return the label if an audio loopback dongle is plugged in."""
274
275 _NAME = 'audio_loopback_dongle'
276
277 def exists(self, host):
278 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
279 ignore_status=True).stdout
280 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
281 cras_utils.node_type_is_plugged('MIC', nodes_info)):
282 return True
283 return False
284
285
286class PowerSupplyLabel(base_label.StringPrefixLabel):
287 """
288 Return the label describing the power supply type.
289
290 Labels representing this host's power supply.
291 * `power:battery` when the device has a battery intended for
292 extended use
293 * `power:AC_primary` when the device has a battery not intended
294 for extended use (for moving the machine, etc)
295 * `power:AC_only` when the device has no battery at all.
296 """
297
298 _NAME = 'power'
299
300 def __init__(self):
301 self.psu_cmd_result = None
302
303
304 def exists(self, host):
305 self.psu_cmd_result = host.run(command='mosys psu type',
306 ignore_status=True)
307 return self.psu_cmd_result.stdout.strip() != 'unknown'
308
309
310 def generate_labels(self, host):
311 if self.psu_cmd_result.exit_status:
312 # The psu command for mosys is not included for all platforms. The
313 # assumption is that the device will have a battery if the command
314 # is not found.
315 return ['battery']
316 return [self.psu_cmd_result.stdout.strip()]
317
318
319class StorageLabel(base_label.StringPrefixLabel):
320 """
321 Return the label describing the storage type.
322
323 Determine if the internal device is SCSI or dw_mmc device.
324 Then check that it is SSD or HDD or eMMC or something else.
325
326 Labels representing this host's internal device type:
327 * `storage:ssd` when internal device is solid state drive
328 * `storage:hdd` when internal device is hard disk drive
329 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700330 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700331 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700332 * None When internal device is something else or
333 when we are unable to determine the type
334 """
335
336 _NAME = 'storage'
337
338 def __init__(self):
339 self.type_str = ''
340
341
342 def exists(self, host):
343 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
344 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
345 '. /usr/share/misc/chromeos-common.sh;',
346 'load_base_vars;',
347 'get_fixed_dst_drive'])
348 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
349 if rootdev.exit_status:
350 logging.info("Fail to run %s", rootdev_cmd)
351 return False
352 rootdev_str = rootdev.stdout.strip()
353
354 if not rootdev_str:
355 return False
356
357 rootdev_base = os.path.basename(rootdev_str)
358
359 mmc_pattern = '/dev/mmcblk[0-9]'
360 if re.match(mmc_pattern, rootdev_str):
361 # Use type to determine if the internal device is eMMC or somthing
362 # else. We can assume that MMC is always an internal device.
363 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
364 type = host.run(command=type_cmd, ignore_status=True)
365 if type.exit_status:
366 logging.info("Fail to run %s", type_cmd)
367 return False
368 type_str = type.stdout.strip()
369
370 if type_str == 'MMC':
371 self.type_str = 'mmc'
372 return True
373
374 scsi_pattern = '/dev/sd[a-z]+'
375 if re.match(scsi_pattern, rootdev.stdout):
376 # Read symlink for /sys/block/sd* to determine if the internal
377 # device is connected via ata or usb.
378 link_cmd = 'readlink /sys/block/%s' % rootdev_base
379 link = host.run(command=link_cmd, ignore_status=True)
380 if link.exit_status:
381 logging.info("Fail to run %s", link_cmd)
382 return False
383 link_str = link.stdout.strip()
384 if 'usb' in link_str:
385 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700386 elif 'ufs' in link_str:
387 self.type_str = 'ufs'
388 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700389
390 # Read rotation to determine if the internal device is ssd or hdd.
391 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
392 % rootdev_base)
393 rotate = host.run(command=rotate_cmd, ignore_status=True)
394 if rotate.exit_status:
395 logging.info("Fail to run %s", rotate_cmd)
396 return False
397 rotate_str = rotate.stdout.strip()
398
399 rotate_dict = {'0':'ssd', '1':'hdd'}
400 self.type_str = rotate_dict.get(rotate_str)
401 return True
402
Gwendal Grignou327fec62017-07-26 15:25:43 -0700403 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
404 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800405 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700406 return True
407
Kevin Chenga2619dc2016-03-28 11:42:08 -0700408 # All other internal device / error case will always fall here
409 return False
410
411
412 def generate_labels(self, host):
413 return [self.type_str]
414
415
416class ServoLabel(base_label.BaseLabel):
417 """Label to apply if a servo is present."""
418
419 _NAME = 'servo'
420
421 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700422 """
423 Check if the servo label should apply to the host or not.
424
425 @returns True if a servo host is detected, False otherwise.
426 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700427 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700428 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700429 if servo_args:
430 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700431 return (servo_host_hostname is not None
432 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700433
434
Ilja H. Friedel50290642017-12-01 19:39:53 -0800435class ArcLabel(base_label.BaseLabel):
436 """Label indicates if host has ARC support."""
437
438 _NAME = 'arc'
439
440 @base_label.forever_exists_decorate
441 def exists(self, host):
442 return 0 == host.run(
443 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
444 ignore_status=True).exit_status
445
446
447class CtsArchLabel(base_label.StringLabel):
448 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700449
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700450 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700451
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700452 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700453 """Return supported CTS ABIs.
454
455 @return List of supported CTS bundle ABIs.
456 """
457 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700458 return cts_abis.get(arch, [])
459
460 def _get_cts_cpus(self, arch):
461 """Return supported CTS native CPUs.
462
463 This is needed for CTS_Instant scheduling.
464 @return List of supported CTS native CPUs.
465 """
466 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
467 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700468
Rohit Makasana5a153502016-06-13 15:50:09 -0700469 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700470 cpu_arch = host.get_cpu_arch()
471 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
472 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
473 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700474
475
Kevin Chenga2619dc2016-03-28 11:42:08 -0700476class VideoGlitchLabel(base_label.BaseLabel):
477 """Label indicates if host supports video glitch detection tests."""
478
479 _NAME = 'video_glitch_detection'
480
481 def exists(self, host):
482 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
483
484 return board in video_test_constants.SUPPORTED_BOARDS
485
486
Kevin Chenga2619dc2016-03-28 11:42:08 -0700487class InternalDisplayLabel(base_label.StringLabel):
488 """Label that determines if the device has an internal display."""
489
490 _NAME = 'internal_display'
491
492 def generate_labels(self, host):
493 from autotest_lib.client.cros.graphics import graphics_utils
494 from autotest_lib.client.common_lib import utils as common_utils
495
496 def __system_output(cmd):
497 return host.run(cmd).stdout
498
499 def __read_file(remote_path):
500 return host.run('cat %s' % remote_path).stdout
501
502 # Hijack the necessary client functions so that we can take advantage
503 # of the client lib here.
504 # FIXME: find a less hacky way than this
505 original_system_output = utils.system_output
506 original_read_file = common_utils.read_file
507 utils.system_output = __system_output
508 common_utils.read_file = __read_file
509 try:
510 return ([self._NAME]
511 if graphics_utils.has_internal_display()
512 else [])
513 finally:
514 utils.system_output = original_system_output
515 common_utils.read_file = original_read_file
516
517
518class LucidSleepLabel(base_label.BaseLabel):
519 """Label that determines if device has support for lucid sleep."""
520
521 # TODO(kevcheng): See if we can determine if this label is applicable a
522 # better way (crbug.com/592146).
523 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700524 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700525
526 def exists(self, host):
527 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
528 return board in self.LUCID_SLEEP_BOARDS
529
530
Kevin Cheng80ad5732016-03-31 16:01:56 -0700531class HWIDLabel(base_label.StringLabel):
532 """Return all the labels generated from the hwid."""
533
534 # We leave out _NAME because hwid_lib will generate everything for us.
535
536 def __init__(self):
537 # Grab the key file needed to access the hwid service.
538 self.key_file = global_config.global_config.get_config_value(
539 'CROS', 'HWID_KEY', type=str)
540
541
542 def generate_labels(self, host):
543 hwid_labels = []
544 hwid = host.run_output('crossystem hwid').strip()
545 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
546 self.key_file).get('labels', [])
547
548 for hwid_info in hwid_info_list:
549 # If it's a prefix, we'll have:
550 # {'name': prefix_label, 'value': postfix_label} and create
551 # 'prefix_label:postfix_label'; otherwise it'll just be
552 # {'name': label} which should just be 'label'.
553 value = hwid_info.get('value', '')
554 name = hwid_info.get('name', '')
555 # There should always be a name but just in case there is not.
556 if name:
557 hwid_labels.append(name if not value else
558 '%s:%s' % (name, value))
559 return hwid_labels
560
561
562 def get_all_labels(self):
563 """We need to try all labels as a prefix and as standalone.
564
565 We don't know for sure which labels are prefix labels and which are
566 standalone so we try all of them as both.
567 """
568 all_hwid_labels = []
569 try:
570 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
571 self.key_file)
572 except IOError:
573 logging.error('Can not open key file: %s', self.key_file)
574 except hwid_lib.HwIdException as e:
575 logging.error('hwid service: %s', e)
576 return all_hwid_labels, all_hwid_labels
577
578
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800579class DetachableBaseLabel(base_label.BaseLabel):
580 """Label indicating if device has detachable keyboard."""
581
582 _NAME = 'detachablebase'
583
584 def exists(self, host):
585 return host.run('which hammerd', ignore_status=True).exit_status == 0
586
587
Tom Hughese9552342018-12-18 14:29:25 -0800588class FingerprintLabel(base_label.BaseLabel):
589 """Label indicating whether device has fingerprint sensor."""
590
591 _NAME = 'fingerprint'
592
593 def exists(self, host):
594 return host.run('test -c /dev/cros_fp',
595 ignore_status=True).exit_status == 0
596
597
Garry Wang17a829e2019-03-20 12:03:18 -0700598class ReferenceDesignLabel(base_label.StringPrefixLabel):
599 """Determine the correct reference design label for the device. """
600
601 _NAME = 'reference_design'
602
603 def __init__(self):
604 self.response = None
605
606 def exists(self, host):
607 self.response = host.run('mosys platform family', ignore_status=True)
608 return self.response.exit_status == 0
609
610 def generate_labels(self, host):
611 if self.exists(host):
612 return [self.response.stdout.strip()]
613
614
Kevin Chenga2619dc2016-03-28 11:42:08 -0700615CROS_LABELS = [
616 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700617 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700618 AudioLoopbackDongleLabel(),
619 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000620 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600621 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700622 ChameleonConnectionLabel(),
623 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800624 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700625 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700626 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800627 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800628 DetachableBaseLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700629 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800630 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700631 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700632 InternalDisplayLabel(),
633 LightSensorLabel(),
634 LucidSleepLabel(),
635 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700636 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700637 ServoLabel(),
638 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700639 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700640]