blob: 2b01b491b9bf077faab4d5b29e83538114341154 [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):
129 result = host.run('test -d /sys/class/bluetooth/hci0',
130 ignore_status=True)
131
132 return result.exit_status == 0
133
134
135class ECLabel(base_label.BaseLabel):
136 """Label to determine the type of EC on this host."""
137
138 _NAME = 'ec:cros'
139
140 def exists(self, host):
141 cmd = 'mosys ec info'
142 # The output should look like these, so that the last field should
143 # match our EC version scheme:
144 #
145 # stm | stm32f100 | snow_v1.3.139-375eb9f
146 # ti | Unknown-10de | peppy_v1.5.114-5d52788
147 #
148 # Non-Chrome OS ECs will look like these:
149 #
150 # ENE | KB932 | 00BE107A00
151 # ite | it8518 | 3.08
152 #
153 # And some systems don't have ECs at all (Lumpy, for example).
154 regexp = r'^.*\|\s*(\S+_v\d+\.\d+\.\d+-[0-9a-f]+)\s*$'
155
156 ecinfo = host.run(command=cmd, ignore_status=True)
157 if ecinfo.exit_status == 0:
158 res = re.search(regexp, ecinfo.stdout)
159 if res:
160 logging.info("EC version is %s", res.groups()[0])
161 return True
162 logging.info("%s got: %s", cmd, ecinfo.stdout)
163 # Has an EC, but it's not a Chrome OS EC
164 logging.info("%s exited with status %d", cmd, ecinfo.exit_status)
165 return False
166
167
Mary Ruthven935ebad2018-06-13 16:13:20 -0700168class Cr50Label(base_label.StringPrefixLabel):
169 """Label indicating the cr50 version."""
170
171 _NAME = 'cr50'
172
173 def __init__(self):
174 self.ver = None
175
176
177 def exists(self, host):
178 # Make sure the gsctool version command runs ok
179 self.ver = host.run('gsctool -a -f', ignore_status=True)
180 return self.ver.exit_status == 0
181
182
183 def generate_labels(self, host):
184 # Check the major version to determine prePVT vs PVT
185 major_ver = int(re.search('RW \d+\.(\d+)\.\d+[\r\n]',
186 self.ver.stdout).group(1))
187 # PVT images have a odd major version prePVT have even
188 return ['pvt' if (major_ver % 2) else 'prepvt']
189
190
Kevin Chenga2619dc2016-03-28 11:42:08 -0700191class AccelsLabel(base_label.BaseLabel):
192 """Determine the type of accelerometers on this host."""
193
194 _NAME = 'accel:cros-ec'
195
196 def exists(self, host):
197 # Check to make sure we have ectool
198 rv = host.run('which ectool', ignore_status=True)
199 if rv.exit_status:
200 logging.info("No ectool cmd found; assuming no EC accelerometers")
201 return False
202
203 # Check that the EC supports the motionsense command
Kevin Cheng856f8a32016-03-31 16:08:08 -0700204 rv = host.run('ectool motionsense', ignore_status=True)
Kevin Chenga2619dc2016-03-28 11:42:08 -0700205 if rv.exit_status:
206 logging.info("EC does not support motionsense command; "
207 "assuming no EC accelerometers")
208 return False
209
210 # Check that EC motion sensors are active
Kevin Cheng17e2f002016-05-04 08:48:03 -0700211 active = host.run('ectool motionsense active').stdout.split('\n')
Kevin Chenga2619dc2016-03-28 11:42:08 -0700212 if active[0] == "0":
213 logging.info("Motion sense inactive; assuming no EC accelerometers")
214 return False
215
216 logging.info("EC accelerometers found")
217 return True
218
219
220class ChameleonLabel(base_label.BaseLabel):
221 """Determine if a Chameleon is connected to this host."""
222
223 _NAME = 'chameleon'
224
225 def exists(self, host):
226 return host._chameleon_host is not None
227
228
229class ChameleonConnectionLabel(base_label.StringPrefixLabel):
230 """Return the Chameleon connection label."""
231
232 _NAME = 'chameleon'
233
234 def exists(self, host):
235 return host._chameleon_host is not None
236
Joseph Hwangeac44312016-08-31 12:08:38 +0800237
Kevin Chenga2619dc2016-03-28 11:42:08 -0700238 def generate_labels(self, host):
239 return [host.chameleon.get_label()]
240
241
Joseph Hwangeac44312016-08-31 12:08:38 +0800242class ChameleonPeripheralsLabel(base_label.StringPrefixLabel):
243 """Return the Chameleon peripherals labels.
244
245 The 'chameleon:bt_hid' label is applied if the bluetooth
246 classic hid device, i.e, RN-42 emulation kit, is detected.
247
248 Any peripherals plugged into the chameleon board would be
249 detected and applied proper labels in this class.
250 """
251
252 _NAME = 'chameleon'
253
254 def exists(self, host):
255 return host._chameleon_host is not None
256
257
258 def generate_labels(self, host):
Joseph Hwangbf6b0752018-08-10 08:18:10 +0800259 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
Joseph Hwangeac44312016-08-31 12:08:38 +0800260 return ['bt_hid'] if bt_hid_device.CheckSerialConnection() else []
261
262
Kevin Chenga2619dc2016-03-28 11:42:08 -0700263class AudioLoopbackDongleLabel(base_label.BaseLabel):
264 """Return the label if an audio loopback dongle is plugged in."""
265
266 _NAME = 'audio_loopback_dongle'
267
268 def exists(self, host):
269 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
270 ignore_status=True).stdout
271 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
272 cras_utils.node_type_is_plugged('MIC', nodes_info)):
273 return True
274 return False
275
276
277class PowerSupplyLabel(base_label.StringPrefixLabel):
278 """
279 Return the label describing the power supply type.
280
281 Labels representing this host's power supply.
282 * `power:battery` when the device has a battery intended for
283 extended use
284 * `power:AC_primary` when the device has a battery not intended
285 for extended use (for moving the machine, etc)
286 * `power:AC_only` when the device has no battery at all.
287 """
288
289 _NAME = 'power'
290
291 def __init__(self):
292 self.psu_cmd_result = None
293
294
295 def exists(self, host):
296 self.psu_cmd_result = host.run(command='mosys psu type',
297 ignore_status=True)
298 return self.psu_cmd_result.stdout.strip() != 'unknown'
299
300
301 def generate_labels(self, host):
302 if self.psu_cmd_result.exit_status:
303 # The psu command for mosys is not included for all platforms. The
304 # assumption is that the device will have a battery if the command
305 # is not found.
306 return ['battery']
307 return [self.psu_cmd_result.stdout.strip()]
308
309
310class StorageLabel(base_label.StringPrefixLabel):
311 """
312 Return the label describing the storage type.
313
314 Determine if the internal device is SCSI or dw_mmc device.
315 Then check that it is SSD or HDD or eMMC or something else.
316
317 Labels representing this host's internal device type:
318 * `storage:ssd` when internal device is solid state drive
319 * `storage:hdd` when internal device is hard disk drive
320 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700321 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700322 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700323 * None When internal device is something else or
324 when we are unable to determine the type
325 """
326
327 _NAME = 'storage'
328
329 def __init__(self):
330 self.type_str = ''
331
332
333 def exists(self, host):
334 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
335 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
336 '. /usr/share/misc/chromeos-common.sh;',
337 'load_base_vars;',
338 'get_fixed_dst_drive'])
339 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
340 if rootdev.exit_status:
341 logging.info("Fail to run %s", rootdev_cmd)
342 return False
343 rootdev_str = rootdev.stdout.strip()
344
345 if not rootdev_str:
346 return False
347
348 rootdev_base = os.path.basename(rootdev_str)
349
350 mmc_pattern = '/dev/mmcblk[0-9]'
351 if re.match(mmc_pattern, rootdev_str):
352 # Use type to determine if the internal device is eMMC or somthing
353 # else. We can assume that MMC is always an internal device.
354 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
355 type = host.run(command=type_cmd, ignore_status=True)
356 if type.exit_status:
357 logging.info("Fail to run %s", type_cmd)
358 return False
359 type_str = type.stdout.strip()
360
361 if type_str == 'MMC':
362 self.type_str = 'mmc'
363 return True
364
365 scsi_pattern = '/dev/sd[a-z]+'
366 if re.match(scsi_pattern, rootdev.stdout):
367 # Read symlink for /sys/block/sd* to determine if the internal
368 # device is connected via ata or usb.
369 link_cmd = 'readlink /sys/block/%s' % rootdev_base
370 link = host.run(command=link_cmd, ignore_status=True)
371 if link.exit_status:
372 logging.info("Fail to run %s", link_cmd)
373 return False
374 link_str = link.stdout.strip()
375 if 'usb' in link_str:
376 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700377 elif 'ufs' in link_str:
378 self.type_str = 'ufs'
379 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700380
381 # Read rotation to determine if the internal device is ssd or hdd.
382 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
383 % rootdev_base)
384 rotate = host.run(command=rotate_cmd, ignore_status=True)
385 if rotate.exit_status:
386 logging.info("Fail to run %s", rotate_cmd)
387 return False
388 rotate_str = rotate.stdout.strip()
389
390 rotate_dict = {'0':'ssd', '1':'hdd'}
391 self.type_str = rotate_dict.get(rotate_str)
392 return True
393
Gwendal Grignou327fec62017-07-26 15:25:43 -0700394 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
395 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800396 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700397 return True
398
Kevin Chenga2619dc2016-03-28 11:42:08 -0700399 # All other internal device / error case will always fall here
400 return False
401
402
403 def generate_labels(self, host):
404 return [self.type_str]
405
406
407class ServoLabel(base_label.BaseLabel):
408 """Label to apply if a servo is present."""
409
410 _NAME = 'servo'
411
412 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700413 """
414 Check if the servo label should apply to the host or not.
415
416 @returns True if a servo host is detected, False otherwise.
417 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700418 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700419 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700420 if servo_args:
421 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700422 return (servo_host_hostname is not None
423 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700424
425
Ilja H. Friedel50290642017-12-01 19:39:53 -0800426class ArcLabel(base_label.BaseLabel):
427 """Label indicates if host has ARC support."""
428
429 _NAME = 'arc'
430
431 @base_label.forever_exists_decorate
432 def exists(self, host):
433 return 0 == host.run(
434 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
435 ignore_status=True).exit_status
436
437
438class CtsArchLabel(base_label.StringLabel):
439 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700440
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700441 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700442
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700443 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700444 """Return supported CTS ABIs.
445
446 @return List of supported CTS bundle ABIs.
447 """
448 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700449 return cts_abis.get(arch, [])
450
451 def _get_cts_cpus(self, arch):
452 """Return supported CTS native CPUs.
453
454 This is needed for CTS_Instant scheduling.
455 @return List of supported CTS native CPUs.
456 """
457 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
458 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700459
Rohit Makasana5a153502016-06-13 15:50:09 -0700460 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700461 cpu_arch = host.get_cpu_arch()
462 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
463 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
464 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700465
466
Kevin Chenga2619dc2016-03-28 11:42:08 -0700467class VideoGlitchLabel(base_label.BaseLabel):
468 """Label indicates if host supports video glitch detection tests."""
469
470 _NAME = 'video_glitch_detection'
471
472 def exists(self, host):
473 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
474
475 return board in video_test_constants.SUPPORTED_BOARDS
476
477
Kevin Chenga2619dc2016-03-28 11:42:08 -0700478class InternalDisplayLabel(base_label.StringLabel):
479 """Label that determines if the device has an internal display."""
480
481 _NAME = 'internal_display'
482
483 def generate_labels(self, host):
484 from autotest_lib.client.cros.graphics import graphics_utils
485 from autotest_lib.client.common_lib import utils as common_utils
486
487 def __system_output(cmd):
488 return host.run(cmd).stdout
489
490 def __read_file(remote_path):
491 return host.run('cat %s' % remote_path).stdout
492
493 # Hijack the necessary client functions so that we can take advantage
494 # of the client lib here.
495 # FIXME: find a less hacky way than this
496 original_system_output = utils.system_output
497 original_read_file = common_utils.read_file
498 utils.system_output = __system_output
499 common_utils.read_file = __read_file
500 try:
501 return ([self._NAME]
502 if graphics_utils.has_internal_display()
503 else [])
504 finally:
505 utils.system_output = original_system_output
506 common_utils.read_file = original_read_file
507
508
509class LucidSleepLabel(base_label.BaseLabel):
510 """Label that determines if device has support for lucid sleep."""
511
512 # TODO(kevcheng): See if we can determine if this label is applicable a
513 # better way (crbug.com/592146).
514 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700515 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700516
517 def exists(self, host):
518 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
519 return board in self.LUCID_SLEEP_BOARDS
520
521
Kevin Cheng80ad5732016-03-31 16:01:56 -0700522class HWIDLabel(base_label.StringLabel):
523 """Return all the labels generated from the hwid."""
524
525 # We leave out _NAME because hwid_lib will generate everything for us.
526
527 def __init__(self):
528 # Grab the key file needed to access the hwid service.
529 self.key_file = global_config.global_config.get_config_value(
530 'CROS', 'HWID_KEY', type=str)
531
532
533 def generate_labels(self, host):
534 hwid_labels = []
535 hwid = host.run_output('crossystem hwid').strip()
536 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
537 self.key_file).get('labels', [])
538
539 for hwid_info in hwid_info_list:
540 # If it's a prefix, we'll have:
541 # {'name': prefix_label, 'value': postfix_label} and create
542 # 'prefix_label:postfix_label'; otherwise it'll just be
543 # {'name': label} which should just be 'label'.
544 value = hwid_info.get('value', '')
545 name = hwid_info.get('name', '')
546 # There should always be a name but just in case there is not.
547 if name:
548 hwid_labels.append(name if not value else
549 '%s:%s' % (name, value))
550 return hwid_labels
551
552
553 def get_all_labels(self):
554 """We need to try all labels as a prefix and as standalone.
555
556 We don't know for sure which labels are prefix labels and which are
557 standalone so we try all of them as both.
558 """
559 all_hwid_labels = []
560 try:
561 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
562 self.key_file)
563 except IOError:
564 logging.error('Can not open key file: %s', self.key_file)
565 except hwid_lib.HwIdException as e:
566 logging.error('hwid service: %s', e)
567 return all_hwid_labels, all_hwid_labels
568
569
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800570class DetachableBaseLabel(base_label.BaseLabel):
571 """Label indicating if device has detachable keyboard."""
572
573 _NAME = 'detachablebase'
574
575 def exists(self, host):
576 return host.run('which hammerd', ignore_status=True).exit_status == 0
577
578
Tom Hughese9552342018-12-18 14:29:25 -0800579class FingerprintLabel(base_label.BaseLabel):
580 """Label indicating whether device has fingerprint sensor."""
581
582 _NAME = 'fingerprint'
583
584 def exists(self, host):
585 return host.run('test -c /dev/cros_fp',
586 ignore_status=True).exit_status == 0
587
588
Garry Wang17a829e2019-03-20 12:03:18 -0700589class ReferenceDesignLabel(base_label.StringPrefixLabel):
590 """Determine the correct reference design label for the device. """
591
592 _NAME = 'reference_design'
593
594 def __init__(self):
595 self.response = None
596
597 def exists(self, host):
598 self.response = host.run('mosys platform family', ignore_status=True)
599 return self.response.exit_status == 0
600
601 def generate_labels(self, host):
602 if self.exists(host):
603 return [self.response.stdout.strip()]
604
605
Kevin Chenga2619dc2016-03-28 11:42:08 -0700606CROS_LABELS = [
607 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700608 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700609 AudioLoopbackDongleLabel(),
610 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000611 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600612 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700613 ChameleonConnectionLabel(),
614 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800615 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700616 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700617 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800618 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800619 DetachableBaseLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700620 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800621 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700622 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700623 InternalDisplayLabel(),
624 LightSensorLabel(),
625 LucidSleepLabel(),
626 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700627 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700628 ServoLabel(),
629 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700630 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700631]