/****************************************************************************
* Copyright (C) 2012 HS Coburg.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.scio;
import android.content.Context;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Runs the pcsc daemon and monitors its output.
* Provides functions to start and stop the pcscd daemon and redirects it output to the logger.
*
* @author Dirk Petrautzki <petrautzki@hs-coburg.de>
*/
public class PCSCDRunner {
private static Logger logger = LoggerFactory.getLogger(PCSCDRunner.class);
private static final String LIBPCSCD = "/lib/libpcscd.so";
private final String pathToExecutable;
private final List<String> args = new ArrayList<String>();
private final Object lock = new Object();
private Process pcscdProcess;
private String last_stdout_line;
/**
* Runs a binary from the assets folder and controls it.
*
* @param ctx the application context to get the files directory
* @throws IOException executing 'chmod' failed
*/
public PCSCDRunner(final Context ctx) throws IOException {
pathToExecutable = ctx.getFilesDir().getParent() + LIBPCSCD;
args.add(pathToExecutable);
args.add("-f"); // run pcsc daemon in foreground
args.add("--info"); // set debug level to info
Runtime.getRuntime().exec("chmod 777 " + pathToExecutable);
Runtime.getRuntime().exec("chmod +X " + pathToExecutable);
}
/**
* Start the pcsc daemon if it is not running.
*
* @throws IOException if the pcsc daemon could not be started due to an I/O error
*/
public void start() throws IOException {
Integer ev = null;
try {
ev = pcscdProcess.exitValue();
} catch (IllegalThreadStateException e) {
// ignore
} catch (NullPointerException e) {
// ignore
}
if (pcscdProcess == null || ev != null) {
final ProcessBuilder pb = new ProcessBuilder(args);
pb.redirectErrorStream(true);
pcscdProcess = pb.start();
startOutputRedirection(pcscdProcess.getInputStream());
}
}
/**
* Return the running status of the pcsc daemon.
*
* @return {@code true} if the pcsc daemon is running, otherwise {@code false}
*/
public boolean isRunning() {
Integer ev = null;
try {
ev = pcscdProcess.exitValue();
} catch (IllegalThreadStateException e) {
// ignore
} catch (NullPointerException e) {
// ignore
}
return pcscdProcess != null && ev == null;
}
/**
* Redirect the output of the pcsc daemon to the logger.
*
* @param in InputStream containing the output from the pcsc daemon
*/
private void startOutputRedirection(final InputStream in) {
Thread t = new Thread() {
public void run() {
try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
while (true) {
synchronized (lock) {
if ((last_stdout_line = reader.readLine()) == null) {
break;
}
}
logger.debug(last_stdout_line);
}
reader.close();
} catch (IOException e) {
// ignore
}
if (pcscdProcess != null) {
try {
pcscdProcess.waitFor();
} catch (InterruptedException e) {
// ignore
}
logger.debug("exit(" + pcscdProcess.exitValue() + ")");
}
}
};
t.start();
}
/**
* Stop the pcscd process.
*/
public void stop() {
pcscdProcess.destroy();
}
}