Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OffScreen - Browser fails to complete loading when CEF is initialized shortly before the browser is created #3850

Closed
jsoldi opened this issue Oct 15, 2021 · 12 comments

Comments

@jsoldi
Copy link

jsoldi commented Oct 15, 2021

Bug Report

  • What version of the product are you using?

  • What architecture x86 or x64?
    Both x86 and x64

  • What version of .Net?
    .Net 4.6.2

  • On what operating system?
    Windows Server 2016 or Win 10

  • Are you using WinForms, WPF or OffScreen?
    OffScreen but the error also occurs on WinForms

  • What steps will reproduce the problem?
    I can reliable reproduce the error in a fresh Windows Server 2016 with 4GB ram. I can't reproduce it on a larger machine, so you may only get the test to fail in a 4GB ram or less machine. The steps to reproduce are:

  1. Download this realse.
  2. Add the following class to the CefSharp.Test\OffScreen folder:
public class NoInitTests
{
    private readonly ITestOutputHelper output;

    public NoInitTests(ITestOutputHelper output)
    {
        this.output = output;
    }

    [Fact]
    public async Task FinishesLoading()
    {
        //Cef.Initialize(new CefSettings());
        //await Task.Delay(5000);
        var tcs = new TaskCompletionSource<bool>();
        var browser = new CefSharp.OffScreen.ChromiumWebBrowser("https://www.google.com", null, null, false);

        browser.LoadingStateChanged += (s, arg) =>
        {
            if (arg.IsLoading == false)
                tcs.TrySetResult(true);
        };

        browser.LoadError += (s, arg) =>
        {
            tcs.TrySetResult(false);
        };

        browser.CreateBrowser();
        var completedTask = await Task.WhenAny(Task.Delay(10000), tcs.Task);
        Assert.Equal(tcs.Task, completedTask);
    }
}
  1. Run the FinishesLoading test.

Note that this test class doesn't use CefSharpFixture because CefSharpFixture initializes CEF before running any test, and in order for the test to fail, the delay between CEF initialization and the first browser load must be as short as possible. This test won't shutdown CEF because the thread in which it initializes it is a different one than the one at the end of the FinishesLoading function.
If the two commented out lines are uncommented, the test passes.

  • What is the expected output? What do you see instead?
    The test should pass.

  • Please provide any additional information below.
    When the browser fails to complete loading, it also becomes unusable. If I open DevTools, the console cannot run any scripts. It seems to be waiting for load to complete. I also set log-severity to verbose and I don't see any errors or warning, just some component initialization log entries.

@amaitland amaitland changed the title Browser fails to complete loading when CEF is initialized shortly before the browser is created OffScreen - Browser fails to complete loading when CEF is initialized shortly before the browser is created Oct 15, 2021
@amaitland
Copy link
Member

error also occurs on WinForms

How are you reproducing this with WinForms exactly? Calling CreateControl immediately?

@jsoldi
Copy link
Author

jsoldi commented Oct 15, 2021

I just mention WinForms because I've also randomly seen my winforms browser get on this "weird" never-completed-loading state, and also confirmed it by logging LoadingStateChanged, but haven't came up with a quick way to replicate it. I doubt this is an issue specific to OffScreen.

@amaitland
Copy link
Member

I just mention WinForms because I've also randomly seen my winforms browser get on this "weird" never-completed-loading state

Have you confirmed the root cause is the same?

@amaitland
Copy link
Member

Fundamentally CEF should support this use case, as internally it should already wait for the context to be ready.

https://github.com/chromiumembedded/cef/blob/4606/libcef/browser/browser_host_create.cc#L90

It might be possible to implement some sort of workaround, the issue likely needs to be reported upstream.

@SchreinerK
Copy link

