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

Commit d81eb133 authored by Benjamin Schwartz's avatar Benjamin Schwartz Committed by Automerger Merge Worker
Browse files

Merge "power/stats: Add default implementation" am: 492edf2a am: 52f8fda5

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1612583

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ia362efaf0e8f53e1cee314ae06d73e1c2863d3e0
parents e6d56be0 52f8fda5
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <PowerStats.h>

#include <android-base/chrono_utils.h>

#include <chrono>
#include <random>

namespace aidl {
namespace android {
namespace hardware {
namespace power {
namespace stats {

class FakeEnergyConsumer : public PowerStats::IEnergyConsumer {
  public:
    FakeEnergyConsumer(EnergyConsumerType type, std::string name) : mType(type), mName(name) {
        mResult.timestampMs = 0;
        mResult.energyUWs = 0;
        mResult.attribution = {};
    }

    ~FakeEnergyConsumer() = default;

    std::string getName() override { return mName; }

    EnergyConsumerType getType() override { return mType; }

    std::optional<EnergyConsumerResult> getEnergyConsumed() override {
        mFakeEnergyConsumerResult.update(&mResult);
        return mResult;
    }

  private:
    class FakeEnergyConsumerResult {
      public:
        FakeEnergyConsumerResult() : mDistribution(1, 100) {}
        void update(EnergyConsumerResult* result) {
            // generates number in the range 1..100
            auto randNum = std::bind(mDistribution, mGenerator);

            // Get current time since boot in milliseconds
            uint64_t now = std::chrono::time_point_cast<std::chrono::milliseconds>(
                                   ::android::base::boot_clock::now())
                                   .time_since_epoch()
                                   .count();
            result->timestampMs = now;
            result->energyUWs += randNum() * 100;
        }

      private:
        std::default_random_engine mGenerator;
        std::uniform_int_distribution<int> mDistribution;
    };

    EnergyConsumerType mType;
    std::string mName;
    FakeEnergyConsumerResult mFakeEnergyConsumerResult;
    EnergyConsumerResult mResult;
};

}  // namespace stats
}  // namespace power
}  // namespace hardware
}  // namespace android
}  // namespace aidl
 No newline at end of file
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <PowerStats.h>

#include <android-base/chrono_utils.h>

#include <chrono>
#include <random>

namespace aidl {
namespace android {
namespace hardware {
namespace power {
namespace stats {

class FakeEnergyMeter : public PowerStats::IEnergyMeter {
  public:
    FakeEnergyMeter(std::vector<std::pair<std::string, std::string>> channelNames) {
        int32_t channelId = 0;
        for (const auto& [name, subsystem] : channelNames) {
            Channel c;
            c.id = channelId++;
            c.name = name;
            c.subsystem = subsystem;

            EnergyMeasurement m;
            m.id = c.id;
            m.timestampMs = 0;
            m.durationMs = 0;
            m.energyUWs = 0;

            mChannels.push_back(c);
            mEnergyMeasurements.push_back(m);
        }
    }
    ~FakeEnergyMeter() = default;
    ndk::ScopedAStatus readEnergyMeter(const std::vector<int32_t>& in_channelIds,
                                       std::vector<EnergyMeasurement>* _aidl_return) override {
        for (auto& measurement : mEnergyMeasurements) {
            mFakeEnergyMeasurement.update(&measurement);
        }

        if (in_channelIds.empty()) {
            *_aidl_return = mEnergyMeasurements;
        } else {
            for (int32_t id : in_channelIds) {
                if (id >= 0 && id < mEnergyMeasurements.size()) {
                    _aidl_return->push_back(mEnergyMeasurements[id]);
                }
            }
        }

        return ndk::ScopedAStatus::ok();
    }

    ndk::ScopedAStatus getEnergyMeterInfo(std::vector<Channel>* _aidl_return) override {
        *_aidl_return = mChannels;
        return ndk::ScopedAStatus::ok();
    }

  private:
    class FakeEnergyMeasurement {
      public:
        FakeEnergyMeasurement() : mDistribution(1, 100) {}
        void update(EnergyMeasurement* measurement) {
            // generates number in the range 1..100
            auto randNum = std::bind(mDistribution, mGenerator);

            // Get current time since boot in milliseconds
            uint64_t now = std::chrono::time_point_cast<std::chrono::milliseconds>(
                                   ::android::base::boot_clock::now())
                                   .time_since_epoch()
                                   .count();
            measurement->timestampMs = now;
            measurement->durationMs = now;
            measurement->energyUWs += randNum() * 100;
        }

      private:
        std::default_random_engine mGenerator;
        std::uniform_int_distribution<int> mDistribution;
    };

    std::vector<Channel> mChannels;
    FakeEnergyMeasurement mFakeEnergyMeasurement;
    std::vector<EnergyMeasurement> mEnergyMeasurements;
};

}  // namespace stats
}  // namespace power
}  // namespace hardware
}  // namespace android
}  // namespace aidl
 No newline at end of file
+87 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <PowerStats.h>

#include <random>

