blob: dc3a3711f7167e630e2df6ebce0dc0cfd4cbc16b [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 = []
Shijin Abraham77c74882019-06-11 09:41:15 -0700287 try:
288 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
289 if bt_hid_device.CheckSerialConnection():
290 labels.append('bt_hid')
291 except:
292 logging.error('Error with initializing bt_hid_mouse')
293 try:
294 ble_hid_device = host.chameleon.get_ble_mouse()
295 if ble_hid_device.CheckSerialConnection():
296 labels.append('bt_ble_hid')
297 except:
298 logging.error('Error with initializing bt_ble_hid')
299 try:
300 bt_a2dp_sink = host.chameleon.get_bluetooth_a2dp_sink()
301 if bt_a2dp_sink.CheckSerialConnection():
302 labels.append('bt_a2dp_sink')
303 except:
304 logging.error('Error with initializing bt_a2dp_sink')
305 if labels != []:
306 labels.append('bt_peer')
307 logging.info('Bluetooth labels are %s', labels)
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700308 return labels
309
310
Joseph Hwangeac44312016-08-31 12:08:38 +0800311
312
Kevin Chenga2619dc2016-03-28 11:42:08 -0700313class AudioLoopbackDongleLabel(base_label.BaseLabel):
314 """Return the label if an audio loopback dongle is plugged in."""
315
316 _NAME = 'audio_loopback_dongle'
317
318 def exists(self, host):
319 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
320 ignore_status=True).stdout
321 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
322 cras_utils.node_type_is_plugged('MIC', nodes_info)):
323 return True
324 return False
325
326
327class PowerSupplyLabel(base_label.StringPrefixLabel):
328 """
329 Return the label describing the power supply type.
330
331 Labels representing this host's power supply.
332 * `power:battery` when the device has a battery intended for
333 extended use
334 * `power:AC_primary` when the device has a battery not intended
335 for extended use (for moving the machine, etc)
336 * `power:AC_only` when the device has no battery at all.
337 """
338
339 _NAME = 'power'
340
341 def __init__(self):
342 self.psu_cmd_result = None
343
344
345 def exists(self, host):
346 self.psu_cmd_result = host.run(command='mosys psu type',
347 ignore_status=True)
348 return self.psu_cmd_result.stdout.strip() != 'unknown'
349
350
351 def generate_labels(self, host):
352 if self.psu_cmd_result.exit_status:
353 # The psu command for mosys is not included for all platforms. The
354 # assumption is that the device will have a battery if the command
355 # is not found.
356 return ['battery']
357 return [self.psu_cmd_result.stdout.strip()]
358
359
360class StorageLabel(base_label.StringPrefixLabel):
361 """
362 Return the label describing the storage type.
363
364 Determine if the internal device is SCSI or dw_mmc device.
365 Then check that it is SSD or HDD or eMMC or something else.
366
367 Labels representing this host's internal device type:
368 * `storage:ssd` when internal device is solid state drive
369 * `storage:hdd` when internal device is hard disk drive
370 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700371 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700372 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700373 * None When internal device is something else or
374 when we are unable to determine the type
375 """
376
377 _NAME = 'storage'
378
379 def __init__(self):
380 self.type_str = ''
381
382
383 def exists(self, host):
384 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
385 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
386 '. /usr/share/misc/chromeos-common.sh;',
387 'load_base_vars;',
388 'get_fixed_dst_drive'])
389 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
390 if rootdev.exit_status:
391 logging.info("Fail to run %s", rootdev_cmd)
392 return False
393 rootdev_str = rootdev.stdout.strip()
394
395 if not rootdev_str:
396 return False
397
398 rootdev_base = os.path.basename(rootdev_str)
399
400 mmc_pattern = '/dev/mmcblk[0-9]'
401 if re.match(mmc_pattern, rootdev_str):
402 # Use type to determine if the internal device is eMMC or somthing
403 # else. We can assume that MMC is always an internal device.
404 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
405 type = host.run(command=type_cmd, ignore_status=True)
406 if type.exit_status:
407 logging.info("Fail to run %s", type_cmd)
408 return False
409 type_str = type.stdout.strip()
410
411 if type_str == 'MMC':
412 self.type_str = 'mmc'
413 return True
414
415 scsi_pattern = '/dev/sd[a-z]+'
416 if re.match(scsi_pattern, rootdev.stdout):
417 # Read symlink for /sys/block/sd* to determine if the internal
418 # device is connected via ata or usb.
419 link_cmd = 'readlink /sys/block/%s' % rootdev_base
420 link = host.run(command=link_cmd, ignore_status=True)
421 if link.exit_status:
422 logging.info("Fail to run %s", link_cmd)
423 return False
424 link_str = link.stdout.strip()
425 if 'usb' in link_str:
426 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700427 elif 'ufs' in link_str:
428 self.type_str = 'ufs'
429 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700430
431 # Read rotation to determine if the internal device is ssd or hdd.
432 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
433 % rootdev_base)
434 rotate = host.run(command=rotate_cmd, ignore_status=True)
435 if rotate.exit_status:
436 logging.info("Fail to run %s", rotate_cmd)
437 return False
438 rotate_str = rotate.stdout.strip()
439
440 rotate_dict = {'0':'ssd', '1':'hdd'}
441 self.type_str = rotate_dict.get(rotate_str)
442 return True
443
Gwendal Grignou327fec62017-07-26 15:25:43 -0700444 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
445 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800446 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700447 return True
448
Kevin Chenga2619dc2016-03-28 11:42:08 -0700449 # All other internal device / error case will always fall here
450 return False
451
452
453 def generate_labels(self, host):
454 return [self.type_str]
455
456
457class ServoLabel(base_label.BaseLabel):
458 """Label to apply if a servo is present."""
459
460 _NAME = 'servo'
461
462 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700463 """
464 Check if the servo label should apply to the host or not.
465
466 @returns True if a servo host is detected, False otherwise.
467 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700468 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700469 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700470 if servo_args:
471 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700472 return (servo_host_hostname is not None
473 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700474
475
Ilja H. Friedel50290642017-12-01 19:39:53 -0800476class ArcLabel(base_label.BaseLabel):
477 """Label indicates if host has ARC support."""
478
479 _NAME = 'arc'
480
481 @base_label.forever_exists_decorate
482 def exists(self, host):
483 return 0 == host.run(
484 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
485 ignore_status=True).exit_status
486
487
488class CtsArchLabel(base_label.StringLabel):
489 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700490
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700491 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700492
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700493 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700494 """Return supported CTS ABIs.
495
496 @return List of supported CTS bundle ABIs.
497 """
498 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700499 return cts_abis.get(arch, [])
500
501 def _get_cts_cpus(self, arch):
502 """Return supported CTS native CPUs.
503
504 This is needed for CTS_Instant scheduling.
505 @return List of supported CTS native CPUs.
506 """
507 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
508 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700509
Rohit Makasana5a153502016-06-13 15:50:09 -0700510 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700511 cpu_arch = host.get_cpu_arch()
512 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
513 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
514 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700515
516
Kevin Chenga2619dc2016-03-28 11:42:08 -0700517class VideoGlitchLabel(base_label.BaseLabel):
518 """Label indicates if host supports video glitch detection tests."""
519
520 _NAME = 'video_glitch_detection'
521
522 def exists(self, host):
523 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
524
525 return board in video_test_constants.SUPPORTED_BOARDS
526
527
Kevin Chenga2619dc2016-03-28 11:42:08 -0700528class InternalDisplayLabel(base_label.StringLabel):
529 """Label that determines if the device has an internal display."""
530
531 _NAME = 'internal_display'
532
533 def generate_labels(self, host):
534 from autotest_lib.client.cros.graphics import graphics_utils
535 from autotest_lib.client.common_lib import utils as common_utils
536
537 def __system_output(cmd):
538 return host.run(cmd).stdout
539
540 def __read_file(remote_path):
541 return host.run('cat %s' % remote_path).stdout
542
543 # Hijack the necessary client functions so that we can take advantage
544 # of the client lib here.
545 # FIXME: find a less hacky way than this
546 original_system_output = utils.system_output
547 original_read_file = common_utils.read_file
548 utils.system_output = __system_output
549 common_utils.read_file = __read_file
550 try:
551 return ([self._NAME]
552 if graphics_utils.has_internal_display()
553 else [])
554 finally:
555 utils.system_output = original_system_output
556 common_utils.read_file = original_read_file
557
558
559class LucidSleepLabel(base_label.BaseLabel):
560 """Label that determines if device has support for lucid sleep."""
561
562 # TODO(kevcheng): See if we can determine if this label is applicable a
563 # better way (crbug.com/592146).
564 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700565 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700566
567 def exists(self, host):
568 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
569 return board in self.LUCID_SLEEP_BOARDS
570
571
Kevin Cheng80ad5732016-03-31 16:01:56 -0700572class HWIDLabel(base_label.StringLabel):
573 """Return all the labels generated from the hwid."""
574
575 # We leave out _NAME because hwid_lib will generate everything for us.
576
577 def __init__(self):
578 # Grab the key file needed to access the hwid service.
579 self.key_file = global_config.global_config.get_config_value(
580 'CROS', 'HWID_KEY', type=str)
581
582
583 def generate_labels(self, host):
584 hwid_labels = []
585 hwid = host.run_output('crossystem hwid').strip()
586 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
587 self.key_file).get('labels', [])
588
589 for hwid_info in hwid_info_list:
590 # If it's a prefix, we'll have:
591 # {'name': prefix_label, 'value': postfix_label} and create
592 # 'prefix_label:postfix_label'; otherwise it'll just be
593 # {'name': label} which should just be 'label'.
594 value = hwid_info.get('value', '')
595 name = hwid_info.get('name', '')
596 # There should always be a name but just in case there is not.
597 if name:
598 hwid_labels.append(name if not value else
599 '%s:%s' % (name, value))
600 return hwid_labels
601
602
603 def get_all_labels(self):
604 """We need to try all labels as a prefix and as standalone.
605
606 We don't know for sure which labels are prefix labels and which are
607 standalone so we try all of them as both.
608 """
609 all_hwid_labels = []
610 try:
611 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
612 self.key_file)
613 except IOError:
614 logging.error('Can not open key file: %s', self.key_file)
615 except hwid_lib.HwIdException as e:
616 logging.error('hwid service: %s', e)
617 return all_hwid_labels, all_hwid_labels
618
619
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800620class DetachableBaseLabel(base_label.BaseLabel):
621 """Label indicating if device has detachable keyboard."""
622
623 _NAME = 'detachablebase'
624
625 def exists(self, host):
626 return host.run('which hammerd', ignore_status=True).exit_status == 0
627
628
Tom Hughese9552342018-12-18 14:29:25 -0800629class FingerprintLabel(base_label.BaseLabel):
630 """Label indicating whether device has fingerprint sensor."""
631
632 _NAME = 'fingerprint'
633
634 def exists(self, host):
635 return host.run('test -c /dev/cros_fp',
636 ignore_status=True).exit_status == 0
637
638
Garry Wang17a829e2019-03-20 12:03:18 -0700639class ReferenceDesignLabel(base_label.StringPrefixLabel):
640 """Determine the correct reference design label for the device. """
641
642 _NAME = 'reference_design'
643
644 def __init__(self):
645 self.response = None
646
647 def exists(self, host):
648 self.response = host.run('mosys platform family', ignore_status=True)
649 return self.response.exit_status == 0
650
651 def generate_labels(self, host):
652 if self.exists(host):
653 return [self.response.stdout.strip()]
654
655
Kevin Chenga2619dc2016-03-28 11:42:08 -0700656CROS_LABELS = [
657 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700658 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700659 AudioLoopbackDongleLabel(),
660 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000661 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600662 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700663 ChameleonConnectionLabel(),
664 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800665 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700666 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700667 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800668 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800669 DetachableBaseLabel(),
C Shapiro8315f5f2019-06-19 15:53:29 -0600670 DeviceSkuLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700671 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800672 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700673 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700674 InternalDisplayLabel(),
675 LightSensorLabel(),
676 LucidSleepLabel(),
677 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700678 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700679 ServoLabel(),
680 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700681 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700682]