refactor: do not pass a DesktopMediaList* to DesktopCapturer::OnListReady()
The list pointer was being used as a proxy for its type, so just pass
the type instead. This solves a lifecycle issue occurring in CI where
the callack can outlive the DesktopMediaList.
Sample error log:
[48471:0428/193441.269750:FATAL:base/allocator/partition_alloc_support.cc:798] Detected dangling raw_ptr in unretained with id=0x0000013c02e14378:
Task trace:
0 Electron Framework 0x000000012283a0ba electron::api::DesktopCapturer::ListObserver::MaybeNotifyReady() + 170
1 Electron Framework 0x0000000133246dc5 NativeDesktopMediaList::Worker::OnRecurrentCaptureResult(webrtc::DesktopCapturer::Result, std::__Cr::unique_ptr<webrtc::DesktopFrame, std::__Cr::default_delete<webrtc::DesktopFrame>>, long) + 357
2 Electron Framework 0x000000013328dbcf (anonymous namespace)::ScreenshotManagerCapturer::OnRecurrentCaptureTimer() + 1343
Stack trace:
0 Electron Framework 0x000000012ade42f2 base::debug::CollectStackTrace(base::span<void const*, 18446744073709551615ul, void const**>) + 18
1 Electron Framework 0x000000012add00e1 base::debug::StackTrace::StackTrace(unsigned long) + 225
2 Electron Framework 0x000000012ade978a base::allocator::UnretainedDanglingRawPtrDetectedCrash(unsigned long) + 90
3 Electron Framework 0x000000012ae437f7 base::internal::RawPtrBackupRefImpl<true>::ReportIfDanglingInternal(unsigned long) + 391
* fix: preserve mouse hook handle when UnhookWindowsHookEx fails
NativeWindowViews::SetForwardMouseMessages() installs a low-level mouse
hook when mouse forwarding begins and unhooks it once no window needs
forwarding. The previous code reset the shared `mouse_hook_` handle to
`nullptr` unconditionally after calling UnhookWindowsHookEx, even when
the unhook call failed.
When unhooking fails, the hook is still installed in the system. Because
`mouse_hook_` is nulled out anyway, the next call to
SetForwardMouseMessages(true) evaluates `if (!mouse_hook_)` as true and
installs a second, duplicate hook via SetWindowsHookEx, so every mouse
message is processed by MouseHookProc multiple times.
Check the return value of UnhookWindowsHookEx and only null the handle
on success. When the call fails, leave `mouse_hook_` pointing at the
existing hook so the next activation reuses it rather than stacking a
new one on top, and log the failure via PLOG to surface the underlying
Windows error.
Fixes: #51064
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
* fix: clear invalid mouse hook handles
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
---------
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
feat: add http cache support to requests from utility process
Add `session` and `partition` options to `utilityProcess.fork()` to
allow utility processes to use a session-specific network context
instead of the system network context. This enables HTTP caching,
cookie isolation, and webRequest interception for utility process
network requests.
When `respondToAuthRequestsFromMainProcess` is true and a session is
provided, HTTP 401/407 auth challenges now emit a `login` event on
the UtilityProcess instance rather than on `app`. Without a session,
auth challenges continue to emit on `app` for backward compatibility.
* feat: support WebAuthn Touch ID platform authenticator on macOS
Adds `app.configureWebAuthn({ touchID: { keychainAccessGroup } })` to enable
the Secure Enclave platform authenticator for `navigator.credentials`.
Credentials are stored under the app-supplied keychain access group with a
per-session metadata secret that is generated on first use and persisted in
prefs.
Also introduces `ElectronAuthenticatorRequestClientDelegate` and wires it via
`ContentBrowserClient::GetWebAuthenticationRequestDelegate()` so that
discoverable-credential `get()` calls with multiple matches emit a new
`select-webauthn-account` session event instead of DCHECK-failing in the base
delegate. If no listener is registered (or the callback is invoked with no
credential), the request is cancelled with NotAllowedError rather than
silently auto-selecting.
Tests use the DevTools virtual authenticator so the account-selection flow is
exercised in CI without entitlements or real hardware.
* fix: register request delegate as FidoRequestHandlerBase observer
The base AuthenticatorRequestClientDelegate::StartObserving() is a no-op, so
observer() on the request handler stayed null. MakeCredentialRequestHandler::
SpecializeRequestForAuthenticator dereferences observer()->SupportsPIN() when
residentKey is 'preferred', crashing with SEGV when a real FIDO2 HID key is
dispatched.
Override StartObserving/StopObserving to register via a ScopedObservation like
ChromeAuthenticatorRequestDelegate does. Added a virtual-authenticator
regression test for create() with residentKey: 'preferred'.
* chore: update copyright attribution for new webauthn files
* fix: address review feedback on webauthn account-select event
- Encode credentialId and userHandle as URL-safe base64 without padding so
the values match PublicKeyCredential.id from navigator.credentials.get()
byte-for-byte; tests now assert the equality rather than transcoding.
- Cancel the pending request when the listener invokes the callback with a
credentialId that does not match any account, instead of leaving the
request hanging while the listener retries. The TypeError still surfaces
so the misuse remains visible to the developer.
- DCHECK that the Touch ID config helpers run on the UI thread, encoding
the threading invariant the read-then-write metadata-secret pref relies
on.
* fix: oxfmt formatting in webauthn spec
* fix: use out-param form of base::Base64UrlEncode
* fix: silently cancel webauthn account select on unknown credentialId
Throwing back into the listener bubbles up as an unhandled exception in
the main process. Match the no-args branch exactly so the listener sees a
single consistent failure mode (cancel + NotAllowedError) whether it
declines deliberately or by mistake.
Remove our implementation of the scripting api and use upstream's
version. It was recently moved to `extensions/` by
https://chromium-review.googlesource.com/c/chromium/src/+/7784831,
so we link it directly.
Update `ElectronExtensionsBrowserClient` to overrides `IsValidTabId()`
and `GetScriptExecutorForTab()` to provide tab validation and
script-executor hooks.
Remove now-redundant local copy of `scripting.idl`.
Upstream now provides everything we used this for.
Updated breaking-changes.md to document a CSS matching difference.
Co-authored-by: GitHub Copilot <github-copilot[bot]@users.noreply.github.com>
* fix: use the non-pass-through path for Fetch-intercepted requests
* Revert "fix: use the non-pass-through path for Fetch-intercepted requests"
This reverts commit 395fb8bb8c.
* fix: use no-op header client for Fetch-intercepted requests
* fix: bring back `DCHECK` that was prematurely removed
* style: reformat code
Replace ClientFrameViewLinux with electron::NativeFrameViewLinux, a thin
wrapper over views::NativeFrameViewLinux. The wrapper provides Electron
integration, such as draggable region support in NonClientHitTest,
and adapting to Electron's sizing conventions.
ElectronDesktopWindowTreeHostLinux and NativeWindowViews now use
FrameViewLinux to query frame geometry and update window states in
addition to LinuxFrameLayout.
Assisted-By: Claude Opus 4.6, Claude Code
* fix: validate header name and value in webRequest.onBeforeSendHeaders
Chromium's net::HttpRequestHeaders::SetHeader() uses CHECK() to enforce
valid header names and values, which causes a fatal crash if the caller
passes invalid strings. When users modify requestHeaders in the
onBeforeSendHeaders callback with invalid header names (e.g. containing
spaces) or invalid header values (e.g. containing CRLF), the
gin::Converter<net::HttpRequestHeaders>::FromV8() calls SetHeader()
directly, triggering the CHECK and crashing the process.
This change adds pre-validation using net::HttpUtil::IsValidHeaderName()
and net::HttpUtil::IsValidHeaderValue() before calling SetHeader(),
silently skipping invalid headers instead of crashing.
* Update shell/common/gin_converters/net_converter.cc
Co-authored-by: Charles Kerr <charles@charleskerr.com>
* Update spec/api-web-request-spec.ts
Co-authored-by: Charles Kerr <charles@charleskerr.com>
* fix: lint
---------
Co-authored-by: Charles Kerr <charles@charleskerr.com>
* chore: bump chromium in DEPS to 149.0.7812.0
* chore: update patches (trivial only)
Co-Authored-By: GitHub Copilot <copilot@github.com>
* fix(patch): declare abort in Node builtin_info
Node's builtin_info.cc uses abort() but doesn't include <cstdlib>.
It used to pick up the declaration by a transitive include, but
that broke in this libc++ roll.
This patch can be removed after it's been upstreamed to Node.js.
* SharedWorker: Enforce same-origin check for IWA and Extensions
Xref: https://chromium-review.googlesource.com/c/chromium/src/+/7784632
* chore: node script/gen-libc++-filenames.js
---------
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
* chore: bump chromium in DEPS to 149.0.7809.0
* chore: bump chromium in DEPS to 149.0.7810.2
* chore: bump chromium in DEPS to 149.0.7811.0
* chore: revert [OSCrypt] Remove sync backend
Electron still depends on the synchronous os_crypt API.
Revert upstream CL 7765593 until migration to async is complete.
Followup: https://github.com/electron/electron/issues/51301
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7765593
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* fix(patch): UAF fix in OnMouseRange
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7780978
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* fix(patch): kGlicTrustFirstOnboarding references removed
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7773143
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* chore: update patches (trivial only)
* fix(patch): SubtlePassKey and profile methods updates
Re-add OSCryptImpl as a friend of crypto::SubtlePassKey (removed by
https://chromium-review.googlesource.com/c/chromium/src/+/7759877)
since Electron still uses the sync backend.
Followup: https://github.com/electron/electron/issues/51301
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* fix(patch): exclude upstream scripting API
CL 7784831 moved the Scripting API from //chrome to //extensions,
which caused duplicate symbols with Electron's own implementation.
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7784831
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* 7748618: [extensions] Move MimeHandlerStreamManager
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7748618
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* 7713176: Move GetURLLoaderFactory from Profile to BrowserContext
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7713176
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* 7755340: Refactor CaptureHandle storage to PageImpl
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7755340
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* 7765593: [OSCrypt] Remove sync backend
No replacement code is needed: Electron already uses the async path.
CookieEncryptionProviderImpl (backed by OSCryptAsync) supplies
encryption to the network service via the cookie_encryption_provider
NetworkContext param, making SetEncryptionKey redundant.
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7765593
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* chore: stop disabling enterprise_cloud_content_analysis
CL 7757742 moved cloud_content_scanning from unconditional deps into
a conditional block gated on enterprise_cloud_content_analysis,
safe_browsing_mode, or is_android. Since Electron sets
safe_browsing_mode = 1, the dep is still included regardless, but
explicitly overriding enterprise_cloud_content_analysis to false now
causes other targets (e.g. chrome/browser/download) to omit enterprise
connectors code that the rest of the build expects to find.
It is simpler to let it default to true than to patch around it.
Electron does not use this feature — our PerformContentAnalysisIfNeeded
is a no-op passthrough that skips straight to NotifyListenerAndEnd.
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7757742
Co-Authored-By: GitHub Copilot (Claude Opus 4.6)
* chore: update patches (trivial only)
* chore: update filenames.libcxx.gni
* chore: add GPU libraries to chromedriver zip manifests
Chromedriver now has transitive runtime dependencies on libEGL,
libGLESv2, and vk_swiftshader on macOS and Windows. These are
transitive deps pulled through chromedriver_server's dependency
on //mojo/core/embedder and //net.
* fix: add MicrotasksScope for worker exit emit in ContextWillDestroy
a39108c5a4 (#47244) replaced gin_helper::EmitEvent with a direct
`v8::Function::Call()` in `WebWorkerObserver::ContextWillDestroy`
to avoid re-entering the microtask checkpoint during worker teardown.
V8 `DCHECK()`s that a policy is set. Under the old code path, this
happened with a node::CallbackScope. Under the new code path, it's
possible for a policy to not be set, causing that `DCHECK()` to fail.
This PR copies a39108c5a4's changes in `ShareEnvironmentWithContext()`:
it explicitly adds a `kDoNotRunMicrotasks` scope.
* chore: override CreateChromeMetadataPacketRecorder in tracing delegate
https://chromium-review.googlesource.com/c/chromium/src/+/7770189
product-version, os-name, and channel metadata from the legacy
ChromeEventBundle path to a new ChromeMetadataPacket recorder callback.
Override the new TracingDelegate virtual so Electron still emits these fields.
---------
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Added Browser::Get()->is_ready() guards to all contentTracing API functions (startRecording, stopRecording, getCategories, getTraceBufferUsage) so they reject their returned Promises with a clear error message instead of crashing when called before app.whenReady().
Added a crash-case fixture test that validates all four APIs reject properly before readiness and work normally after.
* perf: use GIO for Browser::IsDefaultProtocolClient() on Linux
perf: use GIO for Browser::SetAsDefaultProtocolClient() on Linux
Similar to 7d6227a, this speeds up app.isDefaultProtocolClient()
by using the GIO library instead of spawning a shell command to
get the info.
* feat: log errors if g_app_info_set_as_default_for_type() fails
a39108c5a4 (#47244) replaced gin_helper::EmitEvent with a direct
`v8::Function::Call()` in `WebWorkerObserver::ContextWillDestroy`
to avoid re-entering the microtask checkpoint during worker teardown.
V8 `DCHECK()`s that a policy is set. Under the old code path, this
happened with a node::CallbackScope. Under the new code path, it's
possible for a policy to not be set, causing that `DCHECK()` to fail.
This PR copies a39108c5a4's changes in `ShareEnvironmentWithContext()`:
it explicitly adds a `kDoNotRunMicrotasks` scope.
* fix: dispatch toast action and reply events from WinRT activation path
ToastEventHandler::Invoke previously returned S_OK without dispatching
whenever the activation arguments looked structured (type=action,
type=reply, or contained &tag=), on the assumption that the COM
INotificationActivationCallback::Activate path would deliver the event
instead. That assumption only holds when Windows actually invokes the
COM activator — which it does for MSIX-packaged apps launched cold, and
for unpackaged apps with a properly-registered CLSID when the app is
not already running. For non-MSIX apps with activationType="foreground"
while the app is running (the common case), Windows raises only the
in-process WinRT Activated event, so action and reply were silently
dropped.
Dispatch structured activations through the same HandleToastActivation
the COM path uses. User input (reply text, selection values) is pulled
from IToastActivatedEventArgs2::UserInput, which carries the data the
COM callback would otherwise have received via
NOTIFICATION_USER_INPUT_DATA.
Also drop the &tag= term from the structured-args check. Plain clicks
in Electron-generated XML don't carry tag=, and a custom toast_xml that
puts tag= on a click argument should now dispatch as a click rather
than being silently dropped.
* fix: release HSTRING out-params from toast activation
Fix a crash in AutofillPopupView::Show() when the popup
tried to show itself after the parent's native view had
already gone away during teardown.
2026-04-23T20:44:32.7015810Z Received signal 11 SEGV_ACCERR 000000000160
2026-04-23T20:44:32.9322010Z 4 Electron Framework ... views::Widget::IsVisible() const + 28
2026-04-23T20:44:32.9528810Z 6 Electron Framework ... electron::AutofillPopupView::Show() + 200
2026-04-23T20:44:32.9632090Z 7 Electron Framework ... electron::AutofillPopup::CreateView(...) + 1380
2026-04-23T20:44:32.9749770Z 8 Electron Framework ... electron::AutofillDriver::ShowAutofillPopup(...) + 736
2026-04-23T20:44:33.0015220Z ✗ Electron tests failed with kill signal SIGSEGV.
perf: use GIO instead of xdg-mime for app.getApplicationNameForProtocol()
The Linux impl of app.getApplicationNameForProtocol() now uses
`g_app_info_get_default_for_uri_scheme()` + `g_app_info_get_display_name()`
instead of spawning a call to the `xdg-mime` shell command.
Clean up the related tests: remove the xdg-mime mock.
* chore: remove calls to DeprecatedLayoutImmediately
Replace the calls to `DeprecatedLayoutImmediately` that have test
coverage.
- The docked DevTools test added last week covers the three calls in IWCV.
- api-web-contents-view-spec covers the calls from NativeWindow{Views,Mac}.
There are a couple of remaining calls that don't have test coverage yet.
I'll get to them in a followup.
* test: handle both sync or microtask layout
* refactor: add a FlushPendingRootLayout() helper
fix: ignore draggable regions in hidden WebContentsView
Hidden child WebContentsViews were still contributing their draggable
regions to the parent window's non-client hit test, so clicks in the
area where a hidden view's draggable element would render still dragged
the window. Early-return HTNOWHERE when the view is not visible.
After #49428 made `NativeWindowViews::CanResize()` return `resizable_`
for frameless windows (instead of `resizable_ && thick_frame_`),
`HWNDMessageHandler::SizeConstraintsChanged()` started adding
`WS_THICKFRAME` to the window style whenever `CanResize()` reported true.
`WS_THICKFRAME` is incompatible with layered (translucent) windows and
destroys their transparency.
`SetContentSizeConstraints` already guards against this by skipping
`OnSizeConstraintsChanged()` when `!thick_frame_`. `SetResizable` did
not, so toggling resizability on a transparent window (e.g.
`setResizable(false)` then `setResizable(true)`) caused the Chromium
path to add `WS_THICKFRAME` and strip transparency.
Apply the same guard in `SetResizable`. Min/max constraints are still
enforced — Chromium reads them from the widget delegate on every
`WM_GETMINMAXINFO`, independent of `SizeConstraintsChanged()`.
On ARM64 Windows, UnregisterSuspendResumeNotification (user32) forwards
to PowerUnregisterSuspendResumeNotification (powrprof), which treats the
HPOWERNOTIFY handle as a pointer and dereferences it. The user32 API
returns an opaque handle, not a pointer-backed allocation, causing an
access violation at shutdown.
Add crash keys (pm-reg-handle, pm-reg-memstate, pm-unreg-memstate) to
capture
- The handle value
- VirtualQuery memory state at both registration and unregistration
If the handle address is MEM_FREE, it confirms the handle is an opaque
index and powrprof is incorrectly dereferencing it. If MEM_COMMIT, it
would indicate a use-after-free of the underlying allocation.
Refs https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/powerbase/nf-powerbase-powerunregistersuspendresumenotification.md
* ci: run clang-tidy on macOS and Windows
* ci: copy framework headers for clang-tidy on macOS
* chore: exclude electron_smooth_round_rect.cc in CI
* chore: C-style casts are discouraged; use static_cast [google-readability-casting]
* chore: add extra args on Windows to clear out warnings
* ci: fix for macOS --remote-build none
* fix: ensure corsEnabled: false protocol handlers do not work across protocols
Subresource requests for registered custom protocols are routed to
ElectronURLLoaderFactory via the renderer's per-scheme URLLoaderFactoryBundle
entry, which bypasses the network service's CorsURLLoaderFactory. This meant a
cross-origin page could fetch() a scheme registered with {supportFetchAPI: true}
and read the response body even when {corsEnabled: true} was not set.
Replicate CorsURLLoader::StartRequest's kCorsDisabledScheme gate in
ElectronURLLoaderFactory::CreateLoaderAndStart so cross-origin mode=cors
requests to such schemes fail before the JS handler runs, and tag cross-origin
mode=no-cors responses as opaque so the body is not script-readable while <img>
and similar subresource loads continue to work.
Re-enable the long-disabled "disallows CORS and fetch requests when only
supportFetchAPI is specified" test, add coverage for the opaque/no-cors,
same-origin, handler-not-invoked, corsEnabled-unaffected and net.fetch-unaffected
cases, and migrate spec helpers that were exercising a {supportFetchAPI: true}
scheme cross-origin to a corsEnabled scheme.
* chore: oxfmt
* fix: intermittent CI failure is-not-alwaysOnTop
Ensure that the `always-on-top-changed` event always fires with the
right 'alwaysOnTop' boolean, regardless of interaction between
SetZOrderLevel() and MoveBehindTaskBarIfNeeded(). We know what the
value will be when all of the HWND events settle, so use that value.
* test: temporary commit to torture-test the new change with 1000 iterations
* test: keep eventually-becomes-consistent test but do not loop 1000 times
* feat: add `Notification.getHistory()` static method (macOS)
Add `Notification.getHistory()` which returns a `Promise<Notification[]>`
of all delivered notifications still present in Notification Center.
Each returned Notification is a live object connected to the corresponding
delivered notification — interaction events (click, reply, action, close)
will fire on these objects, enabling apps to re-attach event handlers after
a restart.
Key implementation details:
- Queries UNUserNotificationCenter's getDeliveredNotifications API
- Creates live Notification objects with populated id, groupId, title,
subtitle, and body properties from what macOS provides
- Registers each object with the presenter via Restore() so the
NotificationCenterDelegate routes events correctly
- Restored notifications use is_restored_ flag to prevent removal from
Notification Center when the JS object is garbage collected
- Requires code-signed builds (unsigned builds resolve with empty array)
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
* test: fix typecheck
* fix: avoid dangling presenter pointer in GetHistory callback
* fix: document show() behavior
Notifications returned by getHistory() now set is_restored_ so that Dismiss() skips removal from Notification Center on GC. Calling show() on a restored notification removes the original from NC and posts a new one.
* fix: address code review feedback
* test: fix oxfmt linting
* docs: update docs/api/notification.md
Co-authored-by: Erick Zhao <erick@hotmail.ca>
---------
Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
fix: prevent use-after-free when destroying guest WebContents during event emission
Multiple event emission sites in WebContents destroy the underlying C++
object via a JavaScript event handler calling webContents.destroy(), then
continue to dereference the freed `this` pointer. This is exploitable
through <webview> guest WebContents because Destroy() calls `delete this`
synchronously for guests, unlike non-guests which safely defer deletion.
The fix has two layers:
1. A new `is_emitting_event_` flag is checked in Destroy() — when true,
guest deletion is deferred to a posted task instead of executing
synchronously. This is separate from `is_safe_to_delete_` (which
gates LoadURL re-entrancy) to avoid rejecting legitimate loadURL
calls from event handlers.
2. AutoReset<bool> guards on `is_emitting_event_` are added to
CloseContents, RenderViewDeleted, DidFinishNavigation, and
SetContentsBounds, preventing synchronous destruction while their
Emit() calls are on the stack.
Destroy() now requires both `is_safe_to_delete_` (navigation re-entrancy)
and `!is_emitting_event_` (event emission) to allow synchronous guest
deletion. The existing AutoReset guards on `is_safe_to_delete_` in
DidStartNavigation, DidRedirectNavigation, and ReadyToCommitNavigation
are also now effective for guests.
* fix: UAF in api::UtilityProcessWrapper
Detach the wrapper from ServiceProcessHost during termination instead
of waiting for destruction. Add a regression test that forces GC.
This fixes a UAF error reported by ASAN: the wrapper lost its last JS
reference and become collectible after emitting exit *but* before it
had been removed from the global observer list.
UtilityProcessWrapper is now cppgc-managed as of b9e462f397, but its
ServiceProcessHost observer cleanup still depended on destructor-time
teardown.
* fixup! fix: UAF in api::UtilityProcessWrapper
fix: much better cleanup from Deepak code review
The PDF viewer's "save with changes" feature uses
`window.showSaveFilePicker()`, but the PDF extension runs in a
cross-origin iframe (chrome-extension:// inside the app's origin).
Chromium's File System Access API blocks cross-origin subframes from
showing file pickers unless the embedder explicitly allows them via
`ContentClient::IsFilePickerAllowedForCrossOriginSubframe()`.
Chrome overrides this in `ChromeContentClient` to allowlist the PDF
extension origin, but Electron never did — so the picker was always
blocked with a SecurityError.
This adds the same override to `ElectronContentClient`, allowing the
built-in PDF extension origin to bypass the cross-origin check.
* refactor: migrate electron::api::GlobalShortcut to cppgc
* refactor: lazy-create electron::api::GlobalShortcut
copy the lazy-create idom used by electron::api::Screen
* refactor: use gin::WeakCellFactory in GlobalCallbacks
* fix: make a copy of `callback` before running it
safeguard against the callback changing the map, invalidating `cb`
* chore: reduce unnecessary diffs with main
* fixup! refactor: use gin::WeakCellFactory in GlobalCallbacks
fix: must Trace() the weak cell factory
* fix: destruction order
- Setup isolate dispose observer to run destruction sequences
and remove self persistent reference
- Skip NOTREACHED check during destruction, it can happen
as a result of plaform listeners scheduling callbacks when Unregister is invoked.
- Fix the order of unregistration in GlobalShortcut::Unregister
- Add GlobalShortcut::UnregisterAllInternal to avoid any callsites
that can re-enter V8
* fix: crash during gc from incorrect cppgc object headers
* chore: update patches
* chore: cleanup
* chore: fix lint
---------
Co-authored-by: deepak1556 <hop2deep@gmail.com>
refactor: use StartUpdating in desktopCapturer
Replace the one-shot Update() callback model with the continuous
StartUpdating() observer model for NativeDesktopMediaList.
Fixes a macOS DCHECK(can_refresh()) crash in UpdateSourceThumbnail(),
where ScreenCaptureKit's recurrent thumbnail capturer would post
UpdateSourceThumbnail callbacks after the one-shot refresh_callback_
had been consumed. Now, can_refresh() is always true because
refresh_callback_ is repopulated via ScheduleNextRefresh().
Each capturer (window, screen) gets its own ListObserver that tracks
readiness via OnSourceAdded and OnSourceThumbnailChanged events.
Once a list has both sources and thumbnails (or thumbnails aren't
requested), its data is snapshotted and the capturer checks if all
requested types are ready before resolving to JS.
Also remove the "skip_next_refresh_" Chromium patch, which was a
workaround for the timing mismatch between the one-shot Update()
model and ScreenCaptureKit's asynchronous thumbnail delivery.
refactor: simplify state logic in DesktopCapturer