Skip to content

Commit df7ae8c

Browse files
committed
WIP: Edge Browser Scheduled Job timeout
1 parent 50031ab commit df7ae8c

File tree

1 file changed

+94
-24
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser

1 file changed

+94
-24
lines changed

bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,33 @@ class WebViewWrapper {
294294
private ICoreWebView2_11 webView_11;
295295
private ICoreWebView2_12 webView_12;
296296
private ICoreWebView2_13 webView_13;
297+
298+
void releaseWebViews() {
299+
if(webView != null) {
300+
webView.Release();
301+
}
302+
if(webView_2 != null) {
303+
webView_2.Release();
304+
}
305+
if(webView_10 != null) {
306+
webView_10.Release();
307+
}
308+
if(webView_11 != null) {
309+
webView_11.Release();
310+
}
311+
if(webView_12 != null) {
312+
webView_12.Release();
313+
}
314+
if(webView_13 != null) {
315+
webView_13.Release();
316+
}
317+
}
297318
}
298319

299320
class WebViewProvider {
300321

301-
private CompletableFuture<WebViewWrapper> webViewWrapperFuture = new CompletableFuture<>();
302-
private CompletableFuture<Void> lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});;
322+
private CompletableFuture<WebViewWrapper> webViewWrapperFuture;
323+
private CompletableFuture<Void> lastWebViewTask;
303324

304325
ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
305326
long[] ppv = new long[1];
@@ -312,14 +333,38 @@ ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
312333
webViewWrapper.webView_11 = initializeWebView_11(webView);
313334
webViewWrapper.webView_12 = initializeWebView_12(webView);
314335
webViewWrapper.webView_13= initializeWebView_13(webView);
315-
webViewWrapperFuture.complete(webViewWrapper);
336+
boolean success = webViewWrapperFuture.complete(webViewWrapper);
337+
// Release the webViews if the webViewWrapperFuture has already timed out and completed exceptionally
338+
if(!success && webViewWrapperFuture.isCompletedExceptionally()) {
339+
webViewWrapper.releaseWebViews();
340+
return null;
341+
}
316342
return webView;
317343
}
318344

345+
void initializeWebViewFutureWithTimeOut() {
346+
if(webViewWrapperFuture != null) {
347+
return;
348+
}
349+
webViewWrapperFuture = new CompletableFuture<>();
350+
webViewWrapperFuture.orTimeout(3, TimeUnit.SECONDS).exceptionallyAsync(exception -> {
351+
// Needs to be executed on the display thread since the exceptionally spawns a different thread
352+
replaceWithErrorLabel();
353+
// Throw exception on the Display thread directly to prevent CompletableFuture
354+
// to wrap the exception and throw it silently
355+
if (exception instanceof RuntimeException runtimeEx) {
356+
browser.getDisplay().getRuntimeExceptionHandler().accept(runtimeEx);
357+
} else if (exception instanceof Error er) {
358+
browser.getDisplay().getErrorHandler().accept(er);
359+
}
360+
return null;
361+
}, browser.getDisplay());
362+
lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});
363+
}
364+
319365
private void abortInitialization() {
320366
webViewWrapperFuture.cancel(true);
321367
}
322-
323368
private ICoreWebView2_2 initializeWebView_2(ICoreWebView2 webView) {
324369
long[] ppv = new long[1];
325370
int hr = webView.QueryInterface(COM.IID_ICoreWebView2_2, ppv);
@@ -365,6 +410,11 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
365410
return null;
366411
}
367412

