blob: d8626f90a04aac120a1624f3e44d7b614a3885bd [file] [edit]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// 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"
"regexp"
"strings"
configpb "go.chromium.org/chromiumos/config/go/api"
"chromiumos/tast/errors"
"chromiumos/tast/framework/protocol"
"chromiumos/tast/internal/dep"
"chromiumos/tast/testing/wlan"
)
// 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_-]+$`)
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
Intel9000 = wlan.Intel9000
Intel9260 = wlan.Intel9260
Intel22260 = wlan.Intel22260
Intel22560 = wlan.Intel22560
IntelAX211 = wlan.IntelAX211
BroadcomBCM4354SDIO = wlan.BroadcomBCM4354SDIO
BroadcomBCM4356PCIE = wlan.BroadcomBCM4356PCIE
BroadcomBCM4371PCIE = wlan.BroadcomBCM4371PCIE
Realtek8822CPCIE = wlan.Realtek8822CPCIE
Realtek8852APCIE = wlan.Realtek8852APCIE
Realtek8852CPCIE = wlan.Realtek8852CPCIE
MediaTekMT7921PCIE = wlan.MediaTekMT7921PCIE
MediaTekMT7921SDIO = wlan.MediaTekMT7921SDIO
)
// 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.HardwareFeatures.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 unfortnately
// 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...)
// Currently amd64-generic vm does not return a model ID.
// Treat it as a model that does not match any of the known ids.
// TODO(b:190010549): Propagate the error once amd64-generic vm is handled properly.
// if err != nil {
// return withError(err)
// }
if err != nil || !listed {
return unsatisfied("ModelId did not match")
}
return satisfied()
}}
}
// SkipOnModel returns a hardware dependency condition that is satisfied
// iff 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
// iff 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
// iff 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
// iff 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 decvice. 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
// iff 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
// iff 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")
},
}
}
// ChromeEC returns a hardware dependency condition that is satisfied
// iff 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
// iff 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 iff 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()
},
}
}
// Cellular returns a hardware dependency condition that
// is satisfied iff 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()
},
}
}
// Bluetooth returns a hardware dependency condition that
// is satisfied iff 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 iff 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",
)
}
// CPUSupportsSMT returns a hardware dependency condition that is satisfied iff 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 iff 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")
},
}
}
// ECHibernate returns a hardware dependency condition that is satisfied
// iff the EC has the ability to hibernate.
func ECHibernate() Condition {
names := []string{"fizz", "kukui", "puff", "scarlet"}
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("DUT does not support EC hibernate")
}
return satisfied()
},
}
}
// Fingerprint returns a hardware dependency condition that is satisfied
// iff 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().GetLocation() == configpb.HardwareFeatures_Fingerprint_NOT_PRESENT {
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().GetLocation() != configpb.HardwareFeatures_Fingerprint_NOT_PRESENT {
return unsatisfied("DUT has fingerprint sensor")
}
return satisfied()
},
}
}
// InternalDisplay returns a hardware dependency condition that is satisfied
// iff 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")
},
}
}
// NoInternalDisplay returns a hardware dependency condition that is satisfied
// iff 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
// iff 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 satified
// 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
// iff the DUT has a touchpad.
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()
},
}
}
// Wifi80211ac returns a hardware dependency condition that is satisfied
// iff the DUT's WiFi module supports 802.11ac.
func Wifi80211ac() Condition {
// Some of guado and kip SKUs do not support 802.11ac.
// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
return SkipOnPlatform("kip", "guado")
}
// 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
// iff the DUT's WiFi module supports 802.11ax.
func Wifi80211ax() Condition {
// Note: this is currently a blocklist.
// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
// TODO(crbug.com/1115620): remove "Elm" and "Hana" after unibuild migration
// completed.
platformCondition := SkipOnPlatform(
"asuka",
"asurada",
"banjo",
"banon",
"bob", // bob, kevin use the platform name "gru", they do need to be added to SkipOnModel
"buddy",
"candy",
"caroline",
"cave",
"celes",
"chell",
"coral",
"cyan",
"edgar",
"enguarde",
"eve",
"fievel",
"fizz",
"gale",
"gandof",
"gnawty",
"gru", // The mosys for scarlet is gru. scarlet does not support 802.11ax
"grunt",
"guado",
"hana",
"jecht", // The mosys for tidus is jecht. tidus does not support 802.11ax
"kalista",
"kefka",
"kevin",
"kevin64",
"kip",
"kukui", // The mosys for jacuzzi is kukui. jacuzzi does not support 802.11ax
"lars",
"lulu",
"nami",
"nautilus",
"ninja",
"nocturne",
"oak", // The mosys for elm is oak. elm does not support 802.11ax
"octopus",
"orco",
"paine",
"poppy", // The mosys for atlas is poppy. atlas does not support 802.11ax
"puff",
"pyro",
"rammus",
"reef",
"reks",
"relm",
"rikku",
"samus",
"sand",
"sarien",
"sentry",
"setzer",
"snappy",
"soraka",
"strongbad",
"sumo",
"swanky",
"terra",
"tiger",
"trogdor",
"trogdor-kernelnext",
"ultima",
"winky",
"wizpig",
"yuna")
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
// Some models of boards excluded from the platform skip do not support
// 802.11ax. To be precise as possible, we will skip these models as well.
modelCondition := SkipOnModel(
"beadrix",
"beetley",
"blipper",
"dirinboz",
"ezkinil",
"gooey",
"gumboz",
"jelboz",
"jelboz360",
"landia",
"lantis",
"madoo",
"pirette",
"pirika",
"vilboz",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// Wifi80211ax6E returns a hardware dependency condition that is satisfied
// iff the DUT's WiFi module supports WiFi 6E.
func Wifi80211ax6E() Condition {
// Note: this is currently an allowlist. We can move this to a blocklist if the number of platforms gets out of hand.
// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
modelCondition := Model(
"anahera",
"brya",
"felwinter",
"gimble",
"herobrine",
"kano",
"nipperkin",
"primus",
"redrix",
"taeko",
"taeland",
"vell",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiMACAddrRandomize returns a hardware dependency condition that is satisfied
// iff 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,
)
}
// WifiNotMarvell returns a hardware dependency condition that is satisfied iff
// 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 plarform 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 {
// TODO(crbug.com/1070299): we don't yet have relevant fields in device.Config
// about WiFi chip, so list the known platforms here for now.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
// TODO(crbug.com/1115620): remove "Elm" and "Hana" after unibuild migration
// completed.
// NB: Devices in the "scarlet" family use the platform name "gru", so
// "gru" is being used here to represent "scarlet" devices.
platformCondition := SkipOnPlatform(
"asurada", "bob", "cherry", "elm", "fievel", "gru", "grunt", "hana", "herobrine", "jacuzzi",
"kevin", "kevin64", "kukui", "oak", "strongbad", "tiger", "trogdor", "trogdor-kernelnext",
)
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
// NB: These exclusions are somewhat overly broad; for example, some
// (but not all) blooglet devices have Intel WiFi chips. However,
// for now there is no better way to specify the exact hardware
// parameters needed for this dependency. (See crbug.com/1070299.)
modelCondition := SkipOnModel(
"beetley",
"blipper",
"blooglet",
"dewatt",
"dirinboz",
"ezkinil",
"gooey",
"gumboz",
"jelboz",
"jelboz360",
"landia",
"lantis",
"madoo",
"nereid",
"nipperkin",
"pirette",
"pirika",
"vilboz",
"vorticon",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiQualcomm returns a hardware dependency condition that if satisfied, indicates
// that a device uses Qualcomm WiFi.
func WifiQualcomm() Condition {
// TODO(crbug.com/1070299): we don't yet have relevant fields in device.Config
// about WiFi chip, so list the known platforms here for now.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := Platform(
"grunt", "kukui", "scarlet", "strongbad", "trogdor", "trogdor-kernelnext",
)
if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
// barla has Realtek WiFi chip.
modelCondition := SkipOnModel(
"barla",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
},
}
}
// WifiSAP returns a hardware dependency condition that if satisfied, indicates
// that a device supports SoftAP.
func WifiSAP() Condition {
// TODO(crbug.com/1070299): we don't yet have relevant fields in device.Config
// about WiFi chip, so list the known platforms here for now.
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
platformCondition := Platform(
"strongbad", "trogdor", "trogdor-kernelnext",
)
if satisfied, reason, err := platformCondition.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 iff 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()
},
}
}
// 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 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_HASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BROADWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BRASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8173 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8176 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8183 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8192 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8195 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7280 {
return unsatisfied("SoC does not support NV12 Overlays")
}
return satisfied()
},
}
}
// SupportsP010Overlays says true if the SoC supports P010 hardware overlays,
// which are commonly used for high bit-depth video overlays. Only Intel SoCs
// with GPU Gen 11 (JSL), Gen 12 (TGL, RLK) or later support those.
func SupportsP010Overlays() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
// Any ARM CPUs
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_ARM ||
dc.GetCpu() == protocol.DeprecatedDeviceConfig_ARM64 ||
// Unknown SOCs
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_UNSPECIFIED ||
// Intel before Tiger Lake
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BRASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_IVY_BRIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_PINE_TRAIL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SANDY_BRIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BROADWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_HASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_KABYLAKE_U ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_KABYLAKE_Y ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_KABYLAKE_U_R ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_AMBERLAKE_Y ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_COMET_LAKE_U ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_GEMINI_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_WHISKEY_LAKE_U ||
// All AMDs
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_PICASSO {
return unsatisfied("SoC does not support P010 Overlays")
}
return satisfied()
},
}
}
// Supports30bppFramebuffer says true if the SoC supports 30bpp color depth
// primary plane scanout. This is: Intel SOCs Kabylake and onwards, AMD SOCs
// from Zork onwards (codified Picasso), and not ARM SOCs.
func Supports30bppFramebuffer() Condition {
return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
dc := f.GetDeprecatedDeviceConfig()
if dc == nil {
return withErrorStr("DeprecatedDeviceConfig is not given")
}
// Any ARM CPUs
if dc.GetCpu() == protocol.DeprecatedDeviceConfig_ARM ||
dc.GetCpu() == protocol.DeprecatedDeviceConfig_ARM64 ||
// Unknown SOCs
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_UNSPECIFIED ||
// Intel before Kabylake
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BRASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_IVY_BRIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_PINE_TRAIL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SANDY_BRIDGE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_BROADWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_HASWELL ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y ||
// AMD before Zork
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE {
return unsatisfied("SoC does not support scanning out 30bpp framebuffers")
}
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 iff 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")
}}
}
// 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")
}}
}
// 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")
}}
}
// 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 iff 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 iff 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 iff 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()
},
}
}
var smartAmps = []string{
configpb.HardwareFeatures_Audio_MAX98373.String(),
configpb.HardwareFeatures_Audio_MAX98390.String(),
configpb.HardwareFeatures_Audio_ALC1011.String(),
}
// SmartAmp returns a hardware dependency condition that is satisfied iff 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 iff
// 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
// iff 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
// iff 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_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 dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8173 {
return unsatisfied("MT8173 devices only support MT21C output (b/230654454).")
}
if socTypeIsV4l2Stateful(dc.GetSoc()) {
return satisfied()
}
return unsatisfied("SoC does not support V4L2 Stateful 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")
}}
}
// Lid returns a hardware dependency condition that is satisfied iff 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 iff the DUT's form factor has a fixed undettachable 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()
},
}
}
// 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 iff 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 different 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")
}}
}
// SupportsVP9KSVCHWEncoding is satisfied if the SoC supports VP9 k-SVC
// hardware encoding. VP9 k-SVC is a SVC stream in which a frame only on keyframe
// can refer frames in a different spatial layer.
// See https://www.w3.org/TR/webrtc-svc/#dependencydiagrams* for detail.
func SupportsVP9KSVCHWEncoding() 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_JASPER_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_TIGER_LAKE ||
dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_ALDER_LAKE {
return satisfied()
}
return unsatisfied("SoC does not support VP9 k-SVC HW encoding")
}}
}
// 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")
}