/// <summary> /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed. /// </summary> /// <param name="options">Options for launching Chrome</param> /// <param name="chromiumRevision">The revision of Chrome to launch.</param> /// <returns>A connected browser.</returns> /// <remarks> /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a> /// for a description of the differences between Chromium and Chrome. /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users. /// </remarks> public async Task <Browser> LaunchAsync(LaunchOptions options, int chromiumRevision) { var chromeArguments = new List <string>(DefaultArgs); _options = options; if (options.AppMode) { options.Headless = false; } else { chromeArguments.AddRange(AutomationArgs); } var userDataDirOption = options.Args.FirstOrDefault(i => i.StartsWith(UserDataDirArgument, StringComparison.Ordinal)); if (string.IsNullOrEmpty(userDataDirOption)) { if (string.IsNullOrEmpty(options.UserDataDir)) { _temporaryUserDataDir = GetTemporaryDirectory(); chromeArguments.Add($"{UserDataDirArgument}={_temporaryUserDataDir}"); } else { chromeArguments.Add($"{UserDataDirArgument}={options.UserDataDir}"); } } else { _options.UserDataDir = userDataDirOption.Replace($"{UserDataDirArgument}=", string.Empty); } if (options.Devtools) { chromeArguments.Add("--auto-open-devtools-for-tabs"); options.Headless = false; } if (options.Headless) { chromeArguments.AddRange(new[] { "--headless", "--disable-gpu", "--hide-scrollbars", "--mute-audio" }); } var chromeExecutable = options.ExecutablePath; if (string.IsNullOrEmpty(chromeExecutable)) { var downloader = Downloader.CreateDefault(); var revisionInfo = downloader.RevisionInfo(Downloader.CurrentPlatform, chromiumRevision); chromeExecutable = revisionInfo.ExecutablePath; } if (!File.Exists(chromeExecutable)) { throw new FileNotFoundException("Failed to launch chrome! path to executable does not exist", chromeExecutable); } if (options.Args.Any()) { chromeArguments.AddRange(options.Args); } _chromeProcess = new Process(); _chromeProcess.EnableRaisingEvents = true; _chromeProcess.StartInfo.UseShellExecute = false; _chromeProcess.StartInfo.FileName = chromeExecutable; _chromeProcess.StartInfo.Arguments = string.Join(" ", chromeArguments); SetEnvVariables(_chromeProcess.StartInfo.Environment, options.Env, Environment.GetEnvironmentVariables()); if (!options.DumpIO) { _chromeProcess.StartInfo.RedirectStandardOutput = false; _chromeProcess.StartInfo.RedirectStandardError = false; } _chromeProcess.Exited += async(sender, e) => { await AfterProcessExit(); }; try { var connectionDelay = options.SlowMo; var browserWSEndpoint = await WaitForEndpoint(_chromeProcess, options.Timeout, options.DumpIO); var keepAliveInterval = options.KeepAliveInterval; _connection = await Connection.Create(browserWSEndpoint, connectionDelay, keepAliveInterval); _processLoaded = true; if (options.LogProcess) { Console.WriteLine($"PROCESS COUNT: {Interlocked.Increment(ref _processCount)}"); } return(await Browser.CreateAsync(_connection, options, KillChrome)); } catch (Exception ex) { ForceKillChrome(); throw new ChromeProcessException("Failed to create connection", ex); } }