blob: cdd7ec6029e9e8d5c117744624c02538cee04e5d [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/internal/dep"
"chromiumos/tast/internal/protocol"
)
// 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
}
// 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.
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.
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()
}}
}
// 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")
}, CEL: "dut.hardware_features.screen.touch_support == api.HardwareFeatures.Present.PRESENT",
}
}
// 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")
}, CEL: "dut.hardware_features.embedded_controller.present == api.HardwareFeatures.Present.PRESENT && dut.hardware_features.embedded_controller.ec_type == api.HardwareFeatures.EmbeddedController.EmbeddedControllerType.EC_CHROME",
}
}
// 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")
}, CEL: "dut.hardware_features.soc.features.exists(x, x == api.Component.Soc.Features.SMT)",
}
}
// 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()
}, CEL: "dut.hardware_features.fingerprint.location != api.HardwareFeatures.Fingerprint.Location.NOT_PRESENT",
}
}
// 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()
}, CEL: "dut.hardware_features.fingerprint.location == api.HardwareFeatures.Fingerprint.Location.NOT_PRESENT",
}
}
// 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")
}, CEL: "dut.hardware_features.screen.panel_properties.diagonal_milliinch != 0",
}
}
// 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.
c := SkipOnPlatform("kip", "guado")
c.CEL = "dut.hardware_features.wifi.supported_wlan_protocols.exists(x, x == api.Component.Wifi.WLANProtocol.IEEE_802_11_AC)"
return c
}
// 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",
"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",
"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(
"blipper",
"dirinboz",
"ezkinil",
"gumboz",
"jelboz",
"jelboz360",
"lantis",
"madoo",
"pirette",
"pirika",
"vilboz",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
}, CEL: "dut.hardware_features.wifi.supported_wlan_protocols.exists(x, x == api.Component.Wifi.WLANProtocol.IEEE_802_11_AX)",
}
}
// WifiMACAddrRandomize returns a hardware dependency condition that is satisfied
// iff the DUT support WiFi MAC Address Randomization.
func WifiMACAddrRandomize() Condition {
// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
c := SkipOnPlatform(
// mwifiex in 3.10 kernel does not support it.
"kitty",
// 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.
"mickey", "minnie", "speedy",
)
c.CEL = "not_implemented"
return c
}
// WifiNotMarvell returns a hardware dependency condition that is satisfied iff
// the DUT's not using a Marvell WiFi chip.
func WifiNotMarvell() 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.
c := SkipOnPlatform(
"bob", "kevin", "oak", "elm", "hana", "kitty",
"mighty", "jaq", "fievel", "tiger", "jerry",
)
c.CEL = "not_implemented"
return c
}
// WifiNotMarvell8997 returns a hardware dependency condition that is satisfied if
// the DUT is not using Marvell 8997 chipsets.
func WifiNotMarvell8997() Condition {
// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
c := SkipOnPlatform(
"bob", "kevin",
)
c.CEL = "not_implemented"
return c
}
// 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", "elm", "fievel", "gru", "grunt", "hana", "jacuzzi",
"kevin", "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(
"blipper",
"blooglet",
"dirinboz",
"ezkinil",
"gumboz",
"jelboz",
"jelboz360",
"lantis",
"madoo",
"pirette",
"pirika",
"vilboz",
"vorticon",
)
if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
return satisfied, reason, err
}
return satisfied()
}, CEL: "not_implemented",
}
}
// 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()
}, CEL: "not_implemented",
}
}
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 {
return unsatisfied("SoC does not support NV12 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")
}, CEL: "dut.hardware_features.storage.storage_type == api.Component.Storage.StorageType.NVME",
}
}
// 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()
}, CEL: "not_implemented",
}
}
// 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")
}, CEL: "has(dut.hardware_features.audio.speaker_amplifier)",
}
}
// 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")
}, CEL: "(dut.hardware_features.audio.lid_microphone.value > 0 || dut.hardware_features.audio.base_microphone.value > 0)",
}
}
// 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()
}, CEL: "dut.hardware_features.privacy_screen.present == api.HardwareFeatures.Present.PRESENT",
}
}