/* * ChargeDetect.cpp * * Copyright (C) 2017 Spreadtrum Communications Inc. */ #include #include #include #include #include #include "ThermalManager.h" #include "ChargeDetect.h" #include "uevent.h" #include "alog.h" #undef LOG_TAG #define LOG_TAG "ThermalChargeDetect" namespace android { ChargeDetect::ChargeDetect(ThermalManager* handler) { pthread_t pid; mManager = handler; #if 0 int value = property_get_int32(GOVERNOR_CHARGE_ENABLE, 1); if (value == 1) { mChargeEn = true; } else { mChargeEn = false; } #else mChargeEn = true; #endif mIsCharging = getChargeStatus(); ALOGI("init status: ChargeEn=%d, IsCharging=%d", mChargeEn, mIsCharging); if (!mChargeEn || !mIsCharging) { ALOGI("send EVENT_CHGDIS"); mChgActionEn = false; mManager->sendEvent(ThermalManager::EVENT_CHGDIS); } else { mChgActionEn = true; } int ret = pthread_create(&pid, NULL, chargeMonitor, this); if (ret) { ALOGE("create chargeMonitor pthread failed!"); } } ChargeDetect::~ChargeDetect() { close(mUeventFd); } #define UEVENT_MSG_LEN 1024 void* ChargeDetect::chargeMonitor(void* ptr) { ChargeDetect* detector = (ChargeDetect*)ptr; ThermalManager* manager = detector->mManager; struct pollfd pfd; int fd; char msg[UEVENT_MSG_LEN + 2]; char* cp; int n; fd = uevent_open_socket(2 * 1024, true); if (fd < 0) { ALOGE("uevent_init: uevent_open_socket failed: %d\n", fd); return NULL; } detector->mUeventFd = fd; pfd.fd = fd; pfd.events = POLLIN; while (1) { n = poll(&pfd, 1, -1); if (n < 1){ continue; } n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN); if (n <= 0 || n >= UEVENT_MSG_LEN) { continue; } msg[n] = '\0'; msg[n + 1] = '\0'; cp = msg; while (*cp) { if (!strcmp(cp, "SUBSYSTEM=power_supply")) { detector->chargeEvent(); break; } /* advance to after the next \0 */ while (*cp++) ; } } return NULL; } int ChargeDetect::chargeEvent(void) { if (mChargeEn == false) { return 0; } bool isChg = getChargeStatus(); if (mIsCharging == isChg) { return 0; } mIsCharging = isChg; if (isChg && !mChgActionEn) { ALOGI("send EVENT_CHGEN"); mChgActionEn = true; mManager->sendEvent(ThermalManager::EVENT_CHGEN); return 1; } if (!isChg && mChgActionEn) { ALOGI("send EVENT_CHGDIS"); mChgActionEn = false; mManager->sendEvent(ThermalManager::EVENT_CHGDIS); return 1; } return 0; } bool ChargeDetect::getChargeStatus(void) { int fd, len; char buf[20]; fd = open(STAT_PATH, O_RDONLY); if (fd < 0) { ALOGE("open %s failed: %d", STAT_PATH, fd); return false; } len = read(fd, buf, sizeof(buf)); close(fd); buf[len - 1] = '\0'; ALOGI("charge status: %s", buf); if (!strcmp(buf, "Charging") || !strcmp(buf, "Full")) { return true; } else { return false; } } bool ChargeDetect::getChargeEn(void) { return mChargeEn; } int ChargeDetect::enableCharge(bool en) { if (mChargeEn == en) { return 0; } mChargeEn = en; /*if (en) { property_set(GOVERNOR_CHARGE_ENABLE, "1"); } else { property_set(GOVERNOR_CHARGE_ENABLE, "0"); }*/ if (en && mIsCharging && !mChgActionEn) { mChgActionEn = true; ALOGI("send EVENT_CHGEN"); mManager->sendEvent(ThermalManager::EVENT_CHGEN); return 1; } if ((!en || !mIsCharging) && mChgActionEn) { mChgActionEn = false; ALOGI("send EVENT_CHGDIS"); mManager->sendEvent(ThermalManager::EVENT_CHGDIS); return 1; } return 0; } }; // namespace android