382 lines
11 KiB
C++
382 lines
11 KiB
C++
/*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
|