Skip to content

Commit 3c7da0e

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

File tree

1 file changed

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

1 file changed

+90
-24
lines changed

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

Lines changed: 90 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,34 @@ 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+
browser.getDisplay().execute(() -> errorTimedOut(exception));
356+
return null;
357+
}, browser.getDisplay());
358+
lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});
359+
}
360+
319361
private void abortInitialization() {
320362
webViewWrapperFuture.cancel(true);
321363
}
322-
323364
private ICoreWebView2_2 initializeWebView_2(ICoreWebView2 webView) {
324365
long[] ppv = new long[1];
325366
int hr = webView.QueryInterface(COM.IID_ICoreWebView2_2, ppv);
@@ -365,6 +406,11 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
365406
return null;
366407
}
367408

409+
void releaseWebView() {
410+
waitForFutureToFinish(webViewWrapperFuture);
411+
webViewWrapperFuture.join().releaseWebViews();
412+
}
413+
368414
ICoreWebView2 getWebView(boolean waitForPendingWebviewTasksToFinish) {
369415
if(waitForPendingWebviewTasksToFinish) {
370416
waitForFutureToFinish(lastWebViewTask);
@@ -500,6 +546,10 @@ void checkDeadlock() {
500546
}
501547
}
502548

549+
void errorTimedOut(Throwable throwable) {
550+
SWT.error(SWT.ERROR_UNSPECIFIED, throwable, "Edge Browser initialization timed out");
551+
}
552+
503553
WebViewEnvironment createEnvironment() {
504554
Display display = Display.getCurrent();
505555
WebViewEnvironment existingEnvironment = webViewEnvironments.get(display);
@@ -571,8 +621,18 @@ private String getDataDir(Display display) {
571621
return dataDir;
572622
}
573623

624+
private void replaceWithErrorLabel() {
625+
Label errorLabel = new Label(browser.getParent(), SWT.WRAP);
626+
errorLabel.setForeground(browser.getDisplay().getSystemColor(SWT.COLOR_RED));
627+
errorLabel.setText("Edge browser initialization failed");
628+
errorLabel.setLocation(0, 0);
629+
errorLabel.setSize(browser.getSize());
630+
browser.setVisible(false);
631+
}
632+
574633
@Override
575634
public void create(Composite parent, int style) {
635+
webViewProvider.initializeWebViewFutureWithTimeOut();
576636
createInstance(0);
577637
}
578638

@@ -587,38 +647,34 @@ private void createInstance(int previousAttempts) {
587647
}
588648

589649
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-
};
598650
return newCallback((result, pv) -> {
599651
if (browser.isDisposed()) {
600-
initializationRollback.run();
652+
rollbackInitialization();
601653
return COM.S_OK;
602654
}
603655
if (result == OS.HRESULT_FROM_WIN32(OS.ERROR_INVALID_STATE)) {
604-
initializationRollback.run();
656+
rollbackInitialization();
605657
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null,
606-
" Edge instance with same data folder but different environment options already exists");
658+
"Edge Initialization Timed Out");
607659
}
608660
switch ((int) result) {
609661
case COM.S_OK:
610662
new IUnknown(pv).AddRef();
611-
setupBrowser((int) result, pv);
663+
boolean success = setupBrowser((int) result, pv);
664+
if(!success) {
665+
rollbackInitialization();
666+
errorTimedOut(null);
667+
}
612668
break;
613669
case COM.E_WRONG_THREAD:
614-
initializationRollback.run();
670+
rollbackInitialization();
615671
error(SWT.ERROR_THREAD_INVALID_ACCESS, (int) result);
616672
break;
617673
case COM.E_ABORT:
618-
initializationRollback.run();
674+
rollbackInitialization();
619675
break;
620676
default:
621-
initializationRollback.run();
677+
rollbackInitialization();
622678
if (previousAttempts < MAXIMUM_CREATION_RETRIES) {
623679
System.err.println(String.format("Edge initialization failed, retrying (attempt %d / %d)", previousAttempts + 1, MAXIMUM_CREATION_RETRIES));
624680
createInstance(previousAttempts + 1);
@@ -632,10 +688,22 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
632688
});
633689
}
634690

635-
void setupBrowser(int hr, long pv) {
691+
private void rollbackInitialization() {
692+
webViewProvider.abortInitialization();
693+
if (environment2 != null) {
694+
environment2.Release();
695+
environment2 = null;
696+
}
697+
containingEnvironment.instances().remove(this);
698+
}
699+
700+
boolean setupBrowser(int hr, long pv) {
636701
long[] ppv = new long[] {pv};
637702
controller = new ICoreWebView2Controller(ppv[0]);
638703
final ICoreWebView2 webView = webViewProvider.initializeWebView(controller);
704+
if(webView == null) {
705+
return false;
706+
}
639707
webView.get_Settings(ppv);
640708
settings = new ICoreWebView2Settings(ppv[0]);
641709

@@ -735,17 +803,15 @@ void setupBrowser(int hr, long pv) {
735803
if (browser.isFocusControl()) {
736804
browserFocusIn(new Event());
737805
}
806+
return true;
738807
}
739808

740809
void browserDispose(Event event) {
741810
containingEnvironment.instances.remove(this);
742811
webViewProvider.scheduleWebViewTask(() -> {
743-
webViewProvider.getWebView(false).Release();
812+
webViewProvider.releaseWebView();
744813
if (environment2 != null) environment2.Release();
745814
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();
749815
if(controller != null) {
750816
// Bug in WebView2. Closing the controller from an event handler results
751817
// in a crash. The fix is to delay the closure with asyncExec.

0 commit comments

Comments
 (0)