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 ¶ms.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, ¶ms.full_cap, ¶ms.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