You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.2 KiB
159 lines
5.2 KiB
/*
|
|
* Copyright (C) 2020 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.
|
|
*/
|
|
// TODO(b/167628903): Delete this file
|
|
#define LOG_TAG "libpixelpowerstats"
|
|
|
|
#include <android-base/chrono_utils.h>
|
|
#include <android-base/logging.h>
|
|
#include <android-base/properties.h>
|
|
|
|
#include <pixelpowerstats/DisplayStateResidencyDataProvider.h>
|
|
#include <pixelpowerstats/PowerStatsUtils.h>
|
|
|
|
#include <chrono>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace google {
|
|
namespace pixel {
|
|
namespace powerstats {
|
|
|
|
DisplayStateResidencyDataProvider::DisplayStateResidencyDataProvider(
|
|
uint32_t id, std::string path, std::vector<std::string> states)
|
|
: mPath(std::move(path)),
|
|
mPowerEntityId(id),
|
|
mStates(states),
|
|
mCurState(-1),
|
|
mLooper(new Looper(true)) {
|
|
// Construct mResidencies
|
|
mResidencies.reserve(mStates.size());
|
|
for (uint32_t i = 0; i < mStates.size(); ++i) {
|
|
PowerEntityStateResidencyData p = {.powerEntityStateId = i};
|
|
mResidencies.emplace_back(p);
|
|
}
|
|
|
|
// Open display state file descriptor
|
|
LOG(VERBOSE) << "Opening " << mPath;
|
|
mFd = open(mPath.c_str(), O_RDONLY | O_NONBLOCK);
|
|
if (mFd < 0) {
|
|
PLOG(ERROR) << ":Failed to open file " << mPath;
|
|
return;
|
|
}
|
|
|
|
// Add display state file descriptor to be polled by the looper
|
|
mLooper->addFd(mFd, 0, Looper::EVENT_ERROR, nullptr, nullptr);
|
|
|
|
// Run the thread that will poll for changes to display state
|
|
LOG(VERBOSE) << "Starting DisplayStateWatcherThread";
|
|
mThread = std::thread(&DisplayStateResidencyDataProvider::pollLoop, this);
|
|
}
|
|
|
|
DisplayStateResidencyDataProvider::~DisplayStateResidencyDataProvider() {
|
|
if (mFd > 0) {
|
|
close(mFd);
|
|
}
|
|
}
|
|
|
|
bool DisplayStateResidencyDataProvider::getResults(
|
|
std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
|
|
std::scoped_lock lk(mLock);
|
|
|
|
// Get current time since boot in milliseconds
|
|
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
::android::base::boot_clock::now().time_since_epoch())
|
|
.count();
|
|
|
|
// Construct residency result based on current residency data
|
|
PowerEntityStateResidencyResult result = {.powerEntityId = mPowerEntityId,
|
|
.stateResidencyData = mResidencies};
|
|
|
|
if (mCurState > -1) {
|
|
result.stateResidencyData[mCurState].totalTimeInStateMs +=
|
|
now - result.stateResidencyData[mCurState].lastEntryTimestampMs;
|
|
}
|
|
|
|
results.emplace(mPowerEntityId, result);
|
|
return true;
|
|
}
|
|
|
|
std::vector<PowerEntityStateSpace> DisplayStateResidencyDataProvider::getStateSpaces() {
|
|
PowerEntityStateSpace s = {.powerEntityId = mPowerEntityId};
|
|
s.states.resize(mStates.size());
|
|
for (uint32_t i = 0; i < mStates.size(); ++i) {
|
|
s.states[i] = {.powerEntityStateId = i, .powerEntityStateName = mStates[i]};
|
|
}
|
|
|
|
return {s};
|
|
}
|
|
|
|
// Called when there is new data to be read from
|
|
// display state file descriptor indicating a state change
|
|
void DisplayStateResidencyDataProvider::updateStats() {
|
|
char data[32];
|
|
|
|
// Get current time since boot in milliseconds
|
|
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
::android::base::boot_clock::now().time_since_epoch())
|
|
.count();
|
|
// Read display state
|
|
ssize_t ret = pread(mFd, data, sizeof(data) - 1, 0);
|
|
if (ret < 0) {
|
|
PLOG(WARNING) << "Failed to read display state";
|
|
return;
|
|
}
|
|
data[ret] = '\0';
|
|
|
|
LOG(VERBOSE) << "display state: " << data;
|
|
|
|
// Update residency stats based on state read
|
|
{ // acquire lock
|
|
std::scoped_lock lk(mLock);
|
|
for (uint32_t i = 0; i < mStates.size(); ++i) {
|
|
if (strstr(data, mStates[i].c_str())) {
|
|
// Update total time of the previous state
|
|
if (mCurState > -1) {
|
|
mResidencies[mCurState].totalTimeInStateMs +=
|
|
now - mResidencies[mCurState].lastEntryTimestampMs;
|
|
}
|
|
|
|
// Set current state
|
|
mCurState = i;
|
|
mResidencies[i].totalStateEntryCount++;
|
|
mResidencies[i].lastEntryTimestampMs = now;
|
|
break;
|
|
}
|
|
}
|
|
} // release lock
|
|
}
|
|
|
|
void DisplayStateResidencyDataProvider::pollLoop() {
|
|
LOG(VERBOSE) << "DisplayStateResidencyDataProvider polling...";
|
|
while (true) {
|
|
// Poll for display state changes. Timeout set to poll indefinitely
|
|
if (mLooper->pollOnce(-1) >= 0) {
|
|
updateStats();
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace powerstats
|
|
} // namespace pixel
|
|
} // namespace google
|
|
} // namespace hardware
|
|
} // namespace android
|