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