1 /*
2  * Copyright (C) 2018 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/stats/1.0/IPowerStats.h>
21 
22 #include <vector>
23 
24 #include "PowerStatsPuller.h"
25 #include "statslog.h"
26 #include "stats_log_util.h"
27 
28 using android::hardware::hidl_vec;
29 using android::hardware::power::stats::V1_0::IPowerStats;
30 using android::hardware::power::stats::V1_0::EnergyData;
31 using android::hardware::power::stats::V1_0::RailInfo;
32 using android::hardware::power::stats::V1_0::Status;
33 using android::hardware::Return;
34 using android::hardware::Void;
35 
36 using std::make_shared;
37 using std::shared_ptr;
38 
39 namespace android {
40 namespace os {
41 namespace statsd {
42 
43 static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
44 static std::mutex gPowerStatsHalMutex;
45 static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
46 static std::vector<RailInfo> gRailInfo;
47 
48 struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
serviceDiedandroid::os::statsd::PowerStatsPullerDeathRecipient49     virtual void serviceDied(uint64_t cookie,
50             const wp<android::hidl::base::V1_0::IBase>& who) override {
51         // The HAL just died. Reset all handles to HAL services.
52         std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
53         gPowerStatsHal = nullptr;
54     }
55 };
56 
57 static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
58 
getPowerStatsHalLocked()59 static bool getPowerStatsHalLocked() {
60     if (gPowerStatsHal == nullptr && gPowerStatsExist) {
61         gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
62         if (gPowerStatsHal == nullptr) {
63             ALOGW("Couldn't load power.stats HAL service");
64             gPowerStatsExist = false;
65         } else {
66             // Link death recipient to power.stats service handle
67             hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
68             if (!linked.isOk()) {
69                 ALOGE("Transaction error in linking to power.stats HAL death: %s",
70                         linked.description().c_str());
71                 gPowerStatsHal = nullptr;
72                 return false;
73             } else if (!linked) {
74                 ALOGW("Unable to link to power.stats HAL death notifications");
75                 // We should still continue even though linking failed
76             }
77         }
78     }
79     return gPowerStatsHal != nullptr;
80 }
81 
PowerStatsPuller()82 PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
83 }
84 
PullInternal(vector<shared_ptr<LogEvent>> * data)85 bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
86     std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
87 
88     if (!getPowerStatsHalLocked()) {
89         return false;
90     }
91 
92     int64_t wallClockTimestampNs = getWallClockNs();
93     int64_t elapsedTimestampNs = getElapsedRealtimeNs();
94 
95     data->clear();
96 
97     // Pull getRailInfo if necessary
98     if (gRailInfo.empty()) {
99         bool resultSuccess = true;
100         Return<void> ret = gPowerStatsHal->getRailInfo(
101                 [&resultSuccess](const hidl_vec<RailInfo> &list, Status status) {
102                     resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
103                     if (status != Status::SUCCESS) return;
104 
105                     gRailInfo.reserve(list.size());
106                     for (size_t i = 0; i < list.size(); ++i) {
107                         gRailInfo.push_back(list[i]);
108                     }
109                 });
110         if (!resultSuccess || !ret.isOk()) {
111             ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
112             gPowerStatsHal = nullptr;
113             return false;
114         }
115         // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
116         if (gRailInfo.empty()) {
117             ALOGE("power.stats has no rail information");
118             gPowerStatsExist = false; // No rail info, so never try again.
119             gPowerStatsHal = nullptr;
120             return false;
121         }
122     }
123 
124     // Pull getEnergyData and write the data out
125     const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
126     bool resultSuccess = true;
127     Return<void> ret = gPowerStatsHal->getEnergyData(desiredRailIndices,
128                 [&data, wallClockTimestampNs, elapsedTimestampNs, &resultSuccess]
129                 (hidl_vec<EnergyData> energyDataList, Status status) {
130                     resultSuccess = (status == Status::SUCCESS);
131                     if (!resultSuccess) return;
132 
133                     for (size_t i = 0; i < energyDataList.size(); i++) {
134                         const EnergyData& energyData = energyDataList[i];
135 
136                         if (energyData.index >= gRailInfo.size()) {
137                             ALOGE("power.stats getEnergyData() returned an invalid rail index %u.",
138                                     energyData.index);
139                             resultSuccess = false;
140                             return;
141                         }
142                         const RailInfo& rail = gRailInfo[energyData.index];
143 
144                         auto ptr = make_shared<LogEvent>(android::util::ON_DEVICE_POWER_MEASUREMENT,
145                               wallClockTimestampNs, elapsedTimestampNs);
146                         ptr->write(rail.subsysName);
147                         ptr->write(rail.railName);
148                         ptr->write(energyData.timestamp);
149                         ptr->write(energyData.energy);
150                         ptr->init();
151                         data->push_back(ptr);
152 
153                         VLOG("power.stat: %s.%s: %llu, %llu",
154                              rail.subsysName.c_str(),
155                              rail.railName.c_str(),
156                              (unsigned long long)energyData.timestamp,
157                              (unsigned long long)energyData.energy);
158                     }
159                 });
160     if (!resultSuccess || !ret.isOk()) {
161         ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
162         gPowerStatsHal = nullptr;
163         return false;
164     }
165     return true;
166 }
167 
168 }  // namespace statsd
169 }  // namespace os
170 }  // namespace android
171