Skip to content

fix: avoid UIA teardown hang on browser exit#277

Merged
Bush2021 merged 1 commit into
Bush2021:mainfrom
ziboh:fix/uia-session-shutdown
Jul 17, 2026
Merged

fix: avoid UIA teardown hang on browser exit#277
Bush2021 merged 1 commit into
Bush2021:mainfrom
ziboh:fix/uia-session-shutdown

Conversation

@ziboh

@ziboh ziboh commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Prevent Chrome from remaining in the background after all browser windows are closed.

Root cause

The thread-local UiaSession destructor releases UI Automation proxies during the injected DLL's TLS teardown.

When this cleanup runs on Chrome's UI thread, releasing these apartment-bound COM proxies can block indefinitely during process shutdown, leaving Chrome processes in the background.

Regression

The regression was introduced by commit 8b22f8d, which migrated tab and
bookmark handling from IA2 to UI Automation.

On Chrome 150.0.7871.129, the parent commit f7d23b3 exited normally after
the affected interaction, while 8b22f8d still had Chrome processes running
after 15 seconds.

The first affected prerelease was 1.16.0-alpha.1, and the first affected
stable release was 1.16.0.

Fix

Keep the UiaSession isolated per thread, but intentionally give it process lifetime by storing it behind a thread-local pointer.

This prevents UIA and COM cleanup from running during the injected DLL's TLS teardown. The operating system reclaims the process resources when Chrome terminates.

Trade-off

This intentionally skips per-thread UIA and COM teardown.

The UIA session is currently instantiated only on Chrome's browser UI thread through thread-specific input hooks, so the retained state is bounded to one session per browser process.

This project loads version.dll for the lifetime of the browser process and does not support unloading it while Chrome is still running.

Testing

  • Built successfully with xmake build -y.
  • A/B tested with a clean x64 Chrome 150.0.7871.129 installation.
  • Used a fresh user-data directory, disabled extensions and component updates, and applied the minimal configuration from [Bug] chrome关闭后有后台残留 #271.
  • Explicitly initialized the UIA path by opening two tabs and double-clicking one tab before closing the browser.
  • With Chrome++ 1.18.0, Chrome processes were still present after 15 seconds.
  • With this patch, Chrome exited completely in 226 ms, 244 ms, and 232 ms across three successful runs.
  • Also verified the patch with clean Chrome 150.0.7871.125; Chrome exited completely in 254 ms after the same UIA trigger.

Related to #271.

@Bush2021

Copy link
Copy Markdown
Owner

Thanks for the detailed writeup. I followed your exact steps but can't reproduce the residue on my machine. I understand this type of issues are often hard to reproduce, but I still want to pin down the root cause before merging. Could you grab a dump of a stuck chrome.exe and share the main thread's call stack?

And just to make sure, do you disable "Continue running background apps when Google Chrome is closed" in chrome://settings/system?

@ziboh

ziboh commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

I reproduced this with a fresh portable Chrome 150.0.7871.129 installation and a fresh user-data directory, using the pre-fix UIA build from 8b22f8d (Chrome++ 1.15.2).

After opening two tabs, double-clicking one tab to initialize the UIA path, and closing all browser windows, two chrome.exe processes remained. I captured a full dump of the browser process.

The main thread (CrBrowserMain) is blocked during process shutdown in a cross-apartment COM release:

win32u!NtUserMsgWaitForMultipleObjectsEx
combase!CCliModalLoop::BlockFn
combase!ClassicSTAThreadDispatchCrossApartmentCall
...
combase!RemoteReleaseRifRefHelper
combase!CStdMarshal::Disconnect
combase!CGIPTable::_RevokeInterfaceFromGlobal
uiautomationcore!BlockingCoreDispatcher::FinalRelease
uiautomationcore!CUIAutomation7::~CUIAutomation7
uiautomationcore!CUIAutomation7::Release
version.dll
ntdll!ImageTlsCallbackCaller
ntdll!LdrpCallTlsInitializers
ntdll!LdrShutdownProcess

This confirms the process is hanging while the thread-local UIA session is torn down from the injected DLL's TLS destructor. The dump is approximately 649 MB; I can provide it separately.

chrome-plus-1.15.2-stack.txt

@Bush2021

Copy link
Copy Markdown
Owner

Can you try disabling "Continue running background apps when Google Chrome is closed" in chrome://settings/system?

@ziboh

ziboh commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Yes. I confirmed that “Continue running background apps when Google Chrome is closed” is disabled in chrome://settings/system.

I reproduced the same residual chrome.exe processes after closing the fresh portable Chrome profile.

@Bush2021
Bush2021 merged commit f9d662b into Bush2021:main Jul 17, 2026
@Bush2021

Copy link
Copy Markdown
Owner

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants