/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.android_scripting;
import com.googlecode.android_scripting.interpreter.InterpreterConstants;
import com.trilead.ssh2.StreamGobbler;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
public class Process {
private static final int DEFAULT_BUFFER_SIZE = 8192;
private final List<String> mArguments;
private final Map<String, String> mEnvironment;
private static final int PID_INIT_VALUE = -1;
private File mBinary;
private String mName;
private long mStartTime;
private long mEndTime;
protected final AtomicInteger mPid;
protected FileDescriptor mFd;
protected OutputStream mOut;
protected InputStream mIn;
protected File mLog;
public Process() {
mArguments = new ArrayList<String>();
mEnvironment = new HashMap<String, String>();
mPid = new AtomicInteger(PID_INIT_VALUE);
}
public void addArgument(String argument) {
mArguments.add(argument);
}
public void addAllArguments(List<String> arguments) {
mArguments.addAll(arguments);
}
public void putAllEnvironmentVariables(Map<String, String> environment) {
mEnvironment.putAll(environment);
}
public void putEnvironmentVariable(String key, String value) {
mEnvironment.put(key, value);
}
public void setBinary(File binary) {
if (!binary.exists()) {
throw new RuntimeException("Binary " + binary + " does not exist!");
}
mBinary = binary;
}
public Integer getPid() {
return mPid.get();
}
public FileDescriptor getFd() {
return mFd;
}
public OutputStream getOut() {
return mOut;
}
public OutputStream getErr() {
return getOut();
}
public File getLogFile() {
return mLog;
}
public InputStream getIn() {
return mIn;
}
public void start(final Runnable shutdownHook) {
if (isAlive()) {
throw new RuntimeException("Attempted to start process that is already running.");
}
String binaryPath = mBinary.getAbsolutePath();
Log.v("Executing " + binaryPath + " with arguments " + mArguments + " and with environment "
+ mEnvironment.toString());
int[] pid = new int[1];
String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]);
mLog = new File(String.format("%s/%s.log", InterpreterConstants.SDCARD_SL4A_ROOT, getName()));
mFd =
Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(),
getWorkingDirectory(), pid);
mPid.set(pid[0]);
mOut = new FileOutputStream(mFd);
mIn = new StreamGobbler(new FileInputStream(mFd), mLog, DEFAULT_BUFFER_SIZE);
mStartTime = System.currentTimeMillis();
new Thread(new Runnable() {
public void run() {
int result = Exec.waitFor(mPid.get());
mEndTime = System.currentTimeMillis();
int pid = mPid.getAndSet(PID_INIT_VALUE);
Log.v("Process " + pid + " exited with result code " + result + ".");
try {
mIn.close();
} catch (IOException e) {
Log.e(e);
}
try {
mOut.close();
} catch (IOException e) {
Log.e(e);
}
if (shutdownHook != null) {
shutdownHook.run();
}
}
}).start();
}
private String[] getEnvironmentArray() {
List<String> environmentVariables = new ArrayList<String>();
for (Entry<String, String> entry : mEnvironment.entrySet()) {
environmentVariables.add(entry.getKey() + "=" + entry.getValue());
}
String[] environment = environmentVariables.toArray(new String[environmentVariables.size()]);
return environment;
}
public void kill() {
if (isAlive()) {
android.os.Process.killProcess(mPid.get());
Log.v("Killed process " + mPid);
}
}
public boolean isAlive() {
return (mFd != null && mFd.valid()) && mPid.get() != PID_INIT_VALUE;
}
public String getUptime() {
long ms;
if (!isAlive()) {
ms = mEndTime - mStartTime;
} else {
ms = System.currentTimeMillis() - mStartTime;
}
StringBuilder buffer = new StringBuilder();
int days = (int) (ms / (1000 * 60 * 60 * 24));
int hours = (int) (ms % (1000 * 60 * 60 * 24)) / 3600000;
int minutes = (int) (ms % 3600000) / 60000;
int seconds = (int) (ms % 60000) / 1000;
if (days != 0) {
buffer.append(String.format("%02d:%02d:", days, hours));
} else if (hours != 0) {
buffer.append(String.format("%02d:", hours));
}
buffer.append(String.format("%02d:%02d", minutes, seconds));
return buffer.toString();
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
public String getWorkingDirectory() {
return null;
}
}