/*LOGI * ThermalXmlParser.cpp * * Copyright (C) 2016 Spreadtrum Communications Inc. */ #include #include #include #include #include #include #include #include #include #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::iterator iter; for (iter = mSensorDeque.begin(); iter != mSensorDeque.end(); iter++) { delete *iter; } mSensorDeque.clear(); } std::deque& 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& limitTrip = pSensor->getLimitTripDeque(); limitTrip.push_back(pTrip); } else if (!std::strcmp(name, CONFIG_INIT_TRIP)) { ThermalTrip* pTrip = getTripArgs(pSensorChild); std::deque& initTrip = pSensor->getInitTripDeque(); initTrip.push_back(pTrip); } else if (!std::strcmp(name, CONFIG_PERF_TRIP)) { ThermalTrip* pTrip = getTripArgs(pSensorChild); std::deque& 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