blob: 6c7da8dff3f4449d393f042196878d8edd1d10d5 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package hwdep provides the hardware dependency mechanism to select tests to run on
// a DUT based on its hardware features and setup.
package hwdep
import (
"fmt"
"os"
"regexp"
"strings"
configpb "go.chromium.org/chromiumos/config/go/api"
"go.chromium.org/tast/core/errors"
"go.chromium.org/tast/core/internal/dep"
"go.chromium.org/tast/core/testing/cellularconst"
"go.chromium.org/tast/core/testing/wlan"
"go.chromium.org/tast/core/framework/protocol"
)
// These are form factor values that can be passed to FormFactor and SkipOnFormFactor.
const (
FormFactorUnknown = configpb.HardwareFeatures_FormFactor_FORM_FACTOR_UNKNOWN
Clamshell = configpb.HardwareFeatures_FormFactor_CLAMSHELL
Convertible = configpb.HardwareFeatures_FormFactor_CONVERTIBLE
Detachable = configpb.HardwareFeatures_FormFactor_DETACHABLE
Chromebase = configpb.HardwareFeatures_FormFactor_CHROMEBASE
Chromebox = configpb.HardwareFeatures_FormFactor_CHROMEBOX
Chromebit = configpb.HardwareFeatures_FormFactor_CHROMEBIT
Chromeslate = configpb.HardwareFeatures_FormFactor_CHROMESLATE
)
// Deps holds hardware dependencies all of which need to be satisfied to run a test.
type Deps = dep.HardwareDeps
// Condition represents one condition of hardware dependencies.
type Condition = dep.HardwareCondition
// D returns hardware dependencies representing the given Conditions.
func D(conds ...Condition) Deps {
return dep.NewHardwareDeps(conds...)
}
// idRegexp is the pattern that the given model/platform ID names should match with.
var idRegexp = regexp.MustCompile(`^[a-z0-9_-]+$`)
// FWUIType as int.
type FWUIType int
// These are different flavors of UI.
const (
LegacyMenuUI FWUIType = iota
LegacyClamshellUI
MenuUI
)
func satisfied() (bool, string, error) {
return true, "", nil
}
func unsatisfied(reason string) (bool, string, error) {
return false, reason, nil
}
func withError(err error) (bool, string, error) {
return false, "", err
}
func withErrorStr(s string) (bool, string, error) {
return false, "", errors.New(s)
}
// modelListed returns whether the model represented by a protocol.DeprecatedDeviceConfig is listed
// in the given list of names or not.
func modelListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) {
if dc == nil || dc.Id == nil || dc.Id.Model == "" {
return false, errors.New("DeprecatedDeviceConfig does not have model ID")
}
m := dc.Id.Model
// Remove the suffix _signed since it is not a part of a model name.
modelID := strings.TrimSuffix(strings.ToLower(m), "_signed")
for _, name := range names {
if name == modelID {
return true, nil
}
}
return false, nil
}
// platformListed returns whether the platform represented by a protocol.HardwareFeatures
// is listed in the given list of names or not.
func platformListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) {
if dc == nil || dc.Id == nil {
return false, errors.New("DeprecatedDeviceConfig does not have platform ID")
}
p := dc.Id.Platform
platformID := strings.ToLower(p)
for _, name := range names {
if name == platformID {
return true, nil
}
}
return false, nil
}
// WLAN device IDs. Convenience wrappers.
const (
Marvell88w8897SDIO = wlan.Marvell88w8897SDIO
Marvell88w8997PCIE = wlan.Marvell88w8997PCIE
QualcommAtherosQCA6174 = wlan.QualcommAtherosQCA6174
QualcommAtherosQCA6174SDIO = wlan.QualcommAtherosQCA6174SDIO
QualcommWCN3990 = wlan.QualcommWCN3990
QualcommWCN6750 = wlan.QualcommWCN6750
QualcommWCN6855 = wlan.QualcommWCN6855
Intel7260 = wlan.Intel7260
Intel7265 = wlan.Intel7265
Intel8265 = wlan.Intel8265
Intel9000 = wlan.Intel9000
Intel9260 = wlan.Intel9260
Intel22260 = wlan.Intel22260
Intel22560 = wlan.Intel22560
IntelAX201 = wlan.IntelAX201
IntelAX203 = wlan.IntelAX203
IntelAX211 = wlan.IntelAX211
IntelBE200 = wlan.IntelBE200
BroadcomBCM4354SDIO = wlan.BroadcomBCM4354SDIO
BroadcomBCM4356PCIE = wlan.BroadcomBCM4356PCIE
BroadcomBCM4371PCIE = wlan.BroadcomBCM4371PCIE
Realtek8822CPCIE = wlan.Realtek8822CPCIE
Realtek8852APCIE = wlan.Realtek8852APCIE
Realtek8852CPCIE = wlan.Realtek8852CPCIE
MediaTekMT7921PCIE = wlan.MediaTekMT7921PCIE
MediaTekMT7921SDIO = wlan.MediaTekMT7921SDIO
MediaTekMT7922PCIE = wlan.MediaTekMT7922PCIE
)
// wifiDeviceListed returns whether a WiFi device given in HardwareFeatures is listed in the given list of names or not.
func wifiDeviceListed(hwf *protocol.HardwareFeatures, devices ...wlan.DeviceID) (bool, error) {
wifi := hwf.GetHardwareFeatures().GetWifi()
if wifi == nil {
return false, errors.New("Wifi data has not been passed from DUT")
}
chipset := int32(wifi.WifiChips[0])
for _, id := range devices {
if id == wlan.DeviceID(chipset) {
return true, nil
}
}
return false, nil
}
// Model returns a hardware dependency condition that is satisfied if the DUT's model ID is
// one of the given names.
// Practically, this is not recommended to be used in most cases. Please consider again
// if this is the appropriate use, and whether there exists another option, such as
// check whether DUT needs to have touchscreen, some specific SKU, internal display etc.
//
// Expected example use case is; there is a problem in some code where we do not have
// control, such as a device specific driver, or hardware etc., and unfortunately
// it unlikely be fixed for a while.
// Another use case is; a test is stably running on most of models, but failing on some
// specific models. By using Model() and SkipOnModel() combination, the test can be
// promoted to critical on stably running models, while it is still informational
// on other models. Note that, in this case, it is expected that an engineer is
// assigned to stabilize/fix issues of the test on informational models.
func Model(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...)
if err != nil {
return withError(err)
}
if !listed {
return unsatisfied("ModelId did not match")
}
return satisfied()
}}
}
// SkipOnModel returns a hardware dependency condition that is satisfied
// if and only if the DUT's model ID is none of the given names.
// Please find the doc of Model(), too, for details about the expected usage.
func SkipOnModel(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...)
if err != nil {
// Failed to get the model name.
// Run the test to report error if it fails on this device.
return satisfied()
}
if listed {
return unsatisfied("ModelId matched with skip-on list")
}
return satisfied()
}}
}
// Platform returns a hardware dependency condition that is satisfied
// if and only if the DUT's platform ID is one of the give names.
// Please find the doc of Model(), too, for details about the expected usage.
// Deprecated. Use Model() or "board:*" software dependency.
func Platform(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...)
if err != nil {
return withError(err)
}
if !listed {
return unsatisfied("PlatformId did not match")
}
return satisfied()
}}
}
// SkipOnPlatform returns a hardware dependency condition that is satisfied
// if and only if the DUT's platform ID is none of the give names.
// Please find the doc of Model(), too, for details about the expected usage.
// Deprecated. Use SkipOnModel() or "board:*" software dependency.
func SkipOnPlatform(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...)
if err != nil {
return withError(err)
}
if listed {
return unsatisfied("PlatformId matched with skip-on list")
}
return satisfied()
}}
}
// WifiDevice returns a hardware dependency condition that is satisfied
// if and only if the DUT's WiFi device is one of the given names.
// Please find the doc of Model(), too, for details about the expected usage.
func WifiDevice(devices ...wlan.DeviceID) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := wifiDeviceListed(f, devices...)
if err != nil {
// Fail-open. Assumption is that if the device is not recognized, it doesn't match.
return unsatisfied(fmt.Sprintf("Unrecognized device. Assume not matching. Err %v", err))
}
if !listed {
return unsatisfied("WiFi device did not match")
}
return satisfied()
}}
}
// SkipOnWifiDevice returns a hardware dependency condition that is satisfied
// if and only if the DUT's WiFi device is none of the given names.
// Please find the doc of Model(), too, for details about the expected usage.
func SkipOnWifiDevice(devices ...wlan.DeviceID) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := wifiDeviceListed(f, devices...)
if err != nil {
// Failed to get the device id.
// Run the test to report error if it fails on this device.
return satisfied()
}
if listed {
return unsatisfied("WiFi device matched with skip-on list")
}
return satisfied()
}}
}
// TouchScreen returns a hardware dependency condition that is satisfied
// if and only if the DUT has touchscreen.
func TouchScreen() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
if hf.GetScreen().GetTouchSupport() == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("DUT does not have touchscreen")
},
}
}
// NoTouchScreen returns a hardware dependency condition that is satisfied
// if the DUT doesn't have a touchscreen.
func NoTouchScreen() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
if status := hf.GetScreen().GetTouchSupport(); status == configpb.HardwareFeatures_NOT_PRESENT {
return satisfied()
}
return unsatisfied("DUT has a touchscreen")
},
}
}
// ChromeEC returns a hardware dependency condition that is satisfied
// if and only if the DUT has a present EC of the "Chrome EC" type.
func ChromeEC() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
ecIsPresent := hf.GetEmbeddedController().GetPresent() == configpb.HardwareFeatures_PRESENT
ecIsChrome := hf.GetEmbeddedController().GetEcType() == configpb.HardwareFeatures_EmbeddedController_EC_CHROME
if ecIsPresent && ecIsChrome {
return satisfied()
}
return unsatisfied("DUT does not have chrome EC")
},
}
}
// ECFeatureTypecCmd returns a hardware dependency condition that is satisfied
// if and only if the DUT has an EC which supports the EC_FEATURE_TYPEC_CMD feature flag.
func ECFeatureTypecCmd() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
// We only return unsatisfied if we know for sure that the EC doesn't support the feature flag.
// In cases where the result is UNKNOWN, we allow the test to continue and fail.
if hf.GetEmbeddedController().GetFeatureTypecCmd() == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT EC does not support EC_FEATURE_TYPEC_CMD")
}
return satisfied()
},
}
}
// ECFeatureCBI returns a hardware dependency condition that
// is satisfied if and only if the DUT has an EC which supports CBI.
func ECFeatureCBI() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetEmbeddedController().GetCbi(); status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have cbi")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine cbi presence")
}
return satisfied()
},
}
}
// ECFeatureDetachableBase returns a hardware dependency condition that is
// satisfied if and only if the DUT has the detachable base attached.
func ECFeatureDetachableBase() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
status := hf.GetEmbeddedController().GetDetachableBase()
if status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("Detachable base is not attached to DUT")
}
if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine detachable base presence")
}
return satisfied()
},
}
}
// ECFeatureChargeControlV2 returns a hardware dependency condition that is
// satisfied if and only if the DUT supports version 2 of the EC_CMD_CHARGE_CONTROL feature
// (which adds battery sustain).
func ECFeatureChargeControlV2() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetEmbeddedController().GetFeatureChargeControlV2() == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT EC does not support EC_CMD_CHARGE_CONTROL version 2")
}
return satisfied()
},
}
}
// ECFeatureAssertsPanic returns a hardware dependency condition that is
// satisfied if and only if the DUT EC will panic on assertion failure.
func ECFeatureAssertsPanic() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
status := hf.GetEmbeddedController().GetFeatureAssertsPanic()
if status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT EC does not panic on assert failure")
}
if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if DUT EC panics on assert failure")
}
return satisfied()
},
}
}
// ECFeatureSystemSafeMode returns a hardware dependency condition that is
// satisfied if and only if the DUT EC supports system safe mode recovery.
func ECFeatureSystemSafeMode() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
status := hf.GetEmbeddedController().GetFeatureSystemSafeMode()
if status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT EC does not support system safe mode")
}
if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if DUT EC supports system safe mode")
}
return satisfied()
},
}
}
// ECFeatureMemoryDumpCommands returns a hardware dependency condition that is
// satisfied if and only if the DUT EC supports memory dump host commands.
func ECFeatureMemoryDumpCommands() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
status := hf.GetEmbeddedController().GetFeatureMemoryDumpCommands()
if status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT EC does not support memory dump host commands")
}
if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if DUT EC supports memory dump host commands")
}
return satisfied()
},
}
}
// Cellular returns a hardware dependency condition that
// is satisfied if and only if the DUT has a cellular modem.
func Cellular() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a cellular modem")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
return satisfied()
},
}
}
// SkipOnCellularVariant returns a hardware dependency condition that is satisfied
// if and only if the DUT's cellular variant is none of the given names.
func SkipOnCellularVariant(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a cellular modem")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
variant := hf.GetCellular().GetModel()
for _, name := range names {
if name == variant {
return unsatisfied("Variant matched with skip-on list")
}
}
return satisfied()
}}
}
// CellularVariant returns a hardware dependency condition that is satisfied
// if and only if the DUT's cellular variant is one of the given names.
func CellularVariant(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a cellular modem")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
variant := hf.GetCellular().GetModel()
for _, name := range names {
if name == variant {
return satisfied()
}
}
return unsatisfied("Variant did not match")
}}
}
// CellularModemType returns a hardware dependency condition that is satisfied
// if and only if the DUT's cellular modem type is one of the given types.
func CellularModemType(modemTypes ...cellularconst.ModemType) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a cellular modem")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
variant := hf.GetCellular().GetModel()
modemType, err := cellularconst.GetModemTypeFromVariant(variant)
if err != nil {
return withError(err)
}
for _, m := range modemTypes {
if m == modemType {
return satisfied()
}
}
return unsatisfied("Modem type did not match")
}}
}
// SkipOnCellularModemType returns a hardware dependency condition that is satisfied
// if and only if the DUT's cellular modem type is none of the given types.
func SkipOnCellularModemType(modemTypes ...cellularconst.ModemType) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a cellular modem")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
variant := hf.GetCellular().GetModel()
modemType, err := cellularconst.GetModemTypeFromVariant(variant)
if err != nil {
return withError(err)
}
for _, m := range modemTypes {
if m == modemType {
return unsatisfied("Modem type matched with skip-on list")
}
}
return satisfied()
}}
}
// CellularSoftwareDynamicSar returns a hardware dependency condition that
// is satisfied if and only if the DUT has enabled software dynamic sar.
func CellularSoftwareDynamicSar() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().GetDynamicPowerReductionConfig().GetModemManager(); status {
return satisfied()
}
return unsatisfied("DUT does not support cellular sw dynamic sar")
},
}
}
// NoCellular returns a hardware dependency condition that
// is satisfied if and only if the DUT does not have a cellular modem.
func NoCellular() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return satisfied()
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if cellular model is present")
}
return unsatisfied("DUT has a cellular modem")
},
}
}
// Bluetooth returns a hardware dependency condition that
// is satisfied if and only if the DUT has a bluetooth adapter.
func Bluetooth() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if status := hf.GetBluetooth().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("DUT does not have a bluetooth adapter")
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine bluetooth adapter presence")
}
return satisfied()
},
}
}
// GSCUART returns a hardware dependency condition that is satisfied if and only if the DUT has a GSC and that GSC has a working UART.
// TODO(b/224608005): Add a cros_config for this and use that instead.
func GSCUART() Condition {
// There is no way to probe for this condition, and there should be no machines newer than 2017 without working UARTs.
return SkipOnModel(
"astronaut",
"blacktiplte",
"caroline",
"celes",
"electro",
"elm",
"eve",
"hana",
"kefka",
"lars",
"nasher",
"nocturne",
"relm",
"robo360",
"sand",
"sentry",
"snappy",
)
}
// GSCRWKeyIDProd returns a hardware dependency condition that
// is satisfied if and only if the DUT does have a GSC RW image signed with prod key.
func GSCRWKeyIDProd() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetTrustedPlatformModule().GetProductionRwKeyId(); status == configpb.HardwareFeatures_PRESENT {
return satisfied()
} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
return unsatisfied("Could not determine if production RW key is used to sign GSC image")
}
return unsatisfied("DUT has a dev signed GSC image")
},
}
}
// HasNoTpm returns a hardware dependency condition that is satisfied if and only if the DUT
// doesn't have an enabled TPM.
func HasNoTpm() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() != configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED {
return unsatisfied("DUT has an enabled TPM")
}
return satisfied()
},
}
}
// HasTpm returns a hardware dependency condition that is satisfied if and only if the DUT
// does have an enabled TPM.
func HasTpm() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED {
return unsatisfied("DUT has no enabled TPM")
}
return satisfied()
},
}
}
// HasTpm1 returns a hardware dependency condition that is satisfied if and only if the DUT
// does have an enabled TPM1.2.
func HasTpm1() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V1_2 {
return satisfied()
}
return unsatisfied("DUT has no enabled TPM1.2")
},
}
}
// HasTpm2 returns a hardware dependency condition that is satisfied if and only if the DUT
// does have an enabled TPM2.0.
func HasTpm2() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V2 {
return satisfied()
}
return unsatisfied("DUT has no enabled TPM2.0")
},
}
}
// HasGSCCr50 returns a hardware dependency condition that is satisfied if and only if the DUT
// does have a Cr50 GSC.
func HasGSCCr50() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetGscFwName() == configpb.HardwareFeatures_TrustedPlatformModule_GSC_CR50 {
return satisfied()
}
return unsatisfied("DUT has no Cr50 GSC")
},
}
}
// HasGSCTi50 returns a hardware dependency condition that is satisfied if and only if the DUT
// does have a Ti50 GSC.
func HasGSCTi50() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetGscFwName() == configpb.HardwareFeatures_TrustedPlatformModule_GSC_TI50 {
return satisfied()
}
return unsatisfied("DUT has no Ti50 GSC")
},
}
}
// HasTpmNvramRollbackSpace returns a hardware dependency condition that is satisfied if and only
// if the DUT has the TPM space to be used during enterprise enrollment.
func HasTpmNvramRollbackSpace() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTrustedPlatformModule().GetEnterpriseRollbackSpace() == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("DUT's TPM has no enterprise rollback space (0x100e)")
},
}
}
// CPUNotNeedsCoreScheduling returns a hardware dependency condition that is satisfied if and only if the DUT's
// CPU is does not need to use core scheduling to mitigate hardware vulnerabilities.
func CPUNotNeedsCoreScheduling() Condition {
return cpuNeedsCoreScheduling(false)
}
// CPUNeedsCoreScheduling returns a hardware dependency condition that is satisfied if and only if the DUT's
// CPU needs to use core scheduling to mitigate hardware vulnerabilities.
func CPUNeedsCoreScheduling() Condition {
return cpuNeedsCoreScheduling(true)
}
// cpuNeedsCoreScheduling generates a Condition for CPUNeedsCoreScheduling() and its inverse,
// CPUNotNeedsCoreScheduling(). A CPU needs core scheduling if it is vulnerable to either L1TF or
// MDS hardware vulnerabilities.
func cpuNeedsCoreScheduling(enabled bool) Condition {
needsCoreScheduling := func(hf *configpb.HardwareFeatures) (bool, string) {
for _, f := range hf.GetSoc().Vulnerabilities {
if f == configpb.Component_Soc_L1TF {
return true, "CPU is vulnerable to L1TF"
}
if f == configpb.Component_Soc_MDS {
return true, "CPU is vulnerable MDS"
}
}
return false, "CPU is not vulnerable to L1TF or MDS"
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
needed, description := needsCoreScheduling(hf)
if needed == enabled {
return satisfied()
}
return unsatisfied(description)
},
}
}
// HasParavirtSchedControl returns a hardware dependency condition that is satisfied if and only if the
// DUT has kvm module parameter for controlling paravirt scheduling.
func HasParavirtSchedControl() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if _, err := os.Stat("/sys/module/kvm/parameters/kvm_pv_sched"); err != nil {
return unsatisfied("Device doesn't support paravirt scheduling feature")
}
return satisfied()
},
}
}
// HasSchedRTControl returns a hardware dependency condition that is satisfied if and only if the
// DUT has sysctl for deadline server for realtime tasks.
func HasSchedRTControl() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if _, err := os.Stat("/proc/sys/kernel/sched_rr_timeslice_ms"); err != nil {
return unsatisfied("Device doesn't have sched_rr_timeslice_ms")
}
if _, err := os.Stat("/proc/sys/kernel/sched_rt_runtime_us"); err != nil {
return unsatisfied("Device doesn't have sched_rt_runtime_us")
}
if _, err := os.Stat("/proc/sys/kernel/sched_rt_period_us"); err != nil {
return unsatisfied("Device doesn't have sched_rt_period_us")
}
if _, err := os.Stat("/sys/kernel/debug/sched/fair_server"); err != nil {
return unsatisfied("Device doesn't have sched fair_server")
}
return satisfied()
},
}
}
// CPUSupportsSMT returns a hardware dependency condition that is satisfied if and only if the DUT supports
// Symmetric Multi-Threading.
func CPUSupportsSMT() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
for _, f := range hf.GetSoc().Features {
if f == configpb.Component_Soc_SMT {
return satisfied()
}
}
return unsatisfied("CPU does not have SMT support")
},
}
}
// CPUSupportsSHANI returns a hardware dependency condition that is satisfied if and only if the DUT supports
// SHA-NI instruction extension.
func CPUSupportsSHANI() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
for _, f := range hf.GetSoc().Features {
if f == configpb.Component_Soc_SHA_NI {
return satisfied()
}
}
return unsatisfied("CPU does not have SHA-NI support")
},
}
}
// Fingerprint returns a hardware dependency condition that is satisfied
// if and only if the DUT has fingerprint sensor.
func Fingerprint() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if !hf.GetFingerprint().GetPresent() {
return unsatisfied("DUT does not have fingerprint sensor")
}
return satisfied()
},
}
}
// NoFingerprint returns a hardware dependency condition that is satisfied
// if the DUT doesn't have fingerprint sensor.
func NoFingerprint() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetFingerprint().GetPresent() {
return unsatisfied("DUT has fingerprint sensor")
}
return satisfied()
},
}
}
// SkipOnFPMCU returns a hardware dependency condition that is satisfied
// if and only if the DUT's fingerprint board is none of the given names.
func SkipOnFPMCU(names ...string) Condition {
for _, n := range names {
if !idRegexp.MatchString(n) {
return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)}
}
}
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
fingerprintBoard := hf.GetFingerprint().GetBoard()
for _, n := range names {
if fingerprintBoard == n {
return unsatisfied("Fingerprint test skipped on " + fingerprintBoard + " board")
}
}
return satisfied()
}}
}
// FingerprintDiagSupported returns a hardware dependency condition that is
// satisfied if and only if the fingerprint diagnostic is supported on the DUT.
func FingerprintDiagSupported() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if !hf.GetFingerprint().GetFingerprintDiag().GetRoutineEnable() {
return unsatisfied("DUT does not support fingerprint diagnostic routine")
}
return satisfied()
},
}
}
// VRR returns a hardware dependency condition that is satisfied if and only if
// the DUT is VRR Capable (has vrr_capable value set to 1 in modetest).
func VRR() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetVrr().GetPresent() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have VRR")
}
return satisfied()
},
}
}
// Display returns a hardware dependency condition that is satisfied if and
// only if the DUT has some display, internal or external.
func Display() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
display := hf.GetDisplay()
if display == nil {
return withErrorStr("Display is not given")
}
if display.GetType() == configpb.HardwareFeatures_Display_TYPE_UNKNOWN {
return unsatisfied("DUT does not have a display")
}
return satisfied()
},
}
}
// ExternalDisplay returns a hardware dependency condition that is satisfied
// if and only if the DUT has an external display
func ExternalDisplay() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
display := hf.GetDisplay()
if display == nil {
return withErrorStr("Display is not given")
}
if display.GetType() == configpb.HardwareFeatures_Display_TYPE_EXTERNAL || display.GetType() == configpb.HardwareFeatures_Display_TYPE_INTERNAL_EXTERNAL {
return satisfied()
}
return unsatisfied("DUT does not have an external display")
},
}
}
// NoExternalDisplay returns a hardware dependency condition that is satisfied
// if and only if the DUT does not have an external display
func NoExternalDisplay() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hasExternalDisplay, _, err := ExternalDisplay().Satisfied(f)
if err != nil {
return withError(err)
}
if hasExternalDisplay {
return unsatisfied("DUT has an external display")
}
return satisfied()
},
}
}
// HdmiConnected returns a hardware dependency condition that is satisfied
// if and only if the DUT has an external display with HDMI connected.
func HdmiConnected() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetHdmi().GetPresent() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have HDMI Connected")
}
return satisfied()
},
}
}
// InternalDisplay returns a hardware dependency condition that is satisfied
// if and only if the DUT has an internal display, e.g. Chromeboxes and Chromebits don't.
func InternalDisplay() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetScreen().GetPanelProperties() != nil {
return satisfied()
}
return unsatisfied("DUT does not have an internal display")
},
}
}
// InternalDisplayWithHeightPx returns a hardware dependency condition that is
// satisfied if and only if the DUT has an internal display (e.g. Chromeboxes
// and Chromebits don't) and specific height in pixels.
func InternalDisplayWithHeightPx(heightPx int32) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetScreen().GetPanelProperties().HeightPx == heightPx {
return satisfied()
}
return unsatisfied("DUT does not have an internal display with specific height")
},
}
}
// NoInternalDisplay returns a hardware dependency condition that is satisfied
// if and only if the DUT does not have an internal display.
func NoInternalDisplay() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetScreen().GetPanelProperties() != nil {
return unsatisfied("DUT has an internal display")
}
return satisfied()
},
}
}
// Keyboard returns a hardware dependency condition that is satisfied
// if and only if the DUT has an keyboard, e.g. Chromeboxes and Chromebits don't.
// Tablets might have a removable keyboard.
func Keyboard() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetKeyboard() == nil ||
hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_KEYBOARD_TYPE_UNKNOWN ||
hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_NONE {
return unsatisfied("DUT does not have a keyboard")
}
return satisfied()
},
}
}
// KeyboardBacklight returns a hardware dependency condition that is satisfied
// if the DUT supports keyboard backlight functionality.
func KeyboardBacklight() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetKeyboard().GetBacklight() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have keyboard backlight")
}
return satisfied()
},
}
}
// Touchpad returns a hardware dependency condition that is satisfied
// if and only if the DUT has a touchpad, e.g. Chromeboxes and Chromebits don't.
// Tablets might have a detachable touchpad, which also satisfy this condition.
// For a detachable touchpad, this condition does not guarantee that they are
// currently attached. Use this in combination with `ECFeatureDetachableBase`
// if the base being attached is required.
func Touchpad() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetTouchpad().GetPresent() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have a touchpad")
}
return satisfied()
},
}
}
// InternalTouchpad returns a hardware dependency condition that is satisfied if
// and only if the DUT's form factor has a fixed undetachable touchpad.
func InternalTouchpad() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetTouchpad() == nil ||
hf.GetTouchpad().GetPresent() != configpb.HardwareFeatures_PRESENT ||
hf.GetTouchpad().TouchpadType != configpb.HardwareFeatures_Touchpad_INTERNAL {
return unsatisfied("DUT does not have a fixed touchpad")
}
return satisfied()
},
}
}
// WifiWEP returns a hardware dependency condition that is satisfied
// if the DUT's WiFi module supports WEP.
// New generation of Qcom chipsets do not support WEP security protocols.
func WifiWEP() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := SkipOnPlatform(
"herobrine")
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
modelCondition := SkipOnModel(
"nipperkin")
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// Wifi80211ax returns a hardware dependency condition that is satisfied
// if and only if the DUT's WiFi module supports 802.11ax.
func Wifi80211ax() Condition {
return WifiDevice(
QualcommWCN6750,
QualcommWCN6855,
Intel22260,
Intel22560,
IntelAX201,
IntelAX203,
IntelAX211,
IntelBE200,
Realtek8852APCIE,
Realtek8852CPCIE,
MediaTekMT7921PCIE,
MediaTekMT7921SDIO,
MediaTekMT7922PCIE,
)
}
// Wifi80211ax6E returns a hardware dependency condition that is satisfied
// if and only if the DUT's WiFi module supports WiFi 6E.
func Wifi80211ax6E() Condition {
return WifiDevice(
QualcommWCN6855,
IntelAX211,
IntelBE200,
MediaTekMT7922PCIE,
)
}
// Wifi80211be returns a hardware dependency condition that is satisfied
// if and only if the DUT's WiFi module supports WiFi 7.
func Wifi80211be() Condition {
return WifiDevice(
IntelBE200,
)
}
// WifiMACAddrRandomize returns a hardware dependency condition that is satisfied
// if and only if the DUT supports WiFi MAC Address Randomization.
func WifiMACAddrRandomize() Condition {
return SkipOnWifiDevice(
// mwifiex in 3.10 kernel does not support it.
Marvell88w8897SDIO, Marvell88w8997PCIE,
// Broadcom driver has only NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR
// but not NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR. We require randomization
// for all supported scan types.
BroadcomBCM4354SDIO,
// RTL8822CE reports only NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR.
Realtek8822CPCIE,
)
}
// WifiTDLS returns a hardware dependency condition that is satisfied
// if and only if the DUT fully supports TDLS MGMT and OPER.
func WifiTDLS() Condition {
return SkipOnWifiDevice(
// QCA 6174 does not support TDLS.
QualcommAtherosQCA6174, QualcommAtherosQCA6174SDIO,
// MTK7921/SDIO (Pico6) has support issues.
MediaTekMT7921SDIO,
)
}
// WifiFT returns a hardware dependency condition that is satisfied
// if and only if the DUT supports Fast Transition roaming mode.
func WifiFT() Condition {
return SkipOnWifiDevice(Marvell88w8897SDIO, Marvell88w8997PCIE)
}
// WifiNotMarvell returns a hardware dependency condition that is satisfied if and only if
// the DUT's not using a Marvell WiFi chip.
func WifiNotMarvell() Condition {
// TODO(b/187699768): we don't yet have relevant fields in device.Config
// about WiFi chip, so list the known platforms here for now.
// TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration
// completed.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := SkipOnPlatform(
"bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger",
)
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
modelCondition := SkipOnModel(
"bob",
"kevin",
"kevin64",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiNotMarvell8997 returns a hardware dependency condition that is satisfied if
// the DUT is not using Marvell 8997 chipsets.
func WifiNotMarvell8997() Condition {
// TODO(b/187699768): replace this when we have hwdep for WiFi chips.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := SkipOnPlatform(
"bob", "kevin", "kevin64",
)
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
modelCondition := SkipOnModel(
"bob",
"kevin",
"kevin64",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiMarvell returns a hardware dependency condition that is satisfied if the
// the DUT is using a Marvell WiFi chip.
func WifiMarvell() Condition {
// TODO(b/187699768): replace this when we have hwdep for WiFi chips.
// TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration
// completed.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := Platform(
"bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger",
)
if platformSatisfied, _, err := platformCondition.Satisfied(f); err == nil && platformSatisfied {
return satisfied()
}
// bob, kevin may be the platform name or model name,
// return satisfied if its platform name or model name is bob/kevin
modelCondition := Model(
"bob", "kevin", "kevin64",
)
if modelSatisfied, _, err := modelCondition.Satisfied(f); err == nil && modelSatisfied {
return satisfied()
}
return unsatisfied("DUT does not have a Marvell WiFi chip")
},
}
}
// WifiIntel returns a hardware dependency condition that if satisfied, indicates
// that a device uses Intel WiFi. It is not guaranteed that the condition will be
// satisfied for all devices with Intel WiFi.
func WifiIntel() Condition {
return WifiDevice(
Intel7260,
Intel7265,
Intel8265,
Intel9000,
Intel9260,
Intel22260,
Intel22560,
IntelAX201,
IntelAX203,
IntelAX211,
IntelBE200,
)
}
// WifiQualcomm returns a hardware dependency condition that if satisfied, indicates
// that a device uses Qualcomm WiFi.
func WifiQualcomm() Condition {
return WifiDevice(
QualcommAtherosQCA6174,
QualcommAtherosQCA6174SDIO,
QualcommWCN3990,
QualcommWCN6750,
QualcommWCN6855,
)
}
// WifiNotQualcomm returns a hardware dependency condition that if satisfied, indicates
// that a device doesn't use Qualcomm WiFi.
func WifiNotQualcomm() Condition {
return SkipOnWifiDevice(
QualcommAtherosQCA6174,
QualcommAtherosQCA6174SDIO,
QualcommWCN3990,
QualcommWCN6750,
QualcommWCN6855,
)
}
// WifiSAP returns a hardware dependency condition that if satisfied, indicates
// that a device supports SoftAP.
func WifiSAP() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
// For QC, SAP is not yet supported.
QCCondition := WifiNotQualcomm()
if satisfied, reason, err := QCCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
// For MT7921, SAP is not yet supported on kernel 5.4 and 5.10.
modelCondition := SkipOnModel(
"dojo", "tomato", "pico6", "spherion")
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiP2P returns a hardware dependency condition that if satisfied, indicates
// that a device supports P2P.
func WifiP2P() Condition {
return SkipOnWifiDevice(
MediaTekMT7921PCIE,
MediaTekMT7921SDIO,
Realtek8822CPCIE,
QualcommWCN6855,
)
}
// These are the models which utilize SAR tables stored in VPD. See (b/204199379#comment10)
// for the methodology used to determine this list as well as a justification as
// to why it is stable.
var modelsWithVpdSarTables = []string{
"akali360",
"ampton",
"arcada",
"babytiger",
"basking",
"caroline",
"eve",
"leona",
"nautilus",
"nautiluslte",
"pantheon",
"shyvana",
"vayne",
}
// WifiVpdSar returns a hardware dependency condition that if satisfied, indicates
// that a device supports VPD SAR tables, and the device actually has such tables
// in VPD.
func WifiVpdSar() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
modelCondition := Model(modelsWithVpdSarTables...)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
wifi := f.GetHardwareFeatures().GetWifi()
if wifi == nil {
return unsatisfied("WiFi data has not been passed from DUT")
}
if !wifi.GetWifiVpdSar() {
return unsatisfied("Device has no \"wifi_sar\" field in vpd")
}
return satisfied()
},
}
}
// WifiNoVpdSar returns a hardware dependency condition that if satisfied, indicates
// that the device does not support VPD SAR tables.
func WifiNoVpdSar() Condition {
return SkipOnModel(modelsWithVpdSarTables...)
}
// WifiNonSelfManaged returns a hardware dependency condition that if satisfied,
// indicates that the device does not support self-managed WiFi.
func WifiNonSelfManaged() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
// All of Intel WiFi chips supported by ChromiumOS are
// self-managed.
intelCondition := WifiIntel()
if satisfied, _, err := intelCondition.Satisfied(f); err == nil && satisfied {
return unsatisfied("DUT has a Intel self-managed WiFi chip")
}
// WCN6855 and WCN6750 are Qualcomm's self-managed WiFi chips.
wifiCondition := SkipOnWifiDevice(
QualcommWCN6855, QualcommWCN6750)
if satisfied, reason, err := wifiCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
func hasBattery(f *protocol.HardwareFeatures) (bool, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return false, errors.New("DeprecatedDeviceConfig is not given")
}
return dc.GetPower() == protocol.DeprecatedDeviceConfig_POWER_SUPPLY_BATTERY, nil
}
// Battery returns a hardware dependency condition that is satisfied if and only if the DUT
// has a battery, e.g. Chromeboxes and Chromebits don't.
func Battery() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hasBattery, err := hasBattery(f)
if err != nil {
return withError(err)
}
if !hasBattery {
return unsatisfied("DUT does not have a battery")
}
return satisfied()
},
}
}
// NoBatteryBootSupported returns a hardware dependency condition that is satisfied if and only if the DUT
// supports booting without a battery.
func NoBatteryBootSupported() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hasBattery, err := hasBattery(f)
if err != nil {
return withError(err)
}
if !hasBattery {
return unsatisfied("DUT does not have a battery")
}
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if !hf.GetBattery().GetNoBatteryBootSupported() {
return unsatisfied("DUT does not support booting without a battery")
}
return satisfied()
},
}
}
// SupportsHardwareOverlays returns a hardware dependency condition that is satisfied if the SoC
// supports hardware overlays.
func SupportsHardwareOverlays() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 {
return unsatisfied("SoC does not support Hardware Overlays")
}
return satisfied()
},
}
}
// platformHasNV12Overlays returns true if the the given platform is known
// to support NV12 hardware overlays.
func platformHasNV12Overlays(SocType protocol.DeprecatedDeviceConfig_SOC) bool {
return SocType != protocol.DeprecatedDeviceConfig_SOC_HASWELL &&
SocType != protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL &&
SocType != protocol.DeprecatedDeviceConfig_SOC_BROADWELL &&
SocType != protocol.DeprecatedDeviceConfig_SOC_BRASWELL &&
SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U &&
SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y &&
SocType != protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE &&
SocType != protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8173 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8176 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8183 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8192 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8195 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8186 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_MT8188G &&
SocType != protocol.DeprecatedDeviceConfig_SOC_SC7180 &&
SocType != protocol.DeprecatedDeviceConfig_SOC_SC7280
}
// SupportsNV12Overlays says true if the SoC supports NV12 hardware overlays,
// which are commonly used for video overlays. SoCs with Intel Gen 7.5 (Haswell,
// BayTrail) and Gen 8 GPUs (Broadwell, Braswell) for example, don't support
// those.
func SupportsNV12Overlays() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if !platformHasNV12Overlays(dc.GetSoc()) {
return unsatisfied("SoC does not support NV12 Overlays")
}
return satisfied()
},
}
}
// SupportsVideoOverlays says true if the SoC supports some type of YUV
// hardware overlay. This includes NV12, I420, and YUY2.
func SupportsVideoOverlays() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
var supportsYUY2Overlays = dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8183 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8192 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8195 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8186 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8188G
if !platformHasNV12Overlays(dc.GetSoc()) && !supportsYUY2Overlays {
return unsatisfied("SoC does not support Video Overlays")
}
return satisfied()
},
}
}
// Since there are no way to get whether an EC supports force discharging on a device or not,
// list up the models known not to support force discharging here.
var modelsWithoutForceDischargeSupport = []string{
"arcada",
"celes",
"drallion",
"drallion360",
"lulu",
"sarien",
}
// ForceDischarge returns a hardware dependency condition that is satisfied if and only if the DUT
// has a battery and it supports force discharge through `ectool chargecontrol`.
// The devices listed in modelsWithoutForceDischargeSupport do not satisfy this condition
// even though they have a battery since they does not support force discharge via ectool.
// This is a complementary condition of NoForceDischarge.
func ForceDischarge() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hasBattery, err := hasBattery(f)
if err != nil {
return withError(err)
}
if !hasBattery {
return unsatisfied("DUT does not have a battery")
}
doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...)
if err != nil {
return withError(err)
}
if doesNotSupportForceDischarge {
return unsatisfied("DUT has a battery but does not support force discharge")
}
return satisfied()
}}
}
// NoForceDischarge is a complementary condition of ForceDischarge.
func NoForceDischarge() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...)
if err != nil {
return withError(err)
}
if doesNotSupportForceDischarge {
// Devices listed in modelsWithoutForceDischargeSupport
// are known to always satisfy this condition
return satisfied()
}
hasBattery, err := hasBattery(f)
if err != nil {
return withError(err)
}
if hasBattery {
return unsatisfied("DUT supports force discharge")
}
return satisfied()
}}
}
// X86 returns a hardware dependency condition matching x86 ABI compatible platform.
func X86() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
return satisfied()
}
return unsatisfied("DUT's CPU is not x86 compatible")
}}
}
// NoX86 returns a hardware dependency condition matching non-x86 ABI compatible platform.
func NoX86() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86 && dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86_64 {
return satisfied()
}
return unsatisfied("DUT's CPU is x86 compatible")
}}
}
// Emmc returns a hardware dependency condition if the device has an eMMC
// storage device.
func Emmc() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_EMMC {
return satisfied()
}
return unsatisfied("DUT does not have an eMMC storage device")
}}
}
// EmmcOverNvme returns a hardware dependency condition if the device has an eMMC
// storage device proxied by an eMMC to NVMe bridge (e.g. BH799)
func EmmcOverNvme() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_BRIDGED_EMMC {
return satisfied()
}
return unsatisfied("DUT does not have an eMMC over NVMe storage device")
}}
}
// EmmcOrBridge returns a hardware dependency condition if the device has an eMMC
// storage device or an eMMC storage device proxied by an eMMC to NVMe bridge (e.g. BH799)
func EmmcOrBridge() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_EMMC ||
hf.GetStorage().GetStorageType() == configpb.Component_Storage_BRIDGED_EMMC {
return satisfied()
}
return unsatisfied("DUT does not have an eMMC or an eMMC over NVMe storage device")
}}
}
// Nvme returns a hardware dependency condition if the device has an NVMe
// storage device.
func Nvme() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_NVME {
return satisfied()
}
return unsatisfied("DUT does not have an NVMe storage device")
}}
}
// NvmeOrBridge returns a hardware dependency condition if the device has an NVMe
// storage device or an eMMC storage device proxied by an eMMC to NVMe bridge (e.g. BH799)
func NvmeOrBridge() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_NVME ||
hf.GetStorage().GetStorageType() == configpb.Component_Storage_BRIDGED_EMMC {
return satisfied()
}
return unsatisfied("DUT does not have an NVMe or an eMMC over NVMe storage device")
}}
}
// NvmeSelfTest returns a dependency condition if the device has an NVMe storage device which supported NVMe self-test.
func NvmeSelfTest() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.HasNvmeSelfTest {
return satisfied()
}
return unsatisfied("DUT does not have an NVMe storage device which supports self-test")
}}
}
// Ufs returns a hardware dependency condition if the device has a UFS storage
// device.
func Ufs() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage().GetStorageType() == configpb.Component_Storage_UFS {
return satisfied()
}
return unsatisfied("DUT does not have a UFS storage device")
}}
}
// MinStorage returns a hardware dependency condition requiring the minimum size of the storage in gigabytes.
func MinStorage(reqGigabytes int) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetStorage() == nil {
return withErrorStr("Features.Storage was nil")
}
s := hf.GetStorage().GetSizeGb()
if s < uint32(reqGigabytes) {
return unsatisfied(fmt.Sprintf("The total storage size is smaller than required; got %dGB, need %dGB", s, reqGigabytes))
}
return satisfied()
}}
}
// MinMemory returns a hardware dependency condition requiring the minimum size of the memory in megabytes.
func MinMemory(reqMegabytes int) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetMemory() == nil {
return withErrorStr("Features.Memory was nil")
}
if hf.GetMemory().GetProfile() == nil {
return withErrorStr("Features.Memory.Profile was nil")
}
s := hf.GetMemory().GetProfile().GetSizeMegabytes()
if s < int32(reqMegabytes) {
return unsatisfied(fmt.Sprintf("The total memory size is smaller than required; got %dMB, need %dMB", s, reqMegabytes))
}
return satisfied()
}}
}
// MaxMemory returns a hardware dependency condition requiring no more than the
// maximum size of the memory in megabytes.
func MaxMemory(reqMegabytes int) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetMemory() == nil {
return withErrorStr("Features.Memory was nil")
}
if hf.GetMemory().GetProfile() == nil {
return withErrorStr("Features.Memory.Profile was nil")
}
s := hf.GetMemory().GetProfile().GetSizeMegabytes()
if s > int32(reqMegabytes) {
return unsatisfied(fmt.Sprintf("The total memory size is larger than required; got %dMB, need <= %dMB", s, reqMegabytes))
}
return satisfied()
}}
}
// Speaker returns a hardware dependency condition that is satisfied if and only if the DUT has a speaker.
func Speaker() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetAudio().GetSpeakerAmplifier() != nil {
return satisfied()
}
return unsatisfied("DUT does not have speaker")
},
}
}
// Microphone returns a hardware dependency condition that is satisfied if and only if the DUT has a microphone.
func Microphone() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetAudio().GetLidMicrophone().GetValue() > 0 || hf.GetAudio().GetBaseMicrophone().GetValue() > 0 {
return satisfied()
}
return unsatisfied("DUT does not have microphone")
},
}
}
// PrivacyScreen returns a hardware dependency condition that is satisfied if and only if the DUT has a privacy screen.
func PrivacyScreen() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetPrivacyScreen().GetPresent() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have privacy screen")
}
return satisfied()
},
}
}
// NoPrivacyScreen returns a hardware dependency condition that is satisfied if the DUT
// does not have a privacy screen.
func NoPrivacyScreen() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if status := hf.GetPrivacyScreen().GetPresent(); status == configpb.HardwareFeatures_NOT_PRESENT {
return satisfied()
}
return unsatisfied("DUT has a privacy screen")
},
}
}
var smartAmps = []string{
configpb.HardwareFeatures_Audio_MAX98373.String(),
configpb.HardwareFeatures_Audio_MAX98390.String(),
configpb.HardwareFeatures_Audio_ALC1011.String(),
configpb.HardwareFeatures_Audio_CS35L41.String(),
}
// SmartAmp returns a hardware dependency condition that is satisfied if and only if the DUT
// has smart amplifier.
func SmartAmp() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetAudio().GetSpeakerAmplifier() != nil {
for _, amp := range smartAmps {
if amp == hf.GetAudio().GetSpeakerAmplifier().GetName() {
return satisfied()
}
}
}
return unsatisfied("DUT does not has smart amp :" + hf.GetAudio().GetSpeakerAmplifier().GetName())
}}
}
// SmartAmpBootTimeCalibration returns a hardware dependency condition that is satisfied if and only if
// the DUT enables boot time calibration for smart amplifier.
func SmartAmpBootTimeCalibration() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetAudio().GetSpeakerAmplifier() != nil {
for _, feature := range hf.GetAudio().GetSpeakerAmplifier().GetFeatures() {
if feature == configpb.Component_Amplifier_BOOT_TIME_CALIBRATION {
return satisfied()
}
}
}
return unsatisfied("DUT does not enable smart amp boot time calibration")
}}
}
// formFactorListed returns whether the form factor represented by a configpb.HardwareFeatures
// is listed in the given list of form factor values.
func formFactorListed(hf *configpb.HardwareFeatures, ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) bool {
for _, ffValue := range ffList {
if hf.GetFormFactor().FormFactor == ffValue {
return true
}
}
return false
}
// FormFactor returns a hardware dependency condition that is satisfied
// if and only if the DUT's form factor is one of the given values.
func FormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
listed := formFactorListed(hf, ffList...)
if !listed {
return unsatisfied("Form factor did not match")
}
return satisfied()
}}
}
// SkipOnFormFactor returns a hardware dependency condition that is satisfied
// if and only if the DUT's form factor is none of the give values.
func SkipOnFormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
listed := formFactorListed(hf, ffList...)
if listed {
return unsatisfied("Form factor matched to SkipOn list")
}
return satisfied()
}}
}
// socTypeIsV4l2Stateful returns true when stateful API is supported on the given |SocType|
// or returns false when stateless API is supported.
func socTypeIsV4l2Stateful(SocType protocol.DeprecatedDeviceConfig_SOC) bool {
switch SocType {
case protocol.DeprecatedDeviceConfig_SOC_MT8173,
protocol.DeprecatedDeviceConfig_SOC_SC7180,
protocol.DeprecatedDeviceConfig_SOC_SC7280:
return true
case protocol.DeprecatedDeviceConfig_SOC_MT8183,
protocol.DeprecatedDeviceConfig_SOC_MT8192,
protocol.DeprecatedDeviceConfig_SOC_MT8195,
protocol.DeprecatedDeviceConfig_SOC_MT8186,
protocol.DeprecatedDeviceConfig_SOC_MT8188G,
protocol.DeprecatedDeviceConfig_SOC_RK3399:
return false
// TODO(stevecho): stateful is more common for now, but we can change this in the future
default:
return true
}
}
// SupportsV4L2StatefulVideoDecoding says true if the SoC supports the V4L2
// stateful video decoding kernel API. Examples of this are MTK8173 and
// Qualcomm devices (7180, etc). In general, we prefer to use stateless
// decoding APIs, so listing them individually makes sense.
func SupportsV4L2StatefulVideoDecoding() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2")
}
if socTypeIsV4l2Stateful(dc.GetSoc()) {
return satisfied()
}
return unsatisfied("SoC does not support V4L2 Stateful HW video decoding")
}}
}
// SupportsV4L2FlatVideoDecoding says true if the SoC supports V4L2 Flat video decoding [1][2].
// [1] https://source.chromium.org/chromium/chromium/src/+/main:media/gpu/v4l2/v4l2_stateful_video_decoder.cc
// [2] https://source.chromium.org/chromium/chromium/src/+/main:media/gpu/v4l2/stateless/v4l2_stateless_video_decoder.cc
func SupportsV4L2FlatVideoDecoding() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if satisfy, _, err := CPUSocFamily("qualcomm").Satisfied(f); err == nil && satisfy {
return satisfied()
}
if satisfy, _, err := GPUFamily("rogue").Satisfied(f); err == nil && satisfy {
return satisfied()
}
if satisfy, _, err := GPUFamily("mali-g52").Satisfied(f); err == nil && satisfy {
return satisfied()
}
if satisfy, _, err := GPUFamily("mali-g57").Satisfied(f); err == nil && satisfy {
return satisfied()
}
if satisfy, _, err := GPUFamily("mali-g72").Satisfied(f); err == nil && satisfy {
return satisfied()
}
return unsatisfied("SoC does not support V4L2 Flat HW video decoding")
}}
}
// SupportsV4L2StatelessVideoDecoding says true if the SoC supports the V4L2
// stateless video decoding kernel API. Examples of this are MTK8192 (Asurada),
// MTK8195 (Cherry), MTK8186 (Corsola), and RK3399 (scarlet/kevin/bob).
func SupportsV4L2StatelessVideoDecoding() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2")
}
if !socTypeIsV4l2Stateful(dc.GetSoc()) {
return satisfied()
}
return unsatisfied("SoC does not support V4L2 Stateless HW video decoding")
}}
}
// SkipOnV4L2StatelessVideoDecoding says false if the SoC supports the V4L2
// stateless video decoding kernel API. Examples of this are MTK8192 (Asurada),
// MTK8195 (Cherry), MTK8186 (Corsola), and RK3399 (scarlet/kevin/bob).
func SkipOnV4L2StatelessVideoDecoding() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if socTypeIsV4l2Stateful(dc.GetSoc()) {
return satisfied()
}
return unsatisfied("SoC matches V4L2 Stateless HW video decoding SkipOn list")
}}
}
// SupportsHEVCVideoDecodingInChrome says true if the device supports HEVC video
// decoding in Chrome. Note that this might be dif and only iferent from support at the
// platform (i.e. drivers, kernel, hardware) level.
// This function represents a policy: Tast tests using this should still make
// use of SoftwareDeps "caps.HWDecodeHEVC" (or "caps.HWDecodeHEVC10BPP").
func SupportsHEVCVideoDecodingInChrome() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
// Disabled on any device where the config is explicitly disabled.
if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("Chrome has HEVC disabled on this device")
}
// Enabled on any device where the config is explicitly enabled.
if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
// MT8188G does support it.
if f.GetDeprecatedDeviceConfig().GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8188G {
return satisfied()
}
// ARM embedders don't support it.
if satisfy, _, err := CPUSocFamily("mediatek", "rockchip", "qualcomm").Satisfied(f); err == nil && satisfy {
return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
}
// AMD Zork (Picasso) and before also don't.
if satisfy, _, err := GPUFamily("picasso", "stoney").Satisfied(f); err == nil && satisfy {
return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
}
// Other AMD device support it.
if satisfy, _, err := CPUSocFamily("amd").Satisfied(f); err == nil && satisfy {
return satisfied()
}
// Any Intel TGL, ADL-P and MTL do support it.
if satisfy, _, err := GPUFamily("tigerlake", "alderlake", "meteorlake").Satisfied(f); err == nil && satisfy {
return satisfied()
}
return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
}}
}
// Lid returns a hardware dependency condition that is satisfied if and only if the DUT's form factor has a lid.
func Lid() Condition {
return FormFactor(Clamshell, Convertible, Detachable)
}
// InternalKeyboard returns a hardware dependency condition that is satisfied if and only if the DUT's form factor has a fixed undetachable keyboard.
func InternalKeyboard() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetKeyboard() == nil ||
hf.GetKeyboard().KeyboardType != configpb.HardwareFeatures_Keyboard_INTERNAL {
return unsatisfied("DUT does not have a fixed keyboard")
}
return satisfied()
},
}
}
// NoInternalKeyboard returns a hardware dependency condition that is satisfied
// if and only if the DUT's form factor does not have a fixed undetachable
// keyboard.
func NoInternalKeyboard() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
if hf.GetKeyboard() != nil &&
hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_INTERNAL {
return unsatisfied("DUT does have a fixed keyboard")
}
return satisfied()
},
}
}
// DisplayPortConverter is satisfied if a DP converter with one of the given names
// is present.
func DisplayPortConverter(names ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
for _, name := range names {
for _, conv := range hf.GetDpConverter().GetConverters() {
if conv.GetName() == name {
return satisfied()
}
}
}
return unsatisfied("DP converter did not match")
}}
}
// Vboot2 is satisfied if and only if crossystem param 'fw_vboot2' indicates that DUT uses vboot2.
func Vboot2() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.HasVboot2 {
return satisfied()
}
return unsatisfied("DUT is not a vboot2 device")
}}
}
// SupportsVP9KSVCHWDecoding is satisfied if the SoC supports VP9 k-SVC
// hardware decoding. They are x86 devices that are capable of VP9 hardware
// decoding and Qualcomm7180/7280.
// VP9 k-SVC is a SVC stream in which a frame only on keyframe can refer frames
// in a dif and only iferent spatial layer. See https://www.w3.org/TR/webrtc-svc/#dependencydiagrams* for detail.
func SupportsVP9KSVCHWDecoding() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
return satisfied()
}
if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7280 {
return satisfied()
}
return unsatisfied("SoC does not support VP9 k-SVC HW decoding")
}}
}
// AssistantKey is satisfied if a model has an assistant key.
func AssistantKey() Condition {
return Model("eve", "nocturne", "atlas")
}
// NoAssistantKey is satisfied if a model does not have an assistant key.
func NoAssistantKey() Condition {
return SkipOnModel("eve", "nocturne", "atlas")
}
// HapticTouchpad is satisfied if a model has a haptic touchpad.
func HapticTouchpad() Condition {
return Model("vell", "redrix")
}
// HPS is satisfied if the HPS peripheral (go/cros-hps) is present in the DUT.
func HPS() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if status := hf.GetHps().Present; status == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("HPS peripheral is not present")
}}
}
func containsCameraFeature(strs []string, feature string) bool {
for _, f := range strs {
if f == feature {
return true
}
}
return false
}
// CameraFeature is satisfied if all the features listed in |names| are enabled on the DUT.
func CameraFeature(names ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if features := hf.GetCamera().Features; features != nil {
unsatisfiedFeatures := make([]string, 0, 10)
for _, n := range names {
if !containsCameraFeature(features, n) {
unsatisfiedFeatures = append(unsatisfiedFeatures, n)
}
}
if len(unsatisfiedFeatures) != 0 {
return unsatisfied(fmt.Sprintf("Camera features not enabled: %v", unsatisfiedFeatures))
}
return satisfied()
}
return unsatisfied("Camera features not probed")
}}
}
// CameraEnumerated is satisfied if all the camera devices are enumerated on the DUT.
func CameraEnumerated() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if !hf.GetCamera().Enumerated {
return unsatisfied("no camera was enumerated")
}
return satisfied()
}}
}
func isAtLeastOneModuleListed(modules, enumerated []string) bool {
for _, module := range modules {
for _, id := range enumerated {
if module == id {
return true
}
}
}
return false
}
// CameraUSBModule is satisfied if at least one of the module is enumerated on the DUT.
func CameraUSBModule(modules ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if enumerated := hf.GetCamera().EnumeratedUsbIds; enumerated != nil {
if isAtLeastOneModuleListed(modules, enumerated) {
return satisfied()
}
return unsatisfied("no USB Camera with given ID was enumerated")
}
return unsatisfied("no USB Camera was enumerated")
}}
}
// SkipOnCameraUSBModule is satisfied if none of the given modules are enumerated.
// Note that the dependency is satisfied if no camera is enumerated. In some cases,
// this should be used with CameraEnumerated().
func SkipOnCameraUSBModule(modules ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
if hf := f.GetHardwareFeatures(); hf == nil {
return withErrorStr("Did not find hardware features")
} else if enumerated := hf.GetCamera().EnumeratedUsbIds; enumerated != nil {
if isAtLeastOneModuleListed(modules, enumerated) {
return unsatisfied("matched with skip-on list")
}
return satisfied()
}
return satisfied()
}}
}
// ECBuildConfigOptions is satisfied if any of the provided options are enabled.
// This can be used to check alternative option names,
// e.g. CONFIG_DEBUG_ASSERT, CONFIG_PLATFORM_EC_DEBUG_ASSERT
func ECBuildConfigOptions(optionNames ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
buildConfig := hf.GetEmbeddedController().GetBuildConfig()
if buildConfig == nil {
return unsatisfied("EC build config is missing")
}
for _, optionName := range optionNames {
if !strings.HasPrefix(optionName, "CONFIG_") {
optionName = "CONFIG_" + optionName
}
if present, found := buildConfig[optionName]; found && present == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
}
return unsatisfied(fmt.Sprintf("EC config option(s) %s are not enabled", optionNames))
},
}
}
// MainboardHasEarlyLibgfxinit is satisfied if the BIOS was built with Kconfig CONFIG_MAINBOARD_HAS_EARLY_LIBGFXINIT
func MainboardHasEarlyLibgfxinit() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf != nil {
fwc := hf.GetFwConfig()
if fwc != nil {
if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("MainboardHasEarlyLibgfxinit Kconfig disabled")
}
}
}
// Some Brya models default to PRESENT
listed, err := modelListed(f.GetDeprecatedDeviceConfig(), "skolas", "brya0", "kano", "agah", "taeko", "crota", "osiris", "gaelen", "lisbon", "gladios", "marasov", "omnigul", "constitution")
if err != nil {
return withError(err)
}
if listed {
return satisfied()
}
// The default for this Kconfig is off, so not found is the same as disabled.
return unsatisfied("Kconfig not found")
}}
}
// VbootCbfsIntegration is satisfied if the BIOS was built with Kconfig CONFIG_VBOOT_CBFS_INTEGRATION
func VbootCbfsIntegration() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf != nil {
fwc := hf.GetFwConfig()
if fwc != nil {
if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_NOT_PRESENT {
return unsatisfied("VbootCbfsIntegration Kconfig disabled")
}
}
}
// The default for this Kconfig is off, so not found is the same as disabled.
return unsatisfied("Kconfig not found")
}}
}
// RuntimeProbeConfig is satisfied if the probe config of the model exists.
func RuntimeProbeConfig() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
if hf.GetRuntimeProbeConfig().GetPresent() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have Runtime Probe config")
}
return satisfied()
}}
}
// RuntimeProbeConfigPrivate is satisfied if the existence status of private
// probe configs of the model matches given |present|.
func RuntimeProbeConfigPrivate(present bool) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
actualPresent := hf.GetRuntimeProbeConfig().GetEncryptedConfigPresent() == configpb.HardwareFeatures_PRESENT
if present != actualPresent {
if actualPresent {
return unsatisfied("DUT has unexpected private Runtime Probe config")
}
return unsatisfied("DUT does not have private Runtime Probe config")
}
return satisfied()
}}
}
// SeamlessRefreshRate is satisfied if the device supports changing refresh rates without modeset.
func SeamlessRefreshRate() Condition {
// TODO: Determine at runtime if a device meets the requirements by inspecting EDID, kernel, and SoC versions.
return Model("mithrax", "taniks")
}
// GPUFamily is satisfied if the devices GPU family is categorized as one of the families specified.
// For a complete list of values or to add new ones please check the pciid maps at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func GPUFamily(families ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, family := range families {
if hf.GetHardwareProbeConfig().GetGpuFamily() == family {
return satisfied()
}
}
return unsatisfied("DUT GPU family is not met")
}}
}
// SkipGPUFamily is satisfied if the devices GPU family is none of the families specified.
// For a complete list of values or to add new ones please check the pciid maps at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func SkipGPUFamily(families ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, family := range families {
if hf.GetHardwareProbeConfig().GetGpuFamily() == family {
return unsatisfied("DUT GPU family matched with skip list")
}
}
return satisfied()
}}
}
// GPUVendor is satisfied if the devices GPU vendor is categorized as one of the vendors specified.
// For a complete list of values or to add new ones please check the files at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func GPUVendor(vendors ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, vendor := range vendors {
if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor {
return satisfied()
}
}
return unsatisfied("DUT GPU vendor is not met")
}}
}
// SkipGPUVendor is satisfied if the devices GPU vendor is categorized as none of the vendors specified.
// For a complete list of values or to add new ones please check the files at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func SkipGPUVendor(vendors ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, vendor := range vendors {
if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor {
return unsatisfied("DUT GPU vendor matched with skip list")
}
}
return satisfied()
}}
}
// CPUSocFamily is satisfied if the devices CPU SOC family is categorized as one of the families specified.
// For a complete list of values or to add new ones please check the files at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func CPUSocFamily(families ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, family := range families {
if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family {
return satisfied()
}
}
return unsatisfied("DUT CPU soc family is not met")
}}
}
// SkipCPUSocFamily is satisfied if the device's CPU SOC family is none of the families specified.
// For a complete list of values or to add new ones please check the files at
// https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
func SkipCPUSocFamily(families ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("DUT HardwareFeatures data is not given")
}
for _, family := range families {
if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family {
return unsatisfied("DUT CPU soc family matched with skip list")
}
}
return satisfied()
}}
}
// InternalTrackpoint is satisfied if a model has an internal trackpoint.
func InternalTrackpoint() Condition {
return Model("morphius", "primus")
}
// FeatureLevel is satisfied if the feature level of the DUT match the value of
// the parameter level.
func FeatureLevel(level uint32) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetFeatureLevel() != level {
return unsatisfied(fmt.Sprintf("The DUT has different feature level; got %d, need %d",
hf.GetFeatureLevel(), level))
}
return satisfied()
}}
}
// OEM is satisfied if the OEM names on the DUT is in the input allow list.
func OEM(names ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
oem := f.GetHardwareFeatures().GetOemInfo().GetName()
for _, name := range names {
if name == oem {
return satisfied()
}
}
return unsatisfied("DUT OEM name [" + oem + "] is not in the allow list")
}}
}
// SkipOnOEM is satisfied if the OEM names on the DUT is not in the input allow list.
func SkipOnOEM(names ...string) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
oem := f.GetHardwareFeatures().GetOemInfo().GetName()
for _, name := range names {
if name == oem {
return unsatisfied("DUT OEM name [" + oem + "] is in the allow list")
}
}
return satisfied()
}}
}
// legacyMenuUIModels contains models adopting LegacyMenuUI.
var legacyMenuUIModels = []string{
"krane",
"kodama",
"katsu",
"kakadu",
"nocturne",
"soraka",
"dru",
"druwl",
"dumo",
}
// fwUIListed returns whether the dut's firmware ui is listed in the given list
// of firmware ui types. It uses the machine's active firmware version
// represented by a protocol.HardwareFeatures to determine whether menu UI is
// implemented. If not, it will check the legacyMenuUIModels list for
// differentiation between LegacyMenuUI and LegacyClamshellUI.
func fwUIListed(f *protocol.HardwareFeatures, names ...FWUIType) (bool, error) {
rwMajorVersion := f.GetHardwareFeatures().GetFwConfig().GetFwRwVersion().MajorVersion
if rwMajorVersion == 0 {
return false, errors.New("firmware id has not been passed from the DUT")
}
var dutFWUI FWUIType
// Using chromium: 2043102 as a reference, which landed in R83-12992.0.0,
// firmware versions greater than '12992' should have the menu UI
// implemented.
if rwMajorVersion > 12992 {
dutFWUI = MenuUI
} else {
isLegacyMenuUI, err := modelListed(f.GetDeprecatedDeviceConfig(), legacyMenuUIModels...)
if err != nil {
return false, err
}
if isLegacyMenuUI {
dutFWUI = LegacyMenuUI
} else {
dutFWUI = LegacyClamshellUI
}
}
for _, name := range names {
if name == dutFWUI {
return true, nil
}
}
return false, nil
}
// FirmwareUIType returns a dependency condition that is satisfied if
// the DUT's firmware UI is one of the given types.
func FirmwareUIType(fwUIType ...FWUIType) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
listed, err := fwUIListed(f, fwUIType...)
if err != nil {
return withError(err)
}
if !listed {
return unsatisfied("FWUIType did not match")
}
return satisfied()
}}
}
// HasPDPort returns a hardware dependency condition that is satisfied
// if and only if the DUT has a USB-C PD port with the provided index.
// I.e. HasPDPort(1) will match on devices that have 2 or more USB-C PD ports.
func HasPDPort(port uint32) Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf.GetUsbC().GetCount() == nil {
return unsatisfied("Did not find USB-C port count")
}
if hf.GetUsbC().GetCount().GetValue() > port {
return satisfied()
}
return unsatisfied(fmt.Sprintf("DUT does not have PD port %d", port))
},
}
}
// AlternativeFirmware returns a hardware dependency condition that is satisfied if and only if the DUT has altfw.
func AlternativeFirmware() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
sc := f.GetSoftwareConfig()
if sc == nil {
return withErrorStr("Did not find software config")
}
if sc.GetFirmwareInfo() == nil {
return withErrorStr("Did not find firmware info")
}
if sc.GetFirmwareInfo().HasAltFirmware {
return satisfied()
}
return unsatisfied("DUT does not have altfw")
},
}
}
// NmiSupport returns a hardware dependency condition that is satisfied
// this hardware supports NMIs (Non-Maskable Interrupts)
func NmiSupport() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf.GetInterruptControllerInfo().GetNmiSupport() == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("DUT does not support NMIs")
},
}
}
// HasSideVolumeButton returns a hardware dependency condition that is satisfied
// if the DUT has side volume button.
func HasSideVolumeButton() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
if dc.HasSideVolumeButton {
return satisfied()
}
return unsatisfied("DUT does not have side volume button")
}}
}
// MiniOS returns a hardware dependency condition that is satisfied if and only
// if the DUT supports minios.
func MiniOS() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
major := hf.GetFwConfig().GetFwRoVersion().MajorVersion
minor := hf.GetFwConfig().GetFwRoVersion().MinorVersion
// miniOS is supported in firmware UI since CL:3249309 (landed in 14315).
// For ARM, there's a bug which is fixed in CL:3653659 (landed in 14858).
// The fix is cherry-picked to firmware-cherry-14454.B in 14454.34.
if x86Satisfied, _, err := X86().Satisfied(f); err == nil && x86Satisfied && major >= 14315 {
return satisfied()
}
if noX86Satisfied, _, err := NoX86().Satisfied(f); err == nil && noX86Satisfied &&
(major >= 14858 || (major == 14454 && minor >= 34)) {
return satisfied()
}
return unsatisfied("DUT does not support minios")
}}
}
// BaseAccelerometer returns a hardware dependency condition that is satisfied
// if and only if the DUT has the base accelerometer sensor.
func BaseAccelerometer() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.Accelerometer.GetBaseAccelerometer() != configpb.HardwareFeatures_PRESENT {
return unsatisfied("DUT does not have base accelerometer")
}
return satisfied()
},
}
}
// IntelIsh is satisfied if Intel Integrated Sensor Hub is present in the `lspci` output on DUT.
func IntelIsh() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("Did not find hardware features")
}
if hf.GetFwConfig().IntelIsh == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("Intel ISH is not present nor enabled")
}}
}
// FirmwareSplashScreen is satisfied if the BIOS was built with Kconfig
// CONFIG_CHROMEOS_FW_SPLASH_SCREEN or Kconfig CONFIG_BMP_LOGO
func FirmwareSplashScreen() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
fwc := f.GetHardwareFeatures().GetFwConfig()
if fwc != nil {
if fwc.FwSplashScreen == configpb.HardwareFeatures_PRESENT ||
fwc.BmpLogo == configpb.HardwareFeatures_PRESENT {
return satisfied()
}
return unsatisfied("The splash screen feature is not supported")
}
// The default for this Kconfig is off, so not found is the same as disabled.
return unsatisfied("Kconfig not found")
}}
}
// MiniDiag returns a hardware dependency condition that is satisfied if and
// only if the DUT supports minidiag.
func MiniDiag() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
hf := f.GetHardwareFeatures()
if hf == nil {
return withErrorStr("HardwareFeatures is not given")
}
roMajorVersion := hf.GetFwConfig().GetFwRoVersion().MajorVersion
roMinorVersion := hf.GetFwConfig().GetFwRoVersion().MinorVersion
rwMajorVersion := hf.GetFwConfig().GetFwRwVersion().MajorVersion
rwMinorVersion := hf.GetFwConfig().GetFwRwVersion().MinorVersion
// Dirinboz launch MiniDiag earlier (crrev/c/2525502) than other
// zork variants (crrev/c/2677619).
isDirinboz, err := modelListed(f.GetDeprecatedDeviceConfig(), "dirinboz")
if err != nil {
return withError(err)
}
/*
RO: CL:2282867 landed in 13396.0.0 for most of the boards except:
- puff: CL:2353773 landed in firmware-puff-13324.B 13324.35.0
RW: CL:2617391 landed in 13727.0.0 for most of the boards except:
- zork (dirinboz): CL:2525502 landed in firmware-zork-13434.B 13434.106.0
- zork: CL:2677619 landed in firmware-zork-13434.B 13434.267.0
- trogdor: CL:2677612 landed in firmware-trogdor-13577.B 13577.106.0
- dedede: CL:2677618 landed in firmware-dedede-13606.B 13606.99.0
- volteer: CL:2677615 landed in firmware-volteer-13672.B 13672.109.0
*/
roCheck := (roMajorVersion >= 13396 || (roMajorVersion == 13324 && roMinorVersion >= 35))
rwCheck := (rwMajorVersion >= 13727 ||
(rwMajorVersion == 13434 && (rwMinorVersion >= 267 || (isDirinboz && rwMinorVersion >= 106))) ||
(rwMajorVersion == 13577 && rwMinorVersion >= 106) ||
(rwMajorVersion == 13606 && rwMinorVersion >= 99) ||
(rwMajorVersion == 13672 && rwMinorVersion >= 109))
if roCheck && rwCheck {
return satisfied()
}
return unsatisfied("DUT does not support minidiag")
}}
}