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