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 
17 #include <dataproviders/DisplayStateResidencyDataProvider.h>
18 
19 #include <android-base/chrono_utils.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 
23 #include <chrono>
24 #include <cstdio>
25 #include <cstring>
26 
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace power {
31 namespace stats {
32 
33 static const int32_t POLL_TIMEOUT_MILLIS = 300;
34 
DisplayStateResidencyDataProvider(std::string name,std::string path,std::vector<std::string> states)35 DisplayStateResidencyDataProvider::DisplayStateResidencyDataProvider(
36         std::string name, std::string path, std::vector<std::string> states)
37     : mPath(std::move(path)),
38       mName(std::move(name)),
39       mStates(states),
40       mCurState(-1),
41       mLooper(new ::android::Looper(true)) {
42     // Construct mResidencies
43     mResidencies.reserve(mStates.size());
44     for (int32_t i = 0; i < mStates.size(); ++i) {
45         StateResidency p = {.id = i};
46         mResidencies.emplace_back(p);
47     }
48 
49     // Open display state file descriptor
50     LOG(VERBOSE) << "Opening " << mPath;
51     mFd = open(mPath.c_str(), O_RDONLY | O_NONBLOCK);
52     if (mFd < 0) {
53         PLOG(ERROR) << ":Failed to open file " << mPath;
54         return;
55     }
56 
57     // Add display state file descriptor to be polled by the looper
58     mLooper->addFd(mFd, 0, ::android::Looper::EVENT_ERROR, nullptr, nullptr);
59 
60     // Run the thread that will poll for changes to display state
61     LOG(VERBOSE) << "Starting DisplayStateWatcherThread";
62     mThread = std::thread(&DisplayStateResidencyDataProvider::pollLoop, this);
63 }
64 
~DisplayStateResidencyDataProvider()65 DisplayStateResidencyDataProvider::~DisplayStateResidencyDataProvider() {
66     if (mFd >= 0) {
67         close(mFd);
68     }
69 }
70 
getStateResidencies(std::unordered_map<std::string,std::vector<StateResidency>> * residencies)71 bool DisplayStateResidencyDataProvider::getStateResidencies(
72         std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
73     std::scoped_lock lk(mLock);
74 
75     // Get current time since boot in milliseconds
76     uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
77                            ::android::base::boot_clock::now().time_since_epoch())
78                            .count();
79 
80     // Construct residency result based on current residency data
81     auto result = mResidencies;
82 
83     if (mCurState > -1) {
84         result[mCurState].totalTimeInStateMs += now - result[mCurState].lastEntryTimestampMs;
85     }
86 
87     residencies->emplace(mName, result);
88     return true;
89 }
90 
getInfo()91 std::unordered_map<std::string, std::vector<State>> DisplayStateResidencyDataProvider::getInfo() {
92     std::vector<State> stateInfos;
93     stateInfos.reserve(mStates.size());
94     for (int32_t i = 0; i < mStates.size(); ++i) {
95         stateInfos.push_back({.id = i, .name = mStates[i]});
96     }
97 
98     return {{mName, stateInfos}};
99 }
100 
101 // Called when there is new data to be read from
102 // display state file descriptor indicating a state change
updateStats()103 void DisplayStateResidencyDataProvider::updateStats() {
104     char data[32];
105     char *trim;
106 
107     // Get current time since boot in milliseconds
108     uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
109                            ::android::base::boot_clock::now().time_since_epoch())
110                            .count();
111     // Read display state
112     ssize_t ret = pread(mFd, data, sizeof(data) - 1, 0);
113     if (ret < 0) {
114         PLOG(ERROR) << "Failed to read display state";
115         return;
116     }
117 
118     trim = strchr(data, '\n');
119     if (trim) {
120         data[trim - data] = '\0';
121     }
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 (strcmp(data, mStates[i].c_str()) == 0) {
128                 if (i == mCurState) {
129                     break;
130                 }
131 
132                 LOG(VERBOSE) << "display state: " << data;
133 
134                 // Update total time of the previous state
135                 if (mCurState > -1) {
136                     mResidencies[mCurState].totalTimeInStateMs +=
137                             now - mResidencies[mCurState].lastEntryTimestampMs;
138                 }
139 
140                 // Set current state
141                 mCurState = i;
142                 mResidencies[i].totalStateEntryCount++;
143                 mResidencies[i].lastEntryTimestampMs = now;
144                 break;
145             }
146         }
147     }  // release lock
148 }
149 
pollLoop()150 void DisplayStateResidencyDataProvider::pollLoop() {
151     int32_t res;
152     LOG(VERBOSE) << "DisplayStateResidencyDataProvider polling...";
153     while (true) {
154         // Poll for display state changes.
155         res = mLooper->pollOnce(POLL_TIMEOUT_MILLIS);
156         if (res >= 0 || res == ::android::Looper::POLL_TIMEOUT) {
157             updateStats();
158         }
159     }
160 }
161 
162 }  // namespace stats
163 }  // namespace power
164 }  // namespace hardware
165 }  // namespace android
166 }  // namespace aidl
167