• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2020 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: BatteryEEPROM"
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/BatteryEEPROMReporter.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  
40  #define LINESIZE 71
41  #define LINESIZE_V2 31
42  #define LINESIZE_MAX17201_HIST 80
43  
BatteryEEPROMReporter()44  BatteryEEPROMReporter::BatteryEEPROMReporter() {}
45  
checkAndReport(const std::shared_ptr<IStats> & stats_client,const std::string & path)46  void BatteryEEPROMReporter::checkAndReport(const std::shared_ptr<IStats> &stats_client,
47                                             const std::string &path) {
48      std::string file_contents;
49      std::string history_each;
50  
51      const int kSecondsPerMonth = 60 * 60 * 24 * 30;
52      int64_t now = getTimeSecs();
53  
54      if ((report_time_ != 0) && (now - report_time_ < kSecondsPerMonth)) {
55          ALOGD("Not upload time. now: %" PRId64 ", pre: %" PRId64, now, report_time_);
56          return;
57      }
58  
59      if (!ReadFileToString(path.c_str(), &file_contents)) {
60          ALOGE("Unable to read %s - %s", path.c_str(), strerror(errno));
61          return;
62      }
63  
64      int16_t i, num;
65      struct BatteryHistory hist;
66      const int kHistTotalLen = file_contents.size();
67  
68      ALOGD("kHistTotalLen=%d\n", kHistTotalLen);
69  
70      if (kHistTotalLen >= (LINESIZE_V2 * BATT_HIST_NUM_MAX_V2)) {
71          struct BatteryHistoryExtend histv2;
72          for (i = 0; i < BATT_HIST_NUM_MAX_V2; i++) {
73              size_t history_offset = i * LINESIZE_V2;
74              if (history_offset > file_contents.size())
75                  break;
76              history_each = file_contents.substr(history_offset, LINESIZE_V2);
77              unsigned int data[4];
78  
79              /* Format transfer: go/gsx01-eeprom */
80              num = sscanf(history_each.c_str(), "%4" SCNx16 "%4" SCNx16 "%x %x %x %x",
81                          &histv2.tempco, &histv2.rcomp0, &data[0], &data[1], &data[2], &data[3]);
82  
83              if (histv2.tempco == 0xFFFF && histv2.rcomp0 == 0xFFFF)
84                  continue;
85  
86              /* Extract each data */
87              uint64_t tmp = (int64_t)data[3] << 48 |
88                             (int64_t)data[2] << 32 |
89                             (int64_t)data[1] << 16 |
90                             data[0];
91  
92              /* ignore this data if unreasonable */
93              if (tmp <= 0)
94                  continue;
95  
96              /* data format/unit in go/gsx01-eeprom#heading=h.finy98ign34p */
97              histv2.timer_h = tmp & 0xFF;
98              histv2.fullcapnom = (tmp >>= 8) & 0x3FF;
99              histv2.fullcaprep = (tmp >>= 10) & 0x3FF;
100              histv2.mixsoc = (tmp >>= 10) & 0x3F;
101              histv2.vfsoc = (tmp >>= 6) & 0x3F;
102              histv2.maxvolt = (tmp >>= 6) & 0xF;
103              histv2.minvolt = (tmp >>= 4) & 0xF;
104              histv2.maxtemp = (tmp >>= 4) & 0xF;
105              histv2.mintemp = (tmp >>= 4) & 0xF;
106              histv2.maxchgcurr = (tmp >>= 4) & 0xF;
107              histv2.maxdischgcurr = (tmp >>= 4) & 0xF;
108  
109              /* Mapping to original format to collect data */
110              /* go/pixel-battery-eeprom-atom#heading=h.dcawdjiz2ls6 */
111              hist.tempco = histv2.tempco;
112              hist.rcomp0 = histv2.rcomp0;
113              hist.timer_h = (uint8_t)histv2.timer_h * 5;
114              hist.max_temp = (int8_t)histv2.maxtemp * 3 + 22;
115              hist.min_temp = (int8_t)histv2.mintemp * 3 - 20;
116              hist.min_ibatt = (int16_t)histv2.maxchgcurr * 500 * (-1);
117              hist.max_ibatt = (int16_t)histv2.maxdischgcurr * 500;
118              hist.min_vbatt = (uint16_t)histv2.minvolt * 10 + 2500;
119              hist.max_vbatt = (uint16_t)histv2.maxvolt * 20 + 4200;
120              hist.batt_soc = (uint8_t)histv2.vfsoc * 2;
121              hist.msoc = (uint8_t)histv2.mixsoc * 2;
122              hist.full_cap = (int16_t)histv2.fullcaprep * 125 / 1000;
123              hist.full_rep = (int16_t)histv2.fullcapnom * 125 / 1000;
124              hist.cycle_cnt = (i + 1) * 10;
125  
126              reportEvent(stats_client, hist);
127              report_time_ = getTimeSecs();
128          }
129          return;
130      }
131  
132      for (i = 0; i < (LINESIZE * BATT_HIST_NUM_MAX); i = i + LINESIZE) {
133          if (i + LINESIZE > kHistTotalLen)
134              break;
135          history_each = file_contents.substr(i, LINESIZE);
136          num = sscanf(history_each.c_str(),
137                     "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16
138                     "%2" SCNx8 "%2" SCNx8 " %2" SCNx8 "%2" SCNx8
139                     "%2" SCNx8 "%2" SCNx8 " %2" SCNx8 "%2" SCNx8
140                     "%2" SCNx8 "%2" SCNx8 " %4" SCNx16 "%4" SCNx16
141                     "%4" SCNx16 "%4" SCNx16 "%4" SCNx16,
142                     &hist.cycle_cnt, &hist.full_cap, &hist.esr,
143                     &hist.rslow, &hist.batt_temp, &hist.soh,
144                     &hist.cc_soc, &hist.cutoff_soc, &hist.msoc,
145                     &hist.sys_soc, &hist.reserve, &hist.batt_soc,
146                     &hist.min_temp, &hist.max_temp,  &hist.max_vbatt,
147                     &hist.min_vbatt, &hist.max_ibatt, &hist.min_ibatt,
148                     &hist.checksum);
149  
150          if (num != kNumBatteryHistoryFields) {
151              ALOGE("Couldn't process %s", history_each.c_str());
152              continue;
153          }
154  
155          if (checkLogEvent(hist)) {
156              reportEvent(stats_client, hist);
157              report_time_ = getTimeSecs();
158          }
159      }
160  }
161  
getTimeSecs(void)162  int64_t BatteryEEPROMReporter::getTimeSecs(void) {
163      return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
164  }
165  
166  /**
167   * @return true if a log should be reported, else false.
168   * Here we use checksum to confirm the data is usable or not.
169   * The checksum mismatch when storage data overflow or corrupt.
170   * We don't need data in such cases.
171   */
checkLogEvent(struct BatteryHistory hist)172  bool BatteryEEPROMReporter::checkLogEvent(struct BatteryHistory hist) {
173      int checksum = 0;
174  
175      checksum = hist.cycle_cnt + hist.full_cap + hist.esr + hist.rslow
176                  + hist.soh + hist.batt_temp + hist.cutoff_soc + hist.cc_soc
177                  + hist.sys_soc + hist.msoc + hist.batt_soc + hist.reserve
178                  + hist.max_temp + hist.min_temp + hist.max_vbatt
179                  + hist.min_vbatt + hist.max_ibatt + hist.min_ibatt;
180      /* Compare with checksum data */
181      if (checksum == hist.checksum) {
182          return true;
183      } else {
184          return false;
185      }
186  }
187  
reportEvent(const std::shared_ptr<IStats> & stats_client,const struct BatteryHistory & hist)188  void BatteryEEPROMReporter::reportEvent(const std::shared_ptr<IStats> &stats_client,
189                                          const struct BatteryHistory &hist) {
190      // upload atom
191      const std::vector<int> eeprom_history_fields = {
192              BatteryEEPROM::kCycleCntFieldNumber,  BatteryEEPROM::kFullCapFieldNumber,
193              BatteryEEPROM::kEsrFieldNumber,       BatteryEEPROM::kRslowFieldNumber,
194              BatteryEEPROM::kSohFieldNumber,       BatteryEEPROM::kBattTempFieldNumber,
195              BatteryEEPROM::kCutoffSocFieldNumber, BatteryEEPROM::kCcSocFieldNumber,
196              BatteryEEPROM::kSysSocFieldNumber,    BatteryEEPROM::kMsocFieldNumber,
197              BatteryEEPROM::kBattSocFieldNumber,   BatteryEEPROM::kReserveFieldNumber,
198              BatteryEEPROM::kMaxTempFieldNumber,   BatteryEEPROM::kMinTempFieldNumber,
199              BatteryEEPROM::kMaxVbattFieldNumber,  BatteryEEPROM::kMinVbattFieldNumber,
200              BatteryEEPROM::kMaxIbattFieldNumber,  BatteryEEPROM::kMinIbattFieldNumber,
201              BatteryEEPROM::kChecksumFieldNumber,  BatteryEEPROM::kTempcoFieldNumber,
202              BatteryEEPROM::kRcomp0FieldNumber,    BatteryEEPROM::kTimerHFieldNumber,
203              BatteryEEPROM::kFullRepFieldNumber};
204  
205      ALOGD("reportEvent: cycle_cnt:%d, full_cap:%d, esr:%d, rslow:%d, soh:%d, "
206            "batt_temp:%d, cutoff_soc:%d, cc_soc:%d, sys_soc:%d, msoc:%d, "
207            "batt_soc:%d, reserve:%d, max_temp:%d, min_temp:%d, max_vbatt:%d, "
208            "min_vbatt:%d, max_ibatt:%d, min_ibatt:%d, checksum:%#x, full_rep:%d, "
209            "tempco:%#x, rcomp0:%#x, timer_h:%d",
210            hist.cycle_cnt, hist.full_cap, hist.esr, hist.rslow, hist.soh, hist.batt_temp,
211            hist.cutoff_soc, hist.cc_soc, hist.sys_soc, hist.msoc, hist.batt_soc, hist.reserve,
212            hist.max_temp, hist.min_temp, hist.max_vbatt, hist.min_vbatt, hist.max_ibatt,
213            hist.min_ibatt, hist.checksum, hist.full_rep, hist.tempco, hist.rcomp0, hist.timer_h);
214  
215      std::vector<VendorAtomValue> values(eeprom_history_fields.size());
216      VendorAtomValue val;
217  
218      val.set<VendorAtomValue::intValue>(hist.cycle_cnt);
219      values[BatteryEEPROM::kCycleCntFieldNumber - kVendorAtomOffset] = val;
220      val.set<VendorAtomValue::intValue>(hist.full_cap);
221      values[BatteryEEPROM::kFullCapFieldNumber - kVendorAtomOffset] = val;
222      val.set<VendorAtomValue::intValue>(hist.esr);
223      values[BatteryEEPROM::kEsrFieldNumber - kVendorAtomOffset] = val;
224      val.set<VendorAtomValue::intValue>(hist.rslow);
225      values[BatteryEEPROM::kRslowFieldNumber - kVendorAtomOffset] = val;
226      val.set<VendorAtomValue::intValue>(hist.soh);
227      values[BatteryEEPROM::kSohFieldNumber - kVendorAtomOffset] = val;
228      val.set<VendorAtomValue::intValue>(hist.batt_temp);
229      values[BatteryEEPROM::kBattTempFieldNumber - kVendorAtomOffset] = val;
230      val.set<VendorAtomValue::intValue>(hist.cutoff_soc);
231      values[BatteryEEPROM::kCutoffSocFieldNumber - kVendorAtomOffset] = val;
232      val.set<VendorAtomValue::intValue>(hist.cc_soc);
233      values[BatteryEEPROM::kCcSocFieldNumber - kVendorAtomOffset] = val;
234      val.set<VendorAtomValue::intValue>(hist.sys_soc);
235      values[BatteryEEPROM::kSysSocFieldNumber - kVendorAtomOffset] = val;
236      val.set<VendorAtomValue::intValue>(hist.msoc);
237      values[BatteryEEPROM::kMsocFieldNumber - kVendorAtomOffset] = val;
238      val.set<VendorAtomValue::intValue>(hist.batt_soc);
239      values[BatteryEEPROM::kBattSocFieldNumber - kVendorAtomOffset] = val;
240      val.set<VendorAtomValue::intValue>(hist.reserve);
241      values[BatteryEEPROM::kReserveFieldNumber - kVendorAtomOffset] = val;
242      val.set<VendorAtomValue::intValue>(hist.max_temp);
243      values[BatteryEEPROM::kMaxTempFieldNumber - kVendorAtomOffset] = val;
244      val.set<VendorAtomValue::intValue>(hist.min_temp);
245      values[BatteryEEPROM::kMinTempFieldNumber - kVendorAtomOffset] = val;
246      val.set<VendorAtomValue::intValue>(hist.max_vbatt);
247      values[BatteryEEPROM::kMaxVbattFieldNumber - kVendorAtomOffset] = val;
248      val.set<VendorAtomValue::intValue>(hist.min_vbatt);
249      values[BatteryEEPROM::kMinVbattFieldNumber - kVendorAtomOffset] = val;
250      val.set<VendorAtomValue::intValue>(hist.max_ibatt);
251      values[BatteryEEPROM::kMaxIbattFieldNumber - kVendorAtomOffset] = val;
252      val.set<VendorAtomValue::intValue>(hist.min_ibatt);
253      values[BatteryEEPROM::kMinIbattFieldNumber - kVendorAtomOffset] = val;
254      val.set<VendorAtomValue::intValue>(hist.checksum);
255      values[BatteryEEPROM::kChecksumFieldNumber - kVendorAtomOffset] = val;
256      val.set<VendorAtomValue::intValue>(hist.tempco);
257      values[BatteryEEPROM::kTempcoFieldNumber - kVendorAtomOffset] = val;
258      val.set<VendorAtomValue::intValue>(hist.rcomp0);
259      values[BatteryEEPROM::kRcomp0FieldNumber - kVendorAtomOffset] = val;
260      val.set<VendorAtomValue::intValue>(hist.timer_h);
261      values[BatteryEEPROM::kTimerHFieldNumber - kVendorAtomOffset] = val;
262      val.set<VendorAtomValue::intValue>(hist.full_rep);
263      values[BatteryEEPROM::kFullRepFieldNumber - kVendorAtomOffset] = val;
264  
265      VendorAtom event = {.reverseDomainName = "",
266                          .atomId = PixelAtoms::Atom::kBatteryEeprom,
267                          .values = std::move(values)};
268      const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
269      if (!ret.isOk())
270          ALOGE("Unable to report BatteryEEPROM to Stats service");
271  }
272  
checkAndReportGMSR(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & paths)273  void BatteryEEPROMReporter::checkAndReportGMSR(const std::shared_ptr<IStats> &stats_client,
274                                                 const std::vector<std::string> &paths) {
275      struct BatteryHistory gmsr = {.checksum = EvtGMSR};
276      std::string file_contents;
277      std::string path;
278      int16_t num;
279  
280      if (paths.empty())
281          return;
282  
283      for (int i = 0; i < paths.size(); i++) {
284          if (fileExists(paths[i])) {
285              path = paths[i];
286              break;
287          }
288      }
289  
290      if (!ReadFileToString(path, &file_contents)) {
291          ALOGE("Unable to read gmsr path: %s - %s", path.c_str(), strerror(errno));
292          return;
293      }
294  
295      num = sscanf(file_contents.c_str(),  "rcomp0\t:%4" SCNx16 "\ntempco\t:%4" SCNx16
296                   "\nfullcaprep\t:%4" SCNx16 "\ncycles\t:%4" SCNx16 "\nfullcapnom\t:%4" SCNx16
297                   "\nqresidual00\t:%4" SCNx16 "\nqresidual10\t:%4" SCNx16
298                   "\nqresidual20\t:%4" SCNx16 "\nqresidual30\t:%4" SCNx16
299                   "\ncv_mixcap\t:%4" SCNx16 "\nhalftime\t:%4" SCNx16,
300                   &gmsr.rcomp0, &gmsr.tempco, &gmsr.full_rep, &gmsr.cycle_cnt, &gmsr.full_cap,
301                   &gmsr.max_vbatt, &gmsr.min_vbatt, &gmsr.max_ibatt, &gmsr.min_ibatt,
302                   &gmsr.esr, &gmsr.rslow);
303      if (num != kNum77759GMSRFields && num != kNum77779GMSRFields) {
304          ALOGE("Couldn't process GMSR. num=%d\n", num);
305          return;
306      }
307  
308      if (gmsr.tempco == 0xFFFF || gmsr.rcomp0 == 0xFFFF || gmsr.full_cap == 0xFFFF) {
309  	    ALOGD("Ignore invalid gmsr");
310  	    return;
311      }
312  
313      reportEvent(stats_client, gmsr);
314  }
315  
checkAndReportMaxfgHistory(const std::shared_ptr<IStats> & stats_client,const std::string & path)316  void BatteryEEPROMReporter::checkAndReportMaxfgHistory(const std::shared_ptr<IStats> &stats_client,
317                                                         const std::string &path) {
318      std::string file_contents;
319      int16_t i;
320  
321      if (path.empty())
322          return;
323  
324      if (!ReadFileToString(path, &file_contents)) {
325          ALOGD("Unable to read maxfg_hist path: %s - %s", path.c_str(), strerror(errno));
326          return;
327      }
328  
329      std::string hist_each;
330      const int kHistTotalLen = file_contents.size();
331  
332      ALOGD("checkAndReportMaxfgHistory:size=%d\n%s", kHistTotalLen, file_contents.c_str());
333  
334      for (i = 0; i < kHistTotalLen; i++) {
335          struct BatteryHistory maxfg_hist;
336          uint16_t nQRTable00, nQRTable10, nQRTable20, nQRTable30, nCycles, nFullCapNom;
337          uint16_t nRComp0, nTempCo, nIAvgEmpty, nFullCapRep, nVoltTemp, nMaxMinCurr, nMaxMinVolt;
338          uint16_t nMaxMinTemp, nSOC, nTimerH;
339          int16_t num;
340          size_t hist_offset = i * LINESIZE_MAX17201_HIST;
341  
342          if (hist_offset >= file_contents.size())
343              break;
344  
345          hist_each = file_contents.substr(hist_offset, LINESIZE_MAX17201_HIST);
346          num = sscanf(hist_each.c_str(), "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16
347                       "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16
348                       "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16,
349                       &nQRTable00, &nQRTable10, &nQRTable20, &nQRTable30, &nCycles, &nFullCapNom,
350                       &nRComp0, &nTempCo, &nIAvgEmpty, &nFullCapRep, &nVoltTemp, &nMaxMinCurr,
351                       &nMaxMinVolt, &nMaxMinTemp, &nSOC, &nTimerH);
352  
353          if (num != kNum17201HISTFields) {
354              ALOGE("Couldn't process %s (num=%d)", hist_each.c_str(), num);
355              continue;
356          }
357  
358          /* not assign: nQRTable00, nQRTable10, nQRTable20, nQRTable30 */
359          maxfg_hist.reserve = 0xFF;
360          maxfg_hist.tempco = nTempCo;
361          maxfg_hist.rcomp0 = nRComp0;
362          maxfg_hist.full_rep = nFullCapNom;
363          maxfg_hist.full_cap = nFullCapRep;
364          maxfg_hist.cycle_cnt = nCycles * 16 / 100; // LSB: 16%;
365          maxfg_hist.timer_h = (nTimerH * 32 / 10) / 24; // LSB: 3.2 hours
366          maxfg_hist.batt_soc = (nSOC >> 8) & 0x00FF;
367          maxfg_hist.msoc = nSOC & 0x00FF;
368          maxfg_hist.max_ibatt = ((nMaxMinCurr >> 8) & 0x00FF) * 80;
369          maxfg_hist.min_ibatt = (nMaxMinCurr & 0x00FF) * 80 * (-1);
370          maxfg_hist.max_vbatt = ((nMaxMinVolt >> 8) & 0x00FF) * 20;
371          maxfg_hist.min_vbatt = (nMaxMinVolt & 0x00FF) * 20;
372          maxfg_hist.max_temp = (nMaxMinTemp >> 8) & 0x00FF;
373          maxfg_hist.min_temp = nMaxMinTemp & 0x00FF;
374          maxfg_hist.esr = nIAvgEmpty;
375          maxfg_hist.rslow = nVoltTemp;
376  
377          reportEvent(stats_client, maxfg_hist);
378      }
379  }
380  
checkAndReportFGModelLoading(const std::shared_ptr<IStats> & client,const std::vector<std::string> & paths)381  void BatteryEEPROMReporter::checkAndReportFGModelLoading(const std::shared_ptr<IStats> &client,
382                                                           const std::vector<std::string> &paths) {
383      struct BatteryHistory params = {.full_cap = 0, .esr = 0, .rslow = 0,
384                                      .checksum = EvtModelLoading, };
385      std::string file_contents;
386      std::string path;
387      int num, pos = 0;
388      const char *data;
389  
390      if (paths.empty())
391          return;
392  
393      for (int i = 0; i < paths.size(); i++) {
394          if (fileExists(paths[i])) {
395              path = paths[i];
396              break;
397          }
398      }
399  
400      /* not found */
401      if (path.empty())
402          return;
403  
404      if (!ReadFileToString(path, &file_contents)) {
405          ALOGE("Unable to read ModelLoading History path: %s - %s", path.c_str(), strerror(errno));
406          return;
407      }
408  
409      data = file_contents.c_str();
410  
411      num = sscanf(&data[pos],  "ModelNextUpdate: %" SCNu16 "\n"
412                   "%*x:%*x\n%*x:%*x\n%*x:%*x\n%*x:%*x\n%*x:%*x\n%n",
413                   &params.rslow, &pos);
414      if (num != 1) {
415          ALOGE("Couldn't process ModelLoading History. num=%d\n", num);
416          return;
417      }
418  
419      sscanf(&data[pos],  "ATT: %" SCNu16 " FAIL: %" SCNu16, &params.full_cap, &params.esr);
420  
421      /* don't need to report when attempts counter is zero */
422      if (params.full_cap == 0)
423          return;
424  
425      reportEvent(client, params);
426  }
427  
checkAndReportFGLearning(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & paths)428  void BatteryEEPROMReporter::checkAndReportFGLearning(const std::shared_ptr<IStats> &stats_client,
429                                                       const std::vector<std::string> &paths) {
430      struct BatteryHistory params = {.checksum = EvtFGLearningHistory};
431      struct timespec boot_time;
432      auto format = FormatIgnoreAddr;
433      int fg_idx = 0;
434  
435      if (paths.empty())
436          return;
437  
438      clock_gettime(CLOCK_MONOTONIC, &boot_time);
439      for (int path_idx = 0; path_idx < paths.size(); path_idx++) {
440          std::vector<std::vector<uint16_t>> events;
441          std::string path = paths[path_idx];
442  
443          if (!path.empty() && fileExists(path)) {
444              readLogbuffer(path, kNumFGLearningFieldsV2, params.checksum, format, last_lh_check_,
445                            events);
446              if (events.size() == 0)
447                  readLogbuffer(path, kNumFGLearningFieldsV2, "learn", format, last_lh_check_,
448                                events);
449              if (events.size() == 0)
450                  readLogbuffer(path, kNumFGLearningFields, "learn", format, last_lh_check_, events);
451  
452              for (int event_idx = 0; event_idx < events.size(); event_idx++) {
453                  std::vector<uint16_t> &event = events[event_idx];
454  
455                  if (event.size() == kNumFGLearningFieldsV2) {
456                      params.full_cap = event[0];                /* fcnom */
457                      params.esr = event[1];                     /* dpacc */
458                      params.rslow = event[2];                   /* dqacc */
459                      params.full_rep = event[3];                /* fcrep */
460                      params.msoc = (uint8_t)(event[4] >> 8);    /* repsoc */
461                      params.sys_soc = (uint8_t)(event[5] >> 8); /* mixsoc */
462                      params.batt_soc = (uint8_t)(event[6] >> 8);/* vfsoc */
463                      params.min_ibatt = event[7];               /* fstats */
464                      params.max_temp = (int8_t)(event[8] >> 8); /* avgtemp */
465                      params.min_temp = (int8_t)(event[9] >> 8); /* temp */
466                      params.max_ibatt = event[10];              /* qh */
467                      params.max_vbatt = event[11];              /* vcell */
468                      params.min_vbatt = event[12];              /* avgvcell */
469                      params.cycle_cnt = event[13];              /* vfocf */
470                      params.rcomp0 = event[14];                 /* rcomp0 */
471                      params.tempco = event[15];                 /* tempco */
472                      params.reserve = fg_idx  ;                 /* battery index */
473                  } else if (event.size() == kNumFGLearningFields) {
474                      params.full_cap = event[0];     /* fcnom */
475                      params.esr = event[1];          /* dpacc */
476                      params.rslow = event[2];        /* dqacc */
477                      params.max_vbatt = event[3];    /* fcrep */
478                      params.full_rep = event[4];     /* repsoc */
479                      params.min_vbatt = event[5];    /* mixsoc */
480                      params.max_ibatt = event[6];    /* vfsoc */
481                      params.min_ibatt = event[7];    /* fstats */
482                      params.rcomp0 = event[8];       /* rcomp0 */
483                      params.tempco = event[9];       /* tempco */
484                      params.reserve = fg_idx;        /* battery index */
485                  } else {
486                      ALOGE("Not support %zu fields for FG learning event", event.size());
487                      continue;
488                  }
489                  reportEvent(stats_client, params);
490              }
491              fg_idx++;
492          }
493      }
494      last_lh_check_ = (unsigned int)boot_time.tv_sec;
495  }
496  
checkAndReportValidation(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & paths)497  void BatteryEEPROMReporter::checkAndReportValidation(const std::shared_ptr<IStats> &stats_client,
498                                                       const std::vector<std::string> &paths) {
499      struct BatteryHistory params = {.checksum = EvtHistoryValidation};
500      struct timespec boot_time;
501      auto format = FormatIgnoreAddr;
502      int fg_idx = 0;
503  
504      if (paths.empty())
505          return;
506  
507      clock_gettime(CLOCK_MONOTONIC, &boot_time);
508      for (int i = 0; i < paths.size(); i++) {
509          std::vector<std::vector<uint16_t>> events;
510          std::string path = paths[i];
511  
512          if (!path.empty() && fileExists(path)) {
513              readLogbuffer(path, kNumValidationFields, params.checksum, format, last_hv_check_, events);
514              for (int seq = 0; seq < events.size(); seq++) {
515                  std::vector<uint16_t> &event = events[seq];
516                  if (event.size() == kNumValidationFields) {
517                      params.full_cap = event[0]; /* fcnom */
518                      params.esr = event[1];      /* dpacc */
519                      params.rslow = event[2];    /* dqacc */
520                      params.full_rep = event[3]; /* fcrep */
521                      params.reserve = fg_idx;
522                      reportEvent(stats_client, params);
523                  } else {
524                      ALOGE("Not support %zu fields for History Validation event", event.size());
525                  }
526              }
527              fg_idx++;
528          }
529      }
530      last_hv_check_ = (unsigned int)boot_time.tv_sec;
531  }
532  
533  }  // namespace pixel
534  }  // namespace google
535  }  // namespace hardware
536  }  // namespace android
537