Implement the WSLC plugin API#40521
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements the WSLC plugin API by extending the WSL plugin surface and wiring WSLC session/container/image notifications (plus a small WSLC control API) through wslservice.exe to loaded plugins, with corresponding end-to-end test coverage updates.
Changes:
- Adds a WSLC-facing notifier COM interface and threads it through WSLC session creation and container/image lifecycle to notify plugins.
- Extends
WslPluginApi.handPluginManagerwith WSLC plugin hooks and WSLC API calls (mount/unmount, create process, process IO helpers). - Refactors/extends Windows tests and the test plugin to validate WSLC callbacks and API calls.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| test/windows/WSLCTests.cpp | Switches to shared WSLC E2E helpers and updates session-list struct usage. |
| test/windows/wslc/e2e/WSLCE2EHelpers.cpp | Updates local registry helper to ensure the registry image exists in the target session. |
| test/windows/testplugin/Plugin.cpp | Adds WSLC hook implementations and exercises WSLC plugin API calls. |
| test/windows/PluginTests.h | Extends test-mode enum with WSLC test scenarios. |
| test/windows/PluginTests.cpp | Adds new WSLC plugin API tests (success, pull notification, rejection paths). |
| test/windows/Common.h / Common.cpp | Centralizes LoadTestImage and COM error validation helpers for reuse. |
| src/windows/wslcsession/WSLCSessionFactory.h / .cpp | Threads IWSLCPluginNotifier into session initialization. |
| src/windows/wslcsession/WSLCSession.h / .cpp | Stores notifier and emits image-created/image-deleted notifications; passes notifier to containers. |
| src/windows/wslcsession/WSLCContainer.h / .cpp | Emits container-start/container-stopping notifications via the notifier. |
| src/windows/wslc/services/SessionService.cpp | Updates to renamed session-list struct. |
| src/windows/service/inc/wslc.idl | Introduces IWSLCPluginNotifier, changes WSLC session factory/init signatures, renames session list entry struct. |
| src/windows/service/exe/WSLCSessionManager.h / .cpp | Creates and owns plugin notifier per session; triggers plugin session create/stop notifications; adds session lookup for plugin API calls. |
| src/windows/service/exe/ServiceMain.cpp | Loads plugins once at service startup (policy-independent); leaves an unload placeholder comment. |
| src/windows/service/exe/PluginManager.h / .cpp | Extends plugin API vtable with WSLC calls and adds WSLC hook dispatch. |
| src/windows/service/exe/LxssUserSessionFactory.cpp | Switches to global g_pluginManager loaded by service rather than per-policy instantiation. |
| src/windows/service/exe/CMakeLists.txt | Adds WSLC plugin notifier implementation sources/headers to the service build. |
| src/windows/inc/WslPluginApi.h | Defines WSLC plugin hooks + WSLC API call function pointers and related types. |
| msipackage/package.wix.in | Registers the IWSLCPluginNotifier interface for COM proxy/stub. |
| // Creates a new session and returns both the session interface and a service reference. | ||
| HRESULT CreateSession( | ||
| [in] const WSLCSessionInitSettings* Settings, | ||
| [in] IWSLCVirtualMachine* Vm, | ||
| [in, unique] IWSLCPluginNotifier* PluginNotifier, | ||
| [out] IWSLCSession** Session, | ||
| [out] IWSLCSessionReference** ServiceRef); |
| const auto pluginResult = m_pluginNotifier->OnContainerStarted(inspectJson.c_str()); | ||
| if (FAILED(pluginResult)) | ||
| { | ||
| // Forward the COM error message, if available. | ||
| auto comError = wsl::windows::common::wslutil::GetCOMErrorInfo(); | ||
|
|
||
| LOG_HR_MSG(pluginResult, "Plugin rejected start of container '%hs' (0x%x)", m_id.c_str(), pluginResult); | ||
| try | ||
| { | ||
| m_dockerClient.StopContainer(m_id.c_str(), {}, {}); | ||
| } | ||
| CATCH_LOG(); | ||
|
|
||
| if (comError.has_value() && comError->Message) | ||
| { | ||
| THROW_HR_WITH_USER_ERROR(pluginResult, comError->Message.get()); | ||
| } | ||
| else | ||
| { | ||
| THROW_HR(pluginResult); | ||
| } |
benhillis
left a comment
There was a problem hiding this comment.
🤖 AI-generated review (GitHub Copilot CLI, Claude Opus 4.7, run by @benhillis).
This is automated feedback — please use your judgment on every item. I focused on correctness / lifetime / API contract issues and skipped style. Three items from a prior pass were already addressed in 581b849e / af4affd8 (dead UnloadPlugins, nullable notifier contract, path-traversal in WSLCMountFolder) — thanks for those. Remaining items are inline.
Separately: I noted in another context that this design is compatible with #40120 (out-of-process plugin host); the lock-held-across-callbacks point below is the one place where the two PRs would interact and would benefit from a fix in-tree regardless of #40120.
Summary of the Pull Request
This change implements the WSLC plugin API.
Notable design changes:
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed