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