Loading cmds/statsd/src/atoms.proto +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading cmds/statsd/src/external/SubsystemSleepStatePuller.cpp +251 −50 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading @@ -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++) { Loading Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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 Loading
cmds/statsd/src/atoms.proto +9 −2 Original line number Diff line number Diff line Loading @@ -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; Loading
cmds/statsd/src/external/SubsystemSleepStatePuller.cpp +251 −50 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading @@ -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++) { Loading Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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