The "Modern Standby" architecture is a huge change from traditional power management. I have a customer requirement to both enter and exit this state at specific times.
Unfortunately, the changes to the OS don't seem to consider this scenario and provide precious little documentation on how it can be done by a (user mode) application. After much head scratching, I have found reliable method to enter modern standby from user mode. However, I have not been able to find a reliable way to exit this state from user mode. I assume this is intentional.
Consequently, I have started to investigate kernel mode solutions...
I am aware there is an architecture for power management in kernel mode drivers and this is typically implemented using the KMDF framework. However, this is very complex and it looks like a huge mountain (for me) to climb. One possibility I have identified is to create a virtual keyboard (HID) driver that supports wake-up. This could simulate user presence and allow the system to exit the modern standby state in a way indistinguishable from user presence. This would be ideal for my customer requirement but a very roundabout solution.
Please, can I ask:
Is there a recommended way to exit modern standby I have missed? e.g. PoRequestPowerIrp()?
Is a fake HID device the best approach or is there a simpler method to simulate user presence?
Hmmm... yes and no, right? There's the context of "activator" applications that are designed to specifically do this (wake the system intermittently to do something, and go back to sleep). But it's entirely possible that this is currently restricted to MSFT-only apps?
From what you're describing you want to wake the system briefly, do something, then return it immediately back to sleep... like the "activators" currently do?
Yes, "activators" are the MSFT technology that can run background tasks. Unfortunately, they are seem to be poorly documented and, with one exception, I have found no documentation on how to create or register one. The exception is the "bi" activator used to launch UWP/WinRT background tasks. These come with there own limitations.
When modern standby is active, most user programs are suspended and services in session 0 heavily throttled. Interestingly, I have found lots of MSFT inbox programs, running in user sessions which are not suspended. Again, there is no documentation for this exception to the rule.
For these reasons, I think a kernel mode component is required to wake up the system from modern standby and escape the straight jacket imposed by the OS. I don't know how long the wakeup will last. The requirement is to make it wake and stay awake until no longer required.
Is a HID driver the best way? Is there another/better way?
Good question. I haven't researched this enough to know.
You would THINK that a user-mode program could decide to set a time (or something) to allow it to wake the system pretty easily, and that the system would "naturally" fall sleep after the app (and devices) quiesced. I mean...that's not exactly an unreasonable thing for an application to want to do.
I assume you've already looking into simple alternatives like "set a timer" or "make an entry in the task scheduler" or ... whatever.
Yeah... sorry... good question. Wish I had the answer to what seems to be a very reasonable question.
Yes, it is simple to use SetWaitableTimer to wakeup the system at a specific time. This works fine with traditional sleep modes. It also works with modern standby but in this case the system will only stay awake for a minute or so before automatically sleeping again. There seems no (documented) way to treat the wake up as a "full" wakeup equivalent to that instigated by a user.
(This is a bit of a simplification. There is a power setting which can be changed to vary however long the system will stay awake for and allegedly disable this behaviour. However, on test systems with modem standby, this doesn't work and the system still falls asleep again unless a user intervenes).
I know a HID driver is a hack but it seems the most simple way to emulated user input and fool the system into behaving the same as when a user was present. I wish it wasn't necessary, but after weeks of research I haven't found a better idea...
You must have a larger goal that simply waking the system from a low power mode at a time of your choosing? As opposed to what the user has set for power policy and has chosen to do via power buttons, lid closing or simply walking away.
And it may not be up to an individual user either. Many power policies can and are set via group policies that are set by administrators.
Yes, the customer requirement is to be able to completely control sleep and wake dynamically. The legacy code works very well with traditional S1-S4 sleep modes and can wake-up and suspend the system as required. Something similar can be achieved with the task scheduler but it has the same fundamental problem that a modern standby system "wants" to quickly sleep again if it is automatically woken and no user is present.
A complication in our scenario is that no user is present and the code runs in a service (session 0). This wasn't a problem in the past but is a pain with modern standby because traditional APIs like SetSuspendState() don't work with this new paradigm and there is no clear-cut way to enter this state from user mode. We solved this problem by turning off the display. This starts the decent into modern standby which typically occurs a little later. Turning off the display would be easy normally but, with session 0 isolation, requires some complex gymnastics.
Unfortunately, the same trickery cannot be used to exit modern standby and we have yet to find any method that can do this from user mode. Consequently, I have been forced to look at kernel mode solutions. I'm confident that it can be done this way but a newbie in this area so I'm looking for suggestions about the best approach.
Possible options include:
Creating a simulated HID device that can "wake-up" the system
Creating a non-PnP driver that simply changes the power state (but may leave the system unstable)
Something inbetween
Maybe I missed something and there is a way to do this but, AFIK, MSFT don't document how to create an "activator" or any other ways to interface with modern standby. They seem to have forgotten that in some scenarios a user isn't present but we still need to consistently control sleep/wake cycles.
Yes, SetThreadExecutionState() works but will only keep the system awake for a minute or two before something else (unknown) causes the system to return to the previous suspend state. As I said, there is a power setting that claims to change this timeout or disable this feature but this doesn't work either.
Consequently, I'm looking for the best way to resume the system, simulate user presence and escape this loop behaviour.
For the record: You can use SendMessage(..,SC_MONITORPOWER) to turn the display off and enter modern standby. However, this cannot be used from session 0. To workaround this, the solution is to identify the console session and spawn a child process into that session. Unfortunately, the same technique cannot be used to exit modern standby because any child process launched from session 0 whilst the system is in this state is launched suspended and doesn't run until the system resumes. This creates a catch-22.
In my experience, regardless of what the documentation says, when using SetThreadExecutionState you must call it repetitively. In my code, I call it about once per minute while waiting on async network requests that Windows has no other way to know about. ES_CONTINUOUS does not produce the documented behaviour, and regardless of whatever calls you make, the system is free to disregard your request.
But you are asking for something more. An ability to change the power state at will. I doubt that there is any reasonable way. You have already found a way to trigger a low power mode, To return to a high power mode, instead of a fake HID, you might want to look at WOL (wake on lan). I haven't used this in a long time (windows XP / Vista), but at that time it was possible to trigger a system to wake up by crafting an Ethernet frame - no driver required
Yes, I have had the same experience with SetThreadExecutionState(). We call it about every 60 seconds. This works fine with traditional standby but not "modern standby".
The decision to investigate a HID (or similar) device driver is one of desperation. It is a very complicated way to solve a simple problem. Unfortunately, it seems the design of "modern standby" deliberately left out the ability to directly enter and exit it. This makes a whole class of previously simple workflows really difficult.
Well, yes. It's not supposed to be up to a driver or an application to make this decision. It's supposed to be up to the operating system and the BIOS.
Since (at least) the introduction of ACPI, this has been trivial for a user mode program using any available S1-S4 low power mode and SetWaitableTimer. This is a near universal feature that works on most PCs.
The introduction of modern standby has broken this.
This change breaks an entire workflow of automated systems which are in a low power state and periodically wake up to perform useful work. Currently, the only workaround is to leave them on 24/7.
Simulating user presence using a HID driver or similar is a last ditch fudge to workaround this problematic behaviour.
Well, before ACPI is a long time ago. Today most hardware has good power management support, but before the early 2000's, the only hardware that cared about power at all were laptops, and all of them had OEM specific solutions. High end storage too - but that wasn't about saving power. It was about not blowing circuit breakers when the in rush current from all of those motors in the drives tried to start at the same time
An unattended system that wakes up periodically to do work is a normal behaviour for a server. But it is not normal for a desktop. But talking about turning off displays and stuff implies you are working on a desktop. Which version of Windows are you trying to use for this?
The primary customer for this project is using desktop Windows. They have > 250,000 devices. They have been doing this successfully for over a decade. I don't think it would be very helpful for me to tell them that they need to upgrade all devices to Windows Server!
Similarly, saying that it is the responsibility of the operating system is a red herring. This works fine on the majority of devices and has done for years. The operating supports that behaviour using a regular, documented, methods. The recent changes have broken this on (a minority) of devices.
Yes, there are potentially other ways this could be done. However, as above, it is difficult for me to defend that it works fine on many thousands of older devices but not newer devices with modern standby. From a customer perspective, this looks like bug. The best I can honestly say at the moment is MSFT took away the "lever".
From a technical standpoint, turning on the display is a side issue. Strictly speaking, the screen is not required to be on but screen on/off is the gateway to modern standby. e.g. When the screen is on, the device is not in modern standby. Once the screen is off, the modern standby process can start.
Simulated user input via fake keyboard is a complicated and roundabout solution this the customer requirement. We think it will work but it would be better if there was a simpler way.
It would be great to hear technical views on this problem and how it can be solved rather than questioning the customer requirement. They are the customer...
I’m sure you’ve done this, but I have to ask: have you tried something as simple as scheduling your task to run via the Windows task scheduler thingy? My hope is that would be sufficiently integrated with the OS to make it possible to “wake the system at 3am and run this task every day”…
Thank you for the suggestions. Yes, we have wake timers enabled. Yes, we have previously tested task scheduler with mixed results. Scheduled tasks will sometimes run but frequently start late or are suspended after a few minutes operation before completing. Our customer needs more precise control than this akin to that when user is present. Reading other forums, it seems that problems with wake-up and task scheduler are a common complaint on systems with "modern standby". This matches what we found too.
NB: Our experience is that there is something "special" about automatic wake-up by SetWaitableTimer or WoL which distinguishes it from wake-up when a user is present. In the automatic case, the system will default to sleep again unless this is postponed or a user intervenes. This is reflected by the IsSystemResumeAutomatic() API. On systems with traditional S1-S4 power management, the default re-suspend timeout is 2 minutes but this can be changed or even disabled by changing a power setting. Our experience is that this is ignored with "modern standby".
This is why we are looking at a HID driver. It would simulate user presence and allow us to escape the automatic resume limbo and return to normal behaviour on demand.