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