1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 // TODO(b/167628903): Delete this file
17 #define LOG_TAG "libpixelpowerstats"
18
19 #include <android-base/chrono_utils.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22
23 #include <pixelpowerstats/DisplayStateResidencyDataProvider.h>
24 #include <pixelpowerstats/PowerStatsUtils.h>
25
26 #include <chrono>
27 #include <cstdio>
28 #include <cstring>
29
30 namespace android {
31 namespace hardware {
32 namespace google {
33 namespace pixel {
34 namespace powerstats {
35
DisplayStateResidencyDataProvider(uint32_t id,std::string path,std::vector<std::string> states)36 DisplayStateResidencyDataProvider::DisplayStateResidencyDataProvider(
37 uint32_t id, std::string path, std::vector<std::string> states)
38 : mPath(std::move(path)),
39 mPowerEntityId(id),
40 mStates(states),
41 mCurState(-1),
42 mLooper(new Looper(true)) {
43 // Construct mResidencies
44 mResidencies.reserve(mStates.size());
45 for (uint32_t i = 0; i < mStates.size(); ++i) {
46 PowerEntityStateResidencyData p = {.powerEntityStateId = i};
47 mResidencies.emplace_back(p);
48 }
49
50 // Open display state file descriptor
51 LOG(VERBOSE) << "Opening " << mPath;
52 mFd = open(mPath.c_str(), O_RDONLY | O_NONBLOCK);
53 if (mFd < 0) {
54 PLOG(ERROR) << ":Failed to open file " << mPath;
55 return;
56 }
57
58 // Add display state file descriptor to be polled by the looper
59 mLooper->addFd(mFd, 0, Looper::EVENT_ERROR, nullptr, nullptr);
60
61 // Run the thread that will poll for changes to display state
62 LOG(VERBOSE) << "Starting DisplayStateWatcherThread";
63 mThread = std::thread(&DisplayStateResidencyDataProvider::pollLoop, this);
64 }
65
~DisplayStateResidencyDataProvider()66 DisplayStateResidencyDataProvider::~DisplayStateResidencyDataProvider() {
67 if (mFd > 0) {
68 close(mFd);
69 }
70 }
71
getResults(std::unordered_map<uint32_t,PowerEntityStateResidencyResult> & results)72 bool DisplayStateResidencyDataProvider::getResults(
73 std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
74 std::scoped_lock lk(mLock);
75
76 // Get current time since boot in milliseconds
77 uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
78 ::android::base::boot_clock::now().time_since_epoch())
79 .count();
80
81 // Construct residency result based on current residency data
82 PowerEntityStateResidencyResult result = {.powerEntityId = mPowerEntityId,
83 .stateResidencyData = mResidencies};
84
85 if (mCurState > -1) {
86 result.stateResidencyData[mCurState].totalTimeInStateMs +=
87 now - result.stateResidencyData[mCurState].lastEntryTimestampMs;
88 }
89
90 results.emplace(mPowerEntityId, result);
91 return true;
92 }
93
getStateSpaces()94 std::vector<PowerEntityStateSpace> DisplayStateResidencyDataProvider::getStateSpaces() {
95 PowerEntityStateSpace s = {.powerEntityId = mPowerEntityId};
96 s.states.resize(mStates.size());
97 for (uint32_t i = 0; i < mStates.size(); ++i) {
98 s.states[i] = {.powerEntityStateId = i, .powerEntityStateName = mStates[i]};
99 }
100
101 return {s};
102 }
103
104 // Called when there is new data to be read from
105 // display state file descriptor indicating a state change
updateStats()106 void DisplayStateResidencyDataProvider::updateStats() {
107 char data[32];
108
109 // Get current time since boot in milliseconds
110 uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
111 ::android::base::boot_clock::now().time_since_epoch())
112 .count();
113 // Read display state
114 ssize_t ret = pread(mFd, data, sizeof(data) - 1, 0);
115 if (ret < 0) {
116 PLOG(WARNING) << "Failed to read display state";
117 return;
118 }
119 data[ret] = '\0';
120
121 LOG(VERBOSE) << "display state: " << data;
122
123 // Update residency stats based on state read
124 { // acquire lock
125 std::scoped_lock lk(mLock);
126 for (uint32_t i = 0; i < mStates.size(); ++i) {
127 if (strstr(data, mStates[i].c_str())) {
128 // Update total time of the previous state
129 if (mCurState > -1) {
130 mResidencies[mCurState].totalTimeInStateMs +=
131 now - mResidencies[mCurState].lastEntryTimestampMs;
132 }
133
134 // Set current state
135 mCurState = i;
136 mResidencies[i].totalStateEntryCount++;
137 mResidencies[i].lastEntryTimestampMs = now;
138 break;
139 }
140 }
141 } // release lock
142 }
143
pollLoop()144 void DisplayStateResidencyDataProvider::pollLoop() {
145 LOG(VERBOSE) << "DisplayStateResidencyDataProvider polling...";
146 while (true) {
147 // Poll for display state changes. Timeout set to poll indefinitely
148 if (mLooper->pollOnce(-1) >= 0) {
149 updateStats();
150 }
151 }
152 }
153
154 } // namespace powerstats
155 } // namespace pixel
156 } // namespace google
157 } // namespace hardware
158 } // namespace android
159