namespace aidl {
namespace android {
namespace hardware {
namespace power {
namespace stats {

class FakeStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider {
  public:
    FakeStateResidencyDataProvider(const std::string& name, std::vector<State> states)
        : mName(name), mStates(states) {
        for (const auto& state : mStates) {
            StateResidency r;
            r.id = state.id;
            r.totalTimeInStateMs = 0;
            r.totalStateEntryCount = 0;
            r.lastEntryTimestampMs = 0;
            mResidencies.push_back(r);
        }
    }
    ~FakeStateResidencyDataProvider() = default;

    // Methods from PowerStats::IStateResidencyDataProvider
    bool getStateResidencies(
            std::unordered_map<std::string, std::vector<StateResidency>>* residencies) override {
        for (auto& residency : mResidencies) {
            mFakeStateResidency.update(&residency);
        }

        residencies->emplace(mName, mResidencies);
        return true;
    }

    std::unordered_map<std::string, std::vector<State>> getInfo() override {
        return {{mName, mStates}};
    }

  private:
    class FakeStateResidency {
      public:
        FakeStateResidency() : mDistribution(1, 100) {}
        void update(StateResidency* residency) {
            // generates number in the range 1..100
            auto randNum = std::bind(mDistribution, mGenerator);

            residency->totalTimeInStateMs += randNum() * 100;
            residency->totalStateEntryCount += randNum();
            residency->lastEntryTimestampMs += randNum() * 100;
        }

      private:
        std::default_random_engine mGenerator;
        std::uniform_int_distribution<int> mDistribution;
    };

    const std::string mName;
    const std::vector<State> mStates;
    FakeStateResidency mFakeStateResidency;
    std::vector<StateResidency> mResidencies;
};

}  // namespace stats
}  // namespace power
}  // namespace hardware
}  // namespace android
}  // namespace aidl
 No newline at end of file
+124 −13
Original line number Diff line number Diff line
@@ -18,48 +18,159 @@

#include <android-base/logging.h>

#include <numeric>

