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