17
17
package io .appium .java_client .service .local ;
18
18
19
19
import com .google .common .annotations .VisibleForTesting ;
20
- import io .appium .java_client .internal .ReflectionHelpers ;
21
20
import lombok .SneakyThrows ;
22
21
import org .openqa .selenium .net .UrlChecker ;
23
- import org .openqa .selenium .os .CommandLine ;
22
+ import org .openqa .selenium .os .ExternalProcess ;
24
23
import org .openqa .selenium .remote .service .DriverService ;
25
24
import org .slf4j .Logger ;
26
25
import org .slf4j .LoggerFactory ;
49
48
import static io .appium .java_client .service .local .AppiumServiceBuilder .BROADCAST_IP4_ADDRESS ;
50
49
import static io .appium .java_client .service .local .AppiumServiceBuilder .BROADCAST_IP6_ADDRESS ;
51
50
import static java .util .Objects .requireNonNull ;
51
+ import static java .util .Optional .ofNullable ;
52
52
import static org .slf4j .event .Level .DEBUG ;
53
53
import static org .slf4j .event .Level .INFO ;
54
54
@@ -70,7 +70,7 @@ public final class AppiumDriverLocalService extends DriverService {
70
70
private final URL url ;
71
71
private String basePath ;
72
72
73
- private CommandLine process = null ;
73
+ private ExternalProcess process = null ;
74
74
75
75
AppiumDriverLocalService (String ipAddress , File nodeJSExec ,
76
76
int nodeJSPort , Duration startupTimeout ,
@@ -126,7 +126,7 @@ public URL getUrl() {
126
126
public boolean isRunning () {
127
127
lock .lock ();
128
128
try {
129
- if (process == null || !process .isRunning ()) {
129
+ if (process == null || !process .isAlive ()) {
130
130
return false ;
131
131
}
132
132
@@ -172,17 +172,15 @@ public void start() throws AppiumServerHasNotBeenStartedLocallyException {
172
172
}
173
173
174
174
try {
175
- process = new CommandLine (
176
- this .nodeJSExec .getCanonicalPath (),
177
- nodeJSArgs .toArray (new String []{})
178
- );
179
- process .setEnvironmentVariables (nodeJSEnvironment );
180
- process .copyOutputTo (stream );
181
- process .executeAsync ();
175
+ ExternalProcess .Builder processBuilder = ExternalProcess .builder ()
176
+ .command (this .nodeJSExec .getCanonicalPath (), nodeJSArgs )
177
+ .copyOutputTo (stream );
178
+ nodeJSEnvironment .forEach (processBuilder ::environment );
179
+ process = processBuilder .start ();
182
180
ping (startupTimeout );
183
181
} catch (Exception e ) {
184
- final Optional <String > output = Optional . ofNullable (process )
185
- .map (CommandLine :: getStdOut )
182
+ final Optional <String > output = ofNullable (process )
183
+ .map (ExternalProcess :: getOutput )
186
184
.filter (o -> !isNullOrEmpty (o ));
187
185
destroyProcess ();
188
186
List <String > errorLines = new ArrayList <>();
@@ -227,47 +225,16 @@ public void stop() {
227
225
}
228
226
}
229
227
230
- /**
231
- * Destroys the service if it is running.
232
- *
233
- * @param timeout The maximum time to wait before the process will be force-killed.
234
- * @return The exit code of the process or zero if the process was not running.
235
- */
236
- private int destroyProcess (Duration timeout ) {
237
- if (process == null || !process .isRunning ()) {
238
- return 0 ;
239
- }
240
-
241
- // This all magic is necessary, because Selenium does not publicly expose
242
- // process killing timeouts. By default a process is killed forcibly if
243
- // it does not exit after two seconds, which is in most cases not enough for
244
- // Appium
245
- try {
246
- Object osProcess = ReflectionHelpers .getPrivateFieldValue (
247
- process .getClass (), process , "process" , Object .class
248
- );
249
- Object watchdog = ReflectionHelpers .getPrivateFieldValue (
250
- osProcess .getClass (), osProcess , "executeWatchdog" , Object .class
251
- );
252
- Process nativeProcess = ReflectionHelpers .getPrivateFieldValue (
253
- watchdog .getClass (), watchdog , "process" , Process .class
254
- );
255
- nativeProcess .destroy ();
256
- nativeProcess .waitFor (timeout .toMillis (), TimeUnit .MILLISECONDS );
257
- } catch (Exception e ) {
258
- LOG .warn ("No explicit timeout could be applied to the process termination" , e );
259
- }
260
-
261
- return process .destroy ();
262
- }
263
-
264
228
/**
265
229
* Destroys the service.
266
- * This methods waits up to `DESTROY_TIMEOUT` seconds for the Appium service
230
+ * This method waits up to `DESTROY_TIMEOUT` seconds for the Appium service
267
231
* to exit gracefully.
268
232
*/
269
233
private void destroyProcess () {
270
- destroyProcess (DESTROY_TIMEOUT );
234
+ if (process == null || !process .isAlive ()) {
235
+ return ;
236
+ }
237
+ process .shutdown (DESTROY_TIMEOUT );
271
238
}
272
239
273
240
/**
@@ -277,11 +244,7 @@ private void destroyProcess() {
277
244
*/
278
245
@ Nullable
279
246
public String getStdOut () {
280
- if (process != null ) {
281
- return process .getStdOut ();
282
- }
283
-
284
- return null ;
247
+ return ofNullable (process ).map (ExternalProcess ::getOutput ).orElse (null );
285
248
}
286
249
287
250
/**
0 commit comments