159 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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
 |