phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

【Android】Linuxコマンドの実行

AndroidアプリからLinuxコマンドを実行するにはRuntimeクラスを利用する。

package xxxxxxxxxxxx;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import android.util.Log;

public class CommandExecutor {

	private static boolean isStopProcess = false;

	public static String execCommand(String command) throws IOException {
		isStopProcess = false;

		if (command == null || command.equals("")) {
			return null;
		}
		Runtime runtime = Runtime.getRuntime();
		Process process = runtime.exec(command);
		String result = readInputStream(process.getInputStream());
		if (result == null || result.equals("")) {
			result = readInputStream(process.getErrorStream());
		}

		if (process != null) {
			process.destroy();
		}

		return result;
	}

	private static String readInputStream(InputStream in) throws IOException {
		InputStreamReader inReader;
		BufferedReader bufReader = null;
		StringBuffer output = new StringBuffer();
		try {
			inReader = new InputStreamReader(in);
			bufReader = new BufferedReader(inReader);

			String line;
			while (((line = bufReader.readLine()) != null) && !isStopProcess) {
				output.append(line + "\n");
				Log.d("CommandExe", "output:" + output);
			}

		} finally {
			if (bufReader != null) {
				bufReader.close();
			}

		}

		return output.toString();
	}

	public synchronized static void stopProcess() {
		isStopProcess = true;
	}
}

Runtimeクラスはインスタンスを自由に作ることはできず、getRuntime()というメソッドが用意されている。
getRuntime()で取得したインスタンスに対してexec(String prog)メソッドを実行することでコマンドを実行できる。
返り値としてプロセスが返ってくるので、これを利用して結果を読み込む。
今回は readInputStream(InputStream in)というメソッドを用意して結果を読み込んでいる。
というのもコマンドの実行が成功したときと失敗したときで結果が取得できるInputStreamが異なるためである。

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);

//コマンド実行が成功した場合のInputStream
InputStream in = process.getInputStream();

//コマンド実行が失敗した場合のInputStream
InputStream errorin = process.getErrorStream();

今回は結果が空だったら失敗とみなして、エラーの結果を取得する。

String result = readInputStream(process.getInputStream());
if (result == null || result.equals("")) {
	//コマンド実行失敗
	result = readInputStream(process.getErrorStream());
}

また、コマンド実行をメインスレッドで行うと結果が返ってくるまで画面が止まってしまうので、マルチスレッドでコマンドを実行することを想定している。
例えばlogcatを実行した場合、プロセスを停止させるまでずっと結果を取得し続けてしまう。
今回はisStopProcessというbooleanのフラグを用意し、この値がtrueになったら停止するようにしている。
isStopProcesはsynchronizedなstopProcess()メソッドを他のスレッドから呼ぶことでtrueになり、プロセスを停止できる。

private static boolean isStopProcess = false;

private static String readInputStream(InputStream in) throws IOException {
	InputStreamReader inReader;
	BufferedReader bufReader = null;
	StringBuffer output = new StringBuffer();
	try {
		inReader = new InputStreamReader(in);
		bufReader = new BufferedReader(inReader);

		String line;
		//結果がなくなるかフラグがtrueになったら終了
		while (((line = bufReader.readLine()) != null) && !isStopProcess) {
			output.append(line + "\n");
			Log.d("CommandExe", "output:" + output);
		}

	} finally {
		if (bufReader != null) {
			bufReader.close();
		}

	}

	return output.toString();
}

public synchronized static void stopProcess() {
	//プロセスを停止するフラグをtrueにする
	isStopProcess = true;
}