blob: 8c8e11df690933c1df3e1058505ea77e0dfbd02a [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
Ned Nguyene0a619d2019-07-01 15:50:23 -0600116class BrandCodeLabel(base_label.StringPrefixLabel):
117 """Determine the correct brand_code (aka RLZ-code) for the device."""
118
119 _NAME = ds_constants.BRAND_CODE_LABEL
120
121 def generate_labels(self, host):
122 brand_code = host.host_info_store.get().brand_code
123 if brand_code:
124 return [brand_code]
125
126 mosys_cmd = 'mosys platform brand'
127 result = host.run(command=mosys_cmd, ignore_status=True)
128 if result.exit_status == 0:
129 return [result.stdout.strip()]
130
131 return []
132
133
Kevin Chenga2619dc2016-03-28 11:42:08 -0700134class BluetoothLabel(base_label.BaseLabel):
135 """Label indicating if bluetooth is detected."""
136
137 _NAME = 'bluetooth'
138
139 def exists(self, host):
C Shapirobcd9c862019-05-22 17:42:08 -0600140 # Based on crbug.com/966219, the label is flipping sometimes.
141 # Potentially this is caused by testing itself.
142 # Making this label permanently sticky.
143 info = host.host_info_store.get()
144 for label in info.labels:
145 if label.startswith(self._NAME):
146 return True
147
Kevin Chenga2619dc2016-03-28 11:42:08 -0700148 result = host.run('test -d /sys/class/bluetooth/hci0',
149 ignore_status=True)
150
151 return result.exit_status == 0
152
153
154class ECLabel(base_label.BaseLabel):
155 """Label to determine the type of EC on this host."""
156
157 _NAME = 'ec:cros'
158
159 def exists(self, host):
160 cmd = 'mosys ec info'
161 # The output should look like these, so that the last field should
162 # match our EC version scheme:
163 #
164 # stm | stm32f100 | snow_v1.3.139-375eb9f
165 # ti | Unknown-10de | peppy_v1.5.114-5d52788
166 #
167 # Non-Chrome OS ECs will look like these:
168 #
169 # ENE | KB932 | 00BE107A00
170 # ite | it8518 | 3.08
171 #
172 # And some systems don't have ECs at all (Lumpy, for example).
173 regexp = r'^.*\|\s*(\S+_v\d+\.\d+\.\d+-[0-9a-f]+)\s*$'
174
175 ecinfo = host.run(command=cmd, ignore_status=True)
176 if ecinfo.exit_status == 0:
177 res = re.search(regexp, ecinfo.stdout)
178 if res:
179 logging.info("EC version is %s", res.groups()[0])
180 return True
181 logging.info("%s got: %s", cmd, ecinfo.stdout)
182 # Has an EC, but it's not a Chrome OS EC
183 logging.info("%s exited with status %d", cmd, ecinfo.exit_status)
184 return False
185
186
Mary Ruthven935ebad2018-06-13 16:13:20 -0700187class Cr50Label(base_label.StringPrefixLabel):
188 """Label indicating the cr50 version."""
189
190 _NAME = 'cr50'
191
192 def __init__(self):
193 self.ver = None
194
195
196 def exists(self, host):
197 # Make sure the gsctool version command runs ok
198 self.ver = host.run('gsctool -a -f', ignore_status=True)
199 return self.ver.exit_status == 0
200
201
202 def generate_labels(self, host):
203 # Check the major version to determine prePVT vs PVT
Mary Ruthven35207022019-04-15 11:57:29 -0700204 version_info = re.search('RW (\d+\.(\d+)\.\d+)$', self.ver.stdout)
205 full_version = version_info.group(1)
206 major_version = int(version_info.group(2))
Mary Ruthven935ebad2018-06-13 16:13:20 -0700207 # PVT images have a odd major version prePVT have even
Mary Ruthven35207022019-04-15 11:57:29 -0700208 return [full_version, 'pvt' if (major_version % 2) else 'prepvt']
Mary Ruthven935ebad2018-06-13 16:13:20 -0700209
210
Kevin Chenga2619dc2016-03-28 11:42:08 -0700211class AccelsLabel(base_label.BaseLabel):
212 """Determine the type of accelerometers on this host."""
213
214 _NAME = 'accel:cros-ec'
215
216 def exists(self, host):
217 # Check to make sure we have ectool
218 rv = host.run('which ectool', ignore_status=True)
219 if rv.exit_status:
220 logging.info("No ectool cmd found; assuming no EC accelerometers")
221 return False
222
223 # Check that the EC supports the motionsense command
Kevin Cheng856f8a32016-03-31 16:08:08 -0700224 rv = host.run('ectool motionsense', ignore_status=True)
Kevin Chenga2619dc2016-03-28 11:42:08 -0700225 if rv.exit_status:
226 logging.info("EC does not support motionsense command; "
227 "assuming no EC accelerometers")
228 return False
229
230 # Check that EC motion sensors are active
Kevin Cheng17e2f002016-05-04 08:48:03 -0700231 active = host.run('ectool motionsense active').stdout.split('\n')
Kevin Chenga2619dc2016-03-28 11:42:08 -0700232 if active[0] == "0":
233 logging.info("Motion sense inactive; assuming no EC accelerometers")
234 return False
235
236 logging.info("EC accelerometers found")
237 return True
238
239
240class ChameleonLabel(base_label.BaseLabel):
241 """Determine if a Chameleon is connected to this host."""
242
243 _NAME = 'chameleon'
244
245 def exists(self, host):
howardchung83e55272019-08-08 14:08:05 +0800246 return len(host._chameleon_host_list) > 0
Kevin Chenga2619dc2016-03-28 11:42:08 -0700247
248
249class ChameleonConnectionLabel(base_label.StringPrefixLabel):
250 """Return the Chameleon connection label."""
251
252 _NAME = 'chameleon'
253
254 def exists(self, host):
howardchung83e55272019-08-08 14:08:05 +0800255 return len(host._chameleon_host_list) > 0
Kevin Chenga2619dc2016-03-28 11:42:08 -0700256
Joseph Hwangeac44312016-08-31 12:08:38 +0800257
Kevin Chenga2619dc2016-03-28 11:42:08 -0700258 def generate_labels(self, host):
howardchung83e55272019-08-08 14:08:05 +0800259 return [[chameleon.get_label()] for chameleon in host.chameleon_list]
Kevin Chenga2619dc2016-03-28 11:42:08 -0700260
261
Joseph Hwangeac44312016-08-31 12:08:38 +0800262class ChameleonPeripheralsLabel(base_label.StringPrefixLabel):
263 """Return the Chameleon peripherals labels.
264
265 The 'chameleon:bt_hid' label is applied if the bluetooth
266 classic hid device, i.e, RN-42 emulation kit, is detected.
267
268 Any peripherals plugged into the chameleon board would be
269 detected and applied proper labels in this class.
270 """
271
272 _NAME = 'chameleon'
273
274 def exists(self, host):
howardchung83e55272019-08-08 14:08:05 +0800275 return len(host._chameleon_host_list) > 0
Joseph Hwangeac44312016-08-31 12:08:38 +0800276
277
278 def generate_labels(self, host):
howardchung83e55272019-08-08 14:08:05 +0800279 labels_list = []
280
281 for chameleon, chameleon_host in \
282 zip(host.chameleon_list, host._chameleon_host_list):
283 labels = []
284 try:
285 bt_hid_device = chameleon.get_bluetooth_hid_mouse()
286 if bt_hid_device.CheckSerialConnection():
287 labels.append('bt_hid')
288 except:
289 logging.error('Error with initializing bt_hid_mouse on '
290 'chameleon %s', chameleon_host.hostname)
291
292 try:
293 ble_hid_device = chameleon.get_ble_mouse()
294 if ble_hid_device.CheckSerialConnection():
295 labels.append('bt_ble_hid')
296 except:
297 logging.error('Error with initializing ble_hid_mouse on '
298 'chameleon %s', chameleon_host.hostname)
299
300 try:
301 bt_a2dp_sink = chameleon.get_bluetooth_a2dp_sink()
302 if bt_a2dp_sink.CheckSerialConnection():
303 labels.append('bt_a2dp_sink')
304 except:
305 logging.error('Error with initializing bt_a2dp_sink on '
306 'chameleon %s', chameleon_host.hostname)
307
308 if labels != []:
309 labels.append('bt_peer')
310
311 if host.multi_chameleon:
312 labels_list.append(labels)
313 else:
314 labels_list.extend(labels)
315
316
317 logging.info('Bluetooth labels are %s', labels_list)
318 return labels_list
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700319
320
Joseph Hwangeac44312016-08-31 12:08:38 +0800321
322
Kevin Chenga2619dc2016-03-28 11:42:08 -0700323class AudioLoopbackDongleLabel(base_label.BaseLabel):
324 """Return the label if an audio loopback dongle is plugged in."""
325
326 _NAME = 'audio_loopback_dongle'
327
328 def exists(self, host):
Gregory Nisbete280ea22019-08-16 17:50:03 -0700329 # Based on crbug.com/991285, AudioLoopbackDongle sometimes flips.
330 # Ensure that AudioLoopbackDongle.exists returns True
331 # forever, after it returns True *once*.
332 if self._cached_exists(host):
333 # If the current state is True, return it, don't run the command on
334 # the DUT and potentially flip the state.
335 return True
336 # If the current state is not True, run the command on
337 # the DUT. The new state will be set to whatever the command
338 # produces.
339 return self._host_run_exists(host)
340
341 def _cached_exists(self, host):
342 """Get the state of AudioLoopbackDongle in the data store"""
343 info = host.host_info_store.get()
344 for label in info.labels:
345 if label.startswith(self._NAME):
346 return True
347 return False
348
349 def _host_run_exists(self, host):
350 """Detect presence of audio_loopback_dongle by physically
351 running a command on the DUT."""
Kevin Chenga2619dc2016-03-28 11:42:08 -0700352 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
353 ignore_status=True).stdout
354 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
355 cras_utils.node_type_is_plugged('MIC', nodes_info)):
356 return True
357 return False
358
359
360class PowerSupplyLabel(base_label.StringPrefixLabel):
361 """
362 Return the label describing the power supply type.
363
364 Labels representing this host's power supply.
365 * `power:battery` when the device has a battery intended for
366 extended use
367 * `power:AC_primary` when the device has a battery not intended
368 for extended use (for moving the machine, etc)
369 * `power:AC_only` when the device has no battery at all.
370 """
371
372 _NAME = 'power'
373
374 def __init__(self):
375 self.psu_cmd_result = None
376
377
378 def exists(self, host):
379 self.psu_cmd_result = host.run(command='mosys psu type',
380 ignore_status=True)
381 return self.psu_cmd_result.stdout.strip() != 'unknown'
382
383
384 def generate_labels(self, host):
385 if self.psu_cmd_result.exit_status:
386 # The psu command for mosys is not included for all platforms. The
387 # assumption is that the device will have a battery if the command
388 # is not found.
389 return ['battery']
390 return [self.psu_cmd_result.stdout.strip()]
391
392
393class StorageLabel(base_label.StringPrefixLabel):
394 """
395 Return the label describing the storage type.
396
397 Determine if the internal device is SCSI or dw_mmc device.
398 Then check that it is SSD or HDD or eMMC or something else.
399
400 Labels representing this host's internal device type:
401 * `storage:ssd` when internal device is solid state drive
402 * `storage:hdd` when internal device is hard disk drive
403 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700404 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700405 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700406 * None When internal device is something else or
407 when we are unable to determine the type
408 """
409
410 _NAME = 'storage'
411
412 def __init__(self):
413 self.type_str = ''
414
415
416 def exists(self, host):
417 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
418 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
419 '. /usr/share/misc/chromeos-common.sh;',
420 'load_base_vars;',
421 'get_fixed_dst_drive'])
422 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
423 if rootdev.exit_status:
424 logging.info("Fail to run %s", rootdev_cmd)
425 return False
426 rootdev_str = rootdev.stdout.strip()
427
428 if not rootdev_str:
429 return False
430
431 rootdev_base = os.path.basename(rootdev_str)
432
433 mmc_pattern = '/dev/mmcblk[0-9]'
434 if re.match(mmc_pattern, rootdev_str):
435 # Use type to determine if the internal device is eMMC or somthing
436 # else. We can assume that MMC is always an internal device.
437 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
438 type = host.run(command=type_cmd, ignore_status=True)
439 if type.exit_status:
440 logging.info("Fail to run %s", type_cmd)
441 return False
442 type_str = type.stdout.strip()
443
444 if type_str == 'MMC':
445 self.type_str = 'mmc'
446 return True
447
448 scsi_pattern = '/dev/sd[a-z]+'
449 if re.match(scsi_pattern, rootdev.stdout):
450 # Read symlink for /sys/block/sd* to determine if the internal
451 # device is connected via ata or usb.
452 link_cmd = 'readlink /sys/block/%s' % rootdev_base
453 link = host.run(command=link_cmd, ignore_status=True)
454 if link.exit_status:
455 logging.info("Fail to run %s", link_cmd)
456 return False
457 link_str = link.stdout.strip()
458 if 'usb' in link_str:
459 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700460 elif 'ufs' in link_str:
461 self.type_str = 'ufs'
462 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700463
464 # Read rotation to determine if the internal device is ssd or hdd.
465 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
466 % rootdev_base)
467 rotate = host.run(command=rotate_cmd, ignore_status=True)
468 if rotate.exit_status:
469 logging.info("Fail to run %s", rotate_cmd)
470 return False
471 rotate_str = rotate.stdout.strip()
472
473 rotate_dict = {'0':'ssd', '1':'hdd'}
474 self.type_str = rotate_dict.get(rotate_str)
475 return True
476
Gwendal Grignou327fec62017-07-26 15:25:43 -0700477 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
478 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800479 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700480 return True
481
Kevin Chenga2619dc2016-03-28 11:42:08 -0700482 # All other internal device / error case will always fall here
483 return False
484
485
486 def generate_labels(self, host):
487 return [self.type_str]
488
489
490class ServoLabel(base_label.BaseLabel):
491 """Label to apply if a servo is present."""
492
493 _NAME = 'servo'
494
495 def exists(self, host):
Gregory Nisbet8b008f82019-08-20 13:06:19 -0700496 # Based on crbug.com/995900, Servo sometimes flips.
497 # Ensure that ServoLabel.exists returns True
498 # forever, after it returns True *once*.
499 if self._cached_exists(host):
500 # If the current state is True, return it, don't run the command on
501 # the DUT and potentially flip the state.
502 return True
503 # If the current state is not True, run the command on
504 # the DUT. The new state will be set to whatever the command
505 # produces.
506 return self._host_run_exists(host)
507
508 def _cached_exists(self, host):
509 """Get the state of Servo in the data store"""
510 info = host.host_info_store.get()
511 for label in info.labels:
512 if label.startswith(self._NAME):
513 return True
514 return False
515
516 def _host_run_exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700517 """
518 Check if the servo label should apply to the host or not.
519
520 @returns True if a servo host is detected, False otherwise.
521 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700522 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700523 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700524 if servo_args:
525 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700526 return (servo_host_hostname is not None
527 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700528
529
Ilja H. Friedel50290642017-12-01 19:39:53 -0800530class ArcLabel(base_label.BaseLabel):
531 """Label indicates if host has ARC support."""
532
533 _NAME = 'arc'
534
535 @base_label.forever_exists_decorate
536 def exists(self, host):
537 return 0 == host.run(
538 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
539 ignore_status=True).exit_status
540
541
542class CtsArchLabel(base_label.StringLabel):
543 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700544
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700545 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700546
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700547 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700548 """Return supported CTS ABIs.
549
550 @return List of supported CTS bundle ABIs.
551 """
552 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700553 return cts_abis.get(arch, [])
554
555 def _get_cts_cpus(self, arch):
556 """Return supported CTS native CPUs.
557
558 This is needed for CTS_Instant scheduling.
559 @return List of supported CTS native CPUs.
560 """
561 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
562 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700563
Rohit Makasana5a153502016-06-13 15:50:09 -0700564 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700565 cpu_arch = host.get_cpu_arch()
566 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
567 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
568 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700569
570
Kevin Chenga2619dc2016-03-28 11:42:08 -0700571class VideoGlitchLabel(base_label.BaseLabel):
572 """Label indicates if host supports video glitch detection tests."""
573
574 _NAME = 'video_glitch_detection'
575
576 def exists(self, host):
577 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
578
579 return board in video_test_constants.SUPPORTED_BOARDS
580
581
Kevin Chenga2619dc2016-03-28 11:42:08 -0700582class InternalDisplayLabel(base_label.StringLabel):
583 """Label that determines if the device has an internal display."""
584
585 _NAME = 'internal_display'
586
587 def generate_labels(self, host):
588 from autotest_lib.client.cros.graphics import graphics_utils
589 from autotest_lib.client.common_lib import utils as common_utils
590
591 def __system_output(cmd):
592 return host.run(cmd).stdout
593
594 def __read_file(remote_path):
595 return host.run('cat %s' % remote_path).stdout
596
597 # Hijack the necessary client functions so that we can take advantage
598 # of the client lib here.
599 # FIXME: find a less hacky way than this
600 original_system_output = utils.system_output
601 original_read_file = common_utils.read_file
602 utils.system_output = __system_output
603 common_utils.read_file = __read_file
604 try:
605 return ([self._NAME]
606 if graphics_utils.has_internal_display()
607 else [])
608 finally:
609 utils.system_output = original_system_output
610 common_utils.read_file = original_read_file
611
612
613class LucidSleepLabel(base_label.BaseLabel):
614 """Label that determines if device has support for lucid sleep."""
615
616 # TODO(kevcheng): See if we can determine if this label is applicable a
617 # better way (crbug.com/592146).
618 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700619 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700620
621 def exists(self, host):
622 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
623 return board in self.LUCID_SLEEP_BOARDS
624
625
Kevin Cheng80ad5732016-03-31 16:01:56 -0700626class HWIDLabel(base_label.StringLabel):
627 """Return all the labels generated from the hwid."""
628
629 # We leave out _NAME because hwid_lib will generate everything for us.
630
631 def __init__(self):
632 # Grab the key file needed to access the hwid service.
633 self.key_file = global_config.global_config.get_config_value(
634 'CROS', 'HWID_KEY', type=str)
635
636
637 def generate_labels(self, host):
638 hwid_labels = []
639 hwid = host.run_output('crossystem hwid').strip()
640 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
641 self.key_file).get('labels', [])
642
643 for hwid_info in hwid_info_list:
644 # If it's a prefix, we'll have:
645 # {'name': prefix_label, 'value': postfix_label} and create
646 # 'prefix_label:postfix_label'; otherwise it'll just be
647 # {'name': label} which should just be 'label'.
648 value = hwid_info.get('value', '')
649 name = hwid_info.get('name', '')
650 # There should always be a name but just in case there is not.
651 if name:
652 hwid_labels.append(name if not value else
653 '%s:%s' % (name, value))
654 return hwid_labels
655
656
657 def get_all_labels(self):
658 """We need to try all labels as a prefix and as standalone.
659
660 We don't know for sure which labels are prefix labels and which are
661 standalone so we try all of them as both.
662 """
663 all_hwid_labels = []
664 try:
665 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
666 self.key_file)
667 except IOError:
668 logging.error('Can not open key file: %s', self.key_file)
669 except hwid_lib.HwIdException as e:
670 logging.error('hwid service: %s', e)
671 return all_hwid_labels, all_hwid_labels
672
673
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800674class DetachableBaseLabel(base_label.BaseLabel):
675 """Label indicating if device has detachable keyboard."""
676
677 _NAME = 'detachablebase'
678
679 def exists(self, host):
680 return host.run('which hammerd', ignore_status=True).exit_status == 0
681
682
Tom Hughese9552342018-12-18 14:29:25 -0800683class FingerprintLabel(base_label.BaseLabel):
684 """Label indicating whether device has fingerprint sensor."""
685
686 _NAME = 'fingerprint'
687
688 def exists(self, host):
689 return host.run('test -c /dev/cros_fp',
690 ignore_status=True).exit_status == 0
691
692
Garry Wang17a829e2019-03-20 12:03:18 -0700693class ReferenceDesignLabel(base_label.StringPrefixLabel):
694 """Determine the correct reference design label for the device. """
695
696 _NAME = 'reference_design'
697
698 def __init__(self):
699 self.response = None
700
701 def exists(self, host):
702 self.response = host.run('mosys platform family', ignore_status=True)
703 return self.response.exit_status == 0
704
705 def generate_labels(self, host):
706 if self.exists(host):
707 return [self.response.stdout.strip()]
708
709
Kevin Chenga2619dc2016-03-28 11:42:08 -0700710CROS_LABELS = [
711 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700712 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700713 AudioLoopbackDongleLabel(),
714 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000715 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600716 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700717 ChameleonConnectionLabel(),
718 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800719 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700720 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700721 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800722 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800723 DetachableBaseLabel(),
C Shapiro8315f5f2019-06-19 15:53:29 -0600724 DeviceSkuLabel(),
Ned Nguyene0a619d2019-07-01 15:50:23 -0600725 BrandCodeLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700726 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800727 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700728 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700729 InternalDisplayLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700730 LucidSleepLabel(),
731 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700732 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700733 ServoLabel(),
734 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700735 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700736]
Garry Wange4b6d6e2019-06-17 17:08:46 -0700737
738LABSTATION_LABELS = [
739 BoardLabel(),
740 ModelLabel(),
741 common_label.OSLabel(),
742]