java-cef icon indicating copy to clipboard operation
java-cef copied to clipboard

Creating multiple browsers sometimes creates too many Cef Browsers

Open magreenblatt opened this issue 3 years ago • 3 comments

Original report by Philip Hanson (Bitbucket: Philip Hanson).


Linux OS

JCEF Version = 100.0.14.294
CEF Version = 100.0.14
Chromium Version = 100.0.4896.75

Here is a bit of psudo code to explain

Initialize the CefApp

loop 5 {

Create a cef client using cefApp.clientCreate

Create a browser cefClient.create browser

add browser to JFrame

show the Jframe

}

The expected behaviour:

5 Jframes with browsers

CEF Debug window shows 5

Cef lifespanhandler afterCreated is called 5 times

Actual behaviour:

You always get the 5 JFrames

CEF debug window will show more than 5

Cef lifespanhandler afterCreated is calle more than 5 times

Notes:

I have seen over 100 processes created when doing this.

I have tried to wait until each browser has been loaded before creating another but I can still get it to break.

magreenblatt avatar Jul 29 '22 08:07 magreenblatt

Original comment by Tom Hegg (Bitbucket: Tom Hegg).


Any updates on this? I’m working on a similar intermittent problem where onAfterCreate gets called twice for a single browser creation. Maddeningly I can’t repro the problem, only the customer can.

Curious, have you tried calling CefBrowser.createImmediately() right after creating the browser?

magreenblatt avatar Mar 03 '23 19:03 magreenblatt

Original comment by Philip Hanson (Bitbucket: Philip Hanson).


I did try CefBrowser.createImmediately() which did not solve the problem. Currently I am monitoring the number of created browsers on start and if that exceeds the 5 I want I restart the application, this is not ideal but as this only happens very infrequently it will do as a work around until hopefully this gets fixed in a later version of CEF.

magreenblatt avatar Mar 07 '23 08:03 magreenblatt

Original comment by Tom Hegg (Bitbucket: Tom Hegg).


I spent a bit more time on this, jotting my notes here in case they're useful to anybody.

It appears that the problem happens if the time between the call to CefBrowser_N.createBrowser() (from CefBrowserWr.createBrowserIfRequired()) and the ensuing callback from native code to CefBrowser_N.notifyBrowserCreated() is greater than 100ms. The native code called is contained in the 'create()' function in CefBrowser_N.cpp (~line 922). In my case the execution of 'create()' happens on a separate thread.

The 'create()' function in turn calls into the CEF library to launch the browser process(es?), and when THAT returns, 'create()' calls back to Java (CefBrowser_N.notifyBrowserCreated()) to set an 'isPending_' flag, which prevents FUTURE calls to CefBrowser_N.createBrowser from calling the native browser creation code.

The problem is that there is a race due to a Timer set up during construction of CefBrowserWr, which ends up calling createBrowserIfRequired() AGAIN 100ms later. If that happens before the 'isPending_' flag has been set from the previous call, a second browser instance will be created in native code. (And this leads to another call to onAfterCreate() further up the chain).

I can replicate the bug by hacking the CefBrowser_N.notifyBrowserCreated() method to sleep for 150ms before actually setting the isPending_ flag.

As far as a fix? It seems like it would be best if CefBrowser_N.createBrowser() just blocked until the native code was done creating the browser instance. Alternatively, the native code could execute 'create()' directly (synchronously) instead of spawning a new thread. But I have no idea why the code is set up this way (why is there a Timer? why is the create asynchronous?), and I don't have time to become a JCEF black belt.

Apparently the call to 'create()' WILL happen synchronously if CefBrowser_N.createBrowser() is called on CEF's "TID_UI" thread. (Maybe this is why the MainFrame example creates all UI objects including CefBrowserWr on the main thread instead of (per best practice?) the Swing thread?) At any rate this isn't easily possible with my code.

magreenblatt avatar Mar 09 '23 03:03 magreenblatt