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

Commit a630f848 authored by Benjamin Schwartz's avatar Benjamin Schwartz
Browse files

power/stats: Add VTS test cases for power.stats HAL

Adding VTS test cases for power.stats HAL functions
getPowerEntityInfo, getPowerEntityStateInfo, and getPowerEntityStateResidencyData

Bug: 118365266
Test: run vts -m VtsHalPowerStatsV1_0Target
Change-Id: Ib60ac0b37bd30663c5e7434546cdcfbf64915538
parent 61984d22
Loading
Loading
Loading
Loading
+14 −16
Original line number Diff line number Diff line
@@ -105,9 +105,9 @@ interface IPowerStats {
     * consumption.
     *
     * @return powerEntityInfos List of information on each PowerEntity
     * @return status SUCCESS on success or NOT_SUPPORTED if
     *     feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
     *     access error.
     * @return status SUCCESS on success, NOT_SUPPORTED if feature is not
     *     enabled, FILESYSTEM_ERROR if there was an error accessing the
     *     filesystem.
     */
    getPowerEntityInfo()
        generates(vec<PowerEntityInfo> powerEntityInfos, Status status);
@@ -123,12 +123,11 @@ interface IPowerStats {
     *     information for all PowerEntity(s) pass an empty vector.
     *
     * @return powerEntityStateSpaces PowerEntity state space information for
     *     each specified PowerEntity.
     * @return status SUCCESS if powerEntityStateInfos contains state space
     *     information for at least one PowerEntity, NOT_SUPPORTED if feature
     *     is not enabled, INVALID_INPUT if no requested PowerEntity(s)
     *     provide state space information, FILESYSTEM_ERROR if no state space
     *     information is returned due to filesystem errors.
     *     each specified PowerEntity that provides state space information.
     * @return status SUCCESS on success, NOT_SUPPORTED if feature is not
     *     enabled, FILESYSTEM_ERROR if there was an error accessing the
     *     filesystem, INVALID_INPUT if any requested PowerEntity(s) do not
     *     provide state space information and there was not a filesystem error.
     */
    getPowerEntityStateInfo(vec<uint32_t> powerEntityIds)
        generates(vec<PowerEntityStateSpace> powerEntityStateSpaces,
@@ -148,13 +147,12 @@ interface IPowerStats {
     *     residency data is requested. PowerEntity name to ID mapping may
     *     be queried from getPowerEntityInfo(). To get state residency
     *     data for all PowerEntity(s) pass an empty vector.
     * @return stateResidencyResults state residency data for the
     *     specified powerEntity(s)
     * @return status SUCCESS if stateResidencyResults contains residency
     *     data for at least one PowerEntity, NOT_SUPPORTED if
     *     feature is not enabled, INVALID_INPUT if no requested
     *     PowerEntity(s) provide state residency data, FILESYSTEM_ERROR
     *     if no data is returned due to filesystem errors.
     * @return stateResidencyResults state residency data for each specified
     *     PowerEntity that provides state residency data.
     * @return status SUCCESS on success, NOT_SUPPORTED if feature is not
     *     enabled, FILESYSTEM_ERROR if there was an error accessing the
     *     filesystem, INVALID_INPUT if any requested PowerEntity(s) do not
     *     provide state residency data and there was not a filesystem error.
     */
    getPowerEntityStateResidencyData(vec<uint32_t> powerEntityIds)
        generates(vec<PowerEntityStateResidencyResult> stateResidencyResults,
+8 −9
Original line number Diff line number Diff line
@@ -69,19 +69,18 @@ enum PowerEntityType : uint32_t {
 * given PowerEntity.
 */
struct PowerEntityInfo {
    /** ID corresponding to the PowerEntity */
    /** Unique ID corresponding to the PowerEntity */
    uint32_t powerEntityId;
    /**
     * Name of the PowerEntity. This is unique and opaque to the
     * Android framework
     */
    /** Name of the PowerEntity */
    string powerEntityName;
    /** Type of the PowerEntity */
    PowerEntityType type;
};

struct PowerEntityStateInfo {
    /** ID corresponding to the state */
    /**
     * ID corresponding to the state. Unique for a given PowerEntityStateSpace
     */
    uint32_t powerEntityStateId;
    /** Name of the state */
    string powerEntityStateName;
@@ -93,7 +92,7 @@ struct PowerEntityStateInfo {
 * PowerEntity provides residency data for.
 */
struct PowerEntityStateSpace {
    /** ID of the corresponding PowerEntity */
    /** Unique ID of the corresponding PowerEntity */
    uint32_t powerEntityId;

    /** List of states that the PowerEntity may reside in */
@@ -102,7 +101,7 @@ struct PowerEntityStateSpace {

/** Contains residency data for a single state */
struct PowerEntityStateResidencyData {
    /** ID of the corresponding PowerEntityStateInfo */
    /** Unique ID of the corresponding PowerEntityStateInfo */
    uint32_t powerEntityStateId;
    /**
     * Total time in milliseconds that the corresponding PowerEntity resided
@@ -122,7 +121,7 @@ struct PowerEntityStateResidencyData {
};

struct PowerEntityStateResidencyResult {
    /** ID of the corresponding PowerEntity */
    /** Unique ID of the corresponding PowerEntity */
    uint32_t powerEntityId;
    /** Residency data for each state the PowerEntity's state space */
    vec<PowerEntityStateResidencyData> stateResidencyData;
+275 −1
Original line number Diff line number Diff line
@@ -40,6 +40,9 @@ using android::hardware::Return;
using android::hardware::Void;
using android::hardware::power::stats::V1_0::EnergyData;
using android::hardware::power::stats::V1_0::IPowerStats;
using android::hardware::power::stats::V1_0::PowerEntityInfo;
using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
using android::hardware::power::stats::V1_0::RailInfo;
using android::hardware::power::stats::V1_0::Status;

@@ -68,9 +71,281 @@ class PowerStatsHidlTest : public ::testing::VtsHalHidlTargetTestBase {

    virtual void TearDown() override {}

    void getInfos(hidl_vec<PowerEntityInfo>& infos);
    void getStateSpaces(hidl_vec<PowerEntityStateSpace>& stateSpaces,
                        const std::vector<uint32_t>& ids);
    void getResidencyResults(hidl_vec<PowerEntityStateResidencyResult>& results,
                             const std::vector<uint32_t>& ids);
    void getRandomIds(std::vector<uint32_t>& ids);

    sp<IPowerStats> service_;
};

void PowerStatsHidlTest::getInfos(hidl_vec<PowerEntityInfo>& infos) {
    Status status;
    Return<void> ret = service_->getPowerEntityInfo([&status, &infos](auto rInfos, auto rStatus) {
        status = rStatus;
        infos = rInfos;
    });
    ASSERT_TRUE(ret.isOk());

    if (status == Status::SUCCESS) {
        ASSERT_NE(infos.size(), 0) << "powerEntityInfos must have entries if supported";
    } else {
        ASSERT_EQ(status, Status::NOT_SUPPORTED);
        ASSERT_EQ(infos.size(), 0);
        LOG(INFO) << "getPowerEntityInfo not supported";
    }
}

void PowerStatsHidlTest::getStateSpaces(hidl_vec<PowerEntityStateSpace>& stateSpaces,
                                        const std::vector<uint32_t>& ids = {}) {
    Status status;
    Return<void> ret = service_->getPowerEntityStateInfo(
        ids, [&status, &stateSpaces](auto rStateSpaces, auto rStatus) {
            status = rStatus;
            stateSpaces = rStateSpaces;
        });
    ASSERT_TRUE(ret.isOk());

    if (status == Status::SUCCESS) {
        ASSERT_NE(stateSpaces.size(), 0) << "powerEntityStateSpaces must have entries if supported";
    } else {
        ASSERT_EQ(status, Status::NOT_SUPPORTED);
        ASSERT_EQ(stateSpaces.size(), 0);
        LOG(INFO) << "getPowerEntityStateInfo not supported";
    }
}

void PowerStatsHidlTest::getResidencyResults(hidl_vec<PowerEntityStateResidencyResult>& results,
                                             const std::vector<uint32_t>& ids = {}) {
    Status status;
    Return<void> ret = service_->getPowerEntityStateResidencyData(
        ids, [&status, &results](auto rResults, auto rStatus) {
            status = rStatus;
            results = rResults;
        });
    ASSERT_TRUE(ret.isOk());

    if (status == Status::SUCCESS) {
        ASSERT_NE(results.size(), 0);
    } else {
        ASSERT_EQ(status, Status::NOT_SUPPORTED);
        ASSERT_EQ(results.size(), 0);
        LOG(INFO) << "getPowerEntityStateResidencyData not supported";
    }
}

void PowerStatsHidlTest::getRandomIds(std::vector<uint32_t>& ids) {
    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);

    if (stateSpaces.size() == 0) {
        return;
    }

    for (auto stateSpace : stateSpaces) {
        ids.push_back(stateSpace.powerEntityId);
    }

    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    auto gen = std::default_random_engine(seed);
    std::uniform_int_distribution<uint32_t> dist(1, stateSpaces.size());

    std::shuffle(ids.begin(), ids.end(), gen);
    ids.resize(dist(gen));
}

// Each PowerEntity must have a valid name
TEST_F(PowerStatsHidlTest, ValidatePowerEntityNames) {
    hidl_vec<PowerEntityInfo> infos;
    getInfos(infos);
    for (auto info : infos) {
        ASSERT_NE(info.powerEntityName, "");
    }
}

// Each PowerEntity must have a unique ID
TEST_F(PowerStatsHidlTest, ValidatePowerEntityIds) {
    hidl_vec<PowerEntityInfo> infos;
    getInfos(infos);

    set<uint32_t> ids;
    for (auto info : infos) {
        ASSERT_TRUE(ids.insert(info.powerEntityId).second);
    }
}

// Each PowerEntityStateSpace must have an associated PowerEntityInfo
TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociation) {
    hidl_vec<PowerEntityInfo> infos;
    getInfos(infos);

    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);

    std::set<uint32_t> ids;
    for (auto info : infos) {
        ids.insert(info.powerEntityId);
    }

    for (auto stateSpace : stateSpaces) {
        ASSERT_NE(ids.count(stateSpace.powerEntityId), 0);
    }
}

// Each state must have a valid name
TEST_F(PowerStatsHidlTest, ValidateStateNames) {
    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);

    for (auto stateSpace : stateSpaces) {
        for (auto state : stateSpace.states) {
            ASSERT_NE(state.powerEntityStateName, "");
        }
    }
}

// Each state must have an ID that is unique to the PowerEntityStateSpace
TEST_F(PowerStatsHidlTest, ValidateStateUniqueIds) {
    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);

    for (auto stateSpace : stateSpaces) {
        set<uint32_t> stateIds;
        for (auto state : stateSpace.states) {
            ASSERT_TRUE(stateIds.insert(state.powerEntityStateId).second);
        }
    }
}

// getPowerEntityStateInfo must support passing in requested IDs
// Results must contain state space information for all requested IDs
TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) {
    std::vector<uint32_t> randomIds;
    getRandomIds(randomIds);

    if (randomIds.empty()) {
        return;
    }

    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces, randomIds);

    ASSERT_EQ(stateSpaces.size(), randomIds.size());

    std::set<uint32_t> ids;
    for (auto id : randomIds) {
        ids.insert(id);
    }
    for (auto stateSpace : stateSpaces) {
        ASSERT_NE(ids.count(stateSpace.powerEntityId), 0);
    }
}

// Requested state space info must match initially obtained stateinfos
TEST_F(PowerStatsHidlTest, ValidateStateInfoSelect) {
    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);
    if (stateSpaces.size() == 0) {
        return;
    }

    std::vector<uint32_t> randomIds;
    getRandomIds(randomIds);
    ASSERT_FALSE(randomIds.empty());

    hidl_vec<PowerEntityStateSpace> selectedStateSpaces;
    getStateSpaces(selectedStateSpaces, randomIds);

    std::map<uint32_t, PowerEntityStateSpace> stateSpaceMap;
    for (auto stateSpace : stateSpaces) {
        stateSpaceMap[stateSpace.powerEntityId] = stateSpace;
    }

    for (auto stateSpace : selectedStateSpaces) {
        auto it = stateSpaceMap.find(stateSpace.powerEntityId);
        ASSERT_NE(it, stateSpaceMap.end());

        ASSERT_EQ(stateSpace.states.size(), it->second.states.size());
        for (auto i = 0; i < stateSpace.states.size(); i++) {
            ASSERT_EQ(stateSpace.states[i].powerEntityStateId,
                      it->second.states[i].powerEntityStateId);
            ASSERT_EQ(stateSpace.states[i].powerEntityStateName,
                      it->second.states[i].powerEntityStateName);
        }
    }
}

// stateResidencyResults must contain results for every PowerEntityStateSpace
// returned by getPowerEntityStateInfo
TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociation) {
    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces);

    hidl_vec<PowerEntityStateResidencyResult> results;
    getResidencyResults(results);

    std::map<uint32_t, PowerEntityStateResidencyResult> resultsMap;
    for (auto result : results) {
        resultsMap[result.powerEntityId] = result;
    }

    for (auto stateSpace : stateSpaces) {
        auto it = resultsMap.find(stateSpace.powerEntityId);
        ASSERT_NE(it, resultsMap.end());

        ASSERT_EQ(stateSpace.states.size(), it->second.stateResidencyData.size());

        std::set<uint32_t> stateIds;
        for (auto residency : it->second.stateResidencyData) {
            stateIds.insert(residency.powerEntityStateId);
        }

        for (auto state : stateSpace.states) {
            ASSERT_NE(stateIds.count(state.powerEntityStateId), 0);
        }
    }
}

// getPowerEntityStateResidencyData must support passing in requested IDs
// stateResidencyResults must contain results for each PowerEntityStateSpace
// returned by getPowerEntityStateInfo
TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) {
    std::vector<uint32_t> randomIds;
    getRandomIds(randomIds);
    if (randomIds.empty()) {
        return;
    }

    hidl_vec<PowerEntityStateSpace> stateSpaces;
    getStateSpaces(stateSpaces, randomIds);

    hidl_vec<PowerEntityStateResidencyResult> results;
    getResidencyResults(results, randomIds);

    std::map<uint32_t, PowerEntityStateResidencyResult> resultsMap;
    for (auto result : results) {
        resultsMap[result.powerEntityId] = result;
    }

    for (auto stateSpace : stateSpaces) {
        auto it = resultsMap.find(stateSpace.powerEntityId);
        ASSERT_NE(it, resultsMap.end());

        ASSERT_EQ(stateSpace.states.size(), it->second.stateResidencyData.size());

        std::set<uint32_t> stateIds;
        for (auto residency : it->second.stateResidencyData) {
            stateIds.insert(residency.powerEntityStateId);
        }

        for (auto state : stateSpace.states) {
            ASSERT_NE(stateIds.count(state.powerEntityStateId), 0);
        }
    }
}

TEST_F(PowerStatsHidlTest, ValidateRailInfo) {
    hidl_vec<RailInfo> rails[2];
    Status s;
@@ -299,7 +574,6 @@ int main(int argc, char** argv) {
    LOG(INFO) << "Test result = " << status;
    return status;
}

}  // namespace vts
}  // namespace stats
}  // namespace power