/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DumpstateUtil.h" void printTitle(const char *msg) { printf("\n------ %s ------\n", msg); } int getCommandOutput(const char *cmd, std::string *output) { char buffer[1024]; FILE *pipe = popen(cmd, "r"); if (!pipe) { return -1; } while (fgets(buffer, sizeof buffer, pipe) != NULL) { *output += buffer; } pclose(pipe); if (output->back() == '\n') output->pop_back(); return 0; } bool isValidFile(const char *file) { FILE *fp = fopen(file, "r"); if (fp != NULL) { fclose(fp); return true; } return false; } bool isValidDir(const char *directory) { DIR *dir = opendir(directory); if (dir == NULL) return false; closedir(dir); return true; } bool isUserBuild() { return ::android::os::dumpstate::PropertiesHelper::IsUserBuild(); } int getFilesInDir(const char *directory, std::vector *files) { std::string content; struct dirent *entry; DIR *dir = opendir(directory); if (dir == NULL) return -1; files->clear(); while ((entry = readdir(dir)) != NULL) files->push_back(entry->d_name); closedir(dir); sort(files->begin(), files->end()); return 0; } void dumpPowerStatsTimes() { const char *title = "Power Stats Times"; char rBuff[128]; struct timespec rTs; struct sysinfo info; int ret; printTitle(title); sysinfo(&info); const time_t boottime = time(NULL) - info.uptime; ret = clock_gettime(CLOCK_REALTIME, &rTs); if (ret) return; struct tm *nowTime = std::localtime(&rTs.tv_sec); std::strftime(rBuff, sizeof(rBuff), "%m/%d/%Y %H:%M:%S", nowTime); printf("Boot: %s", ctime(&boottime)); printf("Now: %s\n", rBuff); } int readContentsOfDir(const char* title, const char* directory, const char* strMatch, bool useStrMatch = false, bool printDirectory = false) { std::vector files; std::string content; std::string fileLocation; int ret; ret = getFilesInDir(directory, &files); if (ret < 0) return ret; printTitle(title); for (auto &file : files) { if (useStrMatch && std::string::npos == std::string(file).find(strMatch)) { continue; } fileLocation = std::string(directory) + std::string(file); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } if (printDirectory) { printf("\n\n%s\n", fileLocation.c_str()); } if (content.back() == '\n') content.pop_back(); printf("%s\n", content.c_str()); } return 0; } void dumpAcpmStats() { const char* acpmDir = "/sys/devices/platform/acpm_stats/"; const char* statsSubStr = "_stats"; const char* acpmTitle = "ACPM stats"; readContentsOfDir(acpmTitle, acpmDir, statsSubStr, true, true); } void dumpPowerSupplyStats() { const char* dumpList[][2] = { {"CPU PM stats", "/sys/devices/system/cpu/cpupm/cpupm/time_in_state"}, {"GENPD summary", "/d/pm_genpd/pm_genpd_summary"}, {"Power supply property battery", "/sys/class/power_supply/battery/uevent"}, {"Power supply property dc", "/sys/class/power_supply/dc/uevent"}, {"Power supply property gcpm", "/sys/class/power_supply/gcpm/uevent"}, {"Power supply property gcpm_pps", "/sys/class/power_supply/gcpm_pps/uevent"}, {"Power supply property main-charger", "/sys/class/power_supply/main-charger/uevent"}, {"Power supply property dc-mains", "/sys/class/power_supply/dc-mains/uevent"}, {"Power supply property tcpm", "/sys/class/power_supply/tcpm-source-psy-i2c-max77759tcpc/uevent"}, {"Power supply property usb", "/sys/class/power_supply/usb/uevent"}, {"Power supply property wireless", "/sys/class/power_supply/wireless/uevent"}, }; for (const auto &row : dumpList) { dumpFileContent(row[0], row[1]); } } void dumpMaxFg() { const char *maxfgLoc = "/sys/class/power_supply/maxfg"; const char *max77779fgDir = "/sys/class/power_supply/max77779fg"; const char *maxfg [][2] = { {"Power supply property maxfg", "/sys/class/power_supply/maxfg/uevent"}, {"m5_state", "/sys/class/power_supply/maxfg/m5_model_state"}, {"maxfg logbuffer", "/dev/logbuffer_maxfg"}, {"maxfg_monitor logbuffer", "/dev/logbuffer_maxfg_monitor"}, }; const char *max77779fgFiles [][2] = { {"Power supply property max77779fg", "/sys/class/power_supply/max77779fg/uevent"}, {"model_state", "/sys/class/power_supply/max77779fg/model_state"}, {"max77779fg logbuffer", "/dev/logbuffer_max77779fg"}, {"max77779fg_monitor logbuffer", "/dev/logbuffer_max77779fg_monitor"}, }; const char *maxfgSecondary [][2] = { {"Power supply property maxfg_base", "/sys/class/power_supply/maxfg_base/uevent"}, {"Power supply property maxfg_secondary", "/sys/class/power_supply/maxfg_secondary/uevent"}, {"model_state", "/sys/class/power_supply/maxfg_base/model_state"}, {"maxfg_base", "/dev/logbuffer_maxfg_base"}, {"maxfg_secondary", "/dev/logbuffer_maxfg_secondary"}, {"maxfg_base_monitor logbuffer", "/dev/logbuffer_maxfg_base_monitor"}, {"maxfg_secondary_monitor logbuffer", "/dev/logbuffer_maxfg_secondary_monitor"}, }; const char *maxfgHistoryName = "Maxim FG History"; const char *maxfgHistoryDir = "/dev/maxfg_history"; std::string content; if (isValidDir(maxfgLoc)) { for (const auto &row : maxfg) { dumpFileContent(row[0], row[1]); } } else if (isValidDir(max77779fgDir)) { for (const auto &row : max77779fgFiles) { dumpFileContent(row[0], row[1]); } } else { for (const auto &row : maxfgSecondary) { dumpFileContent(row[0], row[1]); } } if (isValidFile(maxfgHistoryDir)) { dumpFileContent(maxfgHistoryName, maxfgHistoryDir); } } void dumpPowerSupplyDock() { const char* powerSupplyPropertyDockTitle = "Power supply property dock"; const char* powerSupplyPropertyDockFile = "/sys/class/power_supply/dock/uevent"; if (isValidFile(powerSupplyPropertyDockFile)) { dumpFileContent(powerSupplyPropertyDockTitle, powerSupplyPropertyDockFile); } } void dumpLogBufferTcpm() { const char* logbufferTcpmTitle = "Logbuffer TCPM"; const char* logbufferTcpmFile = "/dev/logbuffer_tcpm"; const char* debugTcpmFile = "/sys/kernel/debug/tcpm"; const char* tcpmLogTitle = "TCPM logs"; const char* tcpmFile = "/sys/kernel/debug/tcpm"; const char* tcpmFileAlt = "/sys/kernel/debug/usb/tcpm"; int retCode; dumpFileContent(logbufferTcpmTitle, logbufferTcpmFile); retCode = readContentsOfDir(tcpmLogTitle, isValidFile(debugTcpmFile) ? tcpmFile : tcpmFileAlt, NULL); if (retCode < 0) printTitle(tcpmLogTitle); } void dumpTcpc() { int ret; const char* max77759TcpcHead = "TCPC"; const char* i2cSubDirMatch = "i2c-"; const char* directory = "/sys/devices/platform/10d60000.hsi2c/"; const char* max77759Tcpc [][2] { {"registers:", "/i2c-max77759tcpc/registers"}, {"frs:", "/i2c-max77759tcpc/frs"}, {"auto_discharge:", "/i2c-max77759tcpc/auto_discharge"}, {"bcl2_enabled:", "/i2c-max77759tcpc/bcl2_enabled"}, {"cc_toggle_enable:", "/i2c-max77759tcpc/cc_toggle_enable"}, {"containment_detection:", "/i2c-max77759tcpc/containment_detection"}, {"containment_detection_status:", "/i2c-max77759tcpc/containment_detection_status"}, }; std::vector files; std::string content; printTitle(max77759TcpcHead); ret = getFilesInDir(directory, &files); if (ret < 0) { for (auto &tcpcVal : max77759Tcpc) printf("%s\n", tcpcVal[0]); return; } for (auto &file : files) { for (auto &tcpcVal : max77759Tcpc) { printf("%s ", tcpcVal[0]); if (std::string::npos == std::string(file).find(i2cSubDirMatch)) { continue; } std::string fileName = directory + file + "/" + std::string(tcpcVal[1]); if (!android::base::ReadFileToString(fileName, &content)) { continue; } printf("%s\n", content.c_str()); } } } void dumpPdEngine() { const char* pdEngine [][2] { {"TCPC logbuffer", "/dev/logbuffer_usbpd"}, {"pogo_transport logbuffer", "/dev/logbuffer_pogo_transport"}, {"PPS-google_cpm logbuffer", "/dev/logbuffer_cpm"}, }; const char* ppsDcMsg = "PPS-dc logbuffer"; const char* pca9468dir = "/dev/logbuffer_pca9468"; const char* ln8411dir = "/dev/logbuffer_ln8411"; for (const auto &row : pdEngine) { dumpFileContent(row[0], row[1]); } if (isValidFile(pca9468dir)) { dumpFileContent(ppsDcMsg, pca9468dir); } else { dumpFileContent(ppsDcMsg, ln8411dir); } } void dumpBatteryHealth() { const char* batteryHealth [][2] { {"Battery Health", "/sys/class/power_supply/battery/health_index_stats"}, {"Battery Health SoC Residency", "/sys/class/power_supply/battery/swelling_data"}, {"BMS logbuffer", "/dev/logbuffer_ssoc"}, {"TTF logbuffer", "/dev/logbuffer_ttf"}, {"TTF details", "/sys/class/power_supply/battery/ttf_details"}, {"TTF stats", "/sys/class/power_supply/battery/ttf_stats"}, {"aacr_state", "/sys/class/power_supply/battery/aacr_state"}, {"pairing_state", "/sys/class/power_supply/battery/pairing_state"}, {"fwupdate", "/dev/logbuffer_max77779_fwupdate"} }; const char* maxqName = "maxq logbuffer"; const char* maxqDir = "/dev/logbuffer_maxq"; const char* tempDockDefendName = "TEMP/DOCK-DEFEND"; const char* tempDockDefendDir = "/dev/logbuffer_bd"; for (const auto &row : batteryHealth) { dumpFileContent(row[0], row[1]); } if (isValidFile(maxqDir)) dumpFileContent(maxqName, maxqDir); dumpFileContent(tempDockDefendName, tempDockDefendDir); } void dumpBatteryDefend() { const char* defendConfig [][4] { {"TRICKLE-DEFEND Config", "/sys/devices/platform/google,battery/power_supply/battery/", "bd_"}, {"DWELL-DEFEND Config", "/sys/devices/platform/google,charger/", "charge_s"}, {"DWELL-DEFEND Time", "/mnt/vendor/persist/battery/", "defender_"}, {"TEMP-DEFEND Config", "/sys/devices/platform/google,charger/", "bd_"}, }; std::vector files; struct dirent *entry; std::string content; std::string fileLocation; for (auto &config : defendConfig) { DIR *dir = opendir(config[1]); if (dir == NULL) continue; printTitle(config[0]); while ((entry = readdir(dir)) != NULL) { if (std::string(entry->d_name).find(config[2]) != std::string::npos && strncmp(config[2], entry->d_name, strlen(config[2])) == 0) { files.push_back(entry->d_name); } } closedir(dir); sort(files.begin(), files.end()); for (auto &file : files) { fileLocation = std::string(config[1]) + std::string(file); if (!android::base::ReadFileToString(fileLocation, &content) || content.empty()) { content = "\n"; } printf("%s: %s", file.c_str(), content.c_str()); if (content.back() != '\n') printf("\n"); } files.clear(); } } void printValuesOfDirectory(const char *directory, std::string debugfs, const char *strMatch) { std::vector files; auto info = directory; std::string content; struct dirent *entry; DIR *dir = opendir(debugfs.c_str()); if (dir == NULL) return; printTitle((debugfs + std::string(strMatch) + "/" + std::string(info)).c_str()); while ((entry = readdir(dir)) != NULL) if (std::string(entry->d_name).find(strMatch) != std::string::npos) files.push_back(entry->d_name); closedir(dir); sort(files.begin(), files.end()); for (auto &file : files) { std::string fileDirectory = debugfs + file; std::string fileLocation = fileDirectory + "/" + std::string(info); if (!android::base::ReadFileToString(fileLocation, &content)) { content = "\n"; } printf("%s:\n%s", fileDirectory.c_str(), content.c_str()); if (content.back() != '\n') printf("\n"); } files.clear(); } void dumpChg() { const std::string pmic_bus = "/sys/devices/platform/108d0000.hsi2c/i2c-6/6-0066"; const std::string pmic_bus_dev = "/sys/devices/platform/10cb0000.hsi2c/i2c-11/11-0066"; const char* chg_reg_dump_file = "/sys/class/power_supply/main-charger/device/registers_dump"; const std::string chg_name_file = "/sys/class/power_supply/main-charger/device/name"; const std::string pmic_name_file_dev = pmic_bus_dev + "/name"; const std::string pmic_reg_dump_dev_file = pmic_bus_dev + "/registers_dump"; const std::string pmic_name_file = pmic_bus + "/name"; const std::string pmic_reg_dump_file = pmic_bus + "/registers_dump"; const std::string reg_dump_str = " registers dump"; const char* chgConfig [][2] { {"DC_registers dump", "/sys/class/power_supply/dc-mains/device/registers_dump"}, }; std::string chg_name; std::string pmic_name; std::string pmic_reg_dump; printf("\n"); int ret = android::base::ReadFileToString(chg_name_file, &chg_name); if (ret && !chg_name.empty()) { chg_name.erase(chg_name.length() - 1); // remove new line const std::string chg_reg_dump_title = chg_name + reg_dump_str; /* CHG reg dump */ dumpFileContent(chg_reg_dump_title.c_str(), chg_reg_dump_file); } if (isValidDir(pmic_bus.c_str())) { ret = android::base::ReadFileToString(pmic_name_file, &pmic_name); pmic_reg_dump = pmic_reg_dump_file; } else { /* DEV device */ ret = android::base::ReadFileToString(pmic_name_file_dev, &pmic_name); pmic_reg_dump = pmic_reg_dump_dev_file; } if (ret && !pmic_name.empty()) { pmic_name.erase(pmic_name.length() - 1); // remove new line const std::string pmic_reg_dump_title = pmic_name + reg_dump_str; /* PMIC reg dump */ dumpFileContent(pmic_reg_dump_title.c_str(), pmic_reg_dump.c_str()); } for (auto &config : chgConfig) { dumpFileContent(config[0], config[1]); } } void dumpChgUserDebug() { const std::string debugfs = "/d/"; const char *maxFgDir = "/d/maxfg"; const char *maxFgStrMatch = "maxfg"; const char *maxBaseFgDir = "/d/maxfg_base"; const char *maxBaseFgStrMatch = "maxfg_base"; const char *maxSecFgDir = "/d/maxfg_secondary"; const char *maxSecFgStrMatch = "maxfg_secondary"; const char *max77779FgDir = "/d/max77779fg"; const char *maxFg77779StrMatch = "max77779fg"; const char *chgTblName = "Charging table dump"; const char *chgTblDir = "/d/google_battery/chg_raw_profile"; const char *maxFgInfo [] { "fg_model", "algo_ver", "model_ok", "registers", "nv_registers", }; const char *max77779FgInfo [] { "fg_model", "algo_ver", "model_ok", "registers", "debug_registers", }; const char *max1720xFgInfo [] { "registers", "nv_registers", }; if (isUserBuild()) return; dumpFileContent(chgTblName, chgTblDir); if (isValidDir(maxFgDir)) { for (auto & directory : maxFgInfo) { printValuesOfDirectory(directory, debugfs, maxFgStrMatch); } } else if (isValidDir(max77779FgDir)) { for (auto & directory : max77779FgInfo) { printValuesOfDirectory(directory, debugfs, maxFg77779StrMatch); } } else if (isValidDir(maxBaseFgDir)) { for (auto & directory : max77779FgInfo) { printValuesOfDirectory(directory, debugfs, maxBaseFgStrMatch); } if (isValidDir(maxSecFgDir)) { for (auto & directory : max1720xFgInfo) { printValuesOfDirectory(directory, debugfs, maxSecFgStrMatch); } } } } void dumpBatteryEeprom() { const char *title = "Battery EEPROM"; const char *files[] { "/sys/devices/platform/10ca0000.hsi2c/i2c-10/10-0050/eeprom", "/sys/devices/platform/10c90000.hsi2c/i2c-9/9-0050/eeprom", }; std::string result; std::string xxdCmd; printTitle(title); for (auto &file : files) { if (!isValidFile(file)) continue; xxdCmd = "xxd " + std::string(file); int ret = getCommandOutput(xxdCmd.c_str(), &result); if (ret < 0) return; printf("%s\n", result.c_str()); } } void dumpChargerStats() { const char *chgStatsTitle = "Charger Stats"; const char *chgStatsLocation = "/sys/class/power_supply/battery/charge_details"; const char *chargerStats [][3] { {"Google Charger", "/sys/kernel/debug/google_charger/", "pps_"}, {"Google Battery", "/sys/kernel/debug/google_battery/", "ssoc_"}, }; std::vector files; std::string content; struct dirent *entry; dumpFileContent(chgStatsTitle, chgStatsLocation); if (isUserBuild()) return; for (auto &stat : chargerStats) { DIR *dir = opendir(stat[1]); if (dir == NULL) return; printTitle(stat[0]); while ((entry = readdir(dir)) != NULL) if (std::string(entry->d_name).find(stat[2]) != std::string::npos) files.push_back(entry->d_name); closedir(dir); sort(files.begin(), files.end()); for (auto &file : files) { std::string fileLocation = std::string(stat[1]) + file; if (!android::base::ReadFileToString(fileLocation, &content)) { content = "\n"; } printf("%s: %s", file.c_str(), content.c_str()); if (content.back() != '\n') printf("\n"); } files.clear(); } } void dumpWlcLogs() { const char *dumpWlcList [][2] { {"WLC Logs", "/dev/logbuffer_wireless"}, {"WLC VER", "/sys/class/power_supply/wireless/device/version"}, {"WLC STATUS", "/sys/class/power_supply/wireless/device/status"}, {"WLC FW Version", "/sys/class/power_supply/wireless/device/fw_rev"}, {"RTX", "/dev/logbuffer_rtx"}, }; for (auto &row : dumpWlcList) { if (!isValidFile(row[1])) printTitle(row[0]); dumpFileContent(row[0], row[1]); } } void dumpGvoteables() { const char *directory = "/sys/kernel/debug/gvotables/"; const char *statusName = "/status"; const char *title = "gvotables"; std::string content; std::vector files; int ret; if (isUserBuild()) return; ret = getFilesInDir(directory, &files); if (ret < 0) return; printTitle(title); for (auto &file : files) { std::string fileLocation = std::string(directory) + file + std::string(statusName); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } printf("%s: %s", file.c_str(), content.c_str()); if (content.back() != '\n') printf("\n"); } files.clear(); } void dumpMitigation() { const char *mitigationList [][2] { {"LastmealCSV" , "/data/vendor/mitigation/lastmeal.csv"}, {"Lastmeal" , "/data/vendor/mitigation/lastmeal.txt"}, {"Thismeal" , "/data/vendor/mitigation/thismeal.txt"}, }; /* parsing thismeal.bin */ int status; int pid = fork(); if (pid < 0) { printf("Fork failed for parsing thismeal.bin.\n"); exit(EXIT_FAILURE); } else if (pid == 0) { execl("/vendor/bin/hw/battery_mitigation", "battery_mitigation", "-d", nullptr); exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); if (WIFSIGNALED(status)) { printf("Failed to parse thismeal.bin.(killed by: %d)\n", WTERMSIG(status)); } for (auto &row : mitigationList) { if (!isValidFile(row[1])) printTitle(row[0]); dumpFileContent(row[0], row[1]); } } void dumpMitigationStats() { int ret; const char *directory = "/sys/devices/virtual/pmic/mitigation/last_triggered_count/"; const char *capacityDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_capacity/"; const char *timestampDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_timestamp/"; const char *voltageDirectory = "/sys/devices/virtual/pmic/mitigation/last_triggered_voltage/"; const char *capacitySuffix = "_cap"; const char *timeSuffix = "_time"; const char *voltageSuffix = "_volt"; const char *countSuffix = "_count"; const char *title = "Mitigation Stats"; std::vector files; std::string content; std::string fileLocation; std::string source; std::string subModuleName; int count; int soc; int time; int voltage; ret = getFilesInDir(directory, &files); if (ret < 0) return; printTitle(title); printf("Source\t\tCount\tSOC\tTime\tVoltage\n"); for (auto &file : files) { fileLocation = std::string(directory) + std::string(file); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } ret = atoi(android::base::Trim(content).c_str()); if (ret == -1) continue; count = ret; subModuleName = std::string(file); subModuleName.erase(subModuleName.find(countSuffix), strlen(countSuffix)); fileLocation = std::string(capacityDirectory) + std::string(subModuleName) + std::string(capacitySuffix); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } ret = atoi(android::base::Trim(content).c_str()); if (ret == -1) continue; soc = ret; fileLocation = std::string(timestampDirectory) + std::string(subModuleName) + std::string(timeSuffix); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } ret = atoi(android::base::Trim(content).c_str()); if (ret == -1) continue; time = ret; fileLocation = std::string(voltageDirectory) + std::string(subModuleName) + std::string(voltageSuffix); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } ret = atoi(android::base::Trim(content).c_str()); if (ret == -1) continue; voltage = ret; printf("%s \t%i\t%i\t%i\t%i\n", subModuleName.c_str(), count, soc, time, voltage); } } void dumpMitigationDirs() { const int paramCount = 4; const char *titles[] = { "Clock Divider Ratio", "Clock Stats", "Triggered Level", "Instruction", }; const char *directories[] = { "/sys/devices/virtual/pmic/mitigation/clock_ratio/", "/sys/devices/virtual/pmic/mitigation/clock_stats/", "/sys/devices/virtual/pmic/mitigation/triggered_lvl/", "/sys/devices/virtual/pmic/mitigation/instruction/", }; const char *paramSuffix[] = {"_ratio", "_stats", "_lvl", ""}; const char *titleRowVal[] = { "Source\t\tRatio", "Source\t\tStats", "Source\t\tLevel", "", }; const int eraseCnt[] = {6, 6, 4, 0}; const bool useTitleRow[] = {true, true, true, false}; const char *vimon_name = "vimon_buff"; const char delimiter = '\n'; const int vimon_len = strlen(vimon_name); const double VIMON_VMULT = 7.8122e-5; const double VIMON_IMULT = 7.8125e-4; std::vector files; std::string content; std::string fileLocation; std::string source; std::string subModuleName; std::string readout; char *endptr; bool vimon_found = false; for (int i = 0; i < paramCount; i++) { printTitle(titles[i]); if (useTitleRow[i]) { printf("%s\n", titleRowVal[i]); } getFilesInDir(directories[i], &files); for (auto &file : files) { fileLocation = std::string(directories[i]) + std::string(file); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } readout = android::base::Trim(content); if (strncmp(file.c_str(), vimon_name, vimon_len) == 0) vimon_found = true; subModuleName = std::string(file); subModuleName.erase(subModuleName.find(paramSuffix[i]), eraseCnt[i]); if (useTitleRow[i]) { printf("%s \t%s\n", subModuleName.c_str(), readout.c_str()); } else if (vimon_found) { std::vector tokens; std::istringstream tokenStream(readout); std::string token; while (std::getline(tokenStream, token, delimiter)) { tokens.push_back(token); } bool oddEntry = true; for (auto &hexval : tokens) { int val = strtol(hexval.c_str(), &endptr, 16); if (*endptr != '\0') { printf("invalid vimon readout\n"); break; } if (oddEntry) { int vbatt = int(1000 * (val * VIMON_VMULT)); printf("vimon vbatt: %d ", vbatt); } else { int ibatt = int(1000 * (val * VIMON_IMULT)); printf("ibatt: %d\n", ibatt); } oddEntry = !oddEntry; } } else { printf("%s=%s\n", subModuleName.c_str(), readout.c_str()); } } } } void dumpIrqDurationCounts() { const char *title = "IRQ Duration Counts"; const char *colNames = "Source\t\t\t\tlt_5ms_cnt\tbt_5ms_to_10ms_cnt\tgt_10ms_cnt\tCode" "\tCurrent Threshold (uA)\tCurrent Reading (uA)\n"; const int nonOdpmChannelCnt = 12; const int odpmChCnt = 12; enum Duration { LT_5MS, BT_5MS_10MS, GT_10MS, DUR_MAX, }; const char *irqDurDirectories[] = { "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/less_than_5ms_count", "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/between_5ms_to_10ms_count", "/sys/devices/virtual/pmic/mitigation/irq_dur_cnt/greater_than_10ms_count", }; enum PowerWarn { MAIN, SUB, PWRWARN_MAX, }; const char *pwrwarnDirectories[] = { "/sys/devices/virtual/pmic/mitigation/main_pwrwarn/", "/sys/devices/virtual/pmic/mitigation/sub_pwrwarn/", }; const char *lpfCurrentDirs[] = { "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/" "s2mpg14-odpm/iio:device1/lpf_current", "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/" "s2mpg15-odpm/iio:device0/lpf_current", }; const char *lpfCurrentDirsAlt[] = { "/sys/devices/platform/acpm_mfd_bus@15500000/i2c-7/7-001f/s2mpg14-meter/" "s2mpg14-odpm/iio:device0/lpf_current", "/sys/devices/platform/acpm_mfd_bus@15510000/i2c-8/8-002f/s2mpg15-meter/" "s2mpg15-odpm/iio:device1/lpf_current", }; bool titlesInitialized = false; std::vector channelNames; std::vector channelData[DUR_MAX]; std::vector pwrwarnThreshold[PWRWARN_MAX]; std::vector pwrwarnCode[PWRWARN_MAX]; std::vector lpfCurrentVals[PWRWARN_MAX]; std::vector files; std::string content; std::string token; std::string tokenCh; std::string fileLocation; for (int i = 0; i < DUR_MAX; i++) { if (!android::base::ReadFileToString(irqDurDirectories[i], &content)) { return; } std::istringstream tokenStream(content); while (std::getline(tokenStream, token, '\n')) { if (!titlesInitialized) { tokenCh = token; tokenCh.erase(tokenCh.find(':'), tokenCh.length()); channelNames.push_back(tokenCh); } // there is a space after the ':' which needs to be removed token.erase(0, token.find(':') + 1); channelData[i].push_back(token); } if (!titlesInitialized) titlesInitialized = true; } for (int i = 0; i < PWRWARN_MAX; i++) { getFilesInDir(pwrwarnDirectories[i], &files); for (auto &file : files) { fileLocation = std::string(pwrwarnDirectories[i]) + std::string(file); if (!android::base::ReadFileToString(fileLocation, &content)) { continue; } std::string readout; readout = android::base::Trim(content); std::string readoutThreshold = readout; readoutThreshold.erase(0, readoutThreshold.find('=') + 1); std::string readoutCode = readout; readoutCode.erase(readoutCode.find('='), readoutCode.length()); pwrwarnThreshold[i].push_back(readoutThreshold); pwrwarnCode[i].push_back(readoutCode); } } for (int i = 0; i < PWRWARN_MAX; i++) { if (!android::base::ReadFileToString(lpfCurrentDirs[i], &content) && !android::base::ReadFileToString(lpfCurrentDirsAlt[i], &content)) { printf("Cannot find %s\n", lpfCurrentDirs[i]); continue; } std::istringstream tokenStream(content); bool first = true; while (std::getline(tokenStream, token, '\n')) { token.erase(0, token.find(' ')); if (first) { first = false; continue; } lpfCurrentVals[i].push_back(token); } } printTitle(title); printf("%s", colNames); for (uint i = 0; i < channelNames.size(); i++) { std::string code = ""; std::string threshold = ""; std::string current = ""; std::string ltDataMsg = ""; std::string btDataMsg = ""; std::string gtDataMsg = ""; int pmicSel = 0; int offset = 0; std::string channelNameSuffix = " \t"; if (i >= nonOdpmChannelCnt) { offset = nonOdpmChannelCnt; if (i >= (odpmChCnt + nonOdpmChannelCnt)) { pmicSel = 1; offset = odpmChCnt + nonOdpmChannelCnt; } channelNameSuffix = ""; if (pmicSel >= PWRWARN_MAX) { printf("invalid index: pmicSel >= pwrwarnCode size\n"); return; } if (i - offset >= pwrwarnCode[pmicSel].size()) { printf("invalid index: i - offset >= pwrwarnCode size\n"); return; } code = pwrwarnCode[pmicSel][i - offset]; if (i - offset >= pwrwarnThreshold[pmicSel].size()) { printf("invalid index: i - offset >= pwrwarnThreshold size\n"); return; } threshold = pwrwarnThreshold[pmicSel][i - offset]; if (i - offset >= lpfCurrentVals[pmicSel].size()) { printf("invalid index: i - offset >= lpfCurrentVals size\n"); return; } current = lpfCurrentVals[pmicSel][i - offset]; } if (i < channelData[0].size()) ltDataMsg = channelData[0][i]; if (i < channelData[1].size()) btDataMsg = channelData[1][i]; if (i < channelData[2].size()) gtDataMsg = channelData[2][i]; std::string adjustedChannelName = channelNames[i] + channelNameSuffix; printf("%s \t%s\t\t%s\t\t\t%s\t\t%s \t%s \t\t%s\n", adjustedChannelName.c_str(), ltDataMsg.c_str(), btDataMsg.c_str(), gtDataMsg.c_str(), code.c_str(), threshold.c_str(), current.c_str()); } } void dumpEvtCounter() { const char* title = "Event Counter"; const char* evtCntDir = "/sys/devices/virtual/pmic/mitigation/instruction/"; const char* evtCnt [][2] { {"batoilo1", "evt_cnt_batoilo1"}, {"batoilo2", "evt_cnt_batoilo2"}, {"uvlo1", "evt_cnt_uvlo1"}, {"uvlo2", "evt_cnt_uvlo2"}, }; printTitle(title); printf("name\tcount\n"); for (const auto &row : evtCnt) { std::string name = row[0]; std::string fileLocation = std::string(evtCntDir) + std::string(row[1]); std::string count = "N/A\n"; if (!android::base::ReadFileToString(fileLocation, &count)) { count = "invalid\n"; } printf("%s\t%s", name.c_str(), count.c_str()); } } int main() { dumpPowerStatsTimes(); dumpAcpmStats(); dumpPowerSupplyStats(); dumpMaxFg(); dumpPowerSupplyDock(); dumpLogBufferTcpm(); dumpTcpc(); dumpPdEngine(); dumpBatteryHealth(); dumpBatteryDefend(); dumpChg(); dumpChgUserDebug(); dumpBatteryEeprom(); dumpChargerStats(); dumpWlcLogs(); dumpGvoteables(); dumpMitigation(); dumpMitigationStats(); dumpMitigationDirs(); dumpIrqDurationCounts(); dumpEvtCounter(); }