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 ¶ms) {
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 ¶ms.fcnom, ¶ms.dpacc, ¶ms.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