namespace aidl {
namespace android {
namespace hardware {
namespace power {
namespace stats {

void PowerStats::addStateResidencyDataProvider(std::unique_ptr<IStateResidencyDataProvider> p) {
    if (!p) {
        return;
    }

    int32_t id = mPowerEntityInfos.size();

    for (const auto& [entityName, states] : p->getInfo()) {
        PowerEntity i = {
                .id = id++,
                .name = entityName,
                .states = states,
        };
        mPowerEntityInfos.emplace_back(i);
        mStateResidencyDataProviders.emplace_back(std::move(p));
    }
}

void PowerStats::addEnergyConsumer(std::unique_ptr<IEnergyConsumer> p) {
    if (!p) {
        return;
    }

    EnergyConsumerType type = p->getType();
    std::string name = p->getName();
    int32_t count = count_if(mEnergyConsumerInfos.begin(), mEnergyConsumerInfos.end(),
                             [&type](const EnergyConsumer& c) { return type == c.type; });
    int32_t id = mEnergyConsumers.size();
    mEnergyConsumerInfos.emplace_back(
            EnergyConsumer{.id = id, .ordinal = count, .type = type, .name = name});
    mEnergyConsumers.emplace_back(std::move(p));
}

void PowerStats::setEnergyMeter(std::unique_ptr<IEnergyMeter> p) {
    mEnergyMeter = std::move(p);
}

ndk::ScopedAStatus PowerStats::getPowerEntityInfo(std::vector<PowerEntity>* _aidl_return) {
    (void)_aidl_return;
    *_aidl_return = mPowerEntityInfos;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus PowerStats::getStateResidency(const std::vector<int32_t>& in_powerEntityIds,
                                                 std::vector<StateResidencyResult>* _aidl_return) {
    (void)in_powerEntityIds;
    (void)_aidl_return;
    if (mPowerEntityInfos.empty()) {
        return ndk::ScopedAStatus::ok();
    }

    // If in_powerEntityIds is empty then return data for all supported entities
    if (in_powerEntityIds.empty()) {
        std::vector<int32_t> v(mPowerEntityInfos.size());
        std::iota(std::begin(v), std::end(v), 0);
        return getStateResidency(v, _aidl_return);
    }

    binder_status_t err = STATUS_OK;

    std::unordered_map<std::string, std::vector<StateResidency>> stateResidencies;

    for (const int32_t id : in_powerEntityIds) {
        // skip any invalid ids
        if (id < 0 || id >= mPowerEntityInfos.size()) {
            continue;
        }

        // Check to see if we already have data for the given id
        std::string powerEntityName = mPowerEntityInfos[id].name;
        if (stateResidencies.find(powerEntityName) == stateResidencies.end()) {
            mStateResidencyDataProviders[id]->getStateResidencies(&stateResidencies);
        }

        // Append results if we have them
        auto stateResidency = stateResidencies.find(powerEntityName);
        if (stateResidency != stateResidencies.end()) {
            StateResidencyResult res = {
                    .id = id,
                    .stateResidencyData = stateResidency->second,
            };
            _aidl_return->emplace_back(res);
        } else {
            // Failed to retrieve results for the given id.
            err = STATUS_FAILED_TRANSACTION;
        }
    }

    return ndk::ScopedAStatus::fromStatus(err);
}

ndk::ScopedAStatus PowerStats::getEnergyConsumerInfo(std::vector<EnergyConsumer>* _aidl_return) {
    (void)_aidl_return;
    *_aidl_return = mEnergyConsumerInfos;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus PowerStats::getEnergyConsumed(const std::vector<int32_t>& in_energyConsumerIds,
                                                 std::vector<EnergyConsumerResult>* _aidl_return) {
    (void)in_energyConsumerIds;
    (void)_aidl_return;
    if (mEnergyConsumers.empty()) {
        return ndk::ScopedAStatus::ok();
    }

    // If in_powerEntityIds is empty then return data for all supported energy consumers
    if (in_energyConsumerIds.empty()) {
        std::vector<int32_t> v(mEnergyConsumerInfos.size());
        std::iota(std::begin(v), std::end(v), 0);
        return getEnergyConsumed(v, _aidl_return);
    }

    binder_status_t err = STATUS_OK;

    for (const auto id : in_energyConsumerIds) {
        // skip any invalid ids
        if (id < 0 || id >= mEnergyConsumers.size()) {
            continue;
        }

        auto optionalResult = mEnergyConsumers[id]->getEnergyConsumed();
        if (optionalResult) {
            EnergyConsumerResult result = optionalResult.value();
            result.id = id;
            _aidl_return->emplace_back(result);
        } else {
            // Failed to retrieve results for the given id.
            err = STATUS_FAILED_TRANSACTION;
        }
    }

    return ndk::ScopedAStatus::fromStatus(err);
}

ndk::ScopedAStatus PowerStats::getEnergyMeterInfo(std::vector<Channel>* _aidl_return) {
    (void)_aidl_return;
    if (!mEnergyMeter) {
        return ndk::ScopedAStatus::ok();
    }

    return mEnergyMeter->getEnergyMeterInfo(_aidl_return);
}

ndk::ScopedAStatus PowerStats::readEnergyMeter(const std::vector<int32_t>& in_channelIds,
                                               std::vector<EnergyMeasurement>* _aidl_return) {
    (void)in_channelIds;
    (void)_aidl_return;
    if (!mEnergyMeter) {
        return ndk::ScopedAStatus::ok();
    }

    return mEnergyMeter->readEnergyMeter(in_channelIds, _aidl_return);
}

}  // namespace stats
}  // namespace power
}  // namespace hardware
+41 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include <aidl/android/hardware/power/stats/BnPowerStats.h>

#include <unordered_map>

namespace aidl {
namespace android {
namespace hardware {
@@ -26,7 +28,37 @@ namespace stats {

class PowerStats : public BnPowerStats {
  public:
    class IStateResidencyDataProvider {
      public:
        virtual ~IStateResidencyDataProvider() = default;
        virtual bool getStateResidencies(
                std::unordered_map<std::string, std::vector<StateResidency>>* residencies) = 0;
        virtual std::unordered_map<std::string, std::vector<State>> getInfo() = 0;
    };

    class IEnergyConsumer {
      public:
        virtual ~IEnergyConsumer() = default;
        virtual std::string getName() = 0;
        virtual EnergyConsumerType getType() = 0;
        virtual std::optional<EnergyConsumerResult> getEnergyConsumed() = 0;
    };

    class IEnergyMeter {
      public:
        virtual ~IEnergyMeter() = default;
        virtual ndk::ScopedAStatus readEnergyMeter(
                const std::vector<int32_t>& in_channelIds,
                std::vector<EnergyMeasurement>* _aidl_return) = 0;
        virtual ndk::ScopedAStatus getEnergyMeterInfo(std::vector<Channel>* _aidl_return) = 0;
    };

    PowerStats() = default;

    void addStateResidencyDataProvider(std::unique_ptr<IStateResidencyDataProvider> p);
    void addEnergyConsumer(std::unique_ptr<IEnergyConsumer> p);
    void setEnergyMeter(std::unique_ptr<IEnergyMeter> p);

    // Methods from aidl::android::hardware::power::stats::IPowerStats
    ndk::ScopedAStatus getPowerEntityInfo(std::vector<PowerEntity>* _aidl_return) override;
    ndk::ScopedAStatus getStateResidency(const std::vector<int32_t>& in_powerEntityIds,
@@ -37,6 +69,15 @@ class PowerStats : public BnPowerStats {
    ndk::ScopedAStatus getEnergyMeterInfo(std::vector<Channel>* _aidl_return) override;
    ndk::ScopedAStatus readEnergyMeter(const std::vector<int32_t>& in_channelIds,
                                       std::vector<EnergyMeasurement>* _aidl_return) override;

  private:
    std::vector<std::unique_ptr<IStateResidencyDataProvider>> mStateResidencyDataProviders;
    std::vector<PowerEntity> mPowerEntityInfos;

    std::vector<std::unique_ptr<IEnergyConsumer>> mEnergyConsumers;
    std::vector<EnergyConsumer> mEnergyConsumerInfos;

    std::unique_ptr<IEnergyMeter> mEnergyMeter;
};

}  // namespace stats
Loading