starting with 94.4.20 there are loading issues also in CefSharp.Wpf and Wpf.NETCore
with 93.1.140 there are no problems.

	public partial class MainWindow : Window {

		public MainWindow() {
			var settings = new CefSettings {
				RemoteDebuggingPort = 8080
			};
			Cef.Initialize(settings);

			InitializeComponent();
			DataContext = this;

			LeftBrowser.FrameLoadEnd += LeftBrowser_FrameLoadEnd;
			LeftBrowser.LoadError += LeftBrowser_LoadError;

			// == NOT WORKING, only blank page displayed ==
			LeftBrowser.Address = "github.com";
			// Loaded += (s,e) => LeftBrowser.Address = "github.com";
			// Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
			// 	new Action(() => LeftBrowser.Address = "github.com"));
			// Loaded += (s,e) => Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
			// 	new Action(() => LeftBrowser.Address = "github.com"));
			// == END NOT WORKING ==
			
			// == WORKS but waiting is BAD ==
			// new DispatcherTimer(TimeSpan.FromSeconds(3), DispatcherPriority.Normal, (s, e) => {
			// 	((DispatcherTimer)s)?.Stop();
			// 	LeftBrowser.Address = "github.com";
			// }, Dispatcher).Start();
		}

Repo

@jsoldi
Copy link
Author

jsoldi commented Oct 21, 2021

Have you confirmed the root cause is the same?

Yes pretty sure. Here is a new test I did on the usual server (Windows Server 2016 + 4GM ram).

  1. Create a new WinForms project, .NET Framework 4.6.2.
  2. Install CefSharp.WinForms v94.4.20 from nuget.
  3. Add this code to your form:
public partial class Form1 : Form
{
    private CefSharp.WinForms.ChromiumWebBrowser Browser;

    public Form1()
    {
        InitializeComponent();
    }

    private async void Form1_Load(object sender, EventArgs e)
    {
        CefSharp.Cef.Initialize(new CefSharp.WinForms.CefSettings() { LogSeverity = CefSharp.LogSeverity.Verbose });
        //await Task.Delay(5000);
        Browser = new CefSharp.WinForms.ChromiumWebBrowser("https://www.google.com");
        Browser.LoadingStateChanged += Browser_LoadingStateChanged;
        Browser.Dock = DockStyle.Fill;
        Controls.Add(Browser);
    }

    private void Browser_LoadingStateChanged(object sender, CefSharp.LoadingStateChangedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine($"LoadingStateChanged: {e.IsLoading}");
    }
}

Running it will often, but not always, result in LoadingStateChanged being called with IsLoading equal to True, but never False. Uncommenting the commented out line seems to fix the issue. Here is the log when it fails to complete:

[1021/203623.424:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 5CF4C700: set chrome proxy config service to 5CED1300
[1021/203623.463:VERBOSE1:webrtc_internals.cc(117)] Could not get the download directory.
[1021/203623.519:VERBOSE1:media_stream_manager.cc(705)] MSM::InitializeMaybeAsync([this=5CEBDE00])
[1021/203623.529:VERBOSE1:media_stream_manager.cc(705)] MDM::MediaDevicesManager()
[1021/203623.555:VERBOSE1:media_stream_manager.cc(705)] MSM::MediaStreamManager([this=5CEBDE00]))
[1021/203623.611:VERBOSE1:component_installer.cc(276)] StartRegistration for Widevine Content Decryption Module
[1021/203623.705:VERBOSE1:component_installer.cc(421)] FinishRegistration for Widevine Content Decryption Module
[1021/203623.740:VERBOSE1:component_updater_service.cc(92)] CrxUpdateService starting up. First update attempt will take place in 60 seconds. Next update attempt will take place in 18000 seconds. 
[1021/203623.756:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 5CF4D880: set chrome proxy config service to 5CFBFB00
LoadingStateChanged: True
[1021/203624.564:VERBOSE1:media_stream_manager.cc(705)] RFAOSF::Core() [process_id=4, frame_id=1]

And here is the log after uncommenting the delay:

[1021/203753.744:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 22950700: set chrome proxy config service to 228D1300
[1021/203753.793:VERBOSE1:webrtc_internals.cc(117)] Could not get the download directory.
[1021/203753.920:VERBOSE1:component_installer.cc(276)] StartRegistration for Widevine Content Decryption Module
[1021/203753.931:VERBOSE1:component_installer.cc(421)] FinishRegistration for Widevine Content Decryption Module
[1021/203753.933:VERBOSE1:component_updater_service.cc(92)] CrxUpdateService starting up. First update attempt will take place in 60 seconds. Next update attempt will take place in 18000 seconds. 
[1021/203753.970:VERBOSE1:media_stream_manager.cc(705)] MSM::InitializeMaybeAsync([this=228BDE00])
[1021/203753.971:VERBOSE1:media_stream_manager.cc(705)] MDM::MediaDevicesManager()
[1021/203753.971:VERBOSE1:media_stream_manager.cc(705)] MSM::MediaStreamManager([this=228BDE00]))
[1021/203759.002:VERBOSE1:pref_proxy_config_tracker_impl.cc(186)] 22950E00: set chrome proxy config service to 228D0000
LoadingStateChanged: True
[1021/203759.250:VERBOSE1:media_stream_manager.cc(705)] RFAOSF::Core() [process_id=6, frame_id=1]
[1021/203759.294:VERBOSE1:media_stream_manager.cc(705)] RFAOSF::Core() [process_id=6, frame_id=1]
LoadingStateChanged: False

@amaitland
Copy link
Member

starting with 94.4.20 there are loading issues also in CefSharp.Wpf and Wpf.NETCore

@SchreinerK Please confirm if the issue reproduces with

Did You check the log file?

@amaitland
Copy link
Member

Yes pretty sure. Here is a new test I did on the usual server (Windows Server 2016 + 4GM ram).

@jsoldi Thanks. The fact that it only happens with limited resources will make this difficult to debug. Does calling Cef.Initialize in the programs main entry point resolve the issue?

https://github.com/cefsharp/CefSharp.MinimalExample/blob/cefsharp/94/CefSharp.MinimalExample.WinForms/Program.cs

@jsoldi
Copy link
Author

jsoldi commented Oct 22, 2021

Does calling Cef.Initialize in the programs main entry point resolve the issue?

It doesn't. I moved the initialization to the very first line of Main and the issue occurred less often, probably because of the delay between that and the form load event, but it still happened:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        CefSharp.Cef.Initialize(new CefSharp.WinForms.CefSettings() { LogSeverity = CefSharp.LogSeverity.Verbose });
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

amaitland added a commit that referenced this issue Oct 26, 2021
- GlobalContextInitialized wraps a TaskCompletionSource which is resolved
  when the Global CefRequestContext has been created
- Reduce code duplication

If successful we can apply the same changes to WinForms/WPF though they're less likely to have
issues than the OffScreen implementation as the CreateBrowser doesn't happen until much later

Issue #3850 #3634
amaitland added a commit that referenced this issue Oct 28, 2021
- GlobalContextInitialized wraps a TaskCompletionSource which is resolved
  when the Global CefRequestContext has been created
- Reduce code duplication

If successful we can apply the same changes to WinForms/WPF though they're less likely to have
issues than the OffScreen implementation as the CreateBrowser doesn't happen until much later

Issue #3850 #3634
@amaitland
Copy link
Member

There are changes to the OffScreen implementation now available for testing in version 95.7.140-pre

Commit 482b423 changes the behaviour to enqueue browser creation until the Global CefRequestContext has finished initializing. I haven't changed WinForms or WPF at this point.

It doesn't. I moved the initialization to the very first line of Main and the issue occurred less often, probably because of the delay between that and the form load event, but it still happened:

You can use the new Cef.InitializeAsync method that was added in #3634

The Task will be resolved when the Global CefRequestContext has been initialized. For testing purposes you can try something like the following:

var t = CefSharp.Cef.InitializeAsync(new CefSharp.WinForms.CefSettings() { LogSeverity = CefSharp.LogSeverity.Verbose });
t.Wait();

@amaitland
Copy link
Member

starting with 94.4.20 there are loading issues also in CefSharp.Wpf and Wpf.NETCore
with 93.1.140 there are no problems.

@SchreinerK Looking at your example and I don't believe it's related to this particular issue. If I understand @jsoldi correctly then the browser will never actually be created, no amount of delay before setting the Address property would have any effect. If you can reproduce the problem with version 95.7.140-pre then you'll need to create a new issue.

@amaitland
Copy link
Member

The changes have been in the OffScreen version for a number of releases now and no further reports of this issue.

I've not been able to reproduce the issue in WinForms or WPF and no other reports of the problem. Using Cef.InitializeAsync should be possible for anyone experiencing problems there.

Closing now. Can be reopened if further code changes are required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants