Skip to content

Commit

Permalink
Create separate timer to check remaining battery capacity.
Browse files Browse the repository at this point in the history
  • Loading branch information
lvs1974 committed Oct 3, 2021
1 parent e00e978 commit ec8e94e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 32 deletions.
101 changes: 69 additions & 32 deletions HibernationFixup/kern_hbfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,37 +185,10 @@ IOReturn HBFX::IOHibernateSystemWake(void)
void HBFX::IOPMrootDomain_evaluatePolicy(IOPMrootDomain* that, int stimulus, uint32_t arg)
{
DBGLOG("HBFX", "evaluatePolicy called, stimulus = 0x%x", stimulus);


bool forceHibernate = false;
auto autoHibernateMode = ADDPR(hbfx_config).autoHibernateMode;
IOPMPowerSource *power_source = callbackHBFX->getPowerSource();
if (power_source && power_source->batteryInstalled() && !power_source->externalConnected() && !power_source->isCharging()) {
bool whenBatteryIsAtWarnLevel = (autoHibernateMode & Configuration::WhenBatteryIsAtWarnLevel);
bool whenBatteryAtCriticalLevel = (autoHibernateMode & Configuration::WhenBatteryAtCriticalLevel);
int minimalRemainingCapacity = ((autoHibernateMode & 0xF00) >> 8);

if (whenBatteryIsAtWarnLevel && power_source->atWarnLevel()) {
DBGLOG("HBFX", "Auto hibernate: Battery is at warning level, capacity remaining: %d, force to hibernate", power_source->capacityPercentRemaining());
forceHibernate = true;
}

if (whenBatteryAtCriticalLevel && power_source->atCriticalLevel()) {
DBGLOG("HBFX", "Auto hibernate: battery is at critical level, capacity remaining: %d, force to hibernate", power_source->capacityPercentRemaining());
forceHibernate = true;
}

if (!forceHibernate && (whenBatteryIsAtWarnLevel || whenBatteryAtCriticalLevel) && minimalRemainingCapacity != 0 &&
power_source->capacityPercentRemaining() <= minimalRemainingCapacity)
{
DBGLOG("HBFX", "Auto hibernate: capacity remaining: %d less than minimal: %d, force to hibernate", power_source->capacityPercentRemaining(), minimalRemainingCapacity);
forceHibernate = true;
}

if (forceHibernate && callbackHBFX->nextSleepTimer)
callbackHBFX->nextSleepTimer->setTimeoutMS(2000);
}
callbackHBFX->checkCapacity();

auto autoHibernateMode = ADDPR(hbfx_config).autoHibernateMode;
if (autoHibernateMode & Configuration::DisableStimulusDarkWakeActivityTickle) {
if (stimulus == kStimulusDarkWakeActivityTickle) {
DBGLOG("HBFX", "evaluatePolicy prevented kStimulusDarkWakeActivityTickle");
Expand Down Expand Up @@ -569,15 +542,45 @@ void HBFX::processKernel(KernelPatcher &patcher)
bool whenBatteryIsAtWarnLevel = (ADDPR(hbfx_config).autoHibernateMode & Configuration::WhenBatteryIsAtWarnLevel);
bool whenBatteryAtCriticalLevel = (ADDPR(hbfx_config).autoHibernateMode & Configuration::WhenBatteryAtCriticalLevel);

if (auto_hibernate_mode_on || whenBatteryIsAtWarnLevel || whenBatteryAtCriticalLevel) {
if (whenBatteryIsAtWarnLevel || whenBatteryAtCriticalLevel) {
if (!checkCapacityTimer) {
if (!workLoop)
workLoop = IOWorkLoop::workLoop();

if (!workLoop)
workLoop = IOWorkLoop::workLoop();

if (workLoop) {
checkCapacityTimer = IOTimerEventSource::timerEventSource(workLoop,
[](OSObject *owner, IOTimerEventSource *sender) {
callbackHBFX->checkCapacity();
if (sender)
sender->setTimeoutMS(60000);
});

if (checkCapacityTimer) {
IOReturn result = workLoop->addEventSource(checkCapacityTimer);
if (result != kIOReturnSuccess)
SYSLOG("HBFX", "addEventSource failed");
else
checkCapacityTimer->setTimeoutMS(60000);
}
else
SYSLOG("HBFX", "timerEventSource failed");
}
else
SYSLOG("HBFX", "IOService instance does not have workLoop");
}
}

if (auto_hibernate_mode_on) {
KernelPatcher::RouteRequest requests[] = {
{"__ZN14IOPMrootDomain14evaluatePolicyEij", IOPMrootDomain_evaluatePolicy, orgIOPMrootDomain_evaluatePolicy},
{"__ZN14IOPMrootDomain17willEnterFullWakeEv", IOPMrootDomain_willEnterFullWake, orgIOPMrootDomain_willEnterFullWake},
{"__ZN14IOPMrootDomain26setMaintenanceWakeCalendarEPK18IOPMCalendarStruct", IOPMrootDomain_setMaintenanceWakeCalendar, orgIOPMrootDomain_setMaintenanceWakeCalendar},
{"_IOHibernateSystemWake", IOHibernateSystemWake, orgIOHibernateSystemWake}
};
size_t request_count = auto_hibernate_mode_on ? arrsize(requests) : 1;
if (!patcher.routeMultipleLong(KernelPatcher::KernelID, requests, request_count)) {
if (!patcher.routeMultipleLong(KernelPatcher::KernelID, requests, arrsize(requests))) {
SYSLOG("HBFX", "patcher.routeMultiple for %s is failed with error %d", requests[0].symbol, patcher.getError());
patcher.clearError();
}
Expand Down Expand Up @@ -1112,3 +1115,37 @@ IOReturn HBFX::explicitlyCallSetMaintenanceWakeCalendar()
DBGLOG("HBFX", "call setMaintenanceWakeCalendar explicitly");
return IOPMrootDomain_setMaintenanceWakeCalendar(IOService::getPMRootDomain(), &calendar);
}

//==============================================================================

void HBFX::checkCapacity()
{
bool forceHibernate = false;
auto autoHibernateMode = ADDPR(hbfx_config).autoHibernateMode;
IOPMPowerSource *power_source = callbackHBFX->getPowerSource();
if (power_source && power_source->batteryInstalled() && !power_source->externalConnected() && !power_source->isCharging()) {
bool whenBatteryIsAtWarnLevel = (autoHibernateMode & Configuration::WhenBatteryIsAtWarnLevel);
bool whenBatteryAtCriticalLevel = (autoHibernateMode & Configuration::WhenBatteryAtCriticalLevel);
int minimalRemainingCapacity = ((autoHibernateMode & 0xF00) >> 8);

if (whenBatteryIsAtWarnLevel && power_source->atWarnLevel()) {
DBGLOG("HBFX", "Auto hibernate: Battery is at warning level, capacity remaining: %d, force to hibernate", power_source->capacityPercentRemaining());
forceHibernate = true;
}

if (whenBatteryAtCriticalLevel && power_source->atCriticalLevel()) {
DBGLOG("HBFX", "Auto hibernate: battery is at critical level, capacity remaining: %d, force to hibernate", power_source->capacityPercentRemaining());
forceHibernate = true;
}

if (!forceHibernate && (whenBatteryIsAtWarnLevel || whenBatteryAtCriticalLevel) && minimalRemainingCapacity != 0 &&
power_source->capacityPercentRemaining() <= minimalRemainingCapacity)
{
DBGLOG("HBFX", "Auto hibernate: capacity remaining: %d less than minimal: %d, force to hibernate", power_source->capacityPercentRemaining(), minimalRemainingCapacity);
forceHibernate = true;
}

if (forceHibernate && callbackHBFX->nextSleepTimer)
callbackHBFX->nextSleepTimer->setTimeoutMS(2000);
}
}
3 changes: 3 additions & 0 deletions HibernationFixup/kern_hbfx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class HBFX {
bool isStandbyEnabled(uint32_t &delta_time, bool &pmset_default_mode);

IOReturn explicitlyCallSetMaintenanceWakeCalendar();

void checkCapacity();

/**
* Hooked methods / callbacks
Expand Down Expand Up @@ -153,6 +155,7 @@ class HBFX {
NVStorage nvstorage;
IOWorkLoop *workLoop {};
IOTimerEventSource *nextSleepTimer {};
IOTimerEventSource *checkCapacityTimer {};

bool emulatedNVRAM {false};
};
Expand Down

0 comments on commit ec8e94e

Please sign in to comment.