# How Shadowsocks-Windows Handles System Power Suspend/Resume

> Learn how Shadowsocks-Windows manages system power suspend and resume. Discover how the controller stops and restarts proxy services automatically after waking up.

- Repository: [shadowsocks/shadowsocks-windows](https://github.com/shadowsocks/shadowsocks-windows)
- Tags: internals
- Published: 2026-03-05

---

**Shadowsocks-Windows registers a `SystemEvents.PowerModeChanged` handler in [`Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Program.cs) that calls `MainController.Stop()` on suspend and `MainController.Start(true)` on resume, waiting 10 seconds after wake-up to allow network adapters to re-initialize before restarting the proxy services.**

The **shadowsocks/shadowsocks-windows** client must gracefully handle Windows sleep cycles to prevent network leaks and ensure seamless reconnection. The application hooks into the operating system's power management events to coordinate the shutdown and recovery of its core `ShadowsocksController`.

## How Power State Changes Are Detected

The application subscribes to `Microsoft.Win32.SystemEvents.PowerModeChanged` during initialization in [`Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Program.cs). This Windows Forms event provides real-time notifications whenever the OS enters or exits a low-power state.

```csharp
// Registration in Program.cs (lines 110-119)
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;

```

The handler `SystemEvents_PowerModeChanged` inspects the `PowerModeChangedEventArgs.Mode` property to determine whether the system is suspending or resuming.

## Suspend Handling: Graceful Shutdown

When `PowerModes.Suspend` is detected, the application immediately shuts down all active networking components to ensure the OS can safely enter sleep mode without holding open sockets or proxy connections.

The `MainController.Stop()` method performs the following actions:

- Closes the local SOCKS5 listener
- Shuts down the **PAC daemon** and **PAC server**
- Releases all active proxy processes and sockets
- Logs "controller stopped" and "os suspend" for diagnostics

This cleanup is critical because Windows may freeze or terminate applications that hold network resources during sleep transitions.

### Key Code Path for Suspend

In [`Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Program.cs) (lines 110-117 and 210-217), the suspend branch executes:

```csharp
case PowerModes.Suspend:
    // cleanly stop everything before the OS sleeps
    MainController.Stop();
    break;

```

## Resume Handling: Controller Recovery

On `PowerModes.Resume`, the application does not immediately restart. Instead, it spawns a background task that waits **10 seconds** before invoking `MainController.Start(true)`. This delay allows Windows to re-initialize network adapters and restore connectivity.

```csharp
case PowerModes.Resume:
    // give the OS a moment, then restart the controller
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(10_000);
        MainController.Start(true);
    });
    break;

```

### The systemWakeUp Flag

The `ShadowsocksController.Start(bool systemWakeUp)` method (implemented in [`ShadowsocksController.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/ShadowsocksController.cs), lines 14-30) uses the boolean parameter to distinguish between a cold start and a wake-from-suspend recovery:

- **Configuration reload**: `Reload()` refreshes settings and restarts the listener and PAC services
- **System proxy re-application**: The controller reapplies the system proxy settings to restore traffic redirection
- **Skip first-run logic**: When `systemWakeUp` is `true`, the method skips version-upgrade checks (`_config.firstRunOnNewVersion`), allowing immediate recovery

```csharp
public void Start(bool systemWakeUp = false)
{
    // skip first‑run upgrade when waking from suspend
    if (_config.firstRunOnNewVersion && !systemWakeUp) { /* upgrade logic */ }

    Reload();               // re‑load config, listeners, PAC, etc.
    if (!systemWakeUp)      // normal launch: register hotkeys
        HotkeyReg.RegAllHotkeys();
}

```

## Key Implementation Details

| Component | File Path | Role in Power Management |
|-----------|-----------|-------------------------|
| **Power Event Registration** | [`shadowsocks-csharp/Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/shadowsocks-csharp/Program.cs) (lines 110-119) | Subscribes to `SystemEvents.PowerModeChanged` |
| **Suspend Logic** | [`shadowsocks-csharp/Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/shadowsocks-csharp/Program.cs) (lines 110-117) | Calls `MainController.Stop()` to release resources |
| **Resume Logic** | [`shadowsocks-csharp/Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/shadowsocks-csharp/Program.cs) (lines 188-202) | Delays 10s then calls `MainController.Start(true)` |
| **Controller Start** | [`Controller/ShadowsocksController.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Controller/ShadowsocksController.cs) (lines 14-30) | Implements `Start(bool systemWakeUp)` with wake-up detection |
| **Controller Stop** | [`Controller/ShadowsocksController.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Controller/ShadowsocksController.cs) | Implements `Stop()` to close listeners and PAC daemon |
| **PAC Services** | [`Controller/Service/PACDaemon.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Controller/Service/PACDaemon.cs) / [`PACServer.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/PACServer.cs) | Restarted by controller during resume recovery |

## Summary

- **Shadowsocks-Windows** hooks `SystemEvents.PowerModeChanged` in [`Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Program.cs) to monitor power state transitions.
- **During suspend**, `MainController.Stop()` cleanly terminates the proxy listener, PAC daemon, and network sockets to prepare for sleep.
- **During resume**, a background task waits 10 seconds for network adapter initialization, then calls `MainController.Start(true)`.
- **The `systemWakeUp` flag** in `ShadowsocksController.Start()` skips first-run upgrade checks and triggers rapid recovery of proxy services and system proxy settings.

## Frequently Asked Questions

### Why does Shadowsocks-Windows wait 10 seconds after resume?

The 10-second delay in [`Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/Program.cs) (lines 188-202) allows Windows to complete network adapter re-initialization and restore connectivity. Starting the proxy controller too early results in binding failures or unreachable remote servers because the network stack is not yet fully operational during the early seconds of wake-up.

### What components are stopped during system suspend?

According to the source code in `ShadowsocksController.Stop()`, the application shuts down the local SOCKS5 listener, the **PAC daemon**, the **PAC server**, and any active proxy processes. This releases all sockets and allows the OS to enter low-power states safely without hanging on open network connections.

### What is the purpose of the systemWakeUp flag in Start()?

The `systemWakeUp` parameter in `ShadowsocksController.Start(bool systemWakeUp)` signals that the application is recovering from suspend rather than launching fresh. When `true`, the method skips version-upgrade prompts and first-run configuration dialogs, immediately reloading settings and restarting services to minimize downtime.

### Where is the power event handler registered?

The handler is registered in [`shadowsocks-csharp/Program.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/shadowsocks-csharp/Program.cs) at lines 110-119 using `SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;`. This single subscription captures both suspend and resume events, routing them to the appropriate controller methods based on the `PowerModes` enum value.