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

Commit 0126da8a authored by Benjamin Schwartz's avatar Benjamin Schwartz Committed by Android (Google) Code Review
Browse files

Merge "statsd: Migrate statsd SubsystemSleepState to use power.stats HAL"

parents 6383c3c1 51329b72
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -2394,16 +2394,23 @@ message KernelWakelock {
}

/**
 * Pulls low power state information. This includes platform and subsystem sleep state information,
 * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState as defined in
 * Pulls low power state information. If power.stats HAL is not available, this
 * includes platform and subsystem sleep state information,
 * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState
 * as defined in:
 *   hardware/interfaces/power/1.0/types.hal
 *   hardware/interfaces/power/1.1/types.hal
 * If power.stats HAL is available, this includes PowerEntityStateResidencyResult
 * as defined in:
 *   hardware/interfaces/power/stats/1.0/types.hal
 */
message SubsystemSleepState {
    // Subsystem name
    optional string subsystem_name = 1;
    // For PlatformLowPowerStats (hal 1.0), this is the voter name, which could be empty.
    // For SubsystemLowPowerStats (hal 1.1), this is the sleep state name.
    // For PowerEntityStateResidencyResult (hal power/stats/1.0) this is the
    //    powerEntityStateName from the corresponding PowerEntityStateInfo.
    optional string subname = 2;
    // The number of times it entered, or voted for entering the sleep state
    optional uint64 count = 3;
+251 −50
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@

#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/stats/1.0/IPowerStats.h>

#include <fcntl.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
@@ -42,9 +44,12 @@ using android::hardware::hidl_vec;
using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
using android::hardware::power::V1_0::Status;
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
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::Return;
using android::hardware::Void;

@@ -55,44 +60,209 @@ namespace android {
namespace os {
namespace statsd {

std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};

sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;

std::unordered_map<uint32_t, std::string> gEntityNames = {};
std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};

std::mutex gPowerHalMutex;
bool gPowerHalExists = true;

bool getPowerHal() {
    if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
        gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
        if (gPowerHalV1_0 != nullptr) {
            gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
            ALOGI("Loaded power HAL service");
        } else {
            ALOGW("Couldn't load power HAL service");
            gPowerHalExists = false;
// The caller must be holding gPowerHalMutex.
void deinitPowerStatsLocked() {
    gPowerHalV1_0 = nullptr;
    gPowerHalV1_1 = nullptr;
    gPowerStatsHalV1_0 = nullptr;
}

struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient {
    virtual void serviceDied(uint64_t cookie,
        const wp<android::hidl::base::V1_0::IBase>& who) override {
        // The HAL just died. Reset all handles to HAL services.
        std::lock_guard<std::mutex> lock(gPowerHalMutex);
        deinitPowerStatsLocked();
    }
    return gPowerHalV1_0 != nullptr;
};

sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();

SubsystemSleepStatePuller::SubsystemSleepStatePuller() :
    StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
}

SubsystemSleepStatePuller::SubsystemSleepStatePuller() : StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
// The caller must be holding gPowerHalMutex.
bool checkResultLocked(const Return<void> &ret, const char* function) {
    if (!ret.isOk()) {
        ALOGE("%s failed: requested HAL service not available. Description: %s",
            function, ret.description().c_str());
        if (ret.isDeadObject()) {
            deinitPowerStatsLocked();
        }
        return false;
    }
    return true;
}

bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
    std::lock_guard<std::mutex> lock(gPowerHalMutex);
// The caller must be holding gPowerHalMutex.
// gPowerStatsHalV1_0 must not be null
bool initializePowerStats() {
    using android::hardware::power::stats::V1_0::Status;

    // Clear out previous content if we are re-initializing
    gEntityNames.clear();
    gStateNames.clear();

    Return<void> ret;
    ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
        if (status != Status::SUCCESS) {
            ALOGE("Error getting power entity info");
            return;
        }

        // construct lookup table of powerEntityId to power entity name
        for (auto info : infos) {
            gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
        }
    });
    if (!checkResultLocked(ret, __func__)) {
        return false;
    }

    ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
        if (status != Status::SUCCESS) {
            ALOGE("Error getting state info");
            return;
        }

        // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
        for (auto stateSpace : stateSpaces) {
            std::unordered_map<uint32_t, std::string> stateNames = {};
            for (auto state : stateSpace.states) {
                stateNames.emplace(state.powerEntityStateId,
                    state.powerEntityStateName);
            }
            gStateNames.emplace(stateSpace.powerEntityId, stateNames);
        }
    });
    if (!checkResultLocked(ret, __func__)) {
        return false;
    }

    return (!gEntityNames.empty()) && (!gStateNames.empty());
}

