1 /*
2 * Copyright (C) 2017 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 #define DEBUG false // STOPSHIP if true
18 #include "Log.h"
19
20 #include <android/hardware/power/1.0/IPower.h>
21 #include <android/hardware/power/1.1/IPower.h>
22 #include <android/hardware/power/stats/1.0/IPowerStats.h>
23
24 #include <fcntl.h>
25 #include <hardware/power.h>
26 #include <hardware_legacy/power.h>
27 #include <inttypes.h>
28 #include <semaphore.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include "external/SubsystemSleepStatePuller.h"
36 #include "external/StatsPuller.h"
37
38 #include "SubsystemSleepStatePuller.h"
39 #include "logd/LogEvent.h"
40 #include "statslog.h"
41 #include "stats_log_util.h"
42
43 using android::hardware::hidl_vec;
44 using android::hardware::power::V1_0::IPower;
45 using android::hardware::power::V1_0::PowerStatePlatformSleepState;
46 using android::hardware::power::V1_0::PowerStateVoter;
47 using android::hardware::power::V1_1::PowerStateSubsystem;
48 using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
49 using android::hardware::power::stats::V1_0::PowerEntityInfo;
50 using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
51 using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
52
53 using android::hardware::Return;
54 using android::hardware::Void;
55
56 using std::make_shared;
57 using std::shared_ptr;
58
59 namespace android {
60 namespace os {
61 namespace statsd {
62
63 static std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};
64
65 static sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
66 static sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
67 static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
68
69 static std::unordered_map<uint32_t, std::string> gEntityNames = {};
70 static std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
71
72 static std::mutex gPowerHalMutex;
73
74 // The caller must be holding gPowerHalMutex.
deinitPowerStatsLocked()75 static void deinitPowerStatsLocked() {
76 gPowerHalV1_0 = nullptr;
77 gPowerHalV1_1 = nullptr;
78 gPowerStatsHalV1_0 = nullptr;
79 }
80
81 struct SubsystemSleepStatePullerDeathRecipient : virtual public hardware::hidl_death_recipient {
serviceDiedandroid::os::statsd::SubsystemSleepStatePullerDeathRecipient82 virtual void serviceDied(uint64_t cookie,
83 const wp<android::hidl::base::V1_0::IBase>& who) override {
84
85 // The HAL just died. Reset all handles to HAL services.
86 std::lock_guard<std::mutex> lock(gPowerHalMutex);
87 deinitPowerStatsLocked();
88 }
89 };
90
91 static sp<SubsystemSleepStatePullerDeathRecipient> gDeathRecipient =
92 new SubsystemSleepStatePullerDeathRecipient();
93
SubsystemSleepStatePuller()94 SubsystemSleepStatePuller::SubsystemSleepStatePuller() :
95 StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
96 }
97
98 // The caller must be holding gPowerHalMutex.
checkResultLocked(const Return<void> & ret,const char * function)99 static bool checkResultLocked(const Return<void> &ret, const char* function) {
100 if (!ret.isOk()) {
101 ALOGE("%s failed: requested HAL service not available. Description: %s",
102 function, ret.description().c_str());
103 if (ret.isDeadObject()) {
104 deinitPowerStatsLocked();
105 }
106 return false;
107 }
108 return true;
109 }
110
111 // The caller must be holding gPowerHalMutex.
112 // gPowerStatsHalV1_0 must not be null
initializePowerStats()113 static bool initializePowerStats() {
114 using android::hardware::power::stats::V1_0::Status;
115
116 // Clear out previous content if we are re-initializing
117 gEntityNames.clear();
118 gStateNames.clear();
119
120 Return<void> ret;
121 ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
122 if (status != Status::SUCCESS) {
123 ALOGE("Error getting power entity info");
124 return;
125 }
126
127 // construct lookup table of powerEntityId to power entity name
128 for (auto info : infos) {
129 gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
130 }
131 });
132 if (!checkResultLocked(ret, __func__)) {
133 return false;
134 }
135
136 ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
137 if (status != Status::SUCCESS) {
138 ALOGE("Error getting state info");
139 return;
140 }
141
142 // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
143 for (auto stateSpace : stateSpaces) {
144 std::unordered_map<uint32_t, std::string> stateNames = {};
145 for (auto state : stateSpace.states) {
146 stateNames.emplace(state.powerEntityStateId,
147 state.powerEntityStateName);
148 }
149 gStateNames.emplace(stateSpace.powerEntityId, stateNames);
150 }
151 });
152 if (!checkResultLocked(ret, __func__)) {
153 return false;
154 }
155
156 return (!gEntityNames.empty()) && (!gStateNames.empty());
157 }
158
159 // The caller must be holding gPowerHalMutex.
getPowerStatsHalLocked()160 static bool getPowerStatsHalLocked() {
161 if(gPowerStatsHalV1_0 == nullptr) {
162 gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
163 if (gPowerStatsHalV1_0 == nullptr) {
164 ALOGE("Unable to get power.stats HAL service.");
165 return false;
166 }
167
168 // Link death recipient to power.stats service handle
169 hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
170 if (!linked.isOk()) {
171 ALOGE("Transaction error in linking to power.stats HAL death: %s",
172 linked.description().c_str());
173 deinitPowerStatsLocked();
174 return false;
175 } else if (!linked) {
176 ALOGW("Unable to link to power.stats HAL death notifications");
177 // We should still continue even though linking failed
178 }
179 return initializePowerStats();
180 }
181 return true;
182 }
183
184 // The caller must be holding gPowerHalMutex.
getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>> * data)185 static bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
186 using android::hardware::power::stats::V1_0::Status;
187
188 if(!getPowerStatsHalLocked()) {
189 return false;
190 }
191
192 int64_t wallClockTimestampNs = getWallClockNs();
193 int64_t elapsedTimestampNs = getElapsedRealtimeNs();
194
195 // Get power entity state residency data
196 bool success = false;
197 Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
198 [&data, &success, wallClockTimestampNs, elapsedTimestampNs]
199 (auto results, auto status) {
200 if (status == Status::NOT_SUPPORTED) {
201 ALOGW("getPowerEntityStateResidencyData is not supported");
202 success = false;
203 return;
204 }
205
206 for(auto result : results) {
207 for(auto stateResidency : result.stateResidencyData) {
208 auto statePtr = make_shared<LogEvent>(
209 android::util::SUBSYSTEM_SLEEP_STATE,
210 wallClockTimestampNs, elapsedTimestampNs);
211 statePtr->write(gEntityNames.at(result.powerEntityId));
212 statePtr->write(gStateNames.at(result.powerEntityId)
213 .at(stateResidency.powerEntityStateId));
214 statePtr->write(stateResidency.totalStateEntryCount);
215 statePtr->write(stateResidency.totalTimeInStateMs);
216 statePtr->init();
217 data->emplace_back(statePtr);
218 }
219 }
220 success = true;
221 });
222 // Intentionally not returning early here.
223 // bool success determines if this succeeded or not.
224 checkResultLocked(ret, __func__);
225
226 return success;
227 }
228
229 // The caller must be holding gPowerHalMutex.
getPowerHalLocked()230 static bool getPowerHalLocked() {
231 if(gPowerHalV1_0 == nullptr) {
232 gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
233 if(gPowerHalV1_0 == nullptr) {
234 ALOGE("Unable to get power HAL service.");
235 return false;
236 }
237 gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
238
239 // Link death recipient to power service handle
240 hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
241 if (!linked.isOk()) {
242 ALOGE("Transaction error in linking to power HAL death: %s",
243 linked.description().c_str());
244 gPowerHalV1_0 = nullptr;
245 return false;
246 } else if (!linked) {
247 ALOGW("Unable to link to power. death notifications");
248 // We should still continue even though linking failed
249 }
250 }
251 return true;
252 }
253
254 // The caller must be holding gPowerHalMutex.
getIPowerDataLocked(vector<shared_ptr<LogEvent>> * data)255 static bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
256 using android::hardware::power::V1_0::Status;
257
258 if(!getPowerHalLocked()) {
259 return false;
260 }
261
262 int64_t wallClockTimestampNs = getWallClockNs();
263 int64_t elapsedTimestampNs = getElapsedRealtimeNs();
264 Return<void> ret;
265 ret = gPowerHalV1_0->getPlatformLowPowerStats(
266 [&data, wallClockTimestampNs, elapsedTimestampNs]
267 (hidl_vec<PowerStatePlatformSleepState> states, Status status) {
268 if (status != Status::SUCCESS) return;
269
270 for (size_t i = 0; i < states.size(); i++) {
271 const PowerStatePlatformSleepState& state = states[i];
272
273 auto statePtr = make_shared<LogEvent>(
274 android::util::SUBSYSTEM_SLEEP_STATE,
275 wallClockTimestampNs, elapsedTimestampNs);
276 statePtr->write(state.name);
277 statePtr->write("");
278 statePtr->write(state.totalTransitions);
279 statePtr->write(state.residencyInMsecSinceBoot);
280 statePtr->init();
281 data->push_back(statePtr);
282 VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
283 (long long)state.residencyInMsecSinceBoot,
284 (long long)state.totalTransitions,
285 state.supportedOnlyInSuspend ? 1 : 0);
286 for (const auto& voter : state.voters) {
287 auto voterPtr = make_shared<LogEvent>(
288 android::util::SUBSYSTEM_SLEEP_STATE,
289 wallClockTimestampNs, elapsedTimestampNs);
290 voterPtr->write(state.name);
291 voterPtr->write(voter.name);
292 voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
293 voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
294 voterPtr->init();
295 data->push_back(voterPtr);
296 VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
297 voter.name.c_str(),
298 (long long)voter.totalTimeInMsecVotedForSinceBoot,
299 (long long)voter.totalNumberOfTimesVotedSinceBoot);
300 }
301 }
302 });
303 if (!checkResultLocked(ret, __func__)) {
304 return false;
305 }
306
307 // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
308 sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
309 android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
310 if (gPowerHal_1_1 != nullptr) {
311 ret = gPowerHal_1_1->getSubsystemLowPowerStats(
312 [&data, wallClockTimestampNs, elapsedTimestampNs]
313 (hidl_vec<PowerStateSubsystem> subsystems, Status status) {
314 if (status != Status::SUCCESS) return;
315
316 if (subsystems.size() > 0) {
317 for (size_t i = 0; i < subsystems.size(); i++) {
318 const PowerStateSubsystem& subsystem = subsystems[i];
319 for (size_t j = 0; j < subsystem.states.size(); j++) {
320 const PowerStateSubsystemSleepState& state =
321 subsystem.states[j];
322 auto subsystemStatePtr = make_shared<LogEvent>(
323 android::util::SUBSYSTEM_SLEEP_STATE,
324 wallClockTimestampNs, elapsedTimestampNs);
325 subsystemStatePtr->write(subsystem.name);
326 subsystemStatePtr->write(state.name);
327 subsystemStatePtr->write(state.totalTransitions);
328 subsystemStatePtr->write(state.residencyInMsecSinceBoot);
329 subsystemStatePtr->init();
330 data->push_back(subsystemStatePtr);
331 VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
332 subsystem.name.c_str(), state.name.c_str(),
333 (long long)state.residencyInMsecSinceBoot,
334 (long long)state.totalTransitions,
335 (long long)state.lastEntryTimestampMs);
336 }
337 }
338 }
339 });
340 }
341 return true;
342 }
343
344 // The caller must be holding gPowerHalMutex.
getPullerLocked()345 std::function<bool(vector<shared_ptr<LogEvent>>* data)> getPullerLocked() {
346 std::function<bool(vector<shared_ptr<LogEvent>>* data)> ret = {};
347
348 // First see if power.stats HAL is available. Fall back to power HAL if
349 // power.stats HAL is unavailable.
350 if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
351 ALOGI("Using power.stats HAL");
352 ret = getIPowerStatsDataLocked;
353 } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
354 ALOGI("Using power HAL");
355 ret = getIPowerDataLocked;
356 }
357
358 return ret;
359 }
360
PullInternal(vector<shared_ptr<LogEvent>> * data)361 bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
362 std::lock_guard<std::mutex> lock(gPowerHalMutex);
363
364 if(!gPuller) {
365 gPuller = getPullerLocked();
366 }
367
368 if(gPuller) {
369 return gPuller(data);
370 }
371
372 ALOGE("Unable to load Power Hal or power.stats HAL");
373 return false;
374 }
375
376 } // namespace statsd
377 } // namespace os
378 } // namespace android
379