Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6340221c authored by Tim Van Patten's avatar Tim Van Patten
Browse files

gpuservice: Add GPU Vendor ID support to FeatureConfig proto

Add GPU vendor ID support to the FeatureConfig protobuf, to allow
making feature override decisions based on the GPU vendor of the device.
For example, restricting a particular feature override to Intel or ARM
GPU devices.

Bug: 372694741
Test: atest gpuservice_unittest
Test: cmd gpu featureOverrides
Test: atest android.boottime.BootTimeTest#testSuccessiveBoots
Flag: com.android.graphics.graphicsenv.flags.feature_overrides
Change-Id: I6b141ed725db2736ffa523bb50006c609a1e49a1
parent c93479c9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ cc_library_static {
    name: "libfeatureoverride",
    defaults: [
        "libfeatureoverride_deps",
        "libvkjson_deps",
    ],
    srcs: [
        ":feature_config_proto_definitions",
@@ -85,6 +86,9 @@ cc_library_static {
    cppflags: [
        "-Wno-sign-compare",
    ],
    static_libs: [
        "libvkjson",
    ],
    export_include_dirs: ["include"],
    proto: {
        type: "lite",
+65 −5
Original line number Diff line number Diff line
@@ -23,8 +23,10 @@
#include <sys/stat.h>
#include <vector>

#include <android-base/macros.h>
#include <graphicsenv/FeatureOverrides.h>
#include <log/log.h>
#include <vkjson.h>

#include "feature_config.pb.h"

@@ -35,13 +37,53 @@ void resetFeatureOverrides(android::FeatureOverrides &featureOverrides) {
    featureOverrides.mPackageFeatures.clear();
}

bool
gpuVendorIdMatches(const VkJsonInstance &vkJsonInstance,
               const uint32_t &configVendorId) {
    if (vkJsonInstance.devices.empty()) {
        return false;
    }

    // Always match the TEST Vendor ID
    if (configVendorId == feature_override::GpuVendorID::VENDOR_ID_TEST) {
        return true;
    }

    // Always assume one GPU device.
    uint32_t vendorID = vkJsonInstance.devices.front().properties.vendorID;

    return vendorID == configVendorId;
}

bool
conditionsMet(const VkJsonInstance &vkJsonInstance,
              const android::FeatureConfig &featureConfig) {
    bool gpuVendorIdMatch = false;

    if (featureConfig.mGpuVendorIDs.empty()) {
        gpuVendorIdMatch = true;
    } else {
        for (const auto &gpuVendorID: featureConfig.mGpuVendorIDs) {
            if (gpuVendorIdMatches(vkJsonInstance, gpuVendorID)) {
                gpuVendorIdMatch = true;
                break;
            }
        }
    }

    return gpuVendorIdMatch;
}

void initFeatureConfig(android::FeatureConfig &featureConfig,
                       const feature_override::FeatureConfig &featureConfigProto) {
    featureConfig.mFeatureName = featureConfigProto.feature_name();
    featureConfig.mEnabled = featureConfigProto.enabled();
    for (const auto &gpuVendorIdProto: featureConfigProto.gpu_vendor_ids()) {
        featureConfig.mGpuVendorIDs.emplace_back(static_cast<uint32_t>(gpuVendorIdProto));
    }
}

feature_override::FeatureOverrideProtos readFeatureConfigProtos(std::string configFilePath) {
feature_override::FeatureOverrideProtos readFeatureConfigProtos(const std::string &configFilePath) {
    feature_override::FeatureOverrideProtos overridesProtos;

    std::ifstream protobufBinaryFile(configFilePath.c_str());
@@ -78,9 +120,15 @@ std::string FeatureOverrideParser::getFeatureOverrideFilePath() const {

bool FeatureOverrideParser::shouldReloadFeatureOverrides() const {
    std::string configFilePath = getFeatureOverrideFilePath();

    std::ifstream configFile(configFilePath);
    if (!configFile.good()) {
        return false;
    }

    struct stat fileStat{};
    if (stat(getFeatureOverrideFilePath().c_str(), &fileStat) != 0) {
        ALOGE("Error getting file information for '%s': %s", getFeatureOverrideFilePath().c_str(),
    if (stat(configFilePath.c_str(), &fileStat) != 0) {
        ALOGE("Error getting file information for '%s': %s", configFilePath.c_str(),
              strerror(errno));
        // stat'ing the file failed, so return false since reading it will also likely fail.
        return false;
@@ -100,13 +148,23 @@ void FeatureOverrideParser::parseFeatureOverrides() {
    // Clear out the stale values before adding the newly parsed data.
    resetFeatureOverrides(mFeatureOverrides);

    if (overridesProtos.global_features().empty() &&
        overridesProtos.package_features().empty()) {
        // No overrides to parse.
        return;
    }

    const VkJsonInstance vkJsonInstance = VkJsonGetInstance();

    // Global feature overrides.
    for (const auto &featureConfigProto: overridesProtos.global_features()) {
        FeatureConfig featureConfig;
        initFeatureConfig(featureConfig, featureConfigProto);

        if (conditionsMet(vkJsonInstance, featureConfig)) {
            mFeatureOverrides.mGlobalFeatures.emplace_back(featureConfig);
        }
    }

    // App-specific feature overrides.
    for (auto const &pkgConfigProto: overridesProtos.package_features()) {
@@ -122,8 +180,10 @@ void FeatureOverrideParser::parseFeatureOverrides() {
            FeatureConfig featureConfig;
            initFeatureConfig(featureConfig, featureConfigProto);

            if (conditionsMet(vkJsonInstance, featureConfig)) {
                featureConfigs.emplace_back(featureConfig);
            }
        }

        mFeatureOverrides.mPackageFeatures[packageName] = featureConfigs;
    }
+29 −0
Original line number Diff line number Diff line
@@ -20,15 +20,44 @@ package feature_override;

option optimize_for = LITE_RUNTIME;

/**
 * GPU Vendor IDs.
 * Taken from: external/angle/src/libANGLE/renderer/driver_utils.h
 */
enum GpuVendorID
{
    // Test ID matches every GPU Vendor ID.
    VENDOR_ID_TEST = 0;
    VENDOR_ID_AMD = 0x1002;
    VENDOR_ID_ARM = 0x13B5;
    // Broadcom devices won't use PCI, but this is their Vulkan vendor id.
    VENDOR_ID_BROADCOM = 0x14E4;
    VENDOR_ID_GOOGLE = 0x1AE0;
    VENDOR_ID_INTEL = 0x8086;
    VENDOR_ID_MESA = 0x10005;
    VENDOR_ID_MICROSOFT = 0x1414;
    VENDOR_ID_NVIDIA = 0x10DE;
    VENDOR_ID_POWERVR = 0x1010;
    // This is Qualcomm PCI Vendor ID.
    // Android doesn't have a PCI bus, but all we need is a unique id.
    VENDOR_ID_QUALCOMM = 0x5143;
    VENDOR_ID_SAMSUNG = 0x144D;
    VENDOR_ID_VIVANTE = 0x9999;
    VENDOR_ID_VMWARE = 0x15AD;
    VENDOR_ID_VIRTIO = 0x1AF4;
}

/**
 * Feature Configuration
 * feature_name: Feature name (see external/angle/include/platform/autogen/FeaturesVk_autogen.h).
 * enabled: Either enable or disable the feature.
 * gpu_vendor_ids: The GPU architectures this FeatureConfig applies to, if any.
 */
message FeatureConfig
{
    string feature_name         = 1;
    bool enabled                = 2;
    repeated GpuVendorID gpu_vendor_ids = 3;
}

/**
+252 −2
Original line number Diff line number Diff line
@@ -70,14 +70,14 @@ public:
};

testing::AssertionResult validateFeatureConfigTestTxtpbSizes(FeatureOverrides overrides) {
    size_t expectedGlobalFeaturesSize = 1;
    size_t expectedGlobalFeaturesSize = 3;
    if (overrides.mGlobalFeatures.size() != expectedGlobalFeaturesSize) {
        return testing::AssertionFailure()
                << "overrides.mGlobalFeatures.size(): " << overrides.mGlobalFeatures.size()
                << ", expected: " << expectedGlobalFeaturesSize;
    }

    size_t expectedPackageFeaturesSize = 1;
    size_t expectedPackageFeaturesSize = 3;
    if (overrides.mPackageFeatures.size() != expectedPackageFeaturesSize) {
        return testing::AssertionFailure()
                << "overrides.mPackageFeatures.size(): " << overrides.mPackageFeatures.size()
@@ -133,6 +133,96 @@ TEST_F(FeatureOverrideParserTest, globalOverrides1) {
    EXPECT_TRUE(validateGlobalOverrides1(overrides));
}

testing::AssertionResult validateGlobalOverrides2(FeatureOverrides overrides) {
    const int kTestFeatureIndex = 1;
    const std::string expectedFeatureName = "globalOverrides2";
    const FeatureConfig &cfg = overrides.mGlobalFeatures[kTestFeatureIndex];

    if (cfg.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    bool expectedEnabled = true;
    if (cfg.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
                << "cfg.mEnabled: " << cfg.mEnabled
                << ", expected: " << expectedEnabled;
    }

    std::vector<uint32_t> expectedGpuVendorIDs = {
        0,      // GpuVendorID::VENDOR_ID_TEST
        0x13B5, // GpuVendorID::VENDOR_ID_ARM
    };
    if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
        return testing::AssertionFailure()
                << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
                << ", expected: " << expectedGpuVendorIDs.size();
    }
    for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
        if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
            std::stringstream msg;
            msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
                << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
            return testing::AssertionFailure() << msg.str();
        }
    }

    return testing::AssertionSuccess();
}

TEST_F(FeatureOverrideParserTest, globalOverrides2) {
    FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();

    EXPECT_TRUE(validateGlobalOverrides2(overrides));
}

testing::AssertionResult validateGlobalOverrides3(FeatureOverrides overrides) {
    const int kTestFeatureIndex = 2;
    const std::string expectedFeatureName = "globalOverrides3";
    const FeatureConfig &cfg = overrides.mGlobalFeatures[kTestFeatureIndex];

    if (cfg.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    bool expectedEnabled = true;
    if (cfg.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
                << "cfg.mEnabled: " << cfg.mEnabled
                << ", expected: " << expectedEnabled;
    }

    std::vector<uint32_t> expectedGpuVendorIDs = {
            0,      // GpuVendorID::VENDOR_ID_TEST
            0x8086, // GpuVendorID::VENDOR_ID_INTEL
    };
    if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
        return testing::AssertionFailure()
                << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
                << ", expected: " << expectedGpuVendorIDs.size();
    }
    for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
        if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
            std::stringstream msg;
            msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
                << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
            return testing::AssertionFailure() << msg.str();
        }
    }

    return testing::AssertionSuccess();
}

TEST_F(FeatureOverrideParserTest, globalOverrides3) {
FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();

EXPECT_TRUE(validateGlobalOverrides3(overrides));
}

testing::AssertionResult validatePackageOverrides1(FeatureOverrides overrides) {
    const std::string expectedTestPackageName = "com.gpuservice_unittest.packageOverrides1";

@@ -155,6 +245,12 @@ testing::AssertionResult validatePackageOverrides1(FeatureOverrides overrides) {
    const std::string expectedFeatureName = "packageOverrides1";
    const FeatureConfig &cfg = features[0];

    if (cfg.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    bool expectedEnabled = true;
    if (cfg.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
@@ -193,6 +289,160 @@ testing::AssertionResult validateForceFileRead(FeatureOverrides overrides) {
    return testing::AssertionSuccess();
}

testing::AssertionResult validatePackageOverrides2(FeatureOverrides overrides) {
    const std::string expectedPackageName = "com.gpuservice_unittest.packageOverrides2";

    if (!overrides.mPackageFeatures.count(expectedPackageName)) {
        return testing::AssertionFailure()
                << "overrides.mPackageFeatures missing expected package: " << expectedPackageName;
    }

    const std::vector<FeatureConfig>& features = overrides.mPackageFeatures[expectedPackageName];

    size_t expectedFeaturesSize = 1;
    if (features.size() != expectedFeaturesSize) {
        return testing::AssertionFailure()
                << "features.size(): " << features.size()
                << ", expectedFeaturesSize: " << expectedFeaturesSize;
    }

    const std::string expectedFeatureName = "packageOverrides2";
    const FeatureConfig &cfg = features[0];

    if (cfg.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    bool expectedEnabled = false;
    if (cfg.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
                << "cfg.mEnabled: " << cfg.mEnabled
                << ", expected: " << expectedEnabled;
    }

    std::vector<uint32_t> expectedGpuVendorIDs = {
            0,      // GpuVendorID::VENDOR_ID_TEST
            0x8086, // GpuVendorID::VENDOR_ID_INTEL
    };
    if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
        return testing::AssertionFailure()
                << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
                << ", expected: " << expectedGpuVendorIDs.size();
    }
    for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
        if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
            std::stringstream msg;
            msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
                << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
            return testing::AssertionFailure() << msg.str();
        }
    }

    return testing::AssertionSuccess();
}

TEST_F(FeatureOverrideParserTest, packageOverrides2) {
    FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();

    EXPECT_TRUE(validatePackageOverrides2(overrides));
}

testing::AssertionResult validatePackageOverrides3(FeatureOverrides overrides) {
    const std::string expectedPackageName = "com.gpuservice_unittest.packageOverrides3";

    if (!overrides.mPackageFeatures.count(expectedPackageName)) {
        return testing::AssertionFailure()
                << "overrides.mPackageFeatures missing expected package: " << expectedPackageName;
    }

    const std::vector<FeatureConfig>& features = overrides.mPackageFeatures[expectedPackageName];

    size_t expectedFeaturesSize = 2;
    if (features.size() != expectedFeaturesSize) {
        return testing::AssertionFailure()
                << "features.size(): " << features.size()
                << ", expectedFeaturesSize: " << expectedFeaturesSize;
    }

    std::string expectedFeatureName = "packageOverrides3_1";
    const FeatureConfig &cfg_1 = features[0];

    if (cfg_1.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg_1.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    bool expectedEnabled = false;
    if (cfg_1.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
                << "cfg.mEnabled: " << cfg_1.mEnabled
                << ", expected: " << expectedEnabled;
    }

    std::vector<uint32_t> expectedGpuVendorIDs = {
            0,      // GpuVendorID::VENDOR_ID_TEST
            0x13B5, // GpuVendorID::VENDOR_ID_ARM
    };
    if (cfg_1.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
        return testing::AssertionFailure()
                << "cfg.mGpuVendorIDs.size(): " << cfg_1.mGpuVendorIDs.size()
                << ", expected: " << expectedGpuVendorIDs.size();
    }
    for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
        if (cfg_1.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
            std::stringstream msg;
            msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg_1.mGpuVendorIDs[i]
                << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
            return testing::AssertionFailure() << msg.str();
        }
    }

    expectedFeatureName = "packageOverrides3_2";
    const FeatureConfig &cfg_2 = features[1];

    if (cfg_2.mFeatureName != expectedFeatureName) {
        return testing::AssertionFailure()
                << "cfg.mFeatureName: " << cfg_2.mFeatureName
                << ", expected: " << expectedFeatureName;
    }

    expectedEnabled = true;
    if (cfg_2.mEnabled != expectedEnabled) {
        return testing::AssertionFailure()
                << "cfg.mEnabled: " << cfg_2.mEnabled
                << ", expected: " << expectedEnabled;
    }

    expectedGpuVendorIDs = {
            0,      // GpuVendorID::VENDOR_ID_TEST
            0x8086, // GpuVendorID::VENDOR_ID_INTEL
    };
    if (cfg_2.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
        return testing::AssertionFailure()
                << "cfg.mGpuVendorIDs.size(): " << cfg_2.mGpuVendorIDs.size()
                << ", expected: " << expectedGpuVendorIDs.size();
    }
    for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
        if (cfg_2.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
            std::stringstream msg;
            msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg_2.mGpuVendorIDs[i]
                << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
            return testing::AssertionFailure() << msg.str();
        }
    }

    return testing::AssertionSuccess();
}

TEST_F(FeatureOverrideParserTest, packageOverrides3) {
FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();

EXPECT_TRUE(validatePackageOverrides3(overrides));
}

TEST_F(FeatureOverrideParserTest, forceFileRead) {
    FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();

+50 −0
Original line number Diff line number Diff line
@@ -22,6 +22,22 @@ global_features [
    {
        feature_name: "globalOverrides1"
        enabled: False
    },
    {
        feature_name: "globalOverrides2"
        enabled: True
        gpu_vendor_ids: [
            VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
            VENDOR_ID_ARM
        ]
    },
    {
        feature_name: "globalOverrides3"
        enabled: True
        gpu_vendor_ids: [
            VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
            VENDOR_ID_INTEL
        ]
    }
]

@@ -36,5 +52,39 @@ package_features [
                enabled: True
            }
        ]
    },
    {
        package_name: "com.gpuservice_unittest.packageOverrides2"
        feature_configs: [
            {
                feature_name: "packageOverrides2"
                enabled: False
                gpu_vendor_ids: [
                    VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
                    VENDOR_ID_INTEL
                ]
            }
        ]
    },
    {
        package_name: "com.gpuservice_unittest.packageOverrides3"
        feature_configs: [
            {
                feature_name: "packageOverrides3_1"
                enabled: False
                gpu_vendor_ids: [
                    VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
                    VENDOR_ID_ARM
                ]
            },
            {
                feature_name: "packageOverrides3_2"
                enabled: True
                gpu_vendor_ids: [
                    VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
                    VENDOR_ID_INTEL
                ]
            }
        ]
    }
]