// The caller must be holding gPowerHalMutex.
bool getPowerStatsHalLocked() {
    if(gPowerStatsHalV1_0 == nullptr) {
        gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
        if (gPowerStatsHalV1_0 == nullptr) {
            ALOGE("Unable to get power.stats HAL service.");
            return false;
        }

        // Link death recipient to power.stats service handle
        hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
        if (!linked.isOk()) {
            ALOGE("Transaction error in linking to power.stats HAL death: %s",
                    linked.description().c_str());
            deinitPowerStatsLocked();
            return false;
        } else if (!linked) {
            ALOGW("Unable to link to power.stats HAL death notifications");
            // We should still continue even though linking failed
        }
        return initializePowerStats();
    }
    return true;
}

    if (!getPowerHal()) {
        ALOGE("Power Hal not loaded");
// The caller must be holding gPowerHalMutex.
bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
    using android::hardware::power::stats::V1_0::Status;

    if(!getPowerStatsHalLocked()) {
        return false;
    }

    int64_t wallClockTimestampNs = getWallClockNs();
    int64_t elapsedTimestampNs = getElapsedRealtimeNs();

    data->clear();
    // Get power entity state residency data
    bool success = false;
    Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
        [&data, &success, wallClockTimestampNs, elapsedTimestampNs]
        (auto results, auto status) {
        if (status == Status::NOT_SUPPORTED) {
            ALOGW("getPowerEntityStateResidencyData is not supported");
            success = false;
            return;
        }

        for(auto result : results) {
            for(auto stateResidency : result.stateResidencyData) {
                auto statePtr = make_shared<LogEvent>(
                        android::util::SUBSYSTEM_SLEEP_STATE,
                        wallClockTimestampNs, elapsedTimestampNs);
                statePtr->write(gEntityNames.at(result.powerEntityId));
                statePtr->write(gStateNames.at(result.powerEntityId)
                    .at(stateResidency.powerEntityStateId));
                statePtr->write(stateResidency.totalStateEntryCount);
                statePtr->write(stateResidency.totalTimeInStateMs);
                statePtr->init();
                data->emplace_back(statePtr);
            }
        }
        success = true;
    });
    // Intentionally not returning early here.
    // bool success determines if this succeeded or not.
    checkResultLocked(ret, __func__);

    return success;
}

// The caller must be holding gPowerHalMutex.
bool getPowerHalLocked() {
    if(gPowerHalV1_0 == nullptr) {
        gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
        if(gPowerHalV1_0 == nullptr) {
            ALOGE("Unable to get power HAL service.");
            return false;
        }
        gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);

        // Link death recipient to power service handle
        hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
        if (!linked.isOk()) {
            ALOGE("Transaction error in linking to power HAL death: %s",
                    linked.description().c_str());
            gPowerHalV1_0 = nullptr;
            return false;
        } else if (!linked) {
            ALOGW("Unable to link to power. death notifications");
            // We should still continue even though linking failed
        }
    }
    return true;
}

// The caller must be holding gPowerHalMutex.
bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
    using android::hardware::power::V1_0::Status;

    if(!getPowerHalLocked()) {
        return false;
    }

    int64_t wallClockTimestampNs = getWallClockNs();
    int64_t elapsedTimestampNs = getElapsedRealtimeNs();
        Return<void> ret;
        ret = gPowerHalV1_0->getPlatformLowPowerStats(
                [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
                [&data, wallClockTimestampNs, elapsedTimestampNs]
                    (hidl_vec<PowerStatePlatformSleepState> states, Status status) {
                    if (status != Status::SUCCESS) return;

                    for (size_t i = 0; i < states.size(); i++) {
@@ -128,9 +298,7 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
                        }
                    }
                });
        if (!ret.isOk()) {
            ALOGE("getLowPowerStats() failed: power HAL service not available");
            gPowerHalV1_0 = nullptr;
        if (!checkResultLocked(ret, __func__)) {
            return false;
        }

@@ -139,7 +307,8 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
                android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
        if (gPowerHal_1_1 != nullptr) {
            ret = gPowerHal_1_1->getSubsystemLowPowerStats(
                    [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
            [&data, wallClockTimestampNs, elapsedTimestampNs]
            (hidl_vec<PowerStateSubsystem> subsystems, Status status) {
                if (status != Status::SUCCESS) return;

                if (subsystems.size() > 0) {
@@ -170,6 +339,38 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
        return true;
}

// The caller must be holding gPowerHalMutex.
std::function<bool(vector<shared_ptr<LogEvent>>* data)> getPullerLocked() {
    std::function<bool(vector<shared_ptr<LogEvent>>* data)> ret = {};

    // First see if power.stats HAL is available. Fall back to power HAL if
    // power.stats HAL is unavailable.
    if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
        ALOGI("Using power.stats HAL");
        ret = getIPowerStatsDataLocked;
    } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
        ALOGI("Using power HAL");
        ret = getIPowerDataLocked;
    }

    return ret;
}

bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
    std::lock_guard<std::mutex> lock(gPowerHalMutex);

    if(!gPuller) {
        gPuller = getPullerLocked();
    }

    if(gPuller) {
        return gPuller(data);
    }

    ALOGE("Unable to load Power Hal or power.stats HAL");
    return false;
}

}  // namespace statsd
}  // namespace os
}  // namespace android