blob: 60e62f7f31bca4ba921bfe547199305fd5e883d6 [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):
28 """Parses the LSB output and returns key data points for labeling.
29
30 @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)
35
36 unibuild = release_info.get('CHROMEOS_RELEASE_UNIBUILD') == '1'
37 return LsbOutput(unibuild, release_info['CHROMEOS_RELEASE_BOARD'])
38
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.
51 for label in host._afe_host.labels:
52 if label.startswith(self._NAME + ':'):
53 return [label.split(':')[-1]]
54
C Shapiro10970222017-10-24 08:55:55 -060055 return [_parse_lsb_output(host).board]
Kevin Chenga8455302016-08-31 20:54:41 +000056
57
C Shapirob05c00b2017-07-18 15:06:49 -060058class ModelLabel(base_label.StringPrefixLabel):
59 """Determine the correct model label for the device."""
60
61 _NAME = ds_constants.MODEL_LABEL
62
63 def generate_labels(self, host):
C Shapiro32700032017-11-03 12:46:55 -060064 # TODO - Return the existing label once model labels become more stable.
C Shapirob05c00b2017-07-18 15:06:49 -060065
C Shapiro32700032017-11-03 12:46:55 -060066 lsb_output = _parse_lsb_output(host)
67 model = None
68
69 if lsb_output.unibuild:
C Shapiro26fb1012017-12-14 16:38:03 -070070 test_label_cmd = 'cros_config / test-label'
71 result = host.run(command=test_label_cmd, ignore_status=True)
C Shapiro32700032017-11-03 12:46:55 -060072 if result.exit_status == 0:
73 model = result.stdout.strip()
C Shapiro26fb1012017-12-14 16:38:03 -070074 if not model:
75 mosys_cmd = 'mosys platform model'
76 result = host.run(command=mosys_cmd, ignore_status=True)
77 if result.exit_status == 0:
78 model = result.stdout.strip()
C Shapiro32700032017-11-03 12:46:55 -060079
80 # We need some sort of backwards compatibility for boards that
81 # are not yet supported with mosys and unified builds.
82 # This is necessary so that we can begin changing cbuildbot to take
83 # advantage of the model/board label differentiations for
84 # scheduling, while still retaining backwards compatibility.
85 return [model or lsb_output.board]
C Shapirob05c00b2017-07-18 15:06:49 -060086
87
Kevin Chenga2619dc2016-03-28 11:42:08 -070088class LightSensorLabel(base_label.BaseLabel):
89 """Label indicating if a light sensor is detected."""
90
91 _NAME = 'lightsensor'
92 _LIGHTSENSOR_SEARCH_DIR = '/sys/bus/iio/devices'
93 _LIGHTSENSOR_FILES = [
94 "in_illuminance0_input",
95 "in_illuminance_input",
96 "in_illuminance0_raw",
97 "in_illuminance_raw",
98 "illuminance0_input",
99 ]
100
101 def exists(self, host):
102 search_cmd = "find -L %s -maxdepth 4 | egrep '%s'" % (
103 self._LIGHTSENSOR_SEARCH_DIR, '|'.join(self._LIGHTSENSOR_FILES))
104 # Run the search cmd following the symlinks. Stderr_tee is set to
105 # None as there can be a symlink loop, but the command will still
106 # execute correctly with a few messages printed to stderr.
107 result = host.run(search_cmd, stdout_tee=None, stderr_tee=None,
108 ignore_status=True)
109
110 return result.exit_status == 0
111
112
113class BluetoothLabel(base_label.BaseLabel):
114 """Label indicating if bluetooth is detected."""
115
116 _NAME = 'bluetooth'
117
118 def exists(self, host):
119 result = host.run('test -d /sys/class/bluetooth/hci0',
120 ignore_status=True)
121
122 return result.exit_status == 0
123
124
125class ECLabel(base_label.BaseLabel):
126 """Label to determine the type of EC on this host."""
127
128 _NAME = 'ec:cros'
129
130 def exists(self, host):
131 cmd = 'mosys ec info'
132 # The output should look like these, so that the last field should
133 # match our EC version scheme:
134 #
135 # stm | stm32f100 | snow_v1.3.139-375eb9f
136 # ti | Unknown-10de | peppy_v1.5.114-5d52788
137 #
138 # Non-Chrome OS ECs will look like these:
139 #
140 # ENE | KB932 | 00BE107A00
141 # ite | it8518 | 3.08
142 #
143 # And some systems don't have ECs at all (Lumpy, for example).
144 regexp = r'^.*\|\s*(\S+_v\d+\.\d+\.\d+-[0-9a-f]+)\s*$'
145
146 ecinfo = host.run(command=cmd, ignore_status=True)
147 if ecinfo.exit_status == 0:
148 res = re.search(regexp, ecinfo.stdout)
149 if res:
150 logging.info("EC version is %s", res.groups()[0])
151 return True
152 logging.info("%s got: %s", cmd, ecinfo.stdout)
153 # Has an EC, but it's not a Chrome OS EC
154 logging.info("%s exited with status %d", cmd, ecinfo.exit_status)
155 return False
156
157
158class AccelsLabel(base_label.BaseLabel):
159 """Determine the type of accelerometers on this host."""
160
161 _NAME = 'accel:cros-ec'
162
163 def exists(self, host):
164 # Check to make sure we have ectool
165 rv = host.run('which ectool', ignore_status=True)
166 if rv.exit_status:
167 logging.info("No ectool cmd found; assuming no EC accelerometers")
168 return False
169
170 # Check that the EC supports the motionsense command
Kevin Cheng856f8a32016-03-31 16:08:08 -0700171 rv = host.run('ectool motionsense', ignore_status=True)
Kevin Chenga2619dc2016-03-28 11:42:08 -0700172 if rv.exit_status:
173 logging.info("EC does not support motionsense command; "
174 "assuming no EC accelerometers")
175 return False
176
177 # Check that EC motion sensors are active
Kevin Cheng17e2f002016-05-04 08:48:03 -0700178 active = host.run('ectool motionsense active').stdout.split('\n')
Kevin Chenga2619dc2016-03-28 11:42:08 -0700179 if active[0] == "0":
180 logging.info("Motion sense inactive; assuming no EC accelerometers")
181 return False
182
183 logging.info("EC accelerometers found")
184 return True
185
186
187class ChameleonLabel(base_label.BaseLabel):
188 """Determine if a Chameleon is connected to this host."""
189
190 _NAME = 'chameleon'
191
192 def exists(self, host):
193 return host._chameleon_host is not None
194
195
196class ChameleonConnectionLabel(base_label.StringPrefixLabel):
197 """Return the Chameleon connection label."""
198
199 _NAME = 'chameleon'
200
201 def exists(self, host):
202 return host._chameleon_host is not None
203
Joseph Hwangeac44312016-08-31 12:08:38 +0800204
Kevin Chenga2619dc2016-03-28 11:42:08 -0700205 def generate_labels(self, host):
206 return [host.chameleon.get_label()]
207
208
Joseph Hwangeac44312016-08-31 12:08:38 +0800209class ChameleonPeripheralsLabel(base_label.StringPrefixLabel):
210 """Return the Chameleon peripherals labels.
211
212 The 'chameleon:bt_hid' label is applied if the bluetooth
213 classic hid device, i.e, RN-42 emulation kit, is detected.
214
215 Any peripherals plugged into the chameleon board would be
216 detected and applied proper labels in this class.
217 """
218
219 _NAME = 'chameleon'
220
221 def exists(self, host):
222 return host._chameleon_host is not None
223
224
225 def generate_labels(self, host):
226 bt_hid_device = host.chameleon.get_bluetooh_hid_mouse()
227 return ['bt_hid'] if bt_hid_device.CheckSerialConnection() else []
228
229
Kevin Chenga2619dc2016-03-28 11:42:08 -0700230class AudioLoopbackDongleLabel(base_label.BaseLabel):
231 """Return the label if an audio loopback dongle is plugged in."""
232
233 _NAME = 'audio_loopback_dongle'
234
235 def exists(self, host):
236 nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(),
237 ignore_status=True).stdout
238 if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and
239 cras_utils.node_type_is_plugged('MIC', nodes_info)):
240 return True
241 return False
242
243
244class PowerSupplyLabel(base_label.StringPrefixLabel):
245 """
246 Return the label describing the power supply type.
247
248 Labels representing this host's power supply.
249 * `power:battery` when the device has a battery intended for
250 extended use
251 * `power:AC_primary` when the device has a battery not intended
252 for extended use (for moving the machine, etc)
253 * `power:AC_only` when the device has no battery at all.
254 """
255
256 _NAME = 'power'
257
258 def __init__(self):
259 self.psu_cmd_result = None
260
261
262 def exists(self, host):
263 self.psu_cmd_result = host.run(command='mosys psu type',
264 ignore_status=True)
265 return self.psu_cmd_result.stdout.strip() != 'unknown'
266
267
268 def generate_labels(self, host):
269 if self.psu_cmd_result.exit_status:
270 # The psu command for mosys is not included for all platforms. The
271 # assumption is that the device will have a battery if the command
272 # is not found.
273 return ['battery']
274 return [self.psu_cmd_result.stdout.strip()]
275
276
277class StorageLabel(base_label.StringPrefixLabel):
278 """
279 Return the label describing the storage type.
280
281 Determine if the internal device is SCSI or dw_mmc device.
282 Then check that it is SSD or HDD or eMMC or something else.
283
284 Labels representing this host's internal device type:
285 * `storage:ssd` when internal device is solid state drive
286 * `storage:hdd` when internal device is hard disk drive
287 * `storage:mmc` when internal device is mmc drive
Gwendal Grignou327fec62017-07-26 15:25:43 -0700288 * `storage:nvme` when internal device is NVMe drive
Kevin Chenga2619dc2016-03-28 11:42:08 -0700289 * None When internal device is something else or
290 when we are unable to determine the type
291 """
292
293 _NAME = 'storage'
294
295 def __init__(self):
296 self.type_str = ''
297
298
299 def exists(self, host):
300 # The output should be /dev/mmcblk* for SD/eMMC or /dev/sd* for scsi
301 rootdev_cmd = ' '.join(['. /usr/sbin/write_gpt.sh;',
302 '. /usr/share/misc/chromeos-common.sh;',
303 'load_base_vars;',
304 'get_fixed_dst_drive'])
305 rootdev = host.run(command=rootdev_cmd, ignore_status=True)
306 if rootdev.exit_status:
307 logging.info("Fail to run %s", rootdev_cmd)
308 return False
309 rootdev_str = rootdev.stdout.strip()
310
311 if not rootdev_str:
312 return False
313
314 rootdev_base = os.path.basename(rootdev_str)
315
316 mmc_pattern = '/dev/mmcblk[0-9]'
317 if re.match(mmc_pattern, rootdev_str):
318 # Use type to determine if the internal device is eMMC or somthing
319 # else. We can assume that MMC is always an internal device.
320 type_cmd = 'cat /sys/block/%s/device/type' % rootdev_base
321 type = host.run(command=type_cmd, ignore_status=True)
322 if type.exit_status:
323 logging.info("Fail to run %s", type_cmd)
324 return False
325 type_str = type.stdout.strip()
326
327 if type_str == 'MMC':
328 self.type_str = 'mmc'
329 return True
330
331 scsi_pattern = '/dev/sd[a-z]+'
332 if re.match(scsi_pattern, rootdev.stdout):
333 # Read symlink for /sys/block/sd* to determine if the internal
334 # device is connected via ata or usb.
335 link_cmd = 'readlink /sys/block/%s' % rootdev_base
336 link = host.run(command=link_cmd, ignore_status=True)
337 if link.exit_status:
338 logging.info("Fail to run %s", link_cmd)
339 return False
340 link_str = link.stdout.strip()
341 if 'usb' in link_str:
342 return False
343
344 # Read rotation to determine if the internal device is ssd or hdd.
345 rotate_cmd = str('cat /sys/block/%s/queue/rotational'
346 % rootdev_base)
347 rotate = host.run(command=rotate_cmd, ignore_status=True)
348 if rotate.exit_status:
349 logging.info("Fail to run %s", rotate_cmd)
350 return False
351 rotate_str = rotate.stdout.strip()
352
353 rotate_dict = {'0':'ssd', '1':'hdd'}
354 self.type_str = rotate_dict.get(rotate_str)
355 return True
356
Gwendal Grignou327fec62017-07-26 15:25:43 -0700357 nvme_pattern = '/dev/nvme[0-9]+n[0-9]+'
358 if re.match(nvme_pattern, rootdev_str):
Gwendal Grignou3660c192017-12-06 10:11:23 -0800359 self.type_str = 'nvme'
Gwendal Grignou327fec62017-07-26 15:25:43 -0700360 return True
361
Kevin Chenga2619dc2016-03-28 11:42:08 -0700362 # All other internal device / error case will always fall here
363 return False
364
365
366 def generate_labels(self, host):
367 return [self.type_str]
368
369
370class ServoLabel(base_label.BaseLabel):
371 """Label to apply if a servo is present."""
372
373 _NAME = 'servo'
374
375 def exists(self, host):
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700376 """
377 Check if the servo label should apply to the host or not.
378
379 @returns True if a servo host is detected, False otherwise.
380 """
Kevin Cheng745b8162017-05-26 09:48:36 -0700381 servo_host_hostname = None
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700382 servo_args, _ = servo_host._get_standard_servo_args(host)
Kevin Cheng745b8162017-05-26 09:48:36 -0700383 if servo_args:
384 servo_host_hostname = servo_args.get(servo_host.SERVO_HOST_ATTR)
Kevin Chengbbe5cf12016-06-08 21:50:01 -0700385 return (servo_host_hostname is not None
386 and servo_host.servo_host_is_up(servo_host_hostname))
Kevin Chenga2619dc2016-03-28 11:42:08 -0700387
388
389class VideoLabel(base_label.StringLabel):
390 """Labels detailing video capabilities."""
391
392 # List gathered from
393 # https://chromium.googlesource.com/chromiumos/
394 # platform2/+/master/avtest_label_detect/main.c#19
Hirokazu Hondad6cfe922017-10-03 13:07:37 +0900395 # TODO(hiroh): '4k_video' won't be used. It will be removed in the future.
Kevin Chenga2619dc2016-03-28 11:42:08 -0700396 _NAME = [
397 'hw_jpeg_acc_dec',
398 'hw_video_acc_h264',
399 'hw_video_acc_vp8',
400 'hw_video_acc_vp9',
401 'hw_video_acc_enc_h264',
402 'hw_video_acc_enc_vp8',
403 'webcam',
Hirokazu Honda57dbf002017-09-21 16:05:06 +0900404 '4k_video',
Hirokazu Hondad6cfe922017-10-03 13:07:37 +0900405 '4k_video_h264',
406 '4k_video_vp8',
407 '4k_video_vp9',
Kevin Chenga2619dc2016-03-28 11:42:08 -0700408 ]
409
410 def generate_labels(self, host):
411 result = host.run('/usr/local/bin/avtest_label_detect',
412 ignore_status=True).stdout
413 return re.findall('^Detected label: (\w+)$', result, re.M)
414
415
Ilja H. Friedel50290642017-12-01 19:39:53 -0800416class ArcLabel(base_label.BaseLabel):
417 """Label indicates if host has ARC support."""
418
419 _NAME = 'arc'
420
421 @base_label.forever_exists_decorate
422 def exists(self, host):
423 return 0 == host.run(
424 'grep CHROMEOS_ARC_VERSION /etc/lsb-release',
425 ignore_status=True).exit_status
426
427
428class CtsArchLabel(base_label.StringLabel):
429 """Labels to determine the abi of the CTS bundle (arm or x86 only)."""
430 # TODO(ihf): create labels for ABIs supported by container like x86_64.
Rohit Makasana5a153502016-06-13 15:50:09 -0700431
432 _NAME = ['cts_abi_arm', 'cts_abi_x86']
433
434 def _get_cts_abis(self, host):
435 """Return supported CTS ABIs.
436
437 @return List of supported CTS bundle ABIs.
438 """
439 cts_abis = {'x86_64': ['arm', 'x86'], 'arm': ['arm']}
440 return cts_abis.get(host.get_cpu_arch(), [])
441
Rohit Makasana5a153502016-06-13 15:50:09 -0700442 def generate_labels(self, host):
443 return ['cts_abi_' + abi for abi in self._get_cts_abis(host)]
444
445
Ilja H. Friedel50290642017-12-01 19:39:53 -0800446class SparseCoverageLabel(base_label.StringLabel):
447 """Label indicates if it is desirable to cover a test for this build."""
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700448
Ilja H. Friedel50290642017-12-01 19:39:53 -0800449 # Prime numbers. We can easily construct 6, 10, 15 and 30 from these.
450 _NAME = ['sparse_coverage_2', 'sparse_coverage_3', 'sparse_coverage_5']
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700451
Ilja H. Friedel50290642017-12-01 19:39:53 -0800452 def _should_cover(self, host, nth_build):
453 release_info = utils.parse_cmd_output(
454 'cat /etc/lsb-release', run_method=host.run)
455 build = release_info.get('CHROMEOS_RELEASE_BUILD_NUMBER')
456 branch = release_info.get('CHROMEOS_RELEASE_BRANCH_NUMBER')
457 patch = release_info.get('CHROMEOS_RELEASE_PATCH_NUMBER')
458 builder = release_info.get('CHROMEOS_RELEASE_BUILDER_PATH')
459 if not 'release' in builder:
460 # Sparse coverage only makes sense on release/canary builds.
461 return True
462 if patch != '0':
463 # We are on a paladin or pfq build. These are never sparse.
464 # Redundant with release check above but just in case.
465 return True
466 if branch != '0':
467 # We are on a branch. For now these are not sparse.
468 # TODO(ihf): Consider sparse coverage on beta.
469 return True
470 # Now we can be sure we are on master.
471 if int(build) % nth_build == 0:
472 # We only want to cover one in n builds on master. This is the
473 # lucky one.
474 return True
475 # We skip all other builds on master.
476 return False
477
478 def generate_labels(self, host):
479 labels = []
480 for n in [2, 3, 5]:
481 if self._should_cover(host, n):
482 labels.append('sparse_coverage_%d' % n)
483 return labels
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700484
485
Kevin Chenga2619dc2016-03-28 11:42:08 -0700486class VideoGlitchLabel(base_label.BaseLabel):
487 """Label indicates if host supports video glitch detection tests."""
488
489 _NAME = 'video_glitch_detection'
490
491 def exists(self, host):
492 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
493
494 return board in video_test_constants.SUPPORTED_BOARDS
495
496
Kevin Chenga2619dc2016-03-28 11:42:08 -0700497class InternalDisplayLabel(base_label.StringLabel):
498 """Label that determines if the device has an internal display."""
499
500 _NAME = 'internal_display'
501
502 def generate_labels(self, host):
503 from autotest_lib.client.cros.graphics import graphics_utils
504 from autotest_lib.client.common_lib import utils as common_utils
505
506 def __system_output(cmd):
507 return host.run(cmd).stdout
508
509 def __read_file(remote_path):
510 return host.run('cat %s' % remote_path).stdout
511
512 # Hijack the necessary client functions so that we can take advantage
513 # of the client lib here.
514 # FIXME: find a less hacky way than this
515 original_system_output = utils.system_output
516 original_read_file = common_utils.read_file
517 utils.system_output = __system_output
518 common_utils.read_file = __read_file
519 try:
520 return ([self._NAME]
521 if graphics_utils.has_internal_display()
522 else [])
523 finally:
524 utils.system_output = original_system_output
525 common_utils.read_file = original_read_file
526
527
528class LucidSleepLabel(base_label.BaseLabel):
529 """Label that determines if device has support for lucid sleep."""
530
531 # TODO(kevcheng): See if we can determine if this label is applicable a
532 # better way (crbug.com/592146).
533 _NAME = 'lucidsleep'
534 LUCID_SLEEP_BOARDS = ['samus', 'lulu']
535
536 def exists(self, host):
537 board = host.get_board().replace(ds_constants.BOARD_PREFIX, '')
538 return board in self.LUCID_SLEEP_BOARDS
539
540
Kevin Cheng80ad5732016-03-31 16:01:56 -0700541class HWIDLabel(base_label.StringLabel):
542 """Return all the labels generated from the hwid."""
543
544 # We leave out _NAME because hwid_lib will generate everything for us.
545
546 def __init__(self):
547 # Grab the key file needed to access the hwid service.
548 self.key_file = global_config.global_config.get_config_value(
549 'CROS', 'HWID_KEY', type=str)
550
551
552 def generate_labels(self, host):
553 hwid_labels = []
554 hwid = host.run_output('crossystem hwid').strip()
555 hwid_info_list = hwid_lib.get_hwid_info(hwid, hwid_lib.HWID_INFO_LABEL,
556 self.key_file).get('labels', [])
557
558 for hwid_info in hwid_info_list:
559 # If it's a prefix, we'll have:
560 # {'name': prefix_label, 'value': postfix_label} and create
561 # 'prefix_label:postfix_label'; otherwise it'll just be
562 # {'name': label} which should just be 'label'.
563 value = hwid_info.get('value', '')
564 name = hwid_info.get('name', '')
565 # There should always be a name but just in case there is not.
566 if name:
567 hwid_labels.append(name if not value else
568 '%s:%s' % (name, value))
569 return hwid_labels
570
571
572 def get_all_labels(self):
573 """We need to try all labels as a prefix and as standalone.
574
575 We don't know for sure which labels are prefix labels and which are
576 standalone so we try all of them as both.
577 """
578 all_hwid_labels = []
579 try:
580 all_hwid_labels = hwid_lib.get_all_possible_dut_labels(
581 self.key_file)
582 except IOError:
583 logging.error('Can not open key file: %s', self.key_file)
584 except hwid_lib.HwIdException as e:
585 logging.error('hwid service: %s', e)
586 return all_hwid_labels, all_hwid_labels
587
588
Kevin Chenga2619dc2016-03-28 11:42:08 -0700589CROS_LABELS = [
590 AccelsLabel(),
Rohit Makasanac6e5d622016-06-16 17:13:39 -0700591 ArcLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700592 AudioLoopbackDongleLabel(),
593 BluetoothLabel(),
Kevin Chenga8455302016-08-31 20:54:41 +0000594 BoardLabel(),
C Shapiro05dd3222017-09-22 10:42:33 -0600595 ModelLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700596 ChameleonConnectionLabel(),
597 ChameleonLabel(),
Joseph Hwangeac44312016-08-31 12:08:38 +0800598 ChameleonPeripheralsLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700599 common_label.OSLabel(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800600 CtsArchLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700601 ECLabel(),
Kevin Cheng80ad5732016-03-31 16:01:56 -0700602 HWIDLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700603 InternalDisplayLabel(),
604 LightSensorLabel(),
605 LucidSleepLabel(),
606 PowerSupplyLabel(),
607 ServoLabel(),
Ilja H. Friedel50290642017-12-01 19:39:53 -0800608 SparseCoverageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700609 StorageLabel(),
Kevin Chenga2619dc2016-03-28 11:42:08 -0700610 VideoGlitchLabel(),
611 VideoLabel(),
612]