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

Commit 060a1ca3 authored by Michael Sun's avatar Michael Sun
Browse files

BatteryStats: update to use new notifyWakeup with wakeup reasons

As SystemSuspend support notifyWakeup callback with wakeup reason
embedded, BatteryStats no longer required to pull such reasons from
kernel files by itself.

Test: adb shell dumpsys batterystats --history
Bug: 171021049
Change-Id: I69717387586994b744297f5ac0f5b66ef2bdce32
parent a09d15ad
Loading
Loading
Loading
Loading
+43 −25
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
#define LOG_TAG "BatteryStatsService"
//#define LOG_NDEBUG 0

#include <climits>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -28,6 +27,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <climits>
#include <unordered_map>
#include <utility>

@@ -46,15 +46,16 @@
#include <utils/misc.h>
#include <utils/Log.h>

using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
using android::system::suspend::BnSuspendCallback;
using android::hardware::power::stats::V1_0::IPowerStats;
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::hidl_vec;
using android::system::suspend::BnSuspendCallback;
using android::system::suspend::ISuspendControlService;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -62,10 +63,9 @@ using IPowerV1_0 = android::hardware::power::V1_0::IPower;
namespace android
{

#define LAST_RESUME_REASON "/sys/kernel/wakeup_reasons/last_resume_reason"
#define MAX_REASON_SIZE 512

static bool wakeup_init = false;
static std::mutex mReasonsMutex;
static std::vector<std::string> mWakeupReasons;
static sem_t wakeup_sem;
extern sp<IPowerV1_0> getPowerHalHidlV1_0();
extern sp<IPowerV1_1> getPowerHalHidlV1_1();
@@ -84,7 +84,8 @@ std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>>
    gPowerStatsHalStateNames = {};
std::vector<uint32_t> gPowerStatsHalPlatformIds = {};
std::vector<uint32_t> gPowerStatsHalSubsystemIds = {};
sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
sp<IPowerStats> gPowerStatsHalV1_0 = nullptr;

std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
@@ -116,8 +117,24 @@ sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();

class WakeupCallback : public BnSuspendCallback {
public:
    binder::Status notifyWakeup(bool success) override {
    binder::Status notifyWakeup(bool success,
                                const std::vector<std::string>& wakeupReasons) override {
        ALOGI("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
        bool reasonsCaptured = false;
        {
            std::unique_lock<std::mutex> reasonsLock(mReasonsMutex, std::defer_lock);
            if (reasonsLock.try_lock() && mWakeupReasons.empty()) {
                mWakeupReasons = std::move(wakeupReasons);
                reasonsCaptured = true;
            }
        }
        if (!reasonsCaptured) {
            ALOGE("Failed to write wakeup reasons. Reasons dropped:");
            for (auto wakeupReason : wakeupReasons) {
                ALOGE("\t%s", wakeupReason.c_str());
            }
        }

        int ret = sem_post(&wakeup_sem);
        if (ret < 0) {
            char buf[80];
@@ -157,8 +174,6 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)

    // Wait for wakeup.
    ALOGV("Waiting for wakeup...");
    // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup
    // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events.
    int ret = sem_wait(&wakeup_sem);
    if (ret < 0) {
        char buf[80];
@@ -168,20 +183,27 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
        return 0;
    }

    FILE *fp = fopen(LAST_RESUME_REASON, "r");
    if (fp == NULL) {
        ALOGE("Failed to open %s", LAST_RESUME_REASON);
        return -1;
    }

    char* mergedreason = (char*)env->GetDirectBufferAddress(outBuf);
    int remainreasonlen = (int)env->GetDirectBufferCapacity(outBuf);

    ALOGV("Reading wakeup reasons");
    std::vector<std::string> wakeupReasons;
    {
        std::unique_lock<std::mutex> reasonsLock(mReasonsMutex, std::defer_lock);
        if (reasonsLock.try_lock() && !mWakeupReasons.empty()) {
            wakeupReasons = std::move(mWakeupReasons);
            mWakeupReasons.clear();
        }
    }

    if (wakeupReasons.empty()) {
        return 0;
    }

    char* mergedreasonpos = mergedreason;
    char reasonline[128];
    int i = 0;
    while (fgets(reasonline, sizeof(reasonline), fp) != NULL) {
    for (auto wakeupReason : wakeupReasons) {
        auto reasonline = const_cast<char*>(wakeupReason.c_str());
        char* pos = reasonline;
        char* endPos;
        int len;
@@ -238,10 +260,6 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
        *mergedreasonpos = 0;
    }

    if (fclose(fp) != 0) {
        ALOGE("Failed to close %s", LAST_RESUME_REASON);
        return -1;
    }
    return mergedreasonpos - mergedreason;
}

@@ -340,7 +358,7 @@ static bool initializePowerStats() {
// The caller must be holding gPowerHalMutex.
static bool getPowerStatsHalLocked() {
    if (gPowerStatsHalV1_0 == nullptr) {
        gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
        gPowerStatsHalV1_0 = IPowerStats::getService();
        if (gPowerStatsHalV1_0 == nullptr) {
            ALOGE("Unable to get power.stats HAL service.");
            return false;
@@ -833,7 +851,7 @@ static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
static void setUpPowerStatsLocked() {
    // 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) {
    if (IPowerStats::getService() != nullptr) {
        ALOGI("Using power.stats HAL");
        gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
        gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;