blob: dc69b78f03299f390cf958465c7e1c327c804e3d [file] [log] [blame]
Bookatz92da2832018-11-01 18:10:03 -07001/*
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"
Muhammad Qureshic8e22662019-11-20 17:18:03 -080025#include "statslog.h"
Bookatz92da2832018-11-01 18:10:03 -070026#include "stats_log_util.h"
27
28using android::hardware::hidl_vec;
29using android::hardware::power::stats::V1_0::IPowerStats;
30using android::hardware::power::stats::V1_0::EnergyData;
31using android::hardware::power::stats::V1_0::RailInfo;
32using android::hardware::power::stats::V1_0::Status;
33using android::hardware::Return;
34using android::hardware::Void;
35
36using std::make_shared;
37using std::shared_ptr;
38
39namespace android {
40namespace os {
41namespace statsd {
42
Benjamin Schwartzb7e22e22019-02-25 15:18:55 -080043static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
44static std::mutex gPowerStatsHalMutex;
45static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
46static std::vector<RailInfo> gRailInfo;
Bookatz92da2832018-11-01 18:10:03 -070047
Benjamin Schwartzb7e22e22019-02-25 15:18:55 -080048struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
49 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
57static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
58
59static bool getPowerStatsHalLocked() {
Bookatz92da2832018-11-01 18:10:03 -070060 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;
Benjamin Schwartzb7e22e22019-02-25 15:18:55 -080065 } 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 }
Bookatz92da2832018-11-01 18:10:03 -070077 }
78 }
79 return gPowerStatsHal != nullptr;
80}
81
82PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
83}
84
85bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
86 std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
87
Benjamin Schwartzb7e22e22019-02-25 15:18:55 -080088 if (!getPowerStatsHalLocked()) {
Bookatz92da2832018-11-01 18:10:03 -070089 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.
Benjamin Schwartzc0bb3fe2019-05-28 17:09:44 -0700119 gPowerStatsHal = nullptr;
Bookatz92da2832018-11-01 18:10:03 -0700120 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