413+
void releaseWebView() {
414+
waitForFutureToFinish(webViewWrapperFuture);
415+
webViewWrapperFuture.join().releaseWebViews();
416+
}
417+
368418
ICoreWebView2 getWebView(boolean waitForPendingWebviewTasksToFinish) {
369419
if(waitForPendingWebviewTasksToFinish) {
370420
waitForFutureToFinish(lastWebViewTask);
@@ -500,6 +550,10 @@ void checkDeadlock() {
500550
}
501551
}
502552

553+
void errorTimedOut(Throwable throwable) {
554+
SWT.error(SWT.ERROR_UNSPECIFIED, throwable, "Edge Browser initialization timed out");
555+
}
556+
503557
WebViewEnvironment createEnvironment() {
504558
Display display = Display.getCurrent();
505559
WebViewEnvironment existingEnvironment = webViewEnvironments.get(display);
@@ -571,8 +625,18 @@ private String getDataDir(Display display) {
571625
return dataDir;
572626
}
573627

628+
private void replaceWithErrorLabel() {
629+
Label errorLabel = new Label(browser.getParent(), SWT.WRAP);
630+
errorLabel.setForeground(browser.getDisplay().getSystemColor(SWT.COLOR_RED));
631+
errorLabel.setText("Edge browser initialization failed");
632+
errorLabel.setLocation(0, 0);
633+
errorLabel.setSize(browser.getSize());
634+
browser.setVisible(false);
635+
}
636+
574637
@Override
575638
public void create(Composite parent, int style) {
639+
webViewProvider.initializeWebViewFutureWithTimeOut();
576640
createInstance(0);
577641
}
578642

@@ -587,38 +651,34 @@ private void createInstance(int previousAttempts) {
587651
}
588652

589653
private IUnknown createControllerInitializationCallback(int previousAttempts) {
590-
Runnable initializationRollback = () -> {
591-
webViewProvider.abortInitialization();
592-
if (environment2 != null) {
593-
environment2.Release();
594-
environment2 = null;
595-
}
596-
containingEnvironment.instances().remove(this);
597-
};
598654
return newCallback((result, pv) -> {
599655
if (browser.isDisposed()) {
600-
initializationRollback.run();
656+
rollbackInitialization();
601657
return COM.S_OK;
602658
}
603659
if (result == OS.HRESULT_FROM_WIN32(OS.ERROR_INVALID_STATE)) {
604-
initializationRollback.run();
660+
rollbackInitialization();
605661
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null,
606-
" Edge instance with same data folder but different environment options already exists");
662+
"Edge Initialization Timed Out");
607663
}
608664
switch ((int) result) {
609665
case COM.S_OK:
610666
new IUnknown(pv).AddRef();
611-
setupBrowser((int) result, pv);
667+
boolean success = setupBrowser((int) result, pv);
668+
if(!success) {
669+
rollbackInitialization();
670+
errorTimedOut(null);
671+
}
612672
break;
613673
case COM.E_WRONG_THREAD:
614-
initializationRollback.run();
674+
rollbackInitialization();
615675
error(SWT.ERROR_THREAD_INVALID_ACCESS, (int) result);
616676
break;
617677
case COM.E_ABORT:
618-
initializationRollback.run();
678+
rollbackInitialization();
619679
break;
620680
default:
621-
initializationRollback.run();
681+
rollbackInitialization();
622682
if (previousAttempts < MAXIMUM_CREATION_RETRIES) {
623683
System.err.println(String.format("Edge initialization failed, retrying (attempt %d / %d)", previousAttempts + 1, MAXIMUM_CREATION_RETRIES));
624684
createInstance(previousAttempts + 1);
@@ -632,10 +692,22 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
632692
});
633693
}
634694

635-
void setupBrowser(int hr, long pv) {
695+
private void rollbackInitialization() {
696+
webViewProvider.abortInitialization();
697+
if (environment2 != null) {
698+
environment2.Release();
699+
environment2 = null;
700+
}
701+
containingEnvironment.instances().remove(this);
702+
}
703+
704+
boolean setupBrowser(int hr, long pv) {
636705
long[] ppv = new long[] {pv};
637706
controller = new ICoreWebView2Controller(ppv[0]);
638707
final ICoreWebView2 webView = webViewProvider.initializeWebView(controller);
708+
if(webView == null) {
709+
return false;
710+
}
639711
webView.get_Settings(ppv);
640712
settings = new ICoreWebView2Settings(ppv[0]);
641713

@@ -735,17 +807,15 @@ void setupBrowser(int hr, long pv) {
735807
if (browser.isFocusControl()) {
736808
browserFocusIn(new Event());
737809
}
810+
return true;
738811
}
739812

740813
void browserDispose(Event event) {
741814
containingEnvironment.instances.remove(this);
742815
webViewProvider.scheduleWebViewTask(() -> {
743-
webViewProvider.getWebView(false).Release();
816+
webViewProvider.releaseWebView();
744817
if (environment2 != null) environment2.Release();
745818
if (settings != null) settings.Release();
746-
if (webViewProvider.isWebView_2Available()) webViewProvider.getWebView_2(false).Release();
747-
if (webViewProvider.isWebView_11Available()) webViewProvider.getWebView_11(false).Release();
748-
if (webViewProvider.isWebView_12Available()) webViewProvider.getWebView_12(false).Release();
749819
if(controller != null) {
750820
// Bug in WebView2. Closing the controller from an event handler results
751821
// in a crash. The fix is to delay the closure with asyncExec.

0 commit comments

Comments
 (0)