mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 04:59:38 +08:00
[v2, windows] Handle webview2 process crashes and add DisableWebViewRendererCodeIntegrity flag (#2627)
* Add flag to disable webview RendererCodeIntegrity checks * Handle webview2 process crashes
This commit is contained in:
parent
d249c2207b
commit
3853d2d1bf
@ -12,6 +12,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -428,6 +429,9 @@ func (f *Frontend) setupChromium() {
|
||||
if opts.WebviewGpuIsDisabled {
|
||||
chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu")
|
||||
}
|
||||
if opts.WebviewDisableRendererCodeIntegrity {
|
||||
disableFeatues = append(disableFeatues, "RendererCodeIntegrity")
|
||||
}
|
||||
}
|
||||
|
||||
if len(disableFeatues) > 0 {
|
||||
@ -442,6 +446,37 @@ func (f *Frontend) setupChromium() {
|
||||
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
|
||||
return false
|
||||
}
|
||||
chromium.ProcessFailedCallback = func(sender *edge.ICoreWebView2, args *edge.ICoreWebView2ProcessFailedEventArgs) {
|
||||
kind, err := args.GetProcessFailedKind()
|
||||
if err != nil {
|
||||
f.logger.Error("GetProcessFailedKind: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
f.logger.Error("WebVie2wProcess failed with kind %d", kind)
|
||||
switch kind {
|
||||
case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED:
|
||||
// => The app has to recreate a new WebView to recover from this failure.
|
||||
messages := windows.DefaultMessages()
|
||||
if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.Messages != nil {
|
||||
messages = f.frontendOptions.Windows.Messages
|
||||
}
|
||||
winc.Errorf(f.mainWindow, messages.WebView2ProcessCrash)
|
||||
os.Exit(-1)
|
||||
case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED,
|
||||
edge.COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED:
|
||||
// => A new render process is created automatically and navigated to an error page.
|
||||
// => Make sure that the error page is shown.
|
||||
if !f.hasStarted {
|
||||
// NavgiationCompleted didn't come in, make sure the chromium is shown
|
||||
chromium.Show()
|
||||
}
|
||||
if !f.mainWindow.hasBeenShown {
|
||||
// The window has never been shown, make sure to show it
|
||||
f.ShowWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chromium.Embed(f.mainWindow.Handle())
|
||||
chromium.Resize()
|
||||
|
@ -0,0 +1,49 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_PROCESS_FAILED_KIND uint32
|
||||
|
||||
const (
|
||||
// Indicates that the browser process ended unexpectedly. The WebView
|
||||
// automatically moves to the Closed state. The app has to recreate a new
|
||||
// WebView to recover from this failure.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED = 0
|
||||
|
||||
// Indicates that the main frame's render process ended unexpectedly. A new
|
||||
// render process is created automatically and navigated to an error page.
|
||||
// You can use the `Reload` method to try to reload the page that failed.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED = 1
|
||||
|
||||
// Indicates that the main frame's render process is unresponsive.
|
||||
//
|
||||
// Note that this does not seem to work right now.
|
||||
// Does not fire for simple long running script case, the only related test
|
||||
// SitePerProcessBrowserTest::NoCommitTimeoutForInvisibleWebContents is
|
||||
// disabled.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE = 2
|
||||
|
||||
// Indicates that a frame-only render process ended unexpectedly. The process
|
||||
// exit does not affect the top-level document, only a subset of the
|
||||
// subframes within it. The content in these frames is replaced with an error
|
||||
// page in the frame.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED = 3
|
||||
|
||||
// Indicates that a utility process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED = 4
|
||||
|
||||
// Indicates that a sandbox helper process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED = 5
|
||||
|
||||
// Indicates that the GPU process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED = 6
|
||||
|
||||
// Indicates that a PPAPI plugin process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED = 7
|
||||
|
||||
// Indicates that a PPAPI plugin broker process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED = 8
|
||||
|
||||
// Indicates that a process of unspecified kind ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED = 9
|
||||
)
|
@ -0,0 +1,41 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type _ICoreWebView2ProcessFailedEventArgsVtbl struct {
|
||||
_IUnknownVtbl
|
||||
GetProcessFailedKind ComProc
|
||||
}
|
||||
|
||||
type ICoreWebView2ProcessFailedEventArgs struct {
|
||||
vtbl *_ICoreWebView2ProcessFailedEventArgsVtbl
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2ProcessFailedEventArgs) GetProcessFailedKind() (COREWEBVIEW2_PROCESS_FAILED_KIND, error) {
|
||||
kind := COREWEBVIEW2_PROCESS_FAILED_KIND(0xffffffff)
|
||||
hr, _, err := i.vtbl.GetProcessFailedKind.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(&kind)),
|
||||
)
|
||||
|
||||
if windows.Handle(hr) != windows.S_OK {
|
||||
return 0, syscall.Errno(hr)
|
||||
}
|
||||
|
||||
if kind == 0xffffffff {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("unknown error")
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return kind, nil
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type _ICoreWebView2ProcessFailedEventHandlerVtbl struct {
|
||||
_IUnknownVtbl
|
||||
Invoke ComProc
|
||||
}
|
||||
|
||||
type ICoreWebView2ProcessFailedEventHandler struct {
|
||||
vtbl *_ICoreWebView2ProcessFailedEventHandlerVtbl
|
||||
impl _ICoreWebView2ProcessFailedEventHandlerImpl
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2ProcessFailedEventHandler) AddRef() uintptr {
|
||||
return i.AddRef()
|
||||
}
|
||||
func _ICoreWebView2ProcessFailedEventHandlerIUnknownQueryInterface(this *ICoreWebView2ProcessFailedEventHandler, refiid, object uintptr) uintptr {
|
||||
return this.impl.QueryInterface(refiid, object)
|
||||
}
|
||||
|
||||
func _ICoreWebView2ProcessFailedEventHandlerIUnknownAddRef(this *ICoreWebView2ProcessFailedEventHandler) uintptr {
|
||||
return this.impl.AddRef()
|
||||
}
|
||||
|
||||
func _ICoreWebView2ProcessFailedEventHandlerIUnknownRelease(this *ICoreWebView2ProcessFailedEventHandler) uintptr {
|
||||
return this.impl.Release()
|
||||
}
|
||||
|
||||
func _ICoreWebView2ProcessFailedEventHandlerInvoke(this *ICoreWebView2ProcessFailedEventHandler, sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr {
|
||||
return this.impl.ProcessFailed(sender, args)
|
||||
}
|
||||
|
||||
type _ICoreWebView2ProcessFailedEventHandlerImpl interface {
|
||||
_IUnknownImpl
|
||||
ProcessFailed(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr
|
||||
}
|
||||
|
||||
var _ICoreWebView2ProcessFailedEventHandlerFn = _ICoreWebView2ProcessFailedEventHandlerVtbl{
|
||||
_IUnknownVtbl{
|
||||
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownQueryInterface),
|
||||
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownAddRef),
|
||||
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownRelease),
|
||||
},
|
||||
NewComProc(_ICoreWebView2ProcessFailedEventHandlerInvoke),
|
||||
}
|
||||
|
||||
func newICoreWebView2ProcessFailedEventHandler(impl _ICoreWebView2ProcessFailedEventHandlerImpl) *ICoreWebView2ProcessFailedEventHandler {
|
||||
return &ICoreWebView2ProcessFailedEventHandler{
|
||||
vtbl: &_ICoreWebView2ProcessFailedEventHandlerFn,
|
||||
impl: impl,
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ type Chromium struct {
|
||||
webResourceRequested *iCoreWebView2WebResourceRequestedEventHandler
|
||||
acceleratorKeyPressed *ICoreWebView2AcceleratorKeyPressedEventHandler
|
||||
navigationCompleted *ICoreWebView2NavigationCompletedEventHandler
|
||||
processFailed *ICoreWebView2ProcessFailedEventHandler
|
||||
|
||||
environment *ICoreWebView2Environment
|
||||
|
||||
@ -50,6 +51,7 @@ type Chromium struct {
|
||||
MessageCallback func(string)
|
||||
WebResourceRequestedCallback func(request *ICoreWebView2WebResourceRequest, args *ICoreWebView2WebResourceRequestedEventArgs)
|
||||
NavigationCompletedCallback func(sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs)
|
||||
ProcessFailedCallback func(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs)
|
||||
AcceleratorKeyCallback func(uint) bool
|
||||
}
|
||||
|
||||
@ -73,6 +75,7 @@ func NewChromium() *Chromium {
|
||||
e.webResourceRequested = newICoreWebView2WebResourceRequestedEventHandler(e)
|
||||
e.acceleratorKeyPressed = newICoreWebView2AcceleratorKeyPressedEventHandler(e)
|
||||
e.navigationCompleted = newICoreWebView2NavigationCompletedEventHandler(e)
|
||||
e.processFailed = newICoreWebView2ProcessFailedEventHandler(e)
|
||||
e.permissions = make(map[CoreWebView2PermissionKind]CoreWebView2PermissionState)
|
||||
|
||||
return e
|
||||
@ -253,6 +256,11 @@ func (e *Chromium) CreateCoreWebView2ControllerCompleted(res uintptr, controller
|
||||
uintptr(unsafe.Pointer(e.navigationCompleted)),
|
||||
uintptr(unsafe.Pointer(&token)),
|
||||
)
|
||||
e.webview.vtbl.AddProcessFailed.Call(
|
||||
uintptr(unsafe.Pointer(e.webview)),
|
||||
uintptr(unsafe.Pointer(e.processFailed)),
|
||||
uintptr(unsafe.Pointer(&token)),
|
||||
)
|
||||
|
||||
e.controller.AddAcceleratorKeyPressed(e.acceleratorKeyPressed, &token)
|
||||
|
||||
@ -376,6 +384,13 @@ func (e *Chromium) NavigationCompleted(sender *ICoreWebView2, args *ICoreWebView
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *Chromium) ProcessFailed(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr {
|
||||
if e.ProcessFailedCallback != nil {
|
||||
e.ProcessFailedCallback(sender, args)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *Chromium) NotifyParentWindowPositionChanged() error {
|
||||
//It looks like the wndproc function is called before the controller initialization is complete.
|
||||
//Because of this the controller is nil
|
||||
|
@ -478,6 +478,19 @@ func (i *ICoreWebView2) AddNavigationCompleted(eventHandler *ICoreWebView2Naviga
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2) AddProcessFailed(eventHandler *ICoreWebView2ProcessFailedEventHandler, token *_EventRegistrationToken) error {
|
||||
var err error
|
||||
_, _, err = i.vtbl.AddProcessFailed.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(eventHandler)),
|
||||
uintptr(unsafe.Pointer(&token)),
|
||||
)
|
||||
if err != windows.ERROR_SUCCESS {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2) OpenDevToolsWindow() error {
|
||||
var err error
|
||||
_, _, err = i.vtbl.OpenDevToolsWindow.Call(
|
||||
|
@ -13,6 +13,7 @@ type Messages struct {
|
||||
PressOKToInstall string
|
||||
ContactAdmin string
|
||||
InvalidFixedWebview2 string
|
||||
WebView2ProcessCrash string
|
||||
}
|
||||
|
||||
const (
|
||||
@ -102,6 +103,16 @@ type Options struct {
|
||||
|
||||
// WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview
|
||||
WebviewGpuIsDisabled bool
|
||||
|
||||
// WebviewDisableRendererCodeIntegrity disables the `RendererCodeIntegrity` of WebView2. Some Security Endpoint
|
||||
// Protection Software inject themself into the WebView2 with unsigned or wrongly signed dlls, which is not allowed
|
||||
// and will stop the WebView2 processes. Those security software need an update to fix this issue or one can disable
|
||||
// the integrity check with this flag.
|
||||
//
|
||||
// The event viewer log contains `Code Integrity Errors` like mentioned here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2051
|
||||
//
|
||||
// !! Please keep in mind when disabling this feature, this also allows malicious software to inject into the WebView2 !!
|
||||
WebviewDisableRendererCodeIntegrity bool
|
||||
}
|
||||
|
||||
func DefaultMessages() *Messages {
|
||||
@ -116,5 +127,6 @@ func DefaultMessages() *Messages {
|
||||
PressOKToInstall: "Press Ok to install.",
|
||||
ContactAdmin: "The WebView2 runtime is required to run this application. Please contact your system administrator.",
|
||||
InvalidFixedWebview2: "The WebView2 runtime is manually specified, but It is not valid. Check minimum required version and webview2 path.",
|
||||
WebView2ProcessCrash: "The WebView2 process crashed and the application needs to be restarted.",
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Added support for WebKit2GTK 2.40+ on Linux. This brings additional features for the [AssetServer](/docs/reference/options#assetserver), like support for HTTP Request Bodies. The app must be compiled with the Go build tag `webkit2_40` to activate support for this features. This also bumps the minimum requirement of WebKit2GTK to 2.40 for your app. Added by @stffabi in this [PR](https://github.com/wailsapp/wails/pull/2592)
|
||||
- macOS: Added Window menu role with well known shortcuts "Minimize, Full-Screen and Zoom". Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586)
|
||||
- macOS: Added "Hide, Hide Others, Show All“ to appmenu. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586)
|
||||
- Windows: Added flag to disable the WebView2 `RendererCodeIntegrity` checks, please see the comment on the flag for more information. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2627)
|
||||
- Windows: Added handling of WebView2 process crashes, for unrecoverable errors an error message is shown that the app needs to be restarted. If an error occurs that shows a chromium error page, make sure the Window and the WebView2 is visible. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2627)
|
||||
|
||||
### Changed
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user