canonical / canonical/multipass

macOS: VM continues running after lid close causing overheating

Open
#5,124 2 comments 0 reactions 0 assignees View on GitHub
macos
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.