1 /*
2  * Copyright (C) 2024 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 LOG_TAG "pixelstats: BatteryFGReporter"
18 
19 #include <log/log.h>
20 #include <time.h>
21 #include <utils/Timers.h>
22 #include <cinttypes>
23 #include <cmath>
24 
25 #include <android-base/file.h>
26 #include <pixelstats/BatteryFGReporter.h>
27 #include <pixelstats/StatsHelper.h>
28 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
29 
30 namespace android {
31 namespace hardware {
32 namespace google {
33 namespace pixel {
34 
35 using aidl::android::frameworks::stats::VendorAtom;
36 using aidl::android::frameworks::stats::VendorAtomValue;
37 using android::base::ReadFileToString;
38 using android::hardware::google::pixel::PixelAtoms::BatteryEEPROM;
39 using android::hardware::google::pixel::PixelAtoms::FuelGaugeAbnormalityReported;
40 
41 
BatteryFGReporter()42 BatteryFGReporter::BatteryFGReporter() {}
43 
getTimeSecs()44 int64_t BatteryFGReporter::getTimeSecs() {
45     return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
46 }
47 
setAtomFieldValue(std::vector<VendorAtomValue> * values,int offset,int content)48 void BatteryFGReporter::setAtomFieldValue(std::vector<VendorAtomValue> *values, int offset,
49                                           int content) {
50     std::vector<VendorAtomValue> &val = *values;
51     if (offset - kVendorAtomOffset < val.size())
52         val[offset - kVendorAtomOffset].set<VendorAtomValue::intValue>(content);
53 }
54 
reportAbnormalEvent(const std::shared_ptr<IStats> & stats_client,struct BatteryFGAbnormalData data)55 void BatteryFGReporter::reportAbnormalEvent(const std::shared_ptr<IStats> &stats_client,
56                                             struct BatteryFGAbnormalData data) {
57     // Load values array
58     std::vector<VendorAtomValue> values(35);
59     uint32_t duration = 0;
60 
61     /* save time when trigger, calculate duration when clear */
62     if (data.state == 1 && ab_trigger_time_[data.event] == 0) {
63         ab_trigger_time_[data.event] = getTimeSecs();
64     } else {
65         duration = getTimeSecs() - ab_trigger_time_[data.event];
66         ab_trigger_time_[data.event] = 0;
67     }
68 
69     ALOGD("reportEvent: event=%d,state=%d,cycles=%04X,vcel=%04X,avgv=%04X,curr=%04X,avgc=%04X,"
70           "timerh=%04X,temp=%04X,repcap=%04X,mixcap=%04X,fcrep=%04X,fcnom=%04X,qresd=%04X,"
71           "avcap=%04X,vfremcap=%04X,repsoc=%04X,vfsoc=%04X,msoc=%04X,vfocv=%04X,dpacc=%04X,"
72           "dqacc=%04X,qh=%04X,qh0=%04X,vfsoc0=%04X,qrtable20=%04X,qrtable30=%04X,status=%04X,"
73           "fstat=%04X,rcomp0=%04X,tempco=%04X,duration=%u",
74           data.event, data.state, data.cycles, data.vcel, data.avgv, data.curr, data.avgc,
75           data.timerh, data.temp, data.repcap, data.mixcap, data.fcrep, data.fcnom, data.qresd,
76           data.avcap, data.vfremcap, data.repsoc, data.vfsoc, data.msoc, data.vfocv, data.dpacc,
77           data.dqacc, data.qh, data.qh0, data.vfsoc0, data.qrtable20, data.qrtable30, data.status,
78           data.fstat, data.rcomp0, data.tempco, duration);
79 
80     /*
81      * state=0 -> untrigger, state=1 -> trigger
82      * Since atom enum reserves unknown value at 0, offset by 1 here
83      * state=1-> untrigger, state=2 -> trigger
84      */
85     data.state += 1;
86 
87     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kEventFieldNumber, data.event);
88     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kEventStateFieldNumber, data.state);
89     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kDurationSecsFieldNumber, duration);
90     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress1FieldNumber, data.cycles);
91     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData1FieldNumber, data.vcel);
92     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress2FieldNumber, data.avgv);
93     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData2FieldNumber, data.curr);
94     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress3FieldNumber, data.avgc);
95     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData3FieldNumber, data.timerh);
96     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress4FieldNumber, data.temp);
97     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData4FieldNumber, data.repcap);
98     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress5FieldNumber, data.mixcap);
99     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData5FieldNumber, data.fcrep);
100     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress6FieldNumber, data.fcnom);
101     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData6FieldNumber, data.qresd);
102     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress7FieldNumber, data.avcap);
103     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData7FieldNumber, data.vfremcap);
104     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress8FieldNumber, data.repsoc);
105     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData8FieldNumber, data.vfsoc);
106     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress9FieldNumber, data.msoc);
107     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData9FieldNumber, data.vfocv);
108     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress10FieldNumber, data.dpacc);
109     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData10FieldNumber, data.dqacc);
110     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress11FieldNumber, data.qh);
111     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData11FieldNumber, data.qh0);
112     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress12FieldNumber, data.vfsoc0);
113     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData12FieldNumber, data.qrtable20);
114     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress13FieldNumber, data.qrtable30);
115     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData13FieldNumber, data.status);
116     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress14FieldNumber, data.fstat);
117     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData14FieldNumber, data.rcomp0);
118     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress15FieldNumber, data.tempco);
119     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData15FieldNumber, 0);
120     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterAddress16FieldNumber, 0);
121     setAtomFieldValue(&values, FuelGaugeAbnormalityReported::kFgRegisterData16FieldNumber, 0);
122 
123     VendorAtom event = {.reverseDomainName = "",
124                         .atomId = PixelAtoms::Atom::kFuelGaugeAbnormalityReported,
125                         .values = std::move(values)};
126     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
127     if (!ret.isOk())
128         ALOGE("Unable to report FuelGaugeAbnormalityReported to Stats service");
129 }
130 
reportEvent(const std::shared_ptr<IStats> & stats_client,const struct BatteryFGLearningParam & params)131 void BatteryFGReporter::reportEvent(const std::shared_ptr<IStats> &stats_client,
132                                     const struct BatteryFGLearningParam &params) {
133     // upload atom
134     const std::vector<int> eeprom_history_fields = {
135             BatteryEEPROM::kCycleCntFieldNumber,  BatteryEEPROM::kFullCapFieldNumber,
136             BatteryEEPROM::kEsrFieldNumber,       BatteryEEPROM::kRslowFieldNumber,
137             BatteryEEPROM::kSohFieldNumber,       BatteryEEPROM::kBattTempFieldNumber,
138             BatteryEEPROM::kCutoffSocFieldNumber, BatteryEEPROM::kCcSocFieldNumber,
139             BatteryEEPROM::kSysSocFieldNumber,    BatteryEEPROM::kMsocFieldNumber,
140             BatteryEEPROM::kBattSocFieldNumber,   BatteryEEPROM::kReserveFieldNumber,
141             BatteryEEPROM::kMaxTempFieldNumber,   BatteryEEPROM::kMinTempFieldNumber,
142             BatteryEEPROM::kMaxVbattFieldNumber,  BatteryEEPROM::kMinVbattFieldNumber,
143             BatteryEEPROM::kMaxIbattFieldNumber,  BatteryEEPROM::kMinIbattFieldNumber,
144             BatteryEEPROM::kChecksumFieldNumber,  BatteryEEPROM::kTempcoFieldNumber,
145             BatteryEEPROM::kRcomp0FieldNumber,    BatteryEEPROM::kTimerHFieldNumber,
146             BatteryEEPROM::kFullRepFieldNumber};
147 
148     switch(params.type) {
149       case EvtFWUpdate:
150         ALOGD("reportEvent: firmware update try: %u, success: %u, fail: %u",
151               params.fcnom, params.dpacc, params.dqacc);
152               break;
153       default:
154         ALOGD("unknown event type %04x", params.type);
155         break;
156     }
157 
158     std::vector<VendorAtomValue> values(eeprom_history_fields.size());
159     VendorAtomValue val;
160 
161     val.set<VendorAtomValue::intValue>(0);
162     values[BatteryEEPROM::kCycleCntFieldNumber - kVendorAtomOffset] = val;
163     val.set<VendorAtomValue::intValue>(params.fcnom);
164     values[BatteryEEPROM::kFullCapFieldNumber - kVendorAtomOffset] = val;
165     val.set<VendorAtomValue::intValue>(params.dpacc);
166     values[BatteryEEPROM::kEsrFieldNumber - kVendorAtomOffset] = val;
167     val.set<VendorAtomValue::intValue>(params.dqacc);
168     values[BatteryEEPROM::kRslowFieldNumber - kVendorAtomOffset] = val;
169     val.set<VendorAtomValue::intValue>(0);
170     values[BatteryEEPROM::kSohFieldNumber - kVendorAtomOffset] = val;
171     val.set<VendorAtomValue::intValue>(0);
172     values[BatteryEEPROM::kBattTempFieldNumber - kVendorAtomOffset] = val;
173     val.set<VendorAtomValue::intValue>(0);
174     values[BatteryEEPROM::kCutoffSocFieldNumber - kVendorAtomOffset] = val;
175     val.set<VendorAtomValue::intValue>(0);
176     values[BatteryEEPROM::kCcSocFieldNumber - kVendorAtomOffset] = val;
177     val.set<VendorAtomValue::intValue>(0);
178     values[BatteryEEPROM::kSysSocFieldNumber - kVendorAtomOffset] = val;
179     val.set<VendorAtomValue::intValue>(0);
180     values[BatteryEEPROM::kMsocFieldNumber - kVendorAtomOffset] = val;
181     val.set<VendorAtomValue::intValue>(0);
182     values[BatteryEEPROM::kBattSocFieldNumber - kVendorAtomOffset] = val;
183     val.set<VendorAtomValue::intValue>(0);
184     values[BatteryEEPROM::kReserveFieldNumber - kVendorAtomOffset] = val;
185     val.set<VendorAtomValue::intValue>(0);
186     values[BatteryEEPROM::kMaxTempFieldNumber - kVendorAtomOffset] = val;
187     val.set<VendorAtomValue::intValue>(0);
188     values[BatteryEEPROM::kMinTempFieldNumber - kVendorAtomOffset] = val;
189     val.set<VendorAtomValue::intValue>(params.fcrep);
190     values[BatteryEEPROM::kMaxVbattFieldNumber - kVendorAtomOffset] = val;
191     val.set<VendorAtomValue::intValue>(params.msoc);
192     values[BatteryEEPROM::kMinVbattFieldNumber - kVendorAtomOffset] = val;
193     val.set<VendorAtomValue::intValue>(params.vfsoc);
194     values[BatteryEEPROM::kMaxIbattFieldNumber - kVendorAtomOffset] = val;
195     val.set<VendorAtomValue::intValue>(params.fstat);
196     values[BatteryEEPROM::kMinIbattFieldNumber - kVendorAtomOffset] = val;
197     val.set<VendorAtomValue::intValue>((uint16_t)params.type);
198     values[BatteryEEPROM::kChecksumFieldNumber - kVendorAtomOffset] = val;
199     val.set<VendorAtomValue::intValue>(params.tempco);
200     values[BatteryEEPROM::kTempcoFieldNumber - kVendorAtomOffset] = val;
201     val.set<VendorAtomValue::intValue>(params.rcomp0);
202     values[BatteryEEPROM::kRcomp0FieldNumber - kVendorAtomOffset] = val;
203     val.set<VendorAtomValue::intValue>(0);
204     values[BatteryEEPROM::kTimerHFieldNumber - kVendorAtomOffset] = val;
205     val.set<VendorAtomValue::intValue>(params.repsoc);
206     values[BatteryEEPROM::kFullRepFieldNumber - kVendorAtomOffset] = val;
207 
208     VendorAtom event = {.reverseDomainName = "",
209                         .atomId = PixelAtoms::Atom::kBatteryEeprom,
210                         .values = std::move(values)};
211     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
212     if (!ret.isOk())
213         ALOGE("Unable to report BatteryEEPROM to Stats service");
214 }
215 
checkAndReportFwUpdate(const std::shared_ptr<IStats> & stats_client,const std::string & path)216 void BatteryFGReporter::checkAndReportFwUpdate(const std::shared_ptr<IStats> &stats_client,
217                                                const std::string &path) {
218     struct BatteryFGLearningParam params;
219     std::string file_contents;
220     int16_t num;
221 
222     if (path.empty())
223         return;
224 
225     if (!ReadFileToString(path, &file_contents)) {
226         ALOGE("Unable to read FirmwareUpdate path: %s - %s", path.c_str(), strerror(errno));
227         return;
228     }
229 
230     /* FU: Firmware Update */
231     params.type = EvtFWUpdate;
232     num = sscanf(file_contents.c_str(), "%" SCNu16 " %" SCNu16 " %" SCNu16,
233                  &params.fcnom, &params.dpacc, &params.dqacc);
234     if (num != kNumFwUpdateFields) {
235         ALOGE("Couldn't process FirmwareUpdate history path. num=%d\n", num);
236         return;
237     }
238 
239     /* No event to report */
240     if (params.fcnom == 0 )
241         return;
242 
243     /* Reporting data only when can clear */
244     if (::android::base::WriteStringToFile("0", path.c_str()))
245         reportEvent(stats_client, params);
246     else
247         ALOGE("Couldn't clear %s - %s", path.c_str(), strerror(errno));
248 }
249 
checkAndReportFGAbnormality(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & paths)250 void BatteryFGReporter::checkAndReportFGAbnormality(const std::shared_ptr<IStats> &stats_client,
251                                                     const std::vector<std::string> &paths) {
252     std::string path;
253     struct timespec boot_time;
254     std::vector<std::vector<uint16_t>> events;
255 
256     if (paths.empty())
257         return;
258 
259     for (int i = 0; i < paths.size(); i++) {
260         if (fileExists(paths[i])) {
261             path = paths[i];
262             break;
263         }
264     }
265 
266     clock_gettime(CLOCK_MONOTONIC, &boot_time);
267     readLogbuffer(path, kNumAbnormalEventFields, EvtFGAbnormalEvent, FormatNoAddr, last_ab_check_, events);
268     for (int seq = 0; seq < events.size(); seq++) {
269         if (events[seq].size() == kNumAbnormalEventFields) {
270             struct BatteryFGAbnormalData data;
271             uint16_t *pdata = (uint16_t *)&data;
272             for (int i = 0; i < kNumAbnormalEventFields; i++)
273                 *pdata++ = events[seq][i];
274             reportAbnormalEvent(stats_client, data);
275         } else {
276             ALOGE("Not support %zu fields for FG abnormal event", events[seq].size());
277         }
278     }
279 
280     last_ab_check_ = (unsigned int)boot_time.tv_sec;
281 }
282 
283 }  // namespace pixel
284 }  // namespace google
285 }  // namespace hardware
286 }  // namespace android
287