canonical / canonical/multipass
macOS: VM continues running after lid close causing overheating
- Dominant language
- C++
- Stars
- 9.2k
- Forks
- 828
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 44
Description
# macOS: VM continues running after lid close causing overheating
## Problem Description
**Summary**: When closing the MacBook lid (clamshell mode), Multipass VMs continue running, causing the device to overheat and battery to drain quickly.
**Severity**: High - Affects user experience and device safety
**Platform**: macOS (affecting both Intel and Apple Silicon)
**Affected Versions**: All versions up to and including 1.16.3
## Steps to Reproduce
1. Install Multipass 1.16.3 on a MacBook
2. Launch one or more instances: `multipass launch`
3. Close the MacBook lid (clamshell mode)
4. Wait for a few minutes to hours
5. Observe device temperature, fan noise, and battery drain
## Expected Behavior
After closing the lid, Multipass should automatically suspend all running VMs to save power and prevent overheating.
## Actual Behavior
VMs continue running at full speed, causing:
- Device overheating, bottom temperature can reach 40-50°C
- High fan speed (if applicable)
- Rapid battery drain during sleep state
- Noticeable heat when carrying the device
## Root Cause Analysis
After code investigation, the following issues were found:
### 1. Daemon does not subscribe to macOS system sleep notifications
The `UnixSignalHandler` in [`src/daemon/daemon_main.cpp`](https://github.com/canonical/multipass/blob/main/src/daemon/daemon_main.cpp) only handles `SIGTERM`, `SIGINT`, `SIGUSR1` Unix signals, **does not subscribe** to `NSWorkspaceWillSleepNotification` or `IORegisterForSystemPower` system sleep events.
### 2. QEMU/AppleVZ virtual CPU threads are not constrained by sleep
[`src/platform/backends/qemu/macos/qemu_platform_macos.cpp`](https://github.com/canonical/multipass/blob/main/src/platform/backends/qemu/macos/qemu_platform_macos.cpp) uses `-accel hvf` (Hypervisor Framework) to launch VMs. Virtual CPU threads created by HVF run with real-time scheduling priority on the host, **not constrained by macOS clamshell sleep**.
### 3. No automatic suspend mechanism
There is no "auto-suspend instances on system sleep" mechanism in [`src/daemon/daemon.h`](https://github.com/canonical/multipass/blob/main/src/daemon/daemon.h). Users must manually execute `multipass suspend` or `multipass stop`.
## Proposed Solution
### Core Features
Implement **"Auto-suspend instances on lid close"** functionality:
1. **Add `SleepWakeHandler` component**
- Subscribe to `NSWorkspaceWillSleepNotification` and `NSWorkspaceDidWakeNotification`
- Call `Daemon::suspend_all_instances()` when receiving sleep notification
- Call `Daemon::resume_suspended_instances()` when receiving wake notification (configurable)
2. **Add two new settings**
- `local.auto-suspend-on-sleep` (bool, default `true`): Control whether to auto-suspend instances on system sleep
- `local.auto-resume-on-wake` (bool, default `false`): Control whether to auto-resume instances on system wake
3. **Extend Daemon class**
- Add `suspend_all_instances()` method: Suspend all instances in `running` state
- Add `resume_suspended_instances()` method: Resume previously auto-suspended instances
- Record auto-suspended instance names to avoid restarting user-manually suspended instances after wake
### User Interface
```bash
# Enable/disable auto-suspend
multipass set local.auto-suspend-on-sleep=true # default
# Enable/disable auto-resume
multipass set local.auto-resume-on-wake=false # default
```
## Workaround (Temporary)
Before official implementation, users can use the following methods to mitigate:
1. **Manual suspend**: Execute `multipass suspend --all` before closing lid
2. **Use sleepwatcher**: Install [`sleepwatcher`](https://formulae.brew.sh/formula/sleepwatcher) and configure scripts
## Related PR
- PR #5125: feat: auto-suspend instances on macOS lid close
## Environment
```
Multipass version: 1.16.3
macOS version: macOS Sequoia 15.x / macOS Sonoma 14.x
Architecture: Apple Silicon (M1/M2/M3/M4) and Intel
Driver: QEMU (default) / AppleVZ
```
---
**Labels**: `bug`, `macOS`, `enhancement`
Contributor guide
Research direction
Start with src/daemon/daemon_main.cpp and src/daemon/daemon.h to trace daemon signal handling and instance lifecycle, then inspect src/platform/backends/qemu/macos/qemu_platform_macos.cpp for macOS VM behavior. Review related PR #5125 before making changes. Done means sleep notifications suspend running instances without affecting manually suspended ones, with the requested configurable wake behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, macos
- Domain
- backend, operating-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100