blob: ce2245e4c2c447d08219dec6ee7df5979124f8ed [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):
246 return host._chameleon_host is not None
247
248
249class ChameleonConnectionLabel(base_label.StringPrefixLabel):
250 """Return the Chameleon connection label."""
251
252 _NAME = 'chameleon'
253
254 def exists(self, host):
255 return host._chameleon_host is not None
256
Joseph Hwangeac44312016-08-31 12:08:38 +0800257
Kevin Chenga2619dc2016-03-28 11:42:08 -0700258 def generate_labels(self, host):
259 return [host.chameleon.get_label()]
260
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):
275 return host._chameleon_host is not None
276
277
278 def generate_labels(self, host):
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700279 labels = []
Shijin Abraham77c74882019-06-11 09:41:15 -0700280 try:
281 bt_hid_device = host.chameleon.get_bluetooth_hid_mouse()
282 if bt_hid_device.CheckSerialConnection():
283 labels.append('bt_hid')
284 except:
285 logging.error('Error with initializing bt_hid_mouse')
286 try:
287 ble_hid_device = host.chameleon.get_ble_mouse()
288 if ble_hid_device.CheckSerialConnection():
289 labels.append('bt_ble_hid')
290 except:
291 logging.error('Error with initializing bt_ble_hid')
292 try:
293 bt_a2dp_sink = host.chameleon.get_bluetooth_a2dp_sink()
294 if bt_a2dp_sink.CheckSerialConnection():
295 labels.append('bt_a2dp_sink')
296 except:
297 logging.error('Error with initializing bt_a2dp_sink')
298 if labels != []:
299 labels.append('bt_peer')
300 logging.info('Bluetooth labels are %s', labels)
Shijin Abrahamff61ac32019-05-20 12:35:44 -0700301 return labels
302
303
Joseph Hwangeac44312016-08-31 12:08:38 +0800304
305
Kevin Chenga2619dc2016-03-28 11:42:08 -0700306class AudioLoopbackDongleLabel(base_label.BaseLabel):
307 """Return the label if an audio loopback dongle is plugged in."""
308
309 _NAME = 'audio_loopback_dongle'
310
311 def exists(self, host):
Gregory Nisbete280ea22019-08-16 17:50:03 -0700312 # Based on crbug.com/991285, AudioLoopbackDongle sometimes flips.
313 # Ensure that AudioLoopbackDongle.exists returns True
314 # forever, after it returns True *once*.
315 if self._cached_exists(host):
316 # If the current state is True, return it, don't run the command on
317 # the DUT and potentially flip the state.
318 return True
319 # If the current state is not True, run the command on
320 # the DUT. The new state will be set to whatever the command
321 # produces.
322 return self._host_run_exists(host)
323
324 def _cached_exists(self, host):
325 """Get the state of AudioLoopbackDongle in the data store"""
326 info = host.host_info_store.get()
327 for label in info.labels:
328 if label.startswith(self._NAME):
329 return True
330 return False
331
332 def _host_run_exists(self, host):
333 """Detect presence of audio_loopback_dongle by physically
334 running a command on the DUT."""
Kevin Chenga2619dc2016-03-28 11:42:08 -0700335 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
336 ignore_status=True).stdout
337 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
338 cras_utils.node_type_is_plugged('MIC', nodes_info)):
339 return True
340 return False
341
342
343class PowerSupplyLabel(base_label.StringPrefixLabel):
344 """
345 Return the label describing the power supply type.
346
347 Labels representing this host's power supply.
348 * `power:battery` when the device has a battery intended for
349 extended use
350 * `power:AC_primary` when the device has a battery not intended
351 for extended use (for moving the machine, etc)
352 * `power:AC_only` when the device has no battery at all.
353 """
354
355 _NAME = 'power'
356
357 def __init__(self):
358 self.psu_cmd_result = None
359
360
361 def exists(self, host):
362 self.psu_cmd_result = host.run(command='mosys psu type',
363 ignore_status=True)
364 return self.psu_cmd_result.stdout.strip() != 'unknown'
365
366
367 def generate_labels(self, host):
368 if self.psu_cmd_result.exit_status:
369 # The psu command for mosys is not included for all platforms. The
370 # assumption is that the device will have a battery if the command
371 # is not found.
372 return ['battery']
373 return [self.psu_cmd_result.stdout.strip()]
374
375
376class StorageLabel(base_label.StringPrefixLabel):
377 """
378 Return the label describing the storage type.
379
380 Determine if the internal device is SCSI or dw_mmc device.
381 Then check that it is SSD or HDD or eMMC or something else.
382
383 Labels representing this host's internal device type:
384 * `storage:ssd` when internal device is solid state drive
385 * `storage:hdd` when internal device is hard disk drive
386 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700387 * `storage:nvme` when internal device is NVMe drive
Alexis Savery570e7fb2018-06-26 10:48:15 -0700388 * `storage:ufs` when internal device is ufs drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700389 * None When internal device is something else or
390 when we are unable to determine the type
391 """
392
393 _NAME = 'storage'
394
395 def __init__(self):
396 self.type_str = ''
397
398
399 def exists(self, host):
400 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
401 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
402 '. /usr/share/misc/chromeos-common.sh;',
403 'load_base_vars;',
404 'get_fixed_dst_drive'])
405 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
406 if rootdev.exit_status:
407 logging.info("Fail to run %s", rootdev_cmd)
408 return False
409 rootdev_str = rootdev.stdout.strip()
410
411 if not rootdev_str:
412 return False
413
414 rootdev_base = os.path.basename(rootdev_str)
415
416 mmc_pattern = '/dev/mmcblk[0-9]'
417 if re.match(mmc_pattern, rootdev_str):
418 # Use type to determine if the internal device is eMMC or somthing
419 # else. We can assume that MMC is always an internal device.
420 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
421 type = host.run(command=type_cmd, ignore_status=True)
422 if type.exit_status:
423 logging.info("Fail to run %s", type_cmd)
424 return False
425 type_str = type.stdout.strip()
426
427 if type_str == 'MMC':
428 self.type_str = 'mmc'
429 return True
430
431 scsi_pattern = '/dev/sd[a-z]+'
432 if re.match(scsi_pattern, rootdev.stdout):
433 # Read symlink for /sys/block/sd* to determine if the internal
434 # device is connected via ata or usb.
435 link_cmd = 'readlink /sys/block/%s' % rootdev_base
436 link = host.run(command=link_cmd, ignore_status=True)
437 if link.exit_status:
438 logging.info("Fail to run %s", link_cmd)
439 return False
440 link_str = link.stdout.strip()
441 if 'usb' in link_str:
442 return False
Alexis Savery570e7fb2018-06-26 10:48:15 -0700443 elif 'ufs' in link_str:
444 self.type_str = 'ufs'
445 return True
Kevin Chenga2619dc2016-03-28 11:42:08 -0700446
447 # Read rotation to determine if the internal device is ssd or hdd.
448 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
449 % rootdev_base)
450 rotate = host.run(command=rotate_cmd, ignore_status=True)
451 if rotate.exit_status:
452 logging.info("Fail to run %s", rotate_cmd)
453 return False
454 rotate_str = rotate.stdout.strip()
455
456 rotate_dict = {'0':'ssd', '1':'hdd'}
457 self.type_str = rotate_dict.get(rotate_str)
458 return True
459
Gwendal Grignou327fec62017-07-26 15:25:43 -0700460 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
461 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800462 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700463 return True
464
Kevin Chenga2619dc2016-03-28 11:42:08 -0700465 # All other internal device / error case will always fall here
466 return False
467
468
469 def generate_labels(self, host):
470 return [self.type_str]
471
472
473class ServoLabel(base_label.BaseLabel):
474 """Label to apply if a servo is present."""
475
476 _NAME = 'servo'
477
478 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700479 """
480 Check if the servo label should apply to the host or not.
481
482 @returns True if a servo host is detected, False otherwise.
483 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700484 servo_host_hostname = None
Prathmesh Prabhu37ae79b2018-09-12 10:37:44 -0700485 servo_args = servo_host.get_servo_args_for_host(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700486 if servo_args:
487 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700488 return (servo_host_hostname is not None
489 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700490
491
Ilja H. Friedel50290642017-12-01 19:39:53 -0800492class ArcLabel(base_label.BaseLabel):
493 """Label indicates if host has ARC support."""
494
495 _NAME = 'arc'
496
497 @base_label.forever_exists_decorate
498 def exists(self, host):
499 return 0 == host.run(
500 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
501 ignore_status=True).exit_status
502
503
504class CtsArchLabel(base_label.StringLabel):
505 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
Rohit Makasana5a153502016-06-13 15:50:09 -0700506
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700507 _NAME = ['cts_abi_arm', 'cts_abi_x86', 'cts_cpu_arm', 'cts_cpu_x86']
Rohit Makasana5a153502016-06-13 15:50:09 -0700508
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700509 def _get_cts_abis(self, arch):
Rohit Makasana5a153502016-06-13 15:50:09 -0700510 """Return supported CTS ABIs.
511
512 @return List of supported CTS bundle ABIs.
513 """
514 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700515 return cts_abis.get(arch, [])
516
517 def _get_cts_cpus(self, arch):
518 """Return supported CTS native CPUs.
519
520 This is needed for CTS_Instant scheduling.
521 @return List of supported CTS native CPUs.
522 """
523 cts_cpus = {'x86_64': ['x86'], 'arm': ['arm']}
524 return cts_cpus.get(arch, [])
Rohit Makasana5a153502016-06-13 15:50:09 -0700525
Rohit Makasana5a153502016-06-13 15:50:09 -0700526 def generate_labels(self, host):
Ilja H. Friedela7502f52018-10-16 23:33:25 -0700527 cpu_arch = host.get_cpu_arch()
528 abi_labels = ['cts_abi_' + abi for abi in self._get_cts_abis(cpu_arch)]
529 cpu_labels = ['cts_cpu_' + cpu for cpu in self._get_cts_cpus(cpu_arch)]
530 return abi_labels + cpu_labels
Rohit Makasana5a153502016-06-13 15:50:09 -0700531
532
Kevin Chenga2619dc2016-03-28 11:42:08 -0700533class VideoGlitchLabel(base_label.BaseLabel):
534 """Label indicates if host supports video glitch detection tests."""
535
536 _NAME = 'video_glitch_detection'
537
538 def exists(self, host):
539 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
540
541 return board in video_test_constants.SUPPORTED_BOARDS
542
543
Kevin Chenga2619dc2016-03-28 11:42:08 -0700544class InternalDisplayLabel(base_label.StringLabel):
545 """Label that determines if the device has an internal display."""
546
547 _NAME = 'internal_display'
548
549 def generate_labels(self, host):
550 from autotest_lib.client.cros.graphics import graphics_utils
551 from autotest_lib.client.common_lib import utils as common_utils
552
553 def __system_output(cmd):
554 return host.run(cmd).stdout
555
556 def __read_file(remote_path):
557 return host.run('cat %s' % remote_path).stdout
558
559 # Hijack the necessary client functions so that we can take advantage
560 # of the client lib here.
561 # FIXME: find a less hacky way than this
562 original_system_output = utils.system_output
563 original_read_file = common_utils.read_file
564 utils.system_output = __system_output
565 common_utils.read_file = __read_file
566 try:
567 return ([self._NAME]
568 if graphics_utils.has_internal_display()
569 else [])
570 finally:
571 utils.system_output = original_system_output
572 common_utils.read_file = original_read_file
573
574
575class LucidSleepLabel(base_label.BaseLabel):
576 """Label that determines if device has support for lucid sleep."""
577
578 # TODO(kevcheng): See if we can determine if this label is applicable a
579 # better way (crbug.com/592146).
580 _NAME = 'lucidsleep'
RaviChandra Sadinenic06b00e2018-11-03 09:56:11 -0700581 LUCID_SLEEP_BOARDS = ['nocturne', 'poppy']
Kevin Chenga2619dc2016-03-28 11:42:08 -0700582
583 def exists(self, host):
584 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
585 return board in self.LUCID_SLEEP_BOARDS
586
587
Kevin Cheng80ad5732016-03-31 16:01:56 -0700588class HWIDLabel(base_label.StringLabel):
589 """Return all the labels generated from the hwid."""
590
591 # We leave out _NAME because hwid_lib will generate everything for us.
592
593 def __init__(self):
594 # Grab the key file needed to access the hwid service.
595 self.key_file = global_config.global_config.get_config_value(
596 'CROS', 'HWID_KEY', type=str)
597
598
599 def generate_labels(self, host):
600 hwid_labels = []
601 hwid = host.run_output('crossystem hwid').strip()
602 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
603 self.key_file).get('labels', [])
604
605 for hwid_info in hwid_info_list:
606 # If it's a prefix, we'll have:
607 # {'name': prefix_label, 'value': postfix_label} and create
608 # 'prefix_label:postfix_label'; otherwise it'll just be
609 # {'name': label} which should just be 'label'.
610 value = hwid_info.get('value', '')
611 name = hwid_info.get('name', '')
612 # There should always be a name but just in case there is not.
613 if name:
614 hwid_labels.append(name if not value else
615 '%s:%s' % (name, value))
616 return hwid_labels
617
618
619 def get_all_labels(self):
620 """We need to try all labels as a prefix and as standalone.
621
622 We don't know for sure which labels are prefix labels and which are
623 standalone so we try all of them as both.
624 """
625 all_hwid_labels = []
626 try:
627 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
628 self.key_file)
629 except IOError:
630 logging.error('Can not open key file: %s', self.key_file)
631 except hwid_lib.HwIdException as e:
632 logging.error('hwid service: %s', e)
633 return all_hwid_labels, all_hwid_labels
634
635
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800636class DetachableBaseLabel(base_label.BaseLabel):
637 """Label indicating if device has detachable keyboard."""
638
639 _NAME = 'detachablebase'
640
641 def exists(self, host):
642 return host.run('which hammerd', ignore_status=True).exit_status == 0
643
644
Tom Hughese9552342018-12-18 14:29:25 -0800645class FingerprintLabel(base_label.BaseLabel):
646 """Label indicating whether device has fingerprint sensor."""
647
648 _NAME = 'fingerprint'
649
650 def exists(self, host):
651 return host.run('test -c /dev/cros_fp',
652 ignore_status=True).exit_status == 0
653
654
Garry Wang17a829e2019-03-20 12:03:18 -0700655class ReferenceDesignLabel(base_label.StringPrefixLabel):
656 """Determine the correct reference design label for the device. """
657
658 _NAME = 'reference_design'
659
660 def __init__(self):
661 self.response = None
662
663 def exists(self, host):
664 self.response = host.run('mosys platform family', ignore_status=True)
665 return self.response.exit_status == 0
666
667 def generate_labels(self, host):
668 if self.exists(host):
669 return [self.response.stdout.strip()]
670
671
Kevin Chenga2619dc2016-03-28 11:42:08 -0700672CROS_LABELS = [
673 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700674 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700675 AudioLoopbackDongleLabel(),
676 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000677 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600678 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700679 ChameleonConnectionLabel(),
680 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800681 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700682 common_label.OSLabel(),
Mary Ruthven935ebad2018-06-13 16:13:20 -0700683 Cr50Label(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800684 CtsArchLabel(),
Chih-Yu Huangcaca4882018-01-30 11:21:48 +0800685 DetachableBaseLabel(),
C Shapiro8315f5f2019-06-19 15:53:29 -0600686 DeviceSkuLabel(),
Ned Nguyene0a619d2019-07-01 15:50:23 -0600687 BrandCodeLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700688 ECLabel(),
Tom Hughese9552342018-12-18 14:29:25 -0800689 FingerprintLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700690 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700691 InternalDisplayLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700692 LucidSleepLabel(),
693 PowerSupplyLabel(),
Garry Wang17a829e2019-03-20 12:03:18 -0700694 ReferenceDesignLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700695 ServoLabel(),
696 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700697 VideoGlitchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700698]
Garry Wange4b6d6e2019-06-17 17:08:46 -0700699
700LABSTATION_LABELS = [
701 BoardLabel(),
702 ModelLabel(),
703 common_label.OSLabel(),
704]