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

Commit 92da2835 authored by Bookatz's avatar Bookatz
Browse files

Statsd pulls on-device power measurements

Pulls power rail measurements into statslog.

Bug: 119034725
Test: cts-tradefed run cts-dev -m CtsStatsdHostTestCases -t android.cts.statsd.atom.HostAtomTests
(after enabling OPTINAL_TESTS_ENABLED)

Change-Id: If083ae50160d508a9d180f748f9515557d35d8a1
parent 67dd91e6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ cc_defaults {
        "src/external/StatsPuller.cpp",
        "src/external/StatsCompanionServicePuller.cpp",
        "src/external/SubsystemSleepStatePuller.cpp",
        "src/external/PowerStatsPuller.cpp",
        "src/external/ResourceHealthManagerPuller.cpp",
        "src/external/ResourceThermalManagerPuller.cpp",
        "src/external/StatsPullerManager.cpp",
@@ -134,6 +135,7 @@ cc_defaults {
        "android.hardware.health@2.0",
        "android.hardware.power@1.0",
        "android.hardware.power@1.1",
        "android.hardware.power.stats@1.0",
        "android.hardware.thermal@1.0",
        "libpackagelistparser",
        "libsysutils",
+22 −0
Original line number Diff line number Diff line
@@ -190,6 +190,7 @@ message Atom {
        ProcessCpuTime process_cpu_time = 10035;
        NativeProcessMemoryState native_process_memory_state = 10036;
        CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
        OnDevicePowerMeasurement on_device_power_measurement = 10038;
    }

    // DO NOT USE field numbers above 100,000 in AOSP.
@@ -2261,6 +2262,27 @@ message SubsystemSleepState {
    optional uint64 time_millis = 4;
}

/**
 * Pulls on-device power measurement information.
 * Data defined by hardware/interfaces/power/stats/1.0/types.hal.
 * Pulled from:
 *   frameworks/base/cmds/statsd/src/external/PowerStatsPuller.cpp
 */
message OnDevicePowerMeasurement {
    // Name of the subsystem (to which the rail belongs).
    optional string subsystem_name = 1;

    // Rail name. The rail lies within the subsystem.
    optional string rail_name = 2;

    // Time (in ms since boot) at which the rail energy value was measured.
    // This may differ slightly from the time that statsd logs this information.
    optional uint64 measurement_timestamp_millis = 3;

    // Accumulated energy used via the rail since device boot in uWs.
    optional uint64 energy_microwatt_secs = 4;
}

/**
 * Pulls Cpu time per frequency.
 * Pulls the time the cpu spend on the frequency index. Frequency index
+146 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#define DEBUG false  // STOPSHIP if true
#include "Log.h"

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

#include <vector>

#include "PowerStatsPuller.h"
#include "stats_log_util.h"

using android::hardware::hidl_vec;
using android::hardware::power::stats::V1_0::IPowerStats;
using android::hardware::power::stats::V1_0::EnergyData;
using android::hardware::power::stats::V1_0::RailInfo;
using android::hardware::power::stats::V1_0::Status;
using android::hardware::Return;
using android::hardware::Void;

using std::make_shared;
using std::shared_ptr;

namespace android {
namespace os {
namespace statsd {

sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
std::mutex gPowerStatsHalMutex;
bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
std::vector<RailInfo> gRailInfo;

bool getPowerStatsHal() {
    if (gPowerStatsHal == nullptr && gPowerStatsExist) {
        gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
        if (gPowerStatsHal == nullptr) {
            ALOGW("Couldn't load power.stats HAL service");
            gPowerStatsExist = false;
        }
    }
    return gPowerStatsHal != nullptr;
}

PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
}

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

    if (!getPowerStatsHal()) {
        ALOGE("power.stats Hal not loaded");
        return false;
    }

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

    data->clear();

    // Pull getRailInfo if necessary
    if (gRailInfo.empty()) {
        bool resultSuccess = true;
        Return<void> ret = gPowerStatsHal->getRailInfo(
                [&resultSuccess](const hidl_vec<RailInfo> &list, Status status) {
                    resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
                    if (status != Status::SUCCESS) return;

                    gRailInfo.reserve(list.size());
                    for (size_t i = 0; i < list.size(); ++i) {
                        gRailInfo.push_back(list[i]);
                    }
                });
        if (!resultSuccess || !ret.isOk()) {
            ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
            gPowerStatsHal = nullptr;
            return false;
        }
        // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
        if (gRailInfo.empty()) {
            ALOGE("power.stats has no rail information");
            gPowerStatsExist = false; // No rail info, so never try again.
            return false;
        }
    }

    // Pull getEnergyData and write the data out
    const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
    bool resultSuccess = true;
    Return<void> ret = gPowerStatsHal->getEnergyData(desiredRailIndices,
                [&data, wallClockTimestampNs, elapsedTimestampNs, &resultSuccess]
                (hidl_vec<EnergyData> energyDataList, Status status) {
                    resultSuccess = (status == Status::SUCCESS);
                    if (!resultSuccess) return;

                    for (size_t i = 0; i < energyDataList.size(); i++) {
                        const EnergyData& energyData = energyDataList[i];

                        if (energyData.index >= gRailInfo.size()) {
                            ALOGE("power.stats getEnergyData() returned an invalid rail index %u.",
                                    energyData.index);
                            resultSuccess = false;
                            return;
                        }
                        const RailInfo& rail = gRailInfo[energyData.index];

                        auto ptr = make_shared<LogEvent>(android::util::ON_DEVICE_POWER_MEASUREMENT,
                              wallClockTimestampNs, elapsedTimestampNs);
                        ptr->write(rail.subsysName);
                        ptr->write(rail.railName);
                        ptr->write(energyData.timestamp);
                        ptr->write(energyData.energy);
                        ptr->init();
                        data->push_back(ptr);

                        VLOG("power.stat: %s.%s: %llu, %llu",
                             rail.subsysName.c_str(),
                             rail.railName.c_str(),
                             (unsigned long long)energyData.timestamp,
                             (unsigned long long)energyData.energy);
                    }
                });
    if (!resultSuccess || !ret.isOk()) {
        ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
        gPowerStatsHal = nullptr;
        return false;
    }
    return true;
}

}  // namespace statsd
}  // namespace os
}  // namespace android
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 "StatsPuller.h"

namespace android {
namespace os {
namespace statsd {

/**
 * Reads hal for power.stats
 */
class PowerStatsPuller : public StatsPuller {
public:
    PowerStatsPuller();
    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};

}  // namespace statsd
}  // namespace os
}  // namespace android
+4 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "../logd/LogEvent.h"
#include "../stats_log_util.h"
#include "../statscompanion_util.h"
#include "PowerStatsPuller.h"
#include "ResourceHealthManagerPuller.h"
#include "ResourceThermalManagerPuller.h"
#include "StatsCompanionServicePuller.h"
@@ -86,6 +87,9 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
        // subsystem_sleep_state
        {android::util::SUBSYSTEM_SLEEP_STATE,
         {{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
        // on_device_power_measurement
        {android::util::ON_DEVICE_POWER_MEASUREMENT,
         {{}, {}, 1 * NS_PER_SEC, new PowerStatsPuller()}},
        // cpu_time_per_freq
        {android::util::CPU_TIME_PER_FREQ,
         {{3},