Skip to content

Latest commit

 

History

History

README.md

Info

This directory contains headless Chrome wrapper Java helper class and example based on ldaume/headless-chrome

The project has been stale for some time, then tested with Chrome 101 (64 bit) running on Windows 10 VM. To detect the headless run, an environment variable WINDOWS_NO_DISPLAY is set by the launcher script which itself is run by Windowws Scheduled Task with one minute delay after the reboot event.

visual run

task actions

task trigger

processes

results

the log of the headless run ( from the logfile).

running by app 
checking display 
setting WINDOWS_NO_DISPLAY to true
1 
setting WINDOWS_NO_DISPLAY to true
WINDOWS_NO_DISPLAY=true  

Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/2.6/maven-resources-plugin-2.6.pom (8.1 kB at 8.7 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/23/maven-plugins-23.pom
Progress (1): 2.7/9.2 kB
Progress (1): 5.5/9.2 kB
Progress (1): 8.2/9.2 kB
Progress (1): 9.2 kB    
...

[INFO] Scanning for projects...
...
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running software.MinimalTest

Observed environment keys: [PATH, PROCESSOR_LEVEL, SYSTEMDRIVE, M2, ALLUSERSPROFILE, JAVA_OPTS, PROCESSOR_ARCHITECTURE, DRIVERDATA, MAVEN_HOME, PROGRAMFILES, PSMODULEPATH, PROGRAMDATA, USERNAME, WDIR, GROOVY_VERSION, PATHEXT, GRADLE_VERSION, LOG, PROCESSOR_ARCHITEW6432, CLASSWORLDS_JAR, MAVEN_VERSION, TOOL_HOME, WINDOWS_NO_DISPLAY, WINDIR, PROCESSOR_IDENTIFIER, M2_HOME, IVY_VERSION, PUBLIC, IVY_HOME, LOCALAPPDATA, COMMONPROGRAMFILES(X86), USERDOMAIN, JAVA_HOME, PROMPT, PROGRAMFILES(X86), ERROR_CODE, EXEC_DIR, GRADLE_HOME, MAVEN_OPTS, ANT_HOME, GROOVY_HOME, =C:, APPDATA, JAVA_TOOL_OPTIONS, PROGRAMW6432, SYSTEMROOT, JAVA_VERSION, MAVEN_CMD_LINE_ARGS, OS, COMMONPROGRAMW6432, COMPUTERNAME, COMMONPROGRAMFILES, COMSPEC, JAVACMD, MAVEN_PROJECTBASEDIR, PROCESSOR_REVISION, CLASSWORLDS_LAUNCHER, TEMP, USERPROFILE, ANT_VERSION, TMP, PHANTOMJS_HOME, NUMBER_OF_PROCESSORS, JVMCONFIG]
Checking environment JAVA_OPTS: -Xms256m -Xmx512m
Checking environment MAVEN_OPTS: -Xms256m -Xmx512m

Checking environment JAVA_TOOL_OPTIONS: -DWINDOWS_NO_DISPLAY=true  

Detected WINDOWS_NO_DISPLAY

Detected WINDOWS_NO_DISPLAY environment or property

Detected WINDOWS_NO_DISPLAY in JAVA_TOOL_OPTIONS

Switching to headless

Tests run: 3, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 24.27 sec

Picked up JAVA_TOOL_OPTIONS: -DWINDOWS_NO_DISPLAY=true  

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 1

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  38.452 s
[INFO] Finished at: 2022-06-10T01:30:21+03:00
[INFO] ------------------------------------------------------------------------
Done. 

NOTE: - the maven dependencies will be downloaded into the user profile in the first run If the scheduled task is configured to run under NT AUTHORIRY\SYSTEM account

task account

the jars will go into c:\Windows\SysWOW64\config\systemprofile\.m2\repository for 32 bit task on 64 bit system and into c:\Windows\System32\config\systemprofile\.m2\repository otherwise.

The log from the call of the launcher interactively:

client.cmd

running by app 
checking display 
setting WINDOWS_NO_DISPLAY to true
0
clearing WINDOWS_NO_DISPLAY to true
[INFO] Scanning for projects...

...
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running software.MinimalTest
checking environment: [PATH, USERDOMAIN_ROAMINGPROFILE, PROCESSOR_LEVEL, SYSTEMDRIVE, M2, SESSIONNAME, ALLUSERSPROFILE, JAVA_OPTS, PROCESSOR_ARCHITECTURE, DRIVERDATA, MAVEN_HOME, PROGRAMFILES, PSMODULEPATH, PROGRAMDATA, USERNAME, WDIR, GROOVY_VERSION, PATHEXT, GRADLE_VERSION, LOG, PROCESSOR_ARCHITEW6432, CLASSWORLDS_JAR, MAVEN_VERSION, TOOL_HOME, WINDIR, HOMEPATH, PROCESSOR_IDENTIFIER, M2_HOME, IVY_VERSION, PUBLIC, IVY_HOME, =::, =EXITCODE, LOCALAPPDATA, COMMONPROGRAMFILES(X86), USERDOMAIN, LOGONSERVER, JAVA_HOME, PROMPT, PROGRAMFILES(X86), ERROR_CODE, EXEC_DIR, GRADLE_HOME, MAVEN_OPTS, ANT_HOME, GROOVY_HOME, =C:, APPDATA, PROGRAMW6432, SYSTEMROOT, JAVA_VERSION, MAVEN_CMD_LINE_ARGS, OS, COMMONPROGRAMW6432, COMPUTERNAME, COMMONPROGRAMFILES, COMSPEC, JAVACMD, MAVEN_PROJECTBASEDIR, PROCESSOR_REVISION, CLASSWORLDS_LAUNCHER, RUBYOPT, TEMP, HOMEDRIVE, USERPROFILE, ANT_VERSION, TMP, PHANTOMJS_HOME, NUMBER_OF_PROCESSORS, JVMCONFIG]
Switching to / staying visible

Switching to / staying visible

Note About autoadminlogon setting:

Winlogon, the GINA, and network providers are the parts of the interactive logon model. The interactive logon procedure is normally controlled by Winlogon, MSGina.dll, and network providers. To change the interactive logon procedure, MSGina.dll can be replaced with a customized GINA DLL.

GINA is a replaceable dynamically linked library that is loaded early in the boot process in the context of Winlogon

bypass credential

The Windows shell, as it is known today, is an evolution of what began with Windows 95, released in 1995. It is intimately identified with File Explorer, a Windows component that can browse the whole shell namespace.

The headless_detector.cmd script used in this project is checking if the shell process is running by the account that runs the detector script:

tasklist.exe /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME EQ explorer.exe"

when the output shows the process:

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
explorer.exe                  3912 Console                    1    143,648 K

the environment variable WINDOWS_NO_DISPLAY is cleared. Otherwise it is set. There are two alternative ways to do it in Powershell. One requires elevation:

$processname = 'explorer'
get-process -name $processname -includeusername
Get-Process : The 'IncludeUserName' parameter requires elevated user rights.
Try running the command again in a session that has been opened with elevated user rights (that is, Run as Administrator).

the other uses performs p/invoke into advapi32.dll and contains substantial amount of inline C# code (see headless_detector.ps1 script).

The password for the account can be specified in one of two ways. For computers running one of the Windows Server 2003 or Windows XP operating systems, the password should be stored as a secret using the LsaStorePrivateData function. For details, see Protecting the Automatic Logon Password. The other way to store the password plaintext in the Registry.

If no DefaultPassword string is specified, Windows automatically changes the value of the AutoAdminLogon key from 1 (true) to 0 (false), disabling the AutoAdminLogon feature.

The SAS (Secure Attention Sequence) in Reactos and CSRSS (Client Server Runtime Subsystem) in Windows are similar roles sas.c

static BOOL
 StartUserShell(
     IN OUT PWLSESSION Session)

msgina.c

static BOOL GetRegistrySettings(PGINA_CONTEXT pgContext) {    
 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, &hKey);
  rc = ReadRegSzValue(hKey, L"AutoAdminLogon", &lpAutoAdminLogon);
  if (rc == ERROR_SUCCESS)
    if (wcscmp(lpAutoAdminLogon, L"1") == 0)
      pgContext->bAutoAdminLogon = TRUE;

msgina.c

if (pgContext->bAutoAdminLogon) {
  if (pgContext->bIgnoreShiftOverride || (GetKeyState(VK_SHIFT) >= 0)) {
     /* Don't display the window, we want to do an automatic logon */
     pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
214794369
The process hosting the driver for this device has been terminated. (Exception from HRESULT: 0x8007050B)

Grid

grid task actions

these tasks launch hub

hub4.cmd

node

node4.cmd

and test

client.cmd

Note: only tested with Selenium standalone 4.0 this far - unknown if works with downlevel Selenium 3.x

for the sake of passing all options through selenium hub pipeline:

ChromeOptions options = new ChromeOptions();
options.setBinary(osName.equals("windows") ? (new File(
	(System.getenv().containsKey("PROCESSOR_ARCHITECTURE")
	&& System.getenv("PROCESSOR_ARCHITECTURE").matches("(?:AMD64)")) ?
	"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" : "C:/Program Files/Google/Chrome/Application/chrome.exe")) .getAbsolutePath() : "/usr/bin/chromium-browser" /* "/usr/bin/google-chrome" */ );
if (headless) {
	for (String optionAgrument : (new String[] { "headless", "--window-size=1200x800", "disable-gpu" })) {
	options.addArguments(optionAgrument);
}

driver = new RemoteWebDriver(new URL("http://localhost:4444"), options);

the legacy invocation

DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("headless", true);
capabilities.setCapability("platform", "WINDOWS");
capabilities.setCapability("version", "latest");
driver = new RemoteWebDriver(new URL("https://localhost:4444/wd/hub"), capabilities);

was not found to work (more testing is pending)

The error with Selenium Server 3.x called with options:

software.MinimalTest: Unable to create new remote session.
Caused by: org.openqa.selenium.SessionNotCreatedException: 
Unable to create new remote session. desired capabilities = 
Capabilities [{goog:chromeOptions={args=[headless, --window-size=1200x800, disable-gpu], extensions=[], 
binary=C:\Program Files\Google\Chrome\Application\chrome.exe}, browserName=chrome}], 
required capabilities = Capabilities [{}]

the error with Selenium Server 3.x called with capabilities:


org.openqa.selenium.remote.UnreachableBrowserException: 
Could not start a new session. 
Possible causes are invalid address of the remote server or browser start-up failure.

along with that error, the hub console logs the attempt:

04:58:58.274 INFO - Got a request to create a new session: Capabilities [{headless=true, browserName=chrome, version=latest, platform=WINDOWS}]

while if in foreground

06:10:43.595 INFO [LocalDistributor.newSession] - Session request received by the distributor:
 [Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless], extensions: []}}]
06:10:43.595 INFO [LocalDistributor.newSession] - Unable to find slot for request 22073277-e9a3-4701-a62d-15d597cfc43f. May retry: Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless], extensions: []}}6:10:43.595 INFO [LocalDistributor$NewSessionRunnable.handleNewSessionRequest] - Retrying

See also

Author

Serguei Kouzmine