1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "libpixelpowerstats"
17
18 #include <android-base/logging.h>
19 #include <android-base/stringprintf.h>
20 #include <binder/IPCThreadState.h>
21 #include <binder/IServiceManager.h>
22 #include <binder/ProcessState.h>
23 #include <pixelpowerstats/AidlStateResidencyDataProvider.h>
24 #include <time.h>
25 using android::base::StringPrintf;
26
27 static const uint64_t MAX_LATENCY_US = 2000;
28
29 namespace android {
30 namespace hardware {
31 namespace google {
32 namespace pixel {
33 namespace powerstats {
34
addEntity(uint32_t id,std::string entityName,std::vector<std::string> stateNames)35 void AidlStateResidencyDataProvider::addEntity(uint32_t id, std::string entityName,
36 std::vector<std::string> stateNames) {
37 std::lock_guard<std::mutex> lock(mLock);
38 // Create a new entry in the map of power entities
39 mEntityInfos.emplace(entityName, StateSpace{.powerEntityId = id, .stateInfos = {}});
40
41 // Create an entry for each state and assign an Id.
42 uint32_t stateId = 0;
43 auto &stateInfos = mEntityInfos.at(entityName).stateInfos;
44 for (auto stateName : stateNames) {
45 stateInfos.emplace(stateName, stateId++);
46 }
47 }
48
unregisterCallbackInternal(const sp<IBinder> & callback)49 binderStatus AidlStateResidencyDataProvider::unregisterCallbackInternal(
50 const sp<IBinder> &callback) {
51 if (callback == nullptr) {
52 // Callback pointer is null. Return an error.
53 return binderStatus::fromExceptionCode(binderStatus::EX_NULL_POINTER, "callback is null");
54 }
55
56 bool removed = false;
57 std::lock_guard<std::mutex> lock(mLock);
58
59 // Iterate over collection of callbacks and remove the one that matches
60 for (auto it = mCallbacks.begin(); it != mCallbacks.end();) {
61 if (asBinder(it->second) == callback) {
62 LOG(INFO) << "Unregistering callback for " << it->first;
63 it = mCallbacks.erase(it);
64 removed = true;
65 } else {
66 it++;
67 }
68 }
69 (void)callback->unlinkToDeath(this); // ignore errors
70 return removed ? binderStatus::ok()
71 : binderStatus::fromExceptionCode(binderStatus::EX_ILLEGAL_ARGUMENT,
72 "callback not found");
73 }
74
binderDied(const wp<IBinder> & who)75 void AidlStateResidencyDataProvider::binderDied(const wp<IBinder> &who) {
76 binderStatus status = unregisterCallbackInternal(who.promote());
77 if (!status.isOk()) {
78 LOG(ERROR) << __func__ << "failed to unregister callback " << status.toString8();
79 }
80 }
81
unregisterCallback(const sp<IPixelPowerStatsCallback> & callback)82 binderStatus AidlStateResidencyDataProvider::unregisterCallback(
83 const sp<IPixelPowerStatsCallback> &callback) {
84 return unregisterCallbackInternal(asBinder(callback));
85 }
86
registerCallback(const std::string & entityName,const sp<IPixelPowerStatsCallback> & callback)87 binderStatus AidlStateResidencyDataProvider::registerCallback(
88 const std::string &entityName, const sp<IPixelPowerStatsCallback> &callback) {
89 LOG(INFO) << "Registering callback for " << entityName;
90 if (callback == nullptr) {
91 // Callback pointer is null. Return an error.
92 LOG(ERROR) << __func__ << ": "
93 << "Invalid callback. Callback is null";
94 return binderStatus::fromExceptionCode(
95 binderStatus::EX_NULL_POINTER, "Invalid callback. Callback is null");
96 }
97
98 std::lock_guard<std::mutex> lock(mLock);
99 if (mEntityInfos.find(entityName) == mEntityInfos.end()) {
100 // Could not find the entity associated with this callback. Return an error.
101 LOG(ERROR) << __func__ << ": "
102 << "Invalid entity";
103 return binderStatus::fromExceptionCode(binderStatus::EX_ILLEGAL_ARGUMENT, "Invalid entity");
104 }
105
106 mCallbacks.emplace(entityName, callback);
107
108 // death recipient
109 auto linkRet = asBinder(callback)->linkToDeath(this, 0u /* cookie */);
110 if (linkRet != android::OK) {
111 LOG(WARNING) << __func__ << "Cannot link to death: " << linkRet;
112 // ignore the error
113 }
114
115 return binderStatus::ok();
116 }
117
getStatsTimed(const std::pair<std::string,sp<IPixelPowerStatsCallback>> & cb,std::vector<android::vendor::powerstats::StateResidencyData> & stats)118 static binderStatus getStatsTimed(
119 const std::pair<std::string, sp<IPixelPowerStatsCallback>> &cb,
120 std::vector<android::vendor::powerstats::StateResidencyData> &stats) {
121 struct timespec then;
122 struct timespec now;
123
124 clock_gettime(CLOCK_BOOTTIME, &then);
125 binderStatus status = cb.second->getStats(&stats);
126 clock_gettime(CLOCK_BOOTTIME, &now);
127
128 uint64_t time_elapsed_us =
129 ((now.tv_sec - then.tv_sec) * 1000000) + ((now.tv_nsec - then.tv_nsec) / 1000);
130 if (time_elapsed_us > MAX_LATENCY_US) {
131 LOG(WARNING) << "getStats for " << cb.first << " exceeded time allowed: " << time_elapsed_us
132 << "us";
133 }
134 return status;
135 }
136
buildResult(std::string entityName,const std::vector<android::vendor::powerstats::StateResidencyData> & stats,PowerEntityStateResidencyResult & result)137 bool AidlStateResidencyDataProvider::buildResult(
138 std::string entityName,
139 const std::vector<android::vendor::powerstats::StateResidencyData> &stats,
140 PowerEntityStateResidencyResult &result) {
141 auto infosEntry = mEntityInfos.find(entityName);
142 if (infosEntry == mEntityInfos.end()) {
143 LOG(ERROR) << __func__ << " failed: " << entityName << " is not registered.";
144 return false;
145 }
146 auto stateSpace = infosEntry->second;
147 result.powerEntityId = stateSpace.powerEntityId;
148 size_t numStates = stateSpace.stateInfos.size();
149 result.stateResidencyData.resize(numStates);
150 size_t numStatesFound = 0;
151 for (auto stat = stats.begin(); (numStatesFound < numStates) && (stat != stats.end()); stat++) {
152 auto stateInfosEntry = stateSpace.stateInfos.find(stat->state);
153
154 if (stateInfosEntry != stateSpace.stateInfos.end()) {
155 PowerEntityStateResidencyData &data = result.stateResidencyData[numStatesFound++];
156 data.powerEntityStateId = stateInfosEntry->second;
157 data.totalTimeInStateMs = static_cast<uint64_t>(stat->totalTimeInStateMs);
158 data.totalStateEntryCount = static_cast<uint64_t>(stat->totalStateEntryCount);
159 data.lastEntryTimestampMs = static_cast<uint64_t>(stat->lastEntryTimestampMs);
160 } else {
161 LOG(WARNING) << "getStats for " << entityName << " returned data for unknown state "
162 << stat->state;
163 }
164 }
165
166 return (numStatesFound == numStates);
167 }
168
getResults(std::unordered_map<uint32_t,PowerEntityStateResidencyResult> & results)169 bool AidlStateResidencyDataProvider::getResults(
170 std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
171 std::lock_guard<std::mutex> lock(mLock);
172 // TODO (b/126260512): return cached results if time elapsed isn't large
173 size_t numResultsFound = 0;
174 size_t numResults = mEntityInfos.size();
175 for (auto cb : mCallbacks) {
176 std::vector<android::vendor::powerstats::StateResidencyData> stats;
177
178 // Get stats for the current callback
179 binderStatus status = getStatsTimed(cb, stats);
180 if (!status.isOk()) {
181 LOG(ERROR) << "getStats for " << cb.first << " failed: " << status.toString8();
182 }
183
184 PowerEntityStateResidencyResult result;
185 if (buildResult(cb.first, stats, result)) {
186 results.emplace(result.powerEntityId, result);
187 numResultsFound++;
188 } else {
189 LOG(ERROR) << "State residency data missing for " << cb.first;
190 }
191 }
192 bool ret = (numResultsFound == numResults);
193
194 // TODO (b/126260512): Cache results of the call, the return value, and the timestamp.
195 return ret;
196 }
197
getStateSpaces()198 std::vector<PowerEntityStateSpace> AidlStateResidencyDataProvider::getStateSpaces() {
199 std::lock_guard<std::mutex> lock(mLock);
200 std::vector<PowerEntityStateSpace> stateSpaces;
201 stateSpaces.reserve(mEntityInfos.size());
202
203 // Return state space information for every entity for which this is configured to provide data
204 for (auto info : mEntityInfos) {
205 PowerEntityStateSpace statespace = {
206 .powerEntityId = info.second.powerEntityId, .states = {}};
207 statespace.states.resize(info.second.stateInfos.size());
208 size_t i = 0;
209 for (auto state : info.second.stateInfos) {
210 statespace.states[i++] = {
211 .powerEntityStateId = state.second, .powerEntityStateName = state.first};
212 }
213 stateSpaces.emplace_back(statespace);
214 }
215 return stateSpaces;
216 }
217
218 } // namespace powerstats
219 } // namespace pixel
220 } // namespace google
221 } // namespace hardware
222 } // namespace android
223