@@ -68,7 +68,7 @@ static class DefaultProcessProvider implements ProcessProvider {
6868 @ Override
6969 public Process createProcess (InputStream metadata ) throws IOException {
7070 if (metadata == null ) {
71- return null ;
71+ throw new IOException ( "Error creating Process: metadata is null" ) ;
7272 }
7373 List <String > command = extractCertificateProviderCommand (metadata );
7474 return new ProcessBuilder (command ).start ();
@@ -108,12 +108,24 @@ public KeyStore getKeyStore() throws IOException {
108108 }
109109 }
110110
111+ @ Override
112+ public boolean isCertificateSourceAvailable () throws IOException {
113+ try {
114+ this .getKeyStore ();
115+ } catch (CertificateSourceUnavailableException e ) {
116+ return false ;
117+ }
118+ return true ;
119+ }
120+
111121 @ VisibleForTesting
112122 static KeyStore getKeyStore (InputStream metadata , ProcessProvider processProvider )
113123 throws IOException , InterruptedException , GeneralSecurityException {
114124 Process process = processProvider .createProcess (metadata );
115125
116126 // Run the command and timeout after 1000 milliseconds.
127+ // The cert provider command usually finishes instantly (if it doesn't hang),
128+ // so 1000 milliseconds is plenty of time.
117129 int exitCode = runCertificateProviderCommand (process , 1000 );
118130 if (exitCode != 0 ) {
119131 throw new IOException ("Cert provider command failed with exit code: " + exitCode );
@@ -134,28 +146,11 @@ static ImmutableList<String> extractCertificateProviderCommand(InputStream conte
134146 @ VisibleForTesting
135147 static int runCertificateProviderCommand (Process commandProcess , long timeoutMilliseconds )
136148 throws IOException , InterruptedException {
137- long startTime = System .currentTimeMillis ();
138- long remainTime = timeoutMilliseconds ;
139-
140- // In the while loop, keep checking if the process is terminated every 100 milliseconds
141- // until timeout is reached or process is terminated. In getKeyStore we set timeout to
142- // 1000 milliseconds, so 100 millisecond is a good number for the sleep.
143- while (remainTime > 0 ) {
144- Thread .sleep (Math .min (remainTime + 1 , 100 ));
145- remainTime -= System .currentTimeMillis () - startTime ;
146-
147- try {
148- return commandProcess .exitValue ();
149- } catch (IllegalThreadStateException ignored ) {
150- // exitValue throws IllegalThreadStateException if process has not yet terminated.
151- // Once the process is terminated, exitValue no longer throws exception. Therefore
152- // in the while loop, we use exitValue to check if process is terminated. See
153- // https://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#exitValue()
154- // for more details.
155- }
149+ boolean terminated = commandProcess .waitFor (timeoutMilliseconds , TimeUnit .MILLISECONDS );
150+ if (!terminated ) {
151+ commandProcess .destroy ();
152+ throw new IOException ("Cert provider command timed out" );
156153 }
157-
158- commandProcess .destroy ();
159- throw new IOException ("cert provider command timed out" );
154+ return commandProcess .exitValue ();
160155 }
161156}
0 commit comments