539 lines
16 KiB
C++
539 lines
16 KiB
C++
/*
|
|
* ThermalManager.cpp
|
|
*
|
|
* Copyright (C) 2016 Spreadtrum Communications Inc.
|
|
*/
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/un.h>
|
|
#include "ThermalSensor.h"
|
|
#include "ThermalXmlParser.h"
|
|
#include "ThermalManager.h"
|
|
#include "ThermalZoneLevel.h"
|
|
#include "ThermalTrip.h"
|
|
#include "ThermalAction.h"
|
|
#include "ThermalGovernor.h"
|
|
#include "ThermalActionFactory.h"
|
|
#include "ChargeDetect.h"
|
|
#include "alog.h"
|
|
|
|
#undef LOG_TAG
|
|
#define LOG_TAG "ThermalManager"
|
|
|
|
namespace android {
|
|
|
|
ThermalManager::ThermalManager() {
|
|
pthread_mutex_init(&mCountLock, NULL);
|
|
pthread_mutex_init(&mThreadLock, NULL);
|
|
pthread_mutex_init(&mEnCntLock, NULL);
|
|
pthread_cond_init(&mCountFlag, NULL);
|
|
mpXmlParser = new ThermalXmlParser();
|
|
mLimEnCnt = 0;
|
|
mGovEnPrst = 0;
|
|
mLimEnPrst = 0;
|
|
mGovEnCnt = 1;
|
|
mPaEnCnt = 1;
|
|
mChgEnCnt = 0;
|
|
mChgDetector = NULL;
|
|
}
|
|
ThermalManager::~ThermalManager() {
|
|
delete mpXmlParser;
|
|
delete mChgDetector;
|
|
}
|
|
|
|
void ThermalManager::run(void) {
|
|
mSensorDeque = mpXmlParser->initSensorsFromXml();
|
|
|
|
pthread_t pid;
|
|
ALOGI("create thermal monitor pthread");
|
|
int ret = pthread_create(&pid, NULL, thermalMonitor, this);
|
|
if (ret) {
|
|
ALOGE("create thermalMonitor pthread failed!");
|
|
}
|
|
#if 0
|
|
int ret = pthread_create(&pid, NULL, socketListen, this);
|
|
if (ret) {
|
|
ALOGE("create socketListen pthread failed!");
|
|
}
|
|
#endif
|
|
mChgDetector = new ChargeDetect(this);
|
|
|
|
check_property();
|
|
|
|
receiveEvent();
|
|
|
|
return;
|
|
}
|
|
|
|
void ThermalManager::check_property(void) {
|
|
#if 0
|
|
int value;
|
|
pthread_mutex_lock(&mEnCntLock);
|
|
value = property_get_int32(GOVERNOR_ENABLE, 1);
|
|
if (value == 1) {
|
|
mGovEnCnt = 1;
|
|
}
|
|
value = property_get_int32(GOVERNOR_PA_ENABLE, 1);
|
|
if (value == 1) {
|
|
mPaEnCnt = 1;
|
|
} else {
|
|
sendEvent(EVENT_PADIS);
|
|
}
|
|
if (getChargeEn()) {
|
|
mChgEnCnt = 1;
|
|
}
|
|
value = property_get_int32(LIMIT_TRIP_EN, 0);
|
|
if (value == 1) {
|
|
mLimEnCnt = 1;
|
|
}
|
|
if (mGovEnCnt < 1) {
|
|
sendEvent(EVENT_GOVDIS);
|
|
} else if (mLimEnCnt == 1) {
|
|
mGovEnCnt--;
|
|
sendEvent(EVENT_LIMEN);
|
|
} else {
|
|
sendEvent(EVENT_TRIP);
|
|
}
|
|
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
#else
|
|
if (getChargeEn()) {
|
|
mChgEnCnt = 1;
|
|
}
|
|
sendEvent(EVENT_TRIP);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void* ThermalManager::thermalMonitor(void* ptr) {
|
|
int temp;
|
|
bool update_flag = false;
|
|
ThermalManager* handler = (ThermalManager*)(ptr);
|
|
ThermalSensor* sensor;
|
|
std::deque<ThermalSensor*>::iterator iter;
|
|
|
|
while (1) {
|
|
for (iter = handler->mSensorDeque.begin();
|
|
iter != handler->mSensorDeque.end(); iter++) {
|
|
sensor = *iter;
|
|
std::deque<ThermalZoneLevel*>& levelDeque = sensor->getThermalZoneDeque();
|
|
if (levelDeque.size() == 0) {
|
|
continue;
|
|
}
|
|
temp = sensor->fetchSensorTemp();
|
|
sensor->setCurrTemp(temp);
|
|
bool update = sensor->governorUpdate();
|
|
if (update) {
|
|
ThermalEvent* event = new ThermalEvent(EVENT_TRIP, sensor);
|
|
pthread_mutex_lock(&(handler->mCountLock));
|
|
handler->mEventQueue.push(event);
|
|
pthread_mutex_unlock(&(handler->mCountLock));
|
|
update_flag = true;
|
|
ALOGI("send event type=%d, sensor=%s", EVENT_TRIP, sensor->getName());
|
|
}
|
|
}
|
|
if (update_flag) {
|
|
pthread_cond_signal(&(handler->mCountFlag));
|
|
update_flag = false;
|
|
}
|
|
usleep(sensor->getPollingDelay() * 1000);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ThermalManager::receiveEvent(void) {
|
|
while (1) {
|
|
pthread_mutex_lock(&mCountLock);
|
|
bool eventEmpty = mEventQueue.empty();
|
|
bool update = false;
|
|
pthread_mutex_unlock(&mCountLock);
|
|
while (!eventEmpty) {
|
|
pthread_mutex_lock(&mCountLock);
|
|
ThermalEvent* event = mEventQueue.front();
|
|
mEventQueue.pop();
|
|
pthread_mutex_unlock(&mCountLock);
|
|
switch (event->mType) {
|
|
case EVENT_TRIP:
|
|
ALOGI("received EVENT_TRIP, sensor=%s", event->mSensor->getName());
|
|
event->mSensor->tripActions();
|
|
break;
|
|
case EVENT_GOVDIS:
|
|
ALOGI("received EVENT_GOVDIS, sensor=%s, GovEnCnt=%d",
|
|
event->mSensor->getName(), mGovEnCnt);
|
|
pthread_mutex_lock(&mEnCntLock);
|
|
if (mGovEnCnt != 0) {
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
break;
|
|
}
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
|
|
update = event->mSensor->enabledGovernor(false);
|
|
if (update) {
|
|
event->mSensor->tripActions();
|
|
}
|
|
/*if (mGovEnPrst) {
|
|
property_set(GOVERNOR_ENABLE, "0");
|
|
}*/
|
|
break;
|
|
case EVENT_GOVEN:
|
|
ALOGI("received EVENT_GOVDEN, sensor=%s, GovEnCnt=%d",
|
|
event->mSensor->getName(), mGovEnCnt);
|
|
pthread_mutex_lock(&mEnCntLock);
|
|
if (mGovEnCnt != 1) {
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
break;
|
|
}
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
|
|
update = event->mSensor->enabledGovernor(true);
|
|
if (update) {
|
|
event->mSensor->reTripActions();
|
|
}
|
|
/*if (mGovEnPrst) {
|
|
property_set(GOVERNOR_ENABLE, "1");
|
|
}*/
|
|
break;
|
|
case EVENT_PADIS:
|
|
ALOGI("received EVENT_PADIS, sensor=%s, PaEnCnt=%d",
|
|
event->mSensor->getName(), mPaEnCnt);
|
|
pthread_mutex_lock(&mEnCntLock);
|
|
if (mPaEnCnt != 0) {
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
break;
|
|
}
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
|
|
if (!strcmp(event->mSensor->getName(), PA_SENSOR)) {
|
|
update = event->mSensor->enabledGovernor(false);
|
|
if (update) {
|
|
event->mSensor->tripActions();
|
|
}
|
|
} else {
|
|
event->mSensor->enableSensorActions(false, PA_SENSOR);
|
|
}
|
|
//property_set(GOVERNOR_PA_ENABLE, "0");
|
|
break;
|
|
case EVENT_PAEN:
|
|
ALOGI("received EVENT_PAEN, sensor=%s, PaEnCnt=%d",
|
|
event->mSensor->getName(), mPaEnCnt);
|
|
pthread_mutex_lock(&mEnCntLock);
|
|
if (mPaEnCnt != 1) {
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
break;
|
|
}
|
|
pthread_mutex_unlock(&mEnCntLock);
|
|
|
|
if (!strcmp(event->mSensor->getName(), PA_SENSOR)) {
|
|
event->mSensor->enabledGovernor(true);
|
|
} else {
|
|
event->mSensor->enableSensorActions(true, PA_SENSOR);
|
|
}
|
|
//property_set(GOVERNOR_PA_ENABLE, "1");
|
|
break;
|
|
case EVENT_CHGDIS:
|
|
ALOGI("received EVENT_CHGDIS, sensor=%s, ChgEnCnt=%d",
|
|
event->mSensor->getName(), mChgEnCnt);
|
|
if (!strcmp(event->mSensor->getName(), CHARGE_SENSOR)) {
|
|
update = event->mSensor->enabledGovernor(false);
|
|
if (update) {
|
|
event->mSensor->tripActions();
|
|
}
|
|
} else {
|
|
event->mSensor->enableSensorActions(false, CHARGE_SENSOR);
|
|
}
|
|
break;
|
|
case EVENT_CHGEN:
|
|
ALOGI("received EVENT_CHGEN, sensor=%s, ChgEnCnt=%d",
|
|
event->mSensor->getName(), mChgEnCnt);
|
|
if (!strcmp(event->mSensor->getName(), CHARGE_SENSOR)) {
|
|
event->mSensor->enabledGovernor(true);
|
|
} else {
|
|
event->mSensor->enableSensorActions(true, CHARGE_SENSOR);
|
|
}
|
|
if (mGovEnCnt < 1) {
|
|
bool ret = event->mSensor->tripPerfActions();
|
|
if (ret == true) {
|
|
break;
|
|
}
|
|
}
|
|
if (mLimEnCnt) {
|
|
event->mSensor->tripLimitActions();
|
|
break;
|
|
}
|
|
event->mSensor->tripLastChgActions();
|
|
break;
|
|
case EVENT_LIMEN:
|
|
ALOGI("received EVENT_LIMEN, sensor=%s", event->mSensor->getName());
|
|
event->mSensor->limitEnable(true);
|
|
/*if (mLimEnPrst) {
|
|
property_set(LIMIT_TRIP_EN, "1");
|
|
}*/
|
|
break;
|
|
case EVENT_LIMDIS:
|
|
ALOGI("received EVENT_LIMDIS, sensor=%s", event->mSensor->getName());
|
|
update = event->mSensor->limitEnable(false);
|
|
/*if (mLimEnPrst) {
|
|
property_set(LIMIT_TRIP_EN, "0");
|
|
}*/
|
|
if (update) {
|
|
event->mSensor->reTripActions();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
delete event;
|
|
pthread_mutex_lock(&mCountLock);
|
|
eventEmpty = mEventQueue.empty();
|
|
pthread_mutex_unlock(&mCountLock);
|
|
}
|
|
pthread_cond_wait(&mCountFlag, &mThreadLock);
|
|
}
|
|
}
|
|
|
|
ThermalManager::ThermalEvent::ThermalEvent() {}
|
|
|
|
ThermalManager::ThermalEvent::ThermalEvent(enum EventType type,
|
|
ThermalSensor* sensor) {
|
|
ThermalEvent::mType = type;
|
|
ThermalEvent::mSensor = sensor;
|
|
}
|
|
|
|
ThermalManager::ThermalEvent::~ThermalEvent() {}
|
|
|
|
void ThermalManager::sendEvent(enum EventType type) {
|
|
std::deque<ThermalSensor*>::iterator iter;
|
|
for (iter = mSensorDeque.begin(); iter != mSensorDeque.end(); iter++) {
|
|
ThermalSensor* sensor = *iter;
|
|
ThermalEvent* event = new ThermalEvent();
|
|
event->mSensor = sensor;
|
|
event->mType = type;
|
|
ALOGI("send 0x%x, sensor=%s", type, sensor->getName());
|
|
pthread_mutex_lock(&mCountLock);
|
|
mEventQueue.push(event);
|
|
pthread_mutex_unlock(&mCountLock);
|
|
pthread_cond_signal(&mCountFlag);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
#define SOCKET_PATH "/tmp/thermal.domain"
|
|
void* ThermalManager::socketListen(void* ptr) {
|
|
char buf[128];
|
|
int fdListen, new_fd, ret;
|
|
struct sockaddr_un peeraddr;
|
|
socklen_t socklen = sizeof(peeraddr);
|
|
struct sockaddr_un srv_addr;
|
|
|
|
ThermalManager* handler = (ThermalManager*)ptr;
|
|
|
|
fdListen =socket(PF_UNIX,SOCK_STREAM,0);
|
|
if (fdListen < 0) {
|
|
ALOGE("get socket %s failed!", SOCKET_PATH);
|
|
return NULL;
|
|
}
|
|
srv_addr.sun_family=AF_UNIX;
|
|
strncpy(srv_addr.sun_path, SOCKET_PATH, sizeof(srv_addr.sun_path)-1);
|
|
unlink(SOCKET_PATH);
|
|
ret=bind(fdListen, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
|
|
if(ret < 0) {
|
|
ALOGE("socket bind error!");
|
|
close(fdListen);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ALOGI("listen socket ...");
|
|
ret = listen(fdListen, 5);
|
|
if (ret < 0) {
|
|
ALOGE("listen socket error: %d", ret);
|
|
close(fdListen);
|
|
return NULL;
|
|
}
|
|
while (1) {
|
|
new_fd = accept(fdListen, (struct sockaddr*)&peeraddr, &socklen);
|
|
ALOGI("A client is accepted!");
|
|
memset(buf, 0, sizeof(buf));
|
|
int len = recv(new_fd, buf, sizeof(buf), 0);
|
|
if (len <= 0) {
|
|
close(new_fd);
|
|
continue;
|
|
}
|
|
int cmd = atoi(buf);
|
|
if (cmd < 0 || cmd >= THMCMD_MAX ||
|
|
(cmd == 0 && buf[0] != '0')) {
|
|
ALOGE("received cmd: %s is wrong!", buf);
|
|
close(new_fd);
|
|
continue;
|
|
}
|
|
ALOGI("received cmd:%d : %s", cmd, handler->mCmdMsg[cmd]);
|
|
switch (cmd) {
|
|
case THMCMD_SET_EN:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt++;
|
|
handler->mPaEnCnt++;
|
|
handler->mChgEnCnt++;
|
|
handler->mGovEnPrst = 1;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_GOVEN);
|
|
break;
|
|
case THMCMD_SET_DIS:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt--;
|
|
handler->mPaEnCnt--;
|
|
handler->mChgEnCnt--;
|
|
handler->mGovEnPrst = 1;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_GOVDIS);
|
|
break;
|
|
case THMCMD_SET_PERF_EN:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt--;
|
|
handler->mPaEnCnt--;
|
|
handler->mChgEnCnt--;
|
|
handler->mGovEnPrst = 0;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_GOVDIS);
|
|
break;
|
|
case THMCMD_SET_PERF_DIS:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt++;
|
|
handler->mPaEnCnt++;
|
|
handler->mChgEnCnt++;
|
|
handler->mGovEnPrst = 0;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_GOVEN);
|
|
break;
|
|
case THMCMD_GET_STAT:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
if (handler->mGovEnCnt > 0) {
|
|
snprintf(buf, sizeof(buf), "true");
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "false");
|
|
}
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
len = send(new_fd, buf, strlen(buf), 0);
|
|
if (len < (int)strlen(buf)) {
|
|
ALOGE("set ThmPaEn info error: %s", buf);
|
|
}
|
|
break;
|
|
case THMCMD_SET_PA_EN:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mPaEnCnt++;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_PAEN);
|
|
break;
|
|
case THMCMD_SET_PA_DIS:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mPaEnCnt--;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_PADIS);
|
|
break;
|
|
case THMCMD_GET_PA_STAT:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
if (handler->mPaEnCnt > 0) {
|
|
snprintf(buf, sizeof(buf), "true");
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "false");
|
|
}
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
len = send(new_fd, buf, strlen(buf), 0);
|
|
if (len < (int)strlen(buf)) {
|
|
ALOGE("set ThmPaEn info error: %s", buf);
|
|
}
|
|
break;
|
|
case THMCMD_SET_CHG_EN:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mChgEnCnt++;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->enableCharge(true);
|
|
break;
|
|
case THMCMD_SET_CHG_DIS:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mChgEnCnt--;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->enableCharge(false);
|
|
break;
|
|
case THMCMD_GET_CHG_STAT:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
if (handler->mChgEnCnt > 0) {
|
|
snprintf(buf, sizeof(buf), "true");
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "false");
|
|
}
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
len = send(new_fd, buf, strlen(buf), 0);
|
|
if (len < (int)strlen(buf)) {
|
|
ALOGE("set ThmPaEn info error: %s", buf);
|
|
}
|
|
break;
|
|
case THMCMD_SET_LIM_EN:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt--;
|
|
handler->mLimEnCnt = 1;
|
|
handler->mLimEnPrst = 0;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_LIMEN);
|
|
|
|
break;
|
|
case THMCMD_SET_LIM_DIS:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt++;
|
|
handler->mLimEnCnt = 0;
|
|
handler->mLimEnPrst = 0;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_LIMDIS);
|
|
|
|
break;
|
|
case THMCMD_SET_LIM_EN_PRST:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt--;
|
|
handler->mLimEnCnt = 1;
|
|
handler->mLimEnPrst = 1;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_LIMEN);
|
|
|
|
break;
|
|
case THMCMD_SET_LIM_DIS_PRST:
|
|
pthread_mutex_lock(&(handler->mEnCntLock));
|
|
handler->mGovEnCnt++;
|
|
handler->mLimEnCnt = 0;
|
|
handler->mLimEnPrst = 1;
|
|
pthread_mutex_unlock(&(handler->mEnCntLock));
|
|
handler->sendEvent(EVENT_LIMDIS);
|
|
|
|
break;
|
|
default:
|
|
ALOGE("unused cmd: %d", cmd);
|
|
break;
|
|
};
|
|
close(new_fd);
|
|
}
|
|
|
|
close(fdListen);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
bool ThermalManager::getChargeEn(void) {
|
|
if (mChgDetector) {
|
|
return mChgDetector->getChargeEn();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int ThermalManager::enableCharge(bool en) {
|
|
if (mChgDetector) {
|
|
return mChgDetector->enableCharge(en);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
}; // namespace android
|