Home | History | Annotate | Download | only in android_scripting
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.googlecode.android_scripting;
     18 
     19 import com.googlecode.android_scripting.interpreter.InterpreterConstants;
     20 import com.trilead.ssh2.StreamGobbler;
     21 
     22 import java.io.File;
     23 import java.io.FileDescriptor;
     24 import java.io.FileInputStream;
     25 import java.io.FileOutputStream;
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 import java.io.OutputStream;
     29 import java.util.ArrayList;
     30 import java.util.HashMap;
     31 import java.util.List;
     32 import java.util.Map;
     33 import java.util.Map.Entry;
     34 import java.util.concurrent.atomic.AtomicInteger;
     35 
     36 public class Process {
     37 
     38   private static final int DEFAULT_BUFFER_SIZE = 8192;
     39 
     40   private final List<String> mArguments;
     41   private final Map<String, String> mEnvironment;
     42 
     43   private static final int PID_INIT_VALUE = -1;
     44 
     45   private File mBinary;
     46   private String mName;
     47   private long mStartTime;
     48   private long mEndTime;
     49 
     50   protected final AtomicInteger mPid;
     51   protected FileDescriptor mFd;
     52   protected OutputStream mOut;
     53   protected InputStream mIn;
     54   protected File mLog;
     55 
     56   public Process() {
     57     mArguments = new ArrayList<String>();
     58     mEnvironment = new HashMap<String, String>();
     59     mPid = new AtomicInteger(PID_INIT_VALUE);
     60   }
     61 
     62   public void addArgument(String argument) {
     63     mArguments.add(argument);
     64   }
     65 
     66   public void addAllArguments(List<String> arguments) {
     67     mArguments.addAll(arguments);
     68   }
     69 
     70   public void putAllEnvironmentVariables(Map<String, String> environment) {
     71     mEnvironment.putAll(environment);
     72   }
     73 
     74   public void putEnvironmentVariable(String key, String value) {
     75     mEnvironment.put(key, value);
     76   }
     77 
     78   public void setBinary(File binary) {
     79     if (!binary.exists()) {
     80       throw new RuntimeException("Binary " + binary + " does not exist!");
     81     }
     82     mBinary = binary;
     83   }
     84 
     85   public Integer getPid() {
     86     return mPid.get();
     87   }
     88 
     89   public FileDescriptor getFd() {
     90     return mFd;
     91   }
     92 
     93   public OutputStream getOut() {
     94     return mOut;
     95   }
     96 
     97   public OutputStream getErr() {
     98     return getOut();
     99   }
    100 
    101   public File getLogFile() {
    102     return mLog;
    103   }
    104 
    105   public InputStream getIn() {
    106     return mIn;
    107   }
    108 
    109   public void start(final Runnable shutdownHook) {
    110     if (isAlive()) {
    111       throw new RuntimeException("Attempted to start process that is already running.");
    112     }
    113 
    114     String binaryPath = mBinary.getAbsolutePath();
    115     Log.v("Executing " + binaryPath + " with arguments " + mArguments + " and with environment "
    116         + mEnvironment.toString());
    117 
    118     int[] pid = new int[1];
    119     String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]);
    120     mLog = new File(String.format("%s/%s.log", InterpreterConstants.SDCARD_SL4A_ROOT, getName()));
    121 
    122     mFd =
    123         Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(),
    124             getWorkingDirectory(), pid);
    125     mPid.set(pid[0]);
    126     mOut = new FileOutputStream(mFd);
    127     mIn = new StreamGobbler(new FileInputStream(mFd), mLog, DEFAULT_BUFFER_SIZE);
    128     mStartTime = System.currentTimeMillis();
    129 
    130     new Thread(new Runnable() {
    131       public void run() {
    132         int result = Exec.waitFor(mPid.get());
    133         mEndTime = System.currentTimeMillis();
    134         int pid = mPid.getAndSet(PID_INIT_VALUE);
    135         Log.v("Process " + pid + " exited with result code " + result + ".");
    136         try {
    137           mIn.close();
    138         } catch (IOException e) {
    139           Log.e(e);
    140         }
    141         try {
    142           mOut.close();
    143         } catch (IOException e) {
    144           Log.e(e);
    145         }
    146         if (shutdownHook != null) {
    147           shutdownHook.run();
    148         }
    149       }
    150     }).start();
    151   }
    152 
    153   private String[] getEnvironmentArray() {
    154     List<String> environmentVariables = new ArrayList<String>();
    155     for (Entry<String, String> entry : mEnvironment.entrySet()) {
    156       environmentVariables.add(entry.getKey() + "=" + entry.getValue());
    157     }
    158     String[] environment = environmentVariables.toArray(new String[environmentVariables.size()]);
    159     return environment;
    160   }
    161 
    162   public void kill() {
    163     if (isAlive()) {
    164       android.os.Process.killProcess(mPid.get());
    165       Log.v("Killed process " + mPid);
    166     }
    167   }
    168 
    169   public boolean isAlive() {
    170     return (mFd != null && mFd.valid()) && mPid.get() != PID_INIT_VALUE;
    171   }
    172 
    173   public String getUptime() {
    174     long ms;
    175     if (!isAlive()) {
    176       ms = mEndTime - mStartTime;
    177     } else {
    178       ms = System.currentTimeMillis() - mStartTime;
    179     }
    180     StringBuilder buffer = new StringBuilder();
    181     int days = (int) (ms / (1000 * 60 * 60 * 24));
    182     int hours = (int) (ms % (1000 * 60 * 60 * 24)) / 3600000;
    183     int minutes = (int) (ms % 3600000) / 60000;
    184     int seconds = (int) (ms % 60000) / 1000;
    185     if (days != 0) {
    186       buffer.append(String.format("%02d:%02d:", days, hours));
    187     } else if (hours != 0) {
    188       buffer.append(String.format("%02d:", hours));
    189     }
    190     buffer.append(String.format("%02d:%02d", minutes, seconds));
    191     return buffer.toString();
    192   }
    193 
    194   public String getName() {
    195     return mName;
    196   }
    197 
    198   public void setName(String name) {
    199     mName = name;
    200   }
    201 
    202   public String getWorkingDirectory() {
    203     return null;
    204   }
    205 }
    206