github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/testing/hwdep/hwdep.go (about) 1 // Copyright 2023 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Package hwdep provides the hardware dependency mechanism to select tests to run on 6 // a DUT based on its hardware features and setup. 7 package hwdep 8 9 import ( 10 "fmt" 11 "regexp" 12 "strings" 13 14 configpb "go.chromium.org/chromiumos/config/go/api" 15 16 "go.chromium.org/tast/core/errors" 17 "go.chromium.org/tast/core/internal/dep" 18 "go.chromium.org/tast/core/testing/cellularconst" 19 "go.chromium.org/tast/core/testing/wlan" 20 21 "go.chromium.org/tast/core/framework/protocol" 22 ) 23 24 // These are form factor values that can be passed to FormFactor and SkipOnFormFactor. 25 const ( 26 FormFactorUnknown = configpb.HardwareFeatures_FormFactor_FORM_FACTOR_UNKNOWN 27 Clamshell = configpb.HardwareFeatures_FormFactor_CLAMSHELL 28 Convertible = configpb.HardwareFeatures_FormFactor_CONVERTIBLE 29 Detachable = configpb.HardwareFeatures_FormFactor_DETACHABLE 30 Chromebase = configpb.HardwareFeatures_FormFactor_CHROMEBASE 31 Chromebox = configpb.HardwareFeatures_FormFactor_CHROMEBOX 32 Chromebit = configpb.HardwareFeatures_FormFactor_CHROMEBIT 33 Chromeslate = configpb.HardwareFeatures_FormFactor_CHROMESLATE 34 ) 35 36 // Deps holds hardware dependencies all of which need to be satisfied to run a test. 37 type Deps = dep.HardwareDeps 38 39 // Condition represents one condition of hardware dependencies. 40 type Condition = dep.HardwareCondition 41 42 // D returns hardware dependencies representing the given Conditions. 43 func D(conds ...Condition) Deps { 44 return dep.NewHardwareDeps(conds...) 45 } 46 47 // idRegexp is the pattern that the given model/platform ID names should match with. 48 var idRegexp = regexp.MustCompile(`^[a-z0-9_-]+$`) 49 50 func satisfied() (bool, string, error) { 51 return true, "", nil 52 } 53 54 func unsatisfied(reason string) (bool, string, error) { 55 return false, reason, nil 56 } 57 58 func withError(err error) (bool, string, error) { 59 return false, "", err 60 } 61 62 func withErrorStr(s string) (bool, string, error) { 63 return false, "", errors.New(s) 64 } 65 66 // modelListed returns whether the model represented by a protocol.DeprecatedDeviceConfig is listed 67 // in the given list of names or not. 68 func modelListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) { 69 if dc == nil || dc.Id == nil || dc.Id.Model == "" { 70 return false, errors.New("DeprecatedDeviceConfig does not have model ID") 71 } 72 m := dc.Id.Model 73 // Remove the suffix _signed since it is not a part of a model name. 74 modelID := strings.TrimSuffix(strings.ToLower(m), "_signed") 75 for _, name := range names { 76 if name == modelID { 77 return true, nil 78 } 79 } 80 return false, nil 81 } 82 83 // platformListed returns whether the platform represented by a protocol.HardwareFeatures 84 // is listed in the given list of names or not. 85 func platformListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) { 86 if dc == nil || dc.Id == nil { 87 return false, errors.New("DeprecatedDeviceConfig does not have platform ID") 88 } 89 p := dc.Id.Platform 90 platformID := strings.ToLower(p) 91 for _, name := range names { 92 if name == platformID { 93 return true, nil 94 } 95 } 96 return false, nil 97 } 98 99 // WLAN device IDs. Convenience wrappers. 100 const ( 101 Marvell88w8897SDIO = wlan.Marvell88w8897SDIO 102 Marvell88w8997PCIE = wlan.Marvell88w8997PCIE 103 QualcommAtherosQCA6174 = wlan.QualcommAtherosQCA6174 104 QualcommAtherosQCA6174SDIO = wlan.QualcommAtherosQCA6174SDIO 105 QualcommWCN3990 = wlan.QualcommWCN3990 106 QualcommWCN6750 = wlan.QualcommWCN6750 107 QualcommWCN6855 = wlan.QualcommWCN6855 108 Intel7260 = wlan.Intel7260 109 Intel7265 = wlan.Intel7265 110 Intel8265 = wlan.Intel8265 111 Intel9000 = wlan.Intel9000 112 Intel9260 = wlan.Intel9260 113 Intel22260 = wlan.Intel22260 114 Intel22560 = wlan.Intel22560 115 IntelAX201 = wlan.IntelAX201 116 IntelAX203 = wlan.IntelAX203 117 IntelAX211 = wlan.IntelAX211 118 BroadcomBCM4354SDIO = wlan.BroadcomBCM4354SDIO 119 BroadcomBCM4356PCIE = wlan.BroadcomBCM4356PCIE 120 BroadcomBCM4371PCIE = wlan.BroadcomBCM4371PCIE 121 Realtek8822CPCIE = wlan.Realtek8822CPCIE 122 Realtek8852APCIE = wlan.Realtek8852APCIE 123 Realtek8852CPCIE = wlan.Realtek8852CPCIE 124 MediaTekMT7921PCIE = wlan.MediaTekMT7921PCIE 125 MediaTekMT7921SDIO = wlan.MediaTekMT7921SDIO 126 MediaTekMT7922PCIE = wlan.MediaTekMT7922PCIE 127 ) 128 129 // wifiDeviceListed returns whether a WiFi device given in HardwareFeatures is listed in the given list of names or not. 130 func wifiDeviceListed(hwf *protocol.HardwareFeatures, devices ...wlan.DeviceID) (bool, error) { 131 wifi := hwf.GetHardwareFeatures().GetWifi() 132 if wifi == nil { 133 return false, errors.New("Wifi data has not been passed from DUT") 134 } 135 136 chipset := int32(wifi.WifiChips[0]) 137 138 for _, id := range devices { 139 if id == wlan.DeviceID(chipset) { 140 return true, nil 141 } 142 } 143 return false, nil 144 } 145 146 // Model returns a hardware dependency condition that is satisfied if the DUT's model ID is 147 // one of the given names. 148 // Practically, this is not recommended to be used in most cases. Please consider again 149 // if this is the appropriate use, and whether there exists another option, such as 150 // check whether DUT needs to have touchscreen, some specific SKU, internal display etc. 151 // 152 // Expected example use case is; there is a problem in some code where we do not have 153 // control, such as a device specific driver, or hardware etc., and unfortunately 154 // it unlikely be fixed for a while. 155 // Another use case is; a test is stably running on most of models, but failing on some 156 // specific models. By using Model() and SkipOnModel() combination, the test can be 157 // promoted to critical on stably running models, while it is still informational 158 // on other models. Note that, in this case, it is expected that an engineer is 159 // assigned to stabilize/fix issues of the test on informational models. 160 func Model(names ...string) Condition { 161 for _, n := range names { 162 if !idRegexp.MatchString(n) { 163 return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)} 164 } 165 } 166 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 167 listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...) 168 if err != nil { 169 return withError(err) 170 } 171 if !listed { 172 return unsatisfied("ModelId did not match") 173 } 174 return satisfied() 175 }} 176 } 177 178 // SkipOnModel returns a hardware dependency condition that is satisfied 179 // iff the DUT's model ID is none of the given names. 180 // Please find the doc of Model(), too, for details about the expected usage. 181 func SkipOnModel(names ...string) Condition { 182 for _, n := range names { 183 if !idRegexp.MatchString(n) { 184 return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)} 185 } 186 } 187 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 188 listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...) 189 if err != nil { 190 // Failed to get the model name. 191 // Run the test to report error if it fails on this device. 192 return satisfied() 193 } 194 if listed { 195 return unsatisfied("ModelId matched with skip-on list") 196 } 197 return satisfied() 198 }} 199 } 200 201 // Platform returns a hardware dependency condition that is satisfied 202 // iff the DUT's platform ID is one of the give names. 203 // Please find the doc of Model(), too, for details about the expected usage. 204 // Deprecated. Use Model() or "board:*" software dependency. 205 func Platform(names ...string) Condition { 206 for _, n := range names { 207 if !idRegexp.MatchString(n) { 208 return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)} 209 } 210 } 211 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 212 listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...) 213 if err != nil { 214 return withError(err) 215 } 216 if !listed { 217 return unsatisfied("PlatformId did not match") 218 } 219 return satisfied() 220 }} 221 } 222 223 // SkipOnPlatform returns a hardware dependency condition that is satisfied 224 // iff the DUT's platform ID is none of the give names. 225 // Please find the doc of Model(), too, for details about the expected usage. 226 // Deprecated. Use SkipOnModel() or "board:*" software dependency. 227 func SkipOnPlatform(names ...string) Condition { 228 for _, n := range names { 229 if !idRegexp.MatchString(n) { 230 return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)} 231 } 232 } 233 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 234 listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...) 235 if err != nil { 236 return withError(err) 237 } 238 if listed { 239 return unsatisfied("PlatformId matched with skip-on list") 240 } 241 return satisfied() 242 }} 243 } 244 245 // WifiDevice returns a hardware dependency condition that is satisfied 246 // iff the DUT's WiFi device is one of the given names. 247 // Please find the doc of Model(), too, for details about the expected usage. 248 func WifiDevice(devices ...wlan.DeviceID) Condition { 249 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 250 listed, err := wifiDeviceListed(f, devices...) 251 if err != nil { 252 // Fail-open. Assumption is that if the device is not recognized, it doesn't match. 253 return unsatisfied(fmt.Sprintf("Unrecognized device. Assume not matching. Err %v", err)) 254 } 255 if !listed { 256 return unsatisfied("WiFi device did not match") 257 } 258 return satisfied() 259 }} 260 } 261 262 // SkipOnWifiDevice returns a hardware dependency condition that is satisfied 263 // iff the DUT's WiFi device is none of the given names. 264 // Please find the doc of Model(), too, for details about the expected usage. 265 func SkipOnWifiDevice(devices ...wlan.DeviceID) Condition { 266 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 267 listed, err := wifiDeviceListed(f, devices...) 268 if err != nil { 269 // Failed to get the device id. 270 // Run the test to report error if it fails on this device. 271 return satisfied() 272 273 } 274 if listed { 275 return unsatisfied("WiFi device matched with skip-on list") 276 } 277 return satisfied() 278 }} 279 } 280 281 // TouchScreen returns a hardware dependency condition that is satisfied 282 // iff the DUT has touchscreen. 283 func TouchScreen() Condition { 284 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 285 hf := f.GetHardwareFeatures() 286 if hf == nil { 287 return withErrorStr("DUT HardwareFeatures data is not given") 288 } 289 if hf.GetScreen().GetTouchSupport() == configpb.HardwareFeatures_PRESENT { 290 return satisfied() 291 } 292 return unsatisfied("DUT does not have touchscreen") 293 }, 294 } 295 } 296 297 // NoTouchScreen returns a hardware dependency condition that is satisfied 298 // if the DUT doesn't have a touchscreen. 299 func NoTouchScreen() Condition { 300 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 301 hf := f.GetHardwareFeatures() 302 if hf == nil { 303 return withErrorStr("DUT HardwareFeatures data is not given") 304 } 305 if status := hf.GetScreen().GetTouchSupport(); status == configpb.HardwareFeatures_NOT_PRESENT { 306 return satisfied() 307 } 308 return unsatisfied("DUT has a touchscreen") 309 }, 310 } 311 } 312 313 // ChromeEC returns a hardware dependency condition that is satisfied 314 // iff the DUT has a present EC of the "Chrome EC" type. 315 func ChromeEC() Condition { 316 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 317 hf := f.GetHardwareFeatures() 318 if hf == nil { 319 return withErrorStr("Did not find hardware features") 320 } 321 ecIsPresent := hf.GetEmbeddedController().GetPresent() == configpb.HardwareFeatures_PRESENT 322 ecIsChrome := hf.GetEmbeddedController().GetEcType() == configpb.HardwareFeatures_EmbeddedController_EC_CHROME 323 if ecIsPresent && ecIsChrome { 324 return satisfied() 325 } 326 return unsatisfied("DUT does not have chrome EC") 327 }, 328 } 329 } 330 331 // ECFeatureTypecCmd returns a hardware dependency condition that is satisfied 332 // iff the DUT has an EC which supports the EC_FEATURE_TYPEC_CMD feature flag. 333 func ECFeatureTypecCmd() Condition { 334 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 335 hf := f.GetHardwareFeatures() 336 if hf == nil { 337 return withErrorStr("Did not find hardware features") 338 } 339 // We only return unsatisfied if we know for sure that the EC doesn't support the feature flag. 340 // In cases where the result is UNKNOWN, we allow the test to continue and fail. 341 if hf.GetEmbeddedController().GetFeatureTypecCmd() == configpb.HardwareFeatures_NOT_PRESENT { 342 return unsatisfied("DUT EC does not support EC_FEATURE_TYPEC_CMD") 343 } 344 return satisfied() 345 }, 346 } 347 } 348 349 // ECFeatureCBI returns a hardware dependency condition that 350 // is satisfied iff the DUT has an EC which supports CBI. 351 func ECFeatureCBI() Condition { 352 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 353 hf := f.GetHardwareFeatures() 354 if hf == nil { 355 return withErrorStr("Did not find hardware features") 356 } 357 if status := hf.GetEmbeddedController().GetCbi(); status == configpb.HardwareFeatures_NOT_PRESENT { 358 return unsatisfied("DUT does not have cbi") 359 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 360 return unsatisfied("Could not determine cbi presence") 361 } 362 return satisfied() 363 }, 364 } 365 } 366 367 // ECFeatureDetachableBase returns a hardware dependency condition that is 368 // satisfied iff the DUT has the detachable base attached. 369 func ECFeatureDetachableBase() Condition { 370 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 371 hf := f.GetHardwareFeatures() 372 if hf == nil { 373 return withErrorStr("Did not find hardware features") 374 } 375 status := hf.GetEmbeddedController().GetDetachableBase() 376 if status == configpb.HardwareFeatures_NOT_PRESENT { 377 return unsatisfied("Detachable base is not attached to DUT") 378 } 379 if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 380 return unsatisfied("Could not determine detachable base presence") 381 } 382 return satisfied() 383 }, 384 } 385 } 386 387 // ECFeatureChargeControlV2 returns a hardware dependency condition that is 388 // satisfied iff the DUT supports version 2 of the EC_CMD_CHARGE_CONTROL feature 389 // (which adds battery sustain). 390 func ECFeatureChargeControlV2() Condition { 391 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 392 hf := f.GetHardwareFeatures() 393 if hf == nil { 394 return withErrorStr("Did not find hardware features") 395 } 396 if hf.GetEmbeddedController().GetFeatureChargeControlV2() == configpb.HardwareFeatures_NOT_PRESENT { 397 return unsatisfied("DUT EC does not support EC_CMD_CHARGE_CONTROL version 2") 398 } 399 return satisfied() 400 }, 401 } 402 } 403 404 // Cellular returns a hardware dependency condition that 405 // is satisfied iff the DUT has a cellular modem. 406 func Cellular() Condition { 407 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 408 hf := f.GetHardwareFeatures() 409 if hf == nil { 410 return withErrorStr("Did not find hardware features") 411 } 412 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 413 return unsatisfied("DUT does not have a cellular modem") 414 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 415 return unsatisfied("Could not determine if cellular model is present") 416 } 417 return satisfied() 418 }, 419 } 420 } 421 422 // SkipOnCellularVariant returns a hardware dependency condition that is satisfied 423 // iff the DUT's cellular variant is none of the given names. 424 func SkipOnCellularVariant(names ...string) Condition { 425 for _, n := range names { 426 if !idRegexp.MatchString(n) { 427 return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)} 428 } 429 } 430 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 431 hf := f.GetHardwareFeatures() 432 if hf == nil { 433 return withErrorStr("Did not find hardware features") 434 } 435 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 436 return unsatisfied("DUT does not have a cellular modem") 437 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 438 return unsatisfied("Could not determine if cellular model is present") 439 } 440 variant := hf.GetCellular().GetModel() 441 for _, name := range names { 442 if name == variant { 443 return unsatisfied("Variant matched with skip-on list") 444 } 445 } 446 return satisfied() 447 }} 448 } 449 450 // CellularVariant returns a hardware dependency condition that is satisfied 451 // iff the DUT's cellular variant is one of the given names. 452 func CellularVariant(names ...string) Condition { 453 for _, n := range names { 454 if !idRegexp.MatchString(n) { 455 return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)} 456 } 457 } 458 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 459 hf := f.GetHardwareFeatures() 460 if hf == nil { 461 return withErrorStr("Did not find hardware features") 462 } 463 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 464 return unsatisfied("DUT does not have a cellular modem") 465 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 466 return unsatisfied("Could not determine if cellular model is present") 467 } 468 variant := hf.GetCellular().GetModel() 469 for _, name := range names { 470 if name == variant { 471 return satisfied() 472 } 473 } 474 return unsatisfied("Variant did not match") 475 }} 476 } 477 478 // CellularModemType returns a hardware dependency condition that is satisfied 479 // iff the DUT's cellular modem type is one of the given types. 480 func CellularModemType(modemTypes ...cellularconst.ModemType) Condition { 481 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 482 hf := f.GetHardwareFeatures() 483 if hf == nil { 484 return withErrorStr("Did not find hardware features") 485 } 486 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 487 return unsatisfied("DUT does not have a cellular modem") 488 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 489 return unsatisfied("Could not determine if cellular model is present") 490 } 491 variant := hf.GetCellular().GetModel() 492 modemType, err := cellularconst.GetModemTypeFromVariant(variant) 493 if err != nil { 494 return withError(err) 495 } 496 for _, m := range modemTypes { 497 if m == modemType { 498 return satisfied() 499 } 500 } 501 return unsatisfied("Modem type did not match") 502 }} 503 } 504 505 // SkipOnCellularModemType returns a hardware dependency condition that is satisfied 506 // iff the DUT's cellular modem type is none of the given types. 507 func SkipOnCellularModemType(modemTypes ...cellularconst.ModemType) Condition { 508 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 509 hf := f.GetHardwareFeatures() 510 if hf == nil { 511 return withErrorStr("Did not find hardware features") 512 } 513 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 514 return unsatisfied("DUT does not have a cellular modem") 515 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 516 return unsatisfied("Could not determine if cellular model is present") 517 } 518 variant := hf.GetCellular().GetModel() 519 modemType, err := cellularconst.GetModemTypeFromVariant(variant) 520 if err != nil { 521 return withError(err) 522 } 523 for _, m := range modemTypes { 524 if m == modemType { 525 return unsatisfied("Modem type matched with skip-on list") 526 } 527 } 528 return satisfied() 529 }} 530 } 531 532 // CellularSoftwareDynamicSar returns a hardware dependency condition that 533 // is satisfied iff the DUT has enabled software dynamic sar. 534 func CellularSoftwareDynamicSar() Condition { 535 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 536 hf := f.GetHardwareFeatures() 537 if hf == nil { 538 return withErrorStr("Did not find hardware features") 539 } 540 if status := hf.GetCellular().GetDynamicPowerReductionConfig().GetModemManager(); status { 541 return satisfied() 542 } 543 return unsatisfied("DUT does not support cellular sw dynamic sar") 544 }, 545 } 546 } 547 548 // NoCellular returns a hardware dependency condition that 549 // is satisfied iff the DUT does not have a cellular modem. 550 func NoCellular() Condition { 551 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 552 hf := f.GetHardwareFeatures() 553 if hf == nil { 554 return withErrorStr("Did not find hardware features") 555 } 556 if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 557 return satisfied() 558 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 559 return unsatisfied("Could not determine if cellular model is present") 560 } 561 return unsatisfied("DUT has a cellular modem") 562 }, 563 } 564 } 565 566 // Bluetooth returns a hardware dependency condition that 567 // is satisfied iff the DUT has a bluetooth adapter. 568 func Bluetooth() Condition { 569 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 570 if hf := f.GetHardwareFeatures(); hf == nil { 571 return withErrorStr("Did not find hardware features") 572 } else if status := hf.GetBluetooth().Present; status == configpb.HardwareFeatures_NOT_PRESENT { 573 return unsatisfied("DUT does not have a bluetooth adapter") 574 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 575 return unsatisfied("Could not determine bluetooth adapter presence") 576 } 577 return satisfied() 578 }, 579 } 580 } 581 582 // GSCUART returns a hardware dependency condition that is satisfied iff the DUT has a GSC and that GSC has a working UART. 583 // TODO(b/224608005): Add a cros_config for this and use that instead. 584 func GSCUART() Condition { 585 // There is no way to probe for this condition, and there should be no machines newer than 2017 without working UARTs. 586 return SkipOnModel( 587 "astronaut", 588 "blacktiplte", 589 "caroline", 590 "celes", 591 "electro", 592 "elm", 593 "eve", 594 "hana", 595 "kefka", 596 "lars", 597 "nasher", 598 "nocturne", 599 "relm", 600 "robo360", 601 "sand", 602 "sentry", 603 "snappy", 604 ) 605 } 606 607 // GSCRWKeyIDProd returns a hardware dependency condition that 608 // is satisfied iff the DUT does have a GSC RW image signed with prod key. 609 func GSCRWKeyIDProd() Condition { 610 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 611 hf := f.GetHardwareFeatures() 612 if hf == nil { 613 return withErrorStr("Did not find hardware features") 614 } 615 if status := hf.GetTrustedPlatformModule().GetProductionRwKeyId(); status == configpb.HardwareFeatures_PRESENT { 616 return satisfied() 617 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 618 return unsatisfied("Could not determine if production RW key is used to sign GSC image") 619 } 620 return unsatisfied("DUT has a dev signed GSC image") 621 }, 622 } 623 } 624 625 // HasNoTpm returns a hardware dependency condition that is satisfied iff the DUT 626 // doesn't have an enabled TPM. 627 func HasNoTpm() Condition { 628 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 629 hf := f.GetHardwareFeatures() 630 if hf == nil { 631 return withErrorStr("Did not find hardware features") 632 } 633 if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() != configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED { 634 return unsatisfied("DUT has an enabled TPM") 635 } 636 return satisfied() 637 }, 638 } 639 } 640 641 // HasTpm returns a hardware dependency condition that is satisfied iff the DUT 642 // does have an enabled TPM. 643 func HasTpm() Condition { 644 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 645 hf := f.GetHardwareFeatures() 646 if hf == nil { 647 return withErrorStr("Did not find hardware features") 648 } 649 if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED { 650 return unsatisfied("DUT has no enabled TPM") 651 } 652 return satisfied() 653 }, 654 } 655 } 656 657 // HasTpm1 returns a hardware dependency condition that is satisfied iff the DUT 658 // does have an enabled TPM1.2. 659 func HasTpm1() Condition { 660 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 661 hf := f.GetHardwareFeatures() 662 if hf == nil { 663 return withErrorStr("Did not find hardware features") 664 } 665 if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V1_2 { 666 return satisfied() 667 } 668 return unsatisfied("DUT has no enabled TPM1.2") 669 }, 670 } 671 } 672 673 // HasTpm2 returns a hardware dependency condition that is satisfied iff the DUT 674 // does have an enabled TPM2.0. 675 func HasTpm2() Condition { 676 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 677 hf := f.GetHardwareFeatures() 678 if hf == nil { 679 return withErrorStr("Did not find hardware features") 680 } 681 if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V2 { 682 return satisfied() 683 } 684 return unsatisfied("DUT has no enabled TPM2.0") 685 }, 686 } 687 } 688 689 // CPUNotNeedsCoreScheduling returns a hardware dependency condition that is satisfied iff the DUT's 690 // CPU is does not need to use core scheduling to mitigate hardware vulnerabilities. 691 func CPUNotNeedsCoreScheduling() Condition { 692 return cpuNeedsCoreScheduling(false) 693 } 694 695 // CPUNeedsCoreScheduling returns a hardware dependency condition that is satisfied iff the DUT's 696 // CPU needs to use core scheduling to mitigate hardware vulnerabilities. 697 func CPUNeedsCoreScheduling() Condition { 698 return cpuNeedsCoreScheduling(true) 699 } 700 701 // cpuNeedsCoreScheduling generates a Condition for CPUNeedsCoreScheduling() and its inverse, 702 // CPUNotNeedsCoreScheduling(). A CPU needs core scheduling if it is vulnerable to either L1TF or 703 // MDS hardware vulnerabilities. 704 func cpuNeedsCoreScheduling(enabled bool) Condition { 705 needsCoreScheduling := func(hf *configpb.HardwareFeatures) (bool, string) { 706 for _, f := range hf.GetSoc().Vulnerabilities { 707 if f == configpb.Component_Soc_L1TF { 708 return true, "CPU is vulnerable to L1TF" 709 } 710 if f == configpb.Component_Soc_MDS { 711 return true, "CPU is vulnerable MDS" 712 } 713 } 714 return false, "CPU is not vulnerable to L1TF or MDS" 715 } 716 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 717 hf := f.GetHardwareFeatures() 718 if hf == nil { 719 return withErrorStr("HardwareFeatures is not given") 720 } 721 needed, description := needsCoreScheduling(hf) 722 if needed == enabled { 723 return satisfied() 724 } 725 return unsatisfied(description) 726 }, 727 } 728 } 729 730 // CPUSupportsSMT returns a hardware dependency condition that is satisfied iff the DUT supports 731 // Symmetric Multi-Threading. 732 func CPUSupportsSMT() Condition { 733 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 734 hf := f.GetHardwareFeatures() 735 if hf == nil { 736 return withErrorStr("HardwareFeatures is not given") 737 } 738 for _, f := range hf.GetSoc().Features { 739 if f == configpb.Component_Soc_SMT { 740 return satisfied() 741 } 742 } 743 return unsatisfied("CPU does not have SMT support") 744 }, 745 } 746 } 747 748 // CPUSupportsSHANI returns a hardware dependency condition that is satisfied iff the DUT supports 749 // SHA-NI instruction extension. 750 func CPUSupportsSHANI() Condition { 751 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 752 hf := f.GetHardwareFeatures() 753 if hf == nil { 754 return withErrorStr("HardwareFeatures is not given") 755 } 756 for _, f := range hf.GetSoc().Features { 757 if f == configpb.Component_Soc_SHA_NI { 758 return satisfied() 759 } 760 } 761 return unsatisfied("CPU does not have SHA-NI support") 762 }, 763 } 764 } 765 766 // Fingerprint returns a hardware dependency condition that is satisfied 767 // iff the DUT has fingerprint sensor. 768 func Fingerprint() Condition { 769 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 770 hf := f.GetHardwareFeatures() 771 if hf == nil { 772 return withErrorStr("HardwareFeatures is not given") 773 } 774 if !hf.GetFingerprint().GetPresent() { 775 return unsatisfied("DUT does not have fingerprint sensor") 776 } 777 return satisfied() 778 }, 779 } 780 } 781 782 // NoFingerprint returns a hardware dependency condition that is satisfied 783 // if the DUT doesn't have fingerprint sensor. 784 func NoFingerprint() Condition { 785 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 786 hf := f.GetHardwareFeatures() 787 if hf == nil { 788 return withErrorStr("HardwareFeatures is not given") 789 } 790 if hf.GetFingerprint().GetPresent() { 791 return unsatisfied("DUT has fingerprint sensor") 792 } 793 return satisfied() 794 }, 795 } 796 } 797 798 // ExternalDisplay returns a hardware dependency condition that is satisfied 799 // iff the DUT has an external display 800 func ExternalDisplay() Condition { 801 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 802 hf := f.GetHardwareFeatures() 803 if hf == nil { 804 return withErrorStr("HardwareFeatures is not given") 805 } 806 display := hf.GetDisplay() 807 if display == nil { 808 return withErrorStr("Display is not given") 809 } 810 if display.GetType() == configpb.HardwareFeatures_Display_TYPE_EXTERNAL || display.GetType() == configpb.HardwareFeatures_Display_TYPE_INTERNAL_EXTERNAL { 811 return satisfied() 812 } 813 return unsatisfied("DUT does not have an external display") 814 }, 815 } 816 } 817 818 // InternalDisplay returns a hardware dependency condition that is satisfied 819 // iff the DUT has an internal display, e.g. Chromeboxes and Chromebits don't. 820 func InternalDisplay() Condition { 821 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 822 hf := f.GetHardwareFeatures() 823 if hf == nil { 824 return withErrorStr("HardwareFeatures is not given") 825 } 826 if hf.GetScreen().GetPanelProperties() != nil { 827 return satisfied() 828 } 829 return unsatisfied("DUT does not have an internal display") 830 }, 831 } 832 } 833 834 // NoInternalDisplay returns a hardware dependency condition that is satisfied 835 // iff the DUT does not have an internal display. 836 func NoInternalDisplay() Condition { 837 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 838 hf := f.GetHardwareFeatures() 839 if hf == nil { 840 return withErrorStr("HardwareFeatures is not given") 841 } 842 if hf.GetScreen().GetPanelProperties() != nil { 843 return unsatisfied("DUT has an internal display") 844 } 845 return satisfied() 846 }, 847 } 848 } 849 850 // Keyboard returns a hardware dependency condition that is satisfied 851 // iff the DUT has an keyboard, e.g. Chromeboxes and Chromebits don't. 852 // Tablets might have a removable keyboard. 853 func Keyboard() Condition { 854 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 855 hf := f.GetHardwareFeatures() 856 if hf == nil { 857 return withErrorStr("HardwareFeatures is not given") 858 } 859 if hf.GetKeyboard() == nil || 860 hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_KEYBOARD_TYPE_UNKNOWN || 861 hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_NONE { 862 return unsatisfied("DUT does not have a keyboard") 863 } 864 return satisfied() 865 }, 866 } 867 } 868 869 // KeyboardBacklight returns a hardware dependency condition that is satisfied 870 // if the DUT supports keyboard backlight functionality. 871 func KeyboardBacklight() Condition { 872 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 873 hf := f.GetHardwareFeatures() 874 if hf == nil { 875 return withErrorStr("HardwareFeatures is not given") 876 } 877 if hf.GetKeyboard().GetBacklight() != configpb.HardwareFeatures_PRESENT { 878 return unsatisfied("DUT does not have keyboard backlight") 879 } 880 return satisfied() 881 }, 882 } 883 } 884 885 // Touchpad returns a hardware dependency condition that is satisfied 886 // iff the DUT has a touchpad. 887 func Touchpad() Condition { 888 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 889 hf := f.GetHardwareFeatures() 890 if hf == nil { 891 return withErrorStr("Did not find hardware features") 892 } 893 if hf.GetTouchpad().GetPresent() != configpb.HardwareFeatures_PRESENT { 894 return unsatisfied("DUT does not have a touchpad") 895 } 896 return satisfied() 897 }, 898 } 899 } 900 901 // WifiWEP returns a hardware dependency condition that is satisfied 902 // if the DUT's WiFi module supports WEP. 903 // New generation of Qcom chipsets do not support WEP security protocols. 904 func WifiWEP() Condition { 905 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 906 platformCondition := SkipOnPlatform( 907 "herobrine") 908 if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied { 909 return satisfied, reason, err 910 } 911 912 modelCondition := SkipOnModel( 913 "nipperkin") 914 if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied { 915 return satisfied, reason, err 916 } 917 return satisfied() 918 }, 919 } 920 } 921 922 // Wifi80211ax returns a hardware dependency condition that is satisfied 923 // iff the DUT's WiFi module supports 802.11ax. 924 func Wifi80211ax() Condition { 925 return WifiDevice( 926 QualcommWCN6750, 927 QualcommWCN6855, 928 Intel22260, 929 Intel22560, 930 IntelAX201, 931 IntelAX203, 932 IntelAX211, 933 Realtek8852APCIE, 934 Realtek8852CPCIE, 935 MediaTekMT7921PCIE, 936 MediaTekMT7921SDIO, 937 MediaTekMT7922PCIE, 938 ) 939 } 940 941 // Wifi80211ax6E returns a hardware dependency condition that is satisfied 942 // iff the DUT's WiFi module supports WiFi 6E. 943 func Wifi80211ax6E() Condition { 944 // Note: this is currently an allowlist. We can move this to a blocklist if the number of platforms gets out of hand. 945 // TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips. 946 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 947 modelCondition := Model( 948 "anahera", 949 "brya", 950 "felwinter", 951 "gimble", 952 "herobrine", 953 "kano", 954 "nipperkin", 955 "primus", 956 "redrix", 957 "taeko", 958 "taeland", 959 "vell", 960 ) 961 if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied { 962 return satisfied, reason, err 963 } 964 return satisfied() 965 }, 966 } 967 } 968 969 // WifiMACAddrRandomize returns a hardware dependency condition that is satisfied 970 // iff the DUT supports WiFi MAC Address Randomization. 971 func WifiMACAddrRandomize() Condition { 972 return SkipOnWifiDevice( 973 // mwifiex in 3.10 kernel does not support it. 974 Marvell88w8897SDIO, Marvell88w8997PCIE, 975 // Broadcom driver has only NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR 976 // but not NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR. We require randomization 977 // for all supported scan types. 978 BroadcomBCM4354SDIO, 979 // RTL8822CE reports only NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR. 980 Realtek8822CPCIE, 981 ) 982 } 983 984 // WifiTDLS returns a hardware dependency condition that is satisfied 985 // iff the DUT fully supports TDLS MGMT and OPER. 986 func WifiTDLS() Condition { 987 return SkipOnWifiDevice( 988 // QCA 6174 does not support TDLS. 989 QualcommAtherosQCA6174, QualcommAtherosQCA6174SDIO, 990 // MTK7921/SDIO (Pico6) has support issues. 991 MediaTekMT7921SDIO, 992 ) 993 } 994 995 // WifiFT returns a hardware dependency condition that is satisfied 996 // iff the DUT supports Fast Transition roaming mode. 997 func WifiFT() Condition { 998 return SkipOnWifiDevice(Marvell88w8897SDIO, Marvell88w8997PCIE) 999 } 1000 1001 // WifiNotMarvell returns a hardware dependency condition that is satisfied iff 1002 // the DUT's not using a Marvell WiFi chip. 1003 func WifiNotMarvell() Condition { 1004 // TODO(b/187699768): we don't yet have relevant fields in device.Config 1005 // about WiFi chip, so list the known platforms here for now. 1006 // TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration 1007 // completed. 1008 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1009 platformCondition := SkipOnPlatform( 1010 "bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger", 1011 ) 1012 if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied { 1013 return satisfied, reason, err 1014 } 1015 modelCondition := SkipOnModel( 1016 "bob", 1017 "kevin", 1018 "kevin64", 1019 ) 1020 if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied { 1021 return satisfied, reason, err 1022 } 1023 return satisfied() 1024 }, 1025 } 1026 } 1027 1028 // WifiNotMarvell8997 returns a hardware dependency condition that is satisfied if 1029 // the DUT is not using Marvell 8997 chipsets. 1030 func WifiNotMarvell8997() Condition { 1031 // TODO(b/187699768): replace this when we have hwdep for WiFi chips. 1032 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1033 platformCondition := SkipOnPlatform( 1034 "bob", "kevin", "kevin64", 1035 ) 1036 if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied { 1037 return satisfied, reason, err 1038 } 1039 modelCondition := SkipOnModel( 1040 "bob", 1041 "kevin", 1042 "kevin64", 1043 ) 1044 if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied { 1045 return satisfied, reason, err 1046 } 1047 return satisfied() 1048 }, 1049 } 1050 } 1051 1052 // WifiMarvell returns a hardware dependency condition that is satisfied if the 1053 // the DUT is using a Marvell WiFi chip. 1054 func WifiMarvell() Condition { 1055 // TODO(b/187699768): replace this when we have hwdep for WiFi chips. 1056 // TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration 1057 // completed. 1058 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1059 platformCondition := Platform( 1060 "bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger", 1061 ) 1062 if platformSatisfied, _, err := platformCondition.Satisfied(f); err == nil && platformSatisfied { 1063 return satisfied() 1064 } 1065 // bob, kevin may be the platform name or model name, 1066 // return satisfied if its platform name or model name is bob/kevin 1067 modelCondition := Model( 1068 "bob", "kevin", "kevin64", 1069 ) 1070 if modelSatisfied, _, err := modelCondition.Satisfied(f); err == nil && modelSatisfied { 1071 return satisfied() 1072 } 1073 return unsatisfied("DUT does not have a Marvell WiFi chip") 1074 }, 1075 } 1076 } 1077 1078 // WifiIntel returns a hardware dependency condition that if satisfied, indicates 1079 // that a device uses Intel WiFi. It is not guaranteed that the condition will be 1080 // satisfied for all devices with Intel WiFi. 1081 func WifiIntel() Condition { 1082 return WifiDevice( 1083 Intel7260, 1084 Intel7265, 1085 Intel8265, 1086 Intel9000, 1087 Intel9260, 1088 Intel22260, 1089 Intel22560, 1090 IntelAX201, 1091 IntelAX203, 1092 IntelAX211, 1093 ) 1094 } 1095 1096 // WifiQualcomm returns a hardware dependency condition that if satisfied, indicates 1097 // that a device uses Qualcomm WiFi. 1098 func WifiQualcomm() Condition { 1099 return WifiDevice( 1100 QualcommAtherosQCA6174, 1101 QualcommAtherosQCA6174SDIO, 1102 QualcommWCN3990, 1103 QualcommWCN6750, 1104 QualcommWCN6855, 1105 ) 1106 } 1107 1108 // WifiNotQualcomm returns a hardware dependency condition that if satisfied, indicates 1109 // that a device doesn't use Qualcomm WiFi. 1110 func WifiNotQualcomm() Condition { 1111 return SkipOnWifiDevice( 1112 QualcommAtherosQCA6174, 1113 QualcommAtherosQCA6174SDIO, 1114 QualcommWCN3990, 1115 QualcommWCN6750, 1116 QualcommWCN6855, 1117 ) 1118 } 1119 1120 // WifiSAP returns a hardware dependency condition that if satisfied, indicates 1121 // that a device supports SoftAP. 1122 func WifiSAP() Condition { 1123 return SkipOnWifiDevice( 1124 MediaTekMT7921PCIE, 1125 MediaTekMT7921SDIO, 1126 QualcommWCN6855, 1127 ) 1128 } 1129 1130 // WifiP2P returns a hardware dependency condition that if satisfied, indicates 1131 // that a device supports P2P. 1132 func WifiP2P() Condition { 1133 return SkipOnWifiDevice( 1134 MediaTekMT7921PCIE, 1135 MediaTekMT7921SDIO, 1136 Realtek8822CPCIE, 1137 QualcommWCN6855, 1138 ) 1139 } 1140 1141 // These are the models which utilize SAR tables stored in VPD. See (b/204199379#comment10) 1142 // for the methodology used to determine this list as well as a justification as 1143 // to why it is stable. 1144 var modelsWithVpdSarTables = []string{ 1145 "akali360", 1146 "ampton", 1147 "arcada", 1148 "babytiger", 1149 "caroline", 1150 "eve", 1151 "leona", 1152 "nautilus", 1153 "nautiluslte", 1154 "pantheon", 1155 "shyvanna", 1156 "vayne", 1157 } 1158 1159 // WifiVpdSar returns a hardware dependency condition that if satisfied, indicates 1160 // that a device supports VPD SAR tables, and the device actually has such tables 1161 // in VPD. 1162 func WifiVpdSar() Condition { 1163 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1164 modelCondition := Model(modelsWithVpdSarTables...) 1165 if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied { 1166 return satisfied, reason, err 1167 } 1168 wifi := f.GetHardwareFeatures().GetWifi() 1169 if wifi == nil { 1170 return unsatisfied("WiFi data has not been passed from DUT") 1171 } 1172 if !wifi.GetWifiVpdSar() { 1173 return unsatisfied("Device has no \"wifi_sar\" field in vpd") 1174 } 1175 return satisfied() 1176 }, 1177 } 1178 } 1179 1180 // WifiNoVpdSar returns a hardware dependency condition that if satisfied, indicates 1181 // that the device does not support VPD SAR tables. 1182 func WifiNoVpdSar() Condition { 1183 return SkipOnModel(modelsWithVpdSarTables...) 1184 } 1185 1186 func hasBattery(f *protocol.HardwareFeatures) (bool, error) { 1187 dc := f.GetDeprecatedDeviceConfig() 1188 if dc == nil { 1189 return false, errors.New("DeprecatedDeviceConfig is not given") 1190 } 1191 return dc.GetPower() == protocol.DeprecatedDeviceConfig_POWER_SUPPLY_BATTERY, nil 1192 } 1193 1194 // Battery returns a hardware dependency condition that is satisfied iff the DUT 1195 // has a battery, e.g. Chromeboxes and Chromebits don't. 1196 func Battery() Condition { 1197 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1198 hasBattery, err := hasBattery(f) 1199 if err != nil { 1200 return withError(err) 1201 } 1202 if !hasBattery { 1203 return unsatisfied("DUT does not have a battery") 1204 } 1205 return satisfied() 1206 }, 1207 } 1208 } 1209 1210 // NoBatteryBootSupported returns a hardware dependency condition that is satisfied iff the DUT 1211 // supports booting without a battery. 1212 func NoBatteryBootSupported() Condition { 1213 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1214 hasBattery, err := hasBattery(f) 1215 if err != nil { 1216 return withError(err) 1217 } 1218 if !hasBattery { 1219 return unsatisfied("DUT does not have a battery") 1220 } 1221 1222 hf := f.GetHardwareFeatures() 1223 if hf == nil { 1224 return withErrorStr("Did not find hardware features") 1225 } 1226 if !hf.GetBattery().GetNoBatteryBootSupported() { 1227 return unsatisfied("DUT does not support booting without a battery") 1228 } 1229 1230 return satisfied() 1231 }, 1232 } 1233 } 1234 1235 // SupportsHardwareOverlays returns a hardware dependency condition that is satisfied if the SoC 1236 // supports hardware overlays. 1237 func SupportsHardwareOverlays() Condition { 1238 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1239 dc := f.GetDeprecatedDeviceConfig() 1240 if dc == nil { 1241 return withErrorStr("DeprecatedDeviceConfig is not given") 1242 } 1243 1244 if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE || 1245 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 { 1246 return unsatisfied("SoC does not support Hardware Overlays") 1247 } 1248 return satisfied() 1249 }, 1250 } 1251 } 1252 1253 // platformHasNV12Overlays returns true if the the given platform is known 1254 // to support NV12 hardware overlays. 1255 func platformHasNV12Overlays(SocType protocol.DeprecatedDeviceConfig_SOC) bool { 1256 return SocType != protocol.DeprecatedDeviceConfig_SOC_HASWELL && 1257 SocType != protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL && 1258 SocType != protocol.DeprecatedDeviceConfig_SOC_BROADWELL && 1259 SocType != protocol.DeprecatedDeviceConfig_SOC_BRASWELL && 1260 SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U && 1261 SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y && 1262 SocType != protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE && 1263 SocType != protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE && 1264 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8173 && 1265 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8176 && 1266 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8183 && 1267 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8192 && 1268 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8195 && 1269 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8186 && 1270 SocType != protocol.DeprecatedDeviceConfig_SOC_MT8188G && 1271 SocType != protocol.DeprecatedDeviceConfig_SOC_SC7180 && 1272 SocType != protocol.DeprecatedDeviceConfig_SOC_SC7280 1273 } 1274 1275 // SupportsNV12Overlays says true if the SoC supports NV12 hardware overlays, 1276 // which are commonly used for video overlays. SoCs with Intel Gen 7.5 (Haswell, 1277 // BayTrail) and Gen 8 GPUs (Broadwell, Braswell) for example, don't support 1278 // those. 1279 func SupportsNV12Overlays() Condition { 1280 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1281 dc := f.GetDeprecatedDeviceConfig() 1282 if dc == nil { 1283 return withErrorStr("DeprecatedDeviceConfig is not given") 1284 } 1285 if !platformHasNV12Overlays(dc.GetSoc()) { 1286 return unsatisfied("SoC does not support NV12 Overlays") 1287 } 1288 return satisfied() 1289 }, 1290 } 1291 } 1292 1293 // SupportsVideoOverlays says true if the SoC supports some type of YUV 1294 // hardware overlay. This includes NV12, I420, and YUY2. 1295 func SupportsVideoOverlays() Condition { 1296 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1297 dc := f.GetDeprecatedDeviceConfig() 1298 if dc == nil { 1299 return withErrorStr("DeprecatedDeviceConfig is not given") 1300 } 1301 1302 var supportsYUY2Overlays = dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8183 || 1303 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8192 || 1304 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8195 || 1305 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8186 || 1306 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8188G 1307 if !platformHasNV12Overlays(dc.GetSoc()) && !supportsYUY2Overlays { 1308 return unsatisfied("SoC does not support Video Overlays") 1309 } 1310 return satisfied() 1311 }, 1312 } 1313 } 1314 1315 // Since there are no way to get whether an EC supports force discharging on a device or not, 1316 // list up the models known not to support force discharging here. 1317 var modelsWithoutForceDischargeSupport = []string{ 1318 "arcada", 1319 "celes", 1320 "drallion", 1321 "drallion360", 1322 "lulu", 1323 "sarien", 1324 } 1325 1326 // ForceDischarge returns a hardware dependency condition that is satisfied iff the DUT 1327 // has a battery and it supports force discharge through `ectool chargecontrol`. 1328 // The devices listed in modelsWithoutForceDischargeSupport do not satisfy this condition 1329 // even though they have a battery since they does not support force discharge via ectool. 1330 // This is a complementary condition of NoForceDischarge. 1331 func ForceDischarge() Condition { 1332 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1333 hasBattery, err := hasBattery(f) 1334 if err != nil { 1335 return withError(err) 1336 } 1337 if !hasBattery { 1338 return unsatisfied("DUT does not have a battery") 1339 } 1340 doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...) 1341 if err != nil { 1342 return withError(err) 1343 } 1344 if doesNotSupportForceDischarge { 1345 return unsatisfied("DUT has a battery but does not support force discharge") 1346 } 1347 return satisfied() 1348 }} 1349 } 1350 1351 // NoForceDischarge is a complementary condition of ForceDischarge. 1352 func NoForceDischarge() Condition { 1353 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1354 doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...) 1355 if err != nil { 1356 return withError(err) 1357 } 1358 if doesNotSupportForceDischarge { 1359 // Devices listed in modelsWithoutForceDischargeSupport 1360 // are known to always satisfy this condition 1361 return satisfied() 1362 } 1363 hasBattery, err := hasBattery(f) 1364 if err != nil { 1365 return withError(err) 1366 } 1367 if hasBattery { 1368 return unsatisfied("DUT supports force discharge") 1369 } 1370 return satisfied() 1371 }} 1372 } 1373 1374 // X86 returns a hardware dependency condition matching x86 ABI compatible platform. 1375 func X86() Condition { 1376 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1377 dc := f.GetDeprecatedDeviceConfig() 1378 if dc == nil { 1379 return withErrorStr("DeprecatedDeviceConfig is not given") 1380 } 1381 if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 { 1382 return satisfied() 1383 } 1384 return unsatisfied("DUT's CPU is not x86 compatible") 1385 }} 1386 } 1387 1388 // NoX86 returns a hardware dependency condition matching non-x86 ABI compatible platform. 1389 func NoX86() Condition { 1390 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1391 dc := f.GetDeprecatedDeviceConfig() 1392 if dc == nil { 1393 return withErrorStr("DeprecatedDeviceConfig is not given") 1394 } 1395 if dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86 && dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86_64 { 1396 return satisfied() 1397 } 1398 return unsatisfied("DUT's CPU is x86 compatible") 1399 }} 1400 } 1401 1402 // Emmc returns a hardware dependency condition if the device has an eMMC 1403 // storage device. 1404 func Emmc() Condition { 1405 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1406 hf := f.GetHardwareFeatures() 1407 if hf == nil { 1408 return withErrorStr("Did not find hardware features") 1409 } 1410 if hf.GetStorage().GetStorageType() == configpb.Component_Storage_EMMC { 1411 return satisfied() 1412 } 1413 return unsatisfied("DUT does not have an eMMC storage device") 1414 }} 1415 } 1416 1417 // Nvme returns a hardware dependency condition if the device has an NVMe 1418 // storage device. 1419 func Nvme() Condition { 1420 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1421 hf := f.GetHardwareFeatures() 1422 if hf == nil { 1423 return withErrorStr("Did not find hardware features") 1424 } 1425 if hf.GetStorage().GetStorageType() == configpb.Component_Storage_NVME { 1426 return satisfied() 1427 } 1428 return unsatisfied("DUT does not have an NVMe storage device") 1429 }} 1430 } 1431 1432 // NvmeSelfTest returns a dependency condition if the device has an NVMe storage device which supported NVMe self-test. 1433 func NvmeSelfTest() Condition { 1434 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1435 dc := f.GetDeprecatedDeviceConfig() 1436 if dc == nil { 1437 return withErrorStr("DeprecatedDeviceConfig is not given") 1438 } 1439 if dc.HasNvmeSelfTest { 1440 return satisfied() 1441 } 1442 return unsatisfied("DUT does not have an NVMe storage device which supports self-test") 1443 }} 1444 } 1445 1446 // Ufs returns a hardware dependency condition if the device has a UFS storage 1447 // device. 1448 func Ufs() Condition { 1449 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1450 hf := f.GetHardwareFeatures() 1451 if hf == nil { 1452 return withErrorStr("Did not find hardware features") 1453 } 1454 if hf.GetStorage().GetStorageType() == configpb.Component_Storage_UFS { 1455 return satisfied() 1456 } 1457 return unsatisfied("DUT does not have a UFS storage device") 1458 }} 1459 } 1460 1461 // MinStorage returns a hardware dependency condition requiring the minimum size of the storage in gigabytes. 1462 func MinStorage(reqGigabytes int) Condition { 1463 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1464 hf := f.GetHardwareFeatures() 1465 if hf == nil { 1466 return withErrorStr("Did not find hardware features") 1467 } 1468 if hf.GetStorage() == nil { 1469 return withErrorStr("Features.Storage was nil") 1470 } 1471 s := hf.GetStorage().GetSizeGb() 1472 if s < uint32(reqGigabytes) { 1473 return unsatisfied(fmt.Sprintf("The total storage size is smaller than required; got %dGB, need %dGB", s, reqGigabytes)) 1474 } 1475 return satisfied() 1476 }} 1477 } 1478 1479 // MinMemory returns a hardware dependency condition requiring the minimum size of the memory in megabytes. 1480 func MinMemory(reqMegabytes int) Condition { 1481 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1482 hf := f.GetHardwareFeatures() 1483 if hf == nil { 1484 return withErrorStr("Did not find hardware features") 1485 } 1486 if hf.GetMemory() == nil { 1487 return withErrorStr("Features.Memory was nil") 1488 } 1489 if hf.GetMemory().GetProfile() == nil { 1490 return withErrorStr("Features.Memory.Profile was nil") 1491 } 1492 s := hf.GetMemory().GetProfile().GetSizeMegabytes() 1493 if s < int32(reqMegabytes) { 1494 return unsatisfied(fmt.Sprintf("The total memory size is smaller than required; got %dMB, need %dMB", s, reqMegabytes)) 1495 } 1496 return satisfied() 1497 }} 1498 } 1499 1500 // MaxMemory returns a hardware dependency condition requiring no more than the 1501 // maximum size of the memory in megabytes. 1502 func MaxMemory(reqMegabytes int) Condition { 1503 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1504 hf := f.GetHardwareFeatures() 1505 if hf == nil { 1506 return withErrorStr("Did not find hardware features") 1507 } 1508 if hf.GetMemory() == nil { 1509 return withErrorStr("Features.Memory was nil") 1510 } 1511 if hf.GetMemory().GetProfile() == nil { 1512 return withErrorStr("Features.Memory.Profile was nil") 1513 } 1514 s := hf.GetMemory().GetProfile().GetSizeMegabytes() 1515 if s > int32(reqMegabytes) { 1516 return unsatisfied(fmt.Sprintf("The total memory size is larger than required; got %dMB, need <= %dMB", s, reqMegabytes)) 1517 } 1518 return satisfied() 1519 }} 1520 } 1521 1522 // Speaker returns a hardware dependency condition that is satisfied iff the DUT has a speaker. 1523 func Speaker() Condition { 1524 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1525 hf := f.GetHardwareFeatures() 1526 if hf == nil { 1527 return withErrorStr("Did not find hardware features") 1528 } 1529 if hf.GetAudio().GetSpeakerAmplifier() != nil { 1530 return satisfied() 1531 } 1532 return unsatisfied("DUT does not have speaker") 1533 }, 1534 } 1535 } 1536 1537 // Microphone returns a hardware dependency condition that is satisfied iff the DUT has a microphone. 1538 func Microphone() Condition { 1539 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1540 hf := f.GetHardwareFeatures() 1541 if hf == nil { 1542 return withErrorStr("Did not find hardware features") 1543 } 1544 if hf.GetAudio().GetLidMicrophone().GetValue() > 0 || hf.GetAudio().GetBaseMicrophone().GetValue() > 0 { 1545 return satisfied() 1546 } 1547 return unsatisfied("DUT does not have microphone") 1548 }, 1549 } 1550 } 1551 1552 // PrivacyScreen returns a hardware dependency condition that is satisfied iff the DUT has a privacy screen. 1553 func PrivacyScreen() Condition { 1554 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1555 hf := f.GetHardwareFeatures() 1556 if hf == nil { 1557 return withErrorStr("Did not find hardware features") 1558 } 1559 if hf.GetPrivacyScreen().GetPresent() != configpb.HardwareFeatures_PRESENT { 1560 return unsatisfied("DUT does not have privacy screen") 1561 } 1562 return satisfied() 1563 }, 1564 } 1565 } 1566 1567 // NoPrivacyScreen returns a hardware dependency condition that is satisfied if the DUT 1568 // does not have a privacy screen. 1569 func NoPrivacyScreen() Condition { 1570 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1571 hf := f.GetHardwareFeatures() 1572 if hf == nil { 1573 return withErrorStr("Did not find hardware features") 1574 } 1575 if status := hf.GetPrivacyScreen().GetPresent(); status != configpb.HardwareFeatures_NOT_PRESENT { 1576 return satisfied() 1577 } else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN { 1578 return unsatisfied("Could not determine if a privacy screen is present") 1579 } 1580 return unsatisfied("DUT has a privacy screen") 1581 }, 1582 } 1583 } 1584 1585 var smartAmps = []string{ 1586 configpb.HardwareFeatures_Audio_MAX98373.String(), 1587 configpb.HardwareFeatures_Audio_MAX98390.String(), 1588 configpb.HardwareFeatures_Audio_ALC1011.String(), 1589 configpb.HardwareFeatures_Audio_CS35L41.String(), 1590 } 1591 1592 // SmartAmp returns a hardware dependency condition that is satisfied iff the DUT 1593 // has smart amplifier. 1594 func SmartAmp() Condition { 1595 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1596 hf := f.GetHardwareFeatures() 1597 if hf == nil { 1598 return withErrorStr("Did not find hardware features") 1599 } 1600 if hf.GetAudio().GetSpeakerAmplifier() != nil { 1601 for _, amp := range smartAmps { 1602 if amp == hf.GetAudio().GetSpeakerAmplifier().GetName() { 1603 return satisfied() 1604 } 1605 } 1606 } 1607 return unsatisfied("DUT does not has smart amp :" + hf.GetAudio().GetSpeakerAmplifier().GetName()) 1608 }} 1609 } 1610 1611 // SmartAmpBootTimeCalibration returns a hardware dependency condition that is satisfied iff 1612 // the DUT enables boot time calibration for smart amplifier. 1613 func SmartAmpBootTimeCalibration() Condition { 1614 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1615 hf := f.GetHardwareFeatures() 1616 if hf == nil { 1617 return withErrorStr("Did not find hardware features") 1618 } 1619 if hf.GetAudio().GetSpeakerAmplifier() != nil { 1620 for _, feature := range hf.GetAudio().GetSpeakerAmplifier().GetFeatures() { 1621 if feature == configpb.Component_Amplifier_BOOT_TIME_CALIBRATION { 1622 return satisfied() 1623 } 1624 } 1625 } 1626 return unsatisfied("DUT does not enable smart amp boot time calibration") 1627 }} 1628 } 1629 1630 // formFactorListed returns whether the form factor represented by a configpb.HardwareFeatures 1631 // is listed in the given list of form factor values. 1632 func formFactorListed(hf *configpb.HardwareFeatures, ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) bool { 1633 for _, ffValue := range ffList { 1634 if hf.GetFormFactor().FormFactor == ffValue { 1635 return true 1636 } 1637 } 1638 return false 1639 } 1640 1641 // FormFactor returns a hardware dependency condition that is satisfied 1642 // iff the DUT's form factor is one of the given values. 1643 func FormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition { 1644 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1645 hf := f.GetHardwareFeatures() 1646 if hf == nil { 1647 return withErrorStr("HardwareFeatures is not given") 1648 } 1649 listed := formFactorListed(hf, ffList...) 1650 if !listed { 1651 return unsatisfied("Form factor did not match") 1652 } 1653 return satisfied() 1654 }} 1655 } 1656 1657 // SkipOnFormFactor returns a hardware dependency condition that is satisfied 1658 // iff the DUT's form factor is none of the give values. 1659 func SkipOnFormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition { 1660 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1661 hf := f.GetHardwareFeatures() 1662 if hf == nil { 1663 return withErrorStr("HardwareFeatures is not given") 1664 } 1665 listed := formFactorListed(hf, ffList...) 1666 if listed { 1667 return unsatisfied("Form factor matched to SkipOn list") 1668 } 1669 return satisfied() 1670 }} 1671 } 1672 1673 // socTypeIsV4l2Stateful returns true when stateful API is supported on the given |SocType| 1674 // or returns false when stateless API is supported. 1675 func socTypeIsV4l2Stateful(SocType protocol.DeprecatedDeviceConfig_SOC) bool { 1676 switch SocType { 1677 case protocol.DeprecatedDeviceConfig_SOC_MT8173, 1678 protocol.DeprecatedDeviceConfig_SOC_SC7180, 1679 protocol.DeprecatedDeviceConfig_SOC_SC7280: 1680 return true 1681 case protocol.DeprecatedDeviceConfig_SOC_MT8183, 1682 protocol.DeprecatedDeviceConfig_SOC_MT8192, 1683 protocol.DeprecatedDeviceConfig_SOC_MT8195, 1684 protocol.DeprecatedDeviceConfig_SOC_MT8186, 1685 protocol.DeprecatedDeviceConfig_SOC_MT8188G, 1686 protocol.DeprecatedDeviceConfig_SOC_RK3399: 1687 return false 1688 // TODO(stevecho): stateful is more common for now, but we can change this in the future 1689 default: 1690 return true 1691 } 1692 } 1693 1694 // SupportsV4L2StatefulVideoDecoding says true if the SoC supports the V4L2 1695 // stateful video decoding kernel API. Examples of this are MTK8173 and 1696 // Qualcomm devices (7180, etc). In general, we prefer to use stateless 1697 // decoding APIs, so listing them individually makes sense. 1698 func SupportsV4L2StatefulVideoDecoding() Condition { 1699 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1700 dc := f.GetDeprecatedDeviceConfig() 1701 if dc == nil { 1702 return withErrorStr("DeprecatedDeviceConfig is not given") 1703 } 1704 if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 { 1705 return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2") 1706 } 1707 if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8173 { 1708 return unsatisfied("MT8173 devices only support MT21C output (b/230654454).") 1709 } 1710 if socTypeIsV4l2Stateful(dc.GetSoc()) { 1711 return satisfied() 1712 } 1713 return unsatisfied("SoC does not support V4L2 Stateful HW video decoding") 1714 }} 1715 } 1716 1717 // SupportsV4L2StatelessVideoDecoding says true if the SoC supports the V4L2 1718 // stateless video decoding kernel API. Examples of this are MTK8192 (Asurada), 1719 // MTK8195 (Cherry), MTK8186 (Corsola), and RK3399 (scarlet/kevin/bob). 1720 func SupportsV4L2StatelessVideoDecoding() Condition { 1721 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1722 dc := f.GetDeprecatedDeviceConfig() 1723 if dc == nil { 1724 return withErrorStr("DeprecatedDeviceConfig is not given") 1725 } 1726 if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 { 1727 return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2") 1728 } 1729 if !socTypeIsV4l2Stateful(dc.GetSoc()) { 1730 return satisfied() 1731 } 1732 return unsatisfied("SoC does not support V4L2 Stateless HW video decoding") 1733 }} 1734 } 1735 1736 // SupportsHEVCVideoDecodingInChrome says true if the device supports HEVC video 1737 // decoding in Chrome. Note that this might be different from support at the 1738 // platform (i.e. drivers, kernel, hardware) level. 1739 // This function represents a policy: Tast tests using this should still make 1740 // use of SoftwareDeps "caps.HWDecodeHEVC" (or "caps.HWDecodeHEVC10BPP"). 1741 func SupportsHEVCVideoDecodingInChrome() Condition { 1742 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1743 // Disabled on any device where the config is explicitly disabled. 1744 if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_NOT_PRESENT { 1745 return unsatisfied("Chrome has HEVC disabled on this device") 1746 } 1747 // Enabled on any device where the config is explicitly enabled. 1748 if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_PRESENT { 1749 return satisfied() 1750 } 1751 // ARM embedders don't support it. 1752 if satisfied, _, err := SkipCPUSocFamily([]string{"mediatek", "rockchip", "qualcomm"}).Satisfied(f); err != nil || !satisfied { 1753 return unsatisfied("Chrome does not support HEVC video decoding on this SoC") 1754 } 1755 // AMD Zork (Picasso) and before also don't. 1756 if satisfied, _, err := SkipGPUFamily([]string{"picasso", "stoney"}).Satisfied(f); err != nil || !satisfied { 1757 return unsatisfied("Chrome does not support HEVC video decoding on this SoC") 1758 } 1759 // Any Intel TGL, ADL-P do support it. 1760 if supported, _, err := GPUFamily([]string{"tigerlake", "alderlake"}).Satisfied(f); err == nil && supported { 1761 return satisfied() 1762 } 1763 return unsatisfied("Chrome does not support HEVC video decoding on this SoC") 1764 }} 1765 } 1766 1767 // Lid returns a hardware dependency condition that is satisfied iff the DUT's form factor has a lid. 1768 func Lid() Condition { 1769 return FormFactor(Clamshell, Convertible, Detachable) 1770 } 1771 1772 // InternalKeyboard returns a hardware dependency condition that is satisfied iff the DUT's form factor has a fixed undetachable keyboard. 1773 func InternalKeyboard() Condition { 1774 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1775 hf := f.GetHardwareFeatures() 1776 if hf == nil { 1777 return withErrorStr("HardwareFeatures is not given") 1778 } 1779 if hf.GetKeyboard() == nil || 1780 hf.GetKeyboard().KeyboardType != configpb.HardwareFeatures_Keyboard_INTERNAL { 1781 return unsatisfied("DUT does not have a fixed keyboard") 1782 } 1783 return satisfied() 1784 }, 1785 } 1786 } 1787 1788 // DisplayPortConverter is satisfied if a DP converter with one of the given names 1789 // is present. 1790 func DisplayPortConverter(names ...string) Condition { 1791 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1792 hf := f.GetHardwareFeatures() 1793 if hf == nil { 1794 return withErrorStr("HardwareFeatures is not given") 1795 } 1796 1797 for _, name := range names { 1798 for _, conv := range hf.GetDpConverter().GetConverters() { 1799 if conv.GetName() == name { 1800 return satisfied() 1801 } 1802 } 1803 } 1804 return unsatisfied("DP converter did not match") 1805 }} 1806 } 1807 1808 // Vboot2 is satisfied iff crossystem param 'fw_vboot2' indicates that DUT uses vboot2. 1809 func Vboot2() Condition { 1810 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1811 dc := f.GetDeprecatedDeviceConfig() 1812 if dc == nil { 1813 return withErrorStr("DeprecatedDeviceConfig is not given") 1814 } 1815 if dc.HasVboot2 { 1816 return satisfied() 1817 } 1818 return unsatisfied("DUT is not a vboot2 device") 1819 }} 1820 } 1821 1822 // SupportsVP9KSVCHWDecoding is satisfied if the SoC supports VP9 k-SVC 1823 // hardware decoding. They are x86 devices that are capable of VP9 hardware 1824 // decoding and Qualcomm7180/7280. 1825 // VP9 k-SVC is a SVC stream in which a frame only on keyframe can refer frames 1826 // in a different spatial layer. See https://www.w3.org/TR/webrtc-svc/#dependencydiagrams* for detail. 1827 func SupportsVP9KSVCHWDecoding() Condition { 1828 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1829 dc := f.GetDeprecatedDeviceConfig() 1830 if dc == nil { 1831 return withErrorStr("DeprecatedDeviceConfig is not given") 1832 } 1833 1834 if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 { 1835 return satisfied() 1836 } 1837 1838 if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 || 1839 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7280 { 1840 return satisfied() 1841 } 1842 1843 return unsatisfied("SoC does not support VP9 k-SVC HW decoding") 1844 }} 1845 } 1846 1847 // AssistantKey is satisfied if a model has an assistant key. 1848 func AssistantKey() Condition { 1849 return Model("eve", "nocturne", "atlas") 1850 } 1851 1852 // NoAssistantKey is satisfied if a model does not have an assistant key. 1853 func NoAssistantKey() Condition { 1854 return SkipOnModel("eve", "nocturne", "atlas") 1855 } 1856 1857 // HapticTouchpad is satisfied if a model has a haptic touchpad. 1858 func HapticTouchpad() Condition { 1859 return Model("vell", "redrix") 1860 } 1861 1862 // HPS is satisfied if the HPS peripheral (go/cros-hps) is present in the DUT. 1863 func HPS() Condition { 1864 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1865 if hf := f.GetHardwareFeatures(); hf == nil { 1866 return withErrorStr("Did not find hardware features") 1867 } else if status := hf.GetHps().Present; status == configpb.HardwareFeatures_PRESENT { 1868 return satisfied() 1869 } 1870 return unsatisfied("HPS peripheral is not present") 1871 }} 1872 } 1873 1874 func containsCameraFeature(strs []string, feature string) bool { 1875 for _, f := range strs { 1876 if f == feature { 1877 return true 1878 } 1879 } 1880 return false 1881 } 1882 1883 // CameraFeature is satisfied if all the features listed in |names| are enabled on the DUT. 1884 func CameraFeature(names ...string) Condition { 1885 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1886 if hf := f.GetHardwareFeatures(); hf == nil { 1887 return withErrorStr("Did not find hardware features") 1888 } else if features := hf.GetCamera().Features; features != nil { 1889 unsatisfiedFeatures := make([]string, 0, 10) 1890 for _, n := range names { 1891 if !containsCameraFeature(features, n) { 1892 unsatisfiedFeatures = append(unsatisfiedFeatures, n) 1893 } 1894 } 1895 if len(unsatisfiedFeatures) != 0 { 1896 return unsatisfied(fmt.Sprintf("Camera features not enabled: %v", unsatisfiedFeatures)) 1897 } 1898 return satisfied() 1899 } 1900 return unsatisfied("Camera features not probed") 1901 }} 1902 } 1903 1904 // MainboardHasEarlyLibgfxinit is satisfied if the BIOS was built with Kconfig CONFIG_MAINBOARD_HAS_EARLY_LIBGFXINIT 1905 func MainboardHasEarlyLibgfxinit() Condition { 1906 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1907 hf := f.GetHardwareFeatures() 1908 if hf != nil { 1909 fwc := hf.GetFwConfig() 1910 if fwc != nil { 1911 if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_PRESENT { 1912 return satisfied() 1913 } 1914 if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_NOT_PRESENT { 1915 return unsatisfied("MainboardHasEarlyLibgfxinit Kconfig disabled") 1916 } 1917 } 1918 } 1919 // Some Brya models default to PRESENT 1920 listed, err := modelListed(f.GetDeprecatedDeviceConfig(), "skolas", "brya0", "kano", "agah", "taeko", "crota", "osiris", "gaelen", "lisbon", "gladios", "marasov", "omnigul", "constitution") 1921 if err != nil { 1922 return withError(err) 1923 } 1924 if listed { 1925 return satisfied() 1926 } 1927 // The default for this Kconfig is off, so not found is the same as disabled. 1928 return unsatisfied("Kconfig not found") 1929 }} 1930 } 1931 1932 // VbootCbfsIntegration is satisfied if the BIOS was built with Kconfig CONFIG_VBOOT_CBFS_INTEGRATION 1933 func VbootCbfsIntegration() Condition { 1934 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1935 hf := f.GetHardwareFeatures() 1936 if hf != nil { 1937 fwc := hf.GetFwConfig() 1938 if fwc != nil { 1939 if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_PRESENT { 1940 return satisfied() 1941 } 1942 if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_NOT_PRESENT { 1943 return unsatisfied("VbootCbfsIntegration Kconfig disabled") 1944 } 1945 } 1946 } 1947 // The default for this Kconfig is off, so not found is the same as disabled. 1948 return unsatisfied("Kconfig not found") 1949 }} 1950 } 1951 1952 // RuntimeProbeConfig is satisfied if the probe config of the model exists. 1953 func RuntimeProbeConfig() Condition { 1954 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1955 hf := f.GetHardwareFeatures() 1956 if hf == nil { 1957 return withErrorStr("DUT HardwareFeatures data is not given") 1958 } 1959 if hf.GetRuntimeProbeConfig().GetPresent() != configpb.HardwareFeatures_PRESENT { 1960 return unsatisfied("DUT does not have Runtime Probe config") 1961 } 1962 return satisfied() 1963 }} 1964 } 1965 1966 // SeamlessRefreshRate is satisfied if the device supports changing refresh rates without modeset. 1967 func SeamlessRefreshRate() Condition { 1968 // TODO: Determine at runtime if a device meets the requirements by inspecting EDID, kernel, and SoC versions. 1969 return Model("mithrax", "taniks") 1970 } 1971 1972 // GPUFamily is satisfied if the devices GPU family is categorized as one of the families specified. 1973 // For a complete list of values or to add new ones please check the pciid maps at 1974 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 1975 func GPUFamily(families []string) Condition { 1976 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1977 hf := f.GetHardwareFeatures() 1978 if hf == nil { 1979 return withErrorStr("DUT HardwareFeatures data is not given") 1980 } 1981 for _, family := range families { 1982 if hf.GetHardwareProbeConfig().GetGpuFamily() == family { 1983 return satisfied() 1984 } 1985 } 1986 return unsatisfied("DUT GPU family is not met") 1987 }} 1988 } 1989 1990 // SkipGPUFamily is satisfied if the devices GPU family is none of the families specified. 1991 // For a complete list of values or to add new ones please check the pciid maps at 1992 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 1993 func SkipGPUFamily(families []string) Condition { 1994 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 1995 hf := f.GetHardwareFeatures() 1996 if hf == nil { 1997 return withErrorStr("DUT HardwareFeatures data is not given") 1998 } 1999 for _, family := range families { 2000 if hf.GetHardwareProbeConfig().GetGpuFamily() == family { 2001 return unsatisfied("DUT GPU family matched with skip list") 2002 } 2003 } 2004 return satisfied() 2005 }} 2006 } 2007 2008 // GPUVendor is satisfied if the devices GPU vendor is categorized as one of the vendors specified. 2009 // For a complete list of values or to add new ones please check the files at 2010 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 2011 func GPUVendor(vendors []string) Condition { 2012 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 2013 hf := f.GetHardwareFeatures() 2014 if hf == nil { 2015 return withErrorStr("DUT HardwareFeatures data is not given") 2016 } 2017 for _, vendor := range vendors { 2018 if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor { 2019 return satisfied() 2020 } 2021 } 2022 return unsatisfied("DUT GPU vendor is not met") 2023 }} 2024 } 2025 2026 // SkipGPUVendor is satisfied if the devices GPU vendor is categorized as none of the vendors specified. 2027 // For a complete list of values or to add new ones please check the files at 2028 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 2029 func SkipGPUVendor(vendors []string) Condition { 2030 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 2031 hf := f.GetHardwareFeatures() 2032 if hf == nil { 2033 return withErrorStr("DUT HardwareFeatures data is not given") 2034 } 2035 for _, vendor := range vendors { 2036 if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor { 2037 return unsatisfied("DUT GPU vendor matched with skip list") 2038 } 2039 } 2040 return satisfied() 2041 }} 2042 } 2043 2044 // CPUSocFamily is satisfied if the devices CPU SOC family is categorized as one of the families specified. 2045 // For a complete list of values or to add new ones please check the files at 2046 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 2047 func CPUSocFamily(families []string) Condition { 2048 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 2049 hf := f.GetHardwareFeatures() 2050 if hf == nil { 2051 return withErrorStr("DUT HardwareFeatures data is not given") 2052 } 2053 for _, family := range families { 2054 if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family { 2055 return satisfied() 2056 } 2057 } 2058 return unsatisfied("DUT CPU soc family is not met") 2059 }} 2060 } 2061 2062 // SkipCPUSocFamily is satisfied if the device's CPU SOC family is none of the families specified. 2063 // For a complete list of values or to add new ones please check the files at 2064 // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe 2065 func SkipCPUSocFamily(families []string) Condition { 2066 return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) { 2067 hf := f.GetHardwareFeatures() 2068 if hf == nil { 2069 return withErrorStr("DUT HardwareFeatures data is not given") 2070 } 2071 for _, family := range families { 2072 if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family { 2073 return unsatisfied("DUT CPU soc family matched with skip list") 2074 } 2075 } 2076 return satisfied() 2077 }} 2078 } 2079 2080 // InternalTrackpoint is satisfied if a model has an internal trackpoint. 2081 func InternalTrackpoint() Condition { 2082 return Model("morphius") 2083 }