1 /*
2  * Copyright (C) 2019 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 #define LOG_TAG "pwrstats_util"
17 
18 #include "RailEnergyDataProvider.h"
19 #include <android-base/logging.h>
20 #include <android/hardware/power/stats/1.0/IPowerStats.h>
21 
22 using android::sp;
23 using android::hardware::Return;
24 using android::hardware::power::stats::V1_0::IPowerStats;
25 using android::hardware::power::stats::V1_0::Status;
26 
getImpl(PowerStatistic * stat) const27 int RailEnergyDataProvider::getImpl(PowerStatistic* stat) const {
28     sp<android::hardware::power::stats::V1_0::IPowerStats> powerStatsService =
29             android::hardware::power::stats::V1_0::IPowerStats::getService();
30     if (powerStatsService == nullptr) {
31         LOG(ERROR) << "unable to get power.stats HAL service";
32         return 1;
33     }
34 
35     std::unordered_map<uint32_t, std::string> railNames;
36 
37     Return<void> ret;
38     Status retStatus = Status::SUCCESS;
39     ret = powerStatsService->getRailInfo([&railNames, &retStatus](auto railInfos, auto status) {
40         retStatus = status;
41         if (status != Status::SUCCESS) {
42             return;
43         }
44 
45         for (auto const& info : railInfos) {
46             railNames.emplace(info.index, info.railName);
47         }
48     });
49     if (retStatus == Status::NOT_SUPPORTED) {
50         LOG(WARNING) << __func__ << ": rail energy stats not supported";
51         return 0;
52     }
53     if (!ret.isOk() || retStatus != Status::SUCCESS) {
54         LOG(ERROR) << __func__ << ": no rail information available";
55         return 1;
56     }
57 
58     auto railEntries = stat->mutable_rail_energy();
59     bool resultSuccess = true;
60     ret = powerStatsService->getEnergyData(
61             {}, [&railEntries, &railNames, &resultSuccess](auto energyData, auto status) {
62                 if (status != Status::SUCCESS) {
63                     LOG(ERROR) << __func__ << ": unable to get rail energy";
64                     resultSuccess = false;
65                     return;
66                 }
67 
68                 for (auto const& energyDatum : energyData) {
69                     auto entry = railEntries->add_entry();
70                     entry->set_rail_name(railNames.at(energyDatum.index));
71                     entry->set_energy_uws(energyDatum.energy);
72                 }
73             });
74     if (!ret.isOk() || !resultSuccess) {
75         stat->clear_rail_energy();
76         LOG(ERROR) << __func__ << ": failed to get rail energy stats";
77         return 1;
78     }
79 
80     // Sort entries by name. Sorting is needed to make interval processing efficient.
81     std::sort(railEntries->mutable_entry()->begin(), railEntries->mutable_entry()->end(),
82               [](const auto& a, const auto& b) { return a.rail_name() < b.rail_name(); });
83 
84     return 0;
85 }
86 
getImpl(const PowerStatistic & start,PowerStatistic * interval) const87 int RailEnergyDataProvider::getImpl(const PowerStatistic& start, PowerStatistic* interval) const {
88     auto startEnergy = start.rail_energy().entry();
89     auto intervalEnergy = interval->mutable_rail_energy()->mutable_entry();
90 
91     // If start and interval are not the same size then they cannot have matching data
92     if (startEnergy.size() != intervalEnergy->size()) {
93         LOG(ERROR) << __func__ << ": mismatched data";
94         interval->clear_rail_energy();
95         return 1;
96     }
97 
98     for (int i = 0; i < startEnergy.size(); ++i) {
99         // Check and make sure each entry matches. Data are in sorted order so if there is a
100         // mismatch then we will bail.
101         if (startEnergy.Get(i).rail_name() != intervalEnergy->Get(i).rail_name()) {
102             LOG(ERROR) << __func__ << ": mismatched data";
103             interval->clear_rail_energy();
104             return 1;
105         }
106 
107         auto delta = intervalEnergy->Get(i).energy_uws() - startEnergy.Get(i).energy_uws();
108         intervalEnergy->Mutable(i)->set_energy_uws(delta);
109     }
110     return 0;
111 }
112 
dumpImpl(const PowerStatistic & stat,std::ostream * output) const113 void RailEnergyDataProvider::dumpImpl(const PowerStatistic& stat, std::ostream* output) const {
114     *output << "Rail Energy:" << std::endl;
115     for (auto const& rail : stat.rail_energy().entry()) {
116         *output << rail.rail_name() << "=" << rail.energy_uws() << std::endl;
117     }
118     *output << std::endl;
119 }
120 
typeOf() const121 PowerStatCase RailEnergyDataProvider::typeOf() const {
122     return PowerStatCase::kRailEnergy;
123 }
124