| /* | |
| * 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; | |
| } | |
| } |