Files

382 lines
11 KiB
C++
Raw Permalink Normal View History

2026-09-22 09:38:26 +08:00
/*LOGI
* ThermalXmlParser.cpp
*
* Copyright (C) 2016 Spreadtrum Communications Inc.
*/
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <string>
#include <stdio.h>
#include <fcntl.h>
#include <fstream>
#include <errno.h>
#include <sys/types.h>
#include "ThermalAction.h"
#include "ThermalActionFactory.h"
#include "ThermalTrip.h"
#include "ThermalZoneLevel.h"
#include "ThermalSensor.h"
#include "ThermalXmlParser.h"
#include "CvtGovernor.h"
#include "alog.h"
#undef LOG_TAG
#define LOG_TAG "ThermalXmlParser"
namespace android {
ThermalXmlParser::ThermalXmlParser() {}
ThermalXmlParser::~ThermalXmlParser() {
std::deque<ThermalSensor*>::iterator iter;
for (iter = mSensorDeque.begin(); iter != mSensorDeque.end(); iter++) {
delete *iter;
}
mSensorDeque.clear();
}
std::deque<ThermalSensor*>& ThermalXmlParser::initSensorsFromXml(void) {
tinyxml2::XMLDocument xmlDoc;
if (!access(CONFIG_DEBUG_FILE_PATH, F_OK)) {
ALOGI("using debug config file...");
if (!xmlDoc.LoadFile(CONFIG_DEBUG_FILE_PATH))
ALOGI("using debug config file successfully!");
else {
ALOGI("using debug config file unsuccessfully!");
return mSensorDeque;
}
}else if (!access(CONFIG_FILE_PATH, F_OK)) {
ALOGI("using normal config file...");
if (!xmlDoc.LoadFile(CONFIG_FILE_PATH))
ALOGI("using normal config file successfully!");
else {
ALOGI("using normal config file unsuccessfully!");
return mSensorDeque;
}
} else {
ALOGE("not found any config file for thermald!");
return mSensorDeque;
}
tinyxml2::XMLElement* root = xmlDoc.FirstChildElement();
if (root == NULL) {
ALOGE("Failed to read file: No root element.");
return mSensorDeque;
}
tinyxml2::XMLElement* pSensorNode = NULL;
tinyxml2::XMLElement* pChipNode = root->FirstChildElement(CONFIG_CHIP_INFO);
while (pChipNode) {
tinyxml2::XMLElement* pChipIdNode =
pChipNode->FirstChildElement(CONFIG_CHIPID);
if (!pChipIdNode) {
pChipNode = pChipNode->NextSiblingElement();
continue;
}
const tinyxml2::XMLAttribute* attribute = NULL;
attribute = pChipIdNode->FirstAttribute();
int id;
sscanf(attribute->Value(), "%x", &id);
attribute = attribute->Next();
int mask;
sscanf(attribute->Value(), "%x", &mask);
attribute = attribute->Next();
const char* file = attribute->Value();
pChipNode = pChipNode->NextSiblingElement();
}
if (!pSensorNode) {
pSensorNode = root->FirstChildElement(CONFIG_SENSOR);
}
while (pSensorNode) {
tinyxml2::XMLElement* pSensorChild = pSensorNode->FirstChildElement();
ThermalSensor* pSensor = getSensorArgs(pSensorChild);
if (pSensor != NULL) {
mSensorDeque.push_back(pSensor);
}
pSensorNode = pSensorNode->NextSiblingElement();
}
return mSensorDeque;
}
ThermalSensor* ThermalXmlParser::getSensorArgs(
tinyxml2::XMLElement* pSensorChild) {
int id = 0;
ThermalSensor* pSensor = new ThermalSensor();
while (pSensorChild) {
const char* name = pSensorChild->Name();
const char* value = pSensorChild->GetText();
ALOGI("%s=%s", name, value);
if (!std::strcmp(name, CONFIG_SENSOR_TYPE)) {
int ret = searchSensor(pSensorChild, pSensor, value);
if (ret < 0) {
delete pSensor;
return NULL;
}
} else if (!std::strcmp(name, CONFIG_SENSOR_NAME)) {
pSensor->setName(value);
} else if (!std::strcmp(name, CONFIG_SENSOR_FILE)) {
pSensor->setTempFile(value);
} else if (!std::strcmp(name, CONFIG_SENSOR_POLLING_DELAY)) {
pSensor->setPollingDelay(std::atoi(value));
} else if (!std::strcmp(name, CONFIG_SENSOR_AVG_PERIOD)) {
pSensor->setAvgPeriod(std::atoi(value));
} else if (!std::strcmp(name, CONFIG_SENSOR_DRO_PERIOD)) {
pSensor->setDroPeriod(std::atoi(value));
} else if (!std::strcmp(name, CONFIG_ZONE_LEVEL)) {
ThermalZoneLevel* pLevel = getZoneLevelArgs(pSensorChild);
pLevel->setId(id++);
pSensor->pushZoneDeque(pLevel);
} else if (!std::strcmp(name, CONFIG_LIMIT_TRIP)) {
ThermalTrip* pTrip = getTripArgs(pSensorChild);
std::deque<ThermalTrip*>& limitTrip = pSensor->getLimitTripDeque();
limitTrip.push_back(pTrip);
} else if (!std::strcmp(name, CONFIG_INIT_TRIP)) {
ThermalTrip* pTrip = getTripArgs(pSensorChild);
std::deque<ThermalTrip*>& initTrip = pSensor->getInitTripDeque();
initTrip.push_back(pTrip);
} else if (!std::strcmp(name, CONFIG_PERF_TRIP)) {
ThermalTrip* pTrip = getTripArgs(pSensorChild);
std::deque<ThermalTrip*>& perfTrip = pSensor->getPerfTripDeque();
perfTrip.push_back(pTrip);
}
pSensorChild = pSensorChild->NextSiblingElement();
}
CvtGovernor* governor = new CvtGovernor(pSensor);
return pSensor;
}
int ThermalXmlParser::searchSensor(tinyxml2::XMLElement* element,
ThermalSensor* pSensor, const char* type) {
int ret;
tinyxml2::XMLElement* pSensorChild = element;
ret = matchSensorFile(pSensor, type, false);
if (ret < 0) {
ALOGI("can't find %s", type);
pSensorChild = pSensorChild->NextSiblingElement();
const char* name = pSensorChild->Name();
const char* value = pSensorChild->GetText();
if (!std::strcmp(name, CONFIG_BACKUP_SENSOR)) {
ALOGI("search backup sensor: %s", value);
ret = matchSensorFile(pSensor, value, true);
if (ret >= 0) {
return 0;
}
ALOGI("can't find %s", value);
}
ALOGI("can't match any sensor, don't use these parameters!");
return -1;
}
return 0;
}
int ThermalXmlParser::matchSensorFile(ThermalSensor* pSensor, const char* type, bool isBackup) {
int i = 0;
int fd, len;
char path[64];
char buf[16];
std::string sensorName (type);
if (isBackup) {
sensorName += "-backup";
}
while (1){
sprintf(path, "%s/thermal_zone%d/type", CONFIG_FILE_SENSOR_PATH, i);
fd = open(path, O_RDONLY);
if (fd < 0){
return -1;
}
len = read(fd, buf, 15);
close(fd);
if (len < 0){
return -1;
}
buf[len] = '\0';
ALOGI("get thermal_zone%d type: %s", i, buf);
if (!strncmp(buf, type, strlen(type))){
sprintf(path, "%s/thermal_zone%d/temp", CONFIG_FILE_SENSOR_PATH, i);
if (isTempValid(path)) {
pSensor->setName(sensorName.c_str());
pSensor->setTempFile(path);
ALOGI("sensor: %s is thermal_zone%d", type, i);
return 0;
}
}
++i;
}
return -1;
}
bool ThermalXmlParser::isTempValid(const char* tempPath) {
int fd, len;
char buf[8];
fd = open(tempPath, O_RDONLY);
if (fd < 0) {
return false;
}
len = read(fd, buf, 8);
close(fd);
if (len <= 0) {
ALOGI("%s is Invalid!", tempPath);
return false;
}
return true;;
}
ThermalZoneLevel* ThermalXmlParser::getZoneLevelArgs(
tinyxml2::XMLElement* pLevelNode) {
int id = 0;
ThermalZoneLevel* pLevel = new ThermalZoneLevel();
const tinyxml2::XMLAttribute* attribute = NULL;
attribute = pLevelNode->FirstAttribute();
attribute = attribute->Next();
const char* type = attribute->Value();
ALOGI("%s=%s", attribute->Name(), type);
pLevel->setLevelType(type);
tinyxml2::XMLElement* pLevelChild = pLevelNode->FirstChildElement();
while (pLevelChild) {
const char* name = pLevelChild->Name();
if (!std::strcmp(name, CONFIG_TEMP)) {
const char* value = pLevelChild->GetText();
ALOGI("%s=%s", name, value);
pLevel->setTemp(std::atoi(value));
pLevel->setHystTemp(std::atoi(value));
}
if (!std::strcmp(name, CONFIG_HYST_TEMP)) {
const char* value = pLevelChild->GetText();
ALOGI("%s=%s", name, value);
pLevel->setHystTemp(std::atoi(value));
}
if (!std::strcmp(name, CONFIG_TRIP)) {
ThermalTrip* pTrip = getTripArgs(pLevelChild);
pTrip->setId(id++);
pLevel->pushTripDeque(pTrip);
}
pLevelChild = pLevelChild->NextSiblingElement();
}
return pLevel;
}
ThermalTrip* ThermalXmlParser::getTripArgs(tinyxml2::XMLElement* pTripNode) {
ThermalTrip* pTrip = new ThermalTrip();
const tinyxml2::XMLAttribute* attribute = NULL;
tinyxml2::XMLElement* pActionNode = pTripNode->FirstChildElement();
while (pActionNode) {
std::string name;
std::string file;
std::string type;
std::string arg;
attribute = pActionNode->FirstAttribute();
while (attribute) {
if (!std::strcmp(attribute->Name(), CONFIG_ACTION_NAME)) {
name = attribute->Value();
ALOGI("name = %s", name.c_str());
} else if (!std::strcmp(attribute->Name(), CONFIG_ACTION_ARG)) {
arg = attribute->Value();
ALOGI("arg = %s", arg.c_str());
} else if (!std::strcmp(attribute->Name(), CONFIG_ACTION_FILE)) {
file = attribute->Value();
ALOGI("file = %s", file.c_str());
} else {
ALOGE("getTripArgs error name=%s, value=%s", attribute->Name(), attribute->Value());
}
attribute = attribute->Next();
}
if (name.empty()) {
ALOGE("getTripArgs name is NULL");
} else {
matchActionFile(file, name);
ThermalActionFactory factory;
ThermalAction* pAction = factory.getAction(name.c_str());
pAction->setArg(arg.c_str());
pAction->setFile(file.c_str());
pTrip->pushActionDeque(pAction);
}
pActionNode = pActionNode->NextSiblingElement();
}
return pTrip;
}
int ThermalXmlParser::matchActionFile(std::string& file, std::string name)
{
char path[80];
char buf[32];
const char* devType = NULL;
const char* type0 = NULL;
const char* type1 = NULL;
size_t pos = 0;
int i = 0;
pos = file.find("cooling_device");
if (pos != std::string::npos) {
devType = "cooling_device";
strncpy(buf, name.c_str(), 32);
switch (atoi(buf)) {
case 0 : type0 = COOLING_TYPE0;
break;
case 1 : type0 = COOLING_TYPE1;
break;
case 2 : type0 = COOLING_TYPE2;
break;
default:
ALOGI("Can not match cooling_device, should check its type, name=%s\n", name.c_str());
return -1;
}
}
pos = file.find("thermal_zone");
if (pos != std::string::npos) {
devType = "thermal_zone";
type0 = CPU_TYPE0;
type1 = CPU_TYPE1;
}
if (devType == NULL)
return -1;
pos = file.find_last_of('/');
if (pos != std::string::npos) {
file = file.substr(pos + 1);
}
ALOGI("file:%s", file.c_str());
while (1) {
snprintf(path, 80, "%s/%s%d/type", CONFIG_FILE_SENSOR_PATH, devType, i);
int fd = open(path, O_RDONLY);
if (fd < 0) {
ALOGI("open %s fail: %s", path, strerror(errno));
break;
}
ssize_t len = read(fd, buf, 32);
close(fd);
if (len <= 1) {
i++;
continue;
}
buf[--len] = '\0';
if ((!strncmp(buf, type0, strlen(type0))) || ((type1 != NULL) && !strncmp(buf, type1, strlen(type1)))) {
ALOGI("match %s%d type is %s", devType, i, buf);
snprintf(path, 80, "%s/%s%d/", CONFIG_FILE_SENSOR_PATH, devType, i);
file.insert(0, path);
return 0;
}
i++;
}
return -1;
}
}; // namespace android