/* * ThermalManager.cpp * * Copyright (C) 2016 Spreadtrum Communications Inc. */ #include #include #include #include #include #include #include #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::iterator iter; while (1) { for (iter = handler->mSensorDeque.begin(); iter != handler->mSensorDeque.end(); iter++) { sensor = *iter; std::deque& 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::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