content: /**   Copyright (C) 2013  Louis Teboul (a.k.a Androguide)
   *
   *    admin@pimpmyrom.org  || louisteboul@gmail.com
   *    http://pimpmyrom.org || http://androguide.fr
   *    71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE.
   *
   *     This program is free software; you can redistribute it and/or modify
   *     it under the terms of the GNU General Public License as published by
   *     the Free Software Foundation; either version 2 of the License, or
   *     (at your option) any later version.
   *
   *     This program is distributed in the hope that it will be useful,
   *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *     GNU General Public License for more details.
   *
   *      You should have received a copy of the GNU General Public License along
   *      with this program; if not, write to the Free Software Foundation, Inc.,
   *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   **/
  
  package zz.aimsicd.lite.utils;
  
  import android.util.Log;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  
  import static java.lang.System.nanoTime;
  
  public class ChildProcess {
  
      public static final String TAG = "AICDL";
      public static final String mTAG = "XXX";
  
  
      private static final int PIPE_SIZE = 1024;
  
      private class ChildReader extends Thread {
  
          final InputStream mStream;
          final StringBuffer mBuffer;
  
          ChildReader(InputStream is, StringBuffer buf) {
              mStream = is;
              mBuffer = buf;
          }
  
          public void run() {
              byte[] buf = new byte[PIPE_SIZE];
              try {
                  int len;
                  while ((len = mStream.read(buf)) != -1) {
                      String s = new String(buf, 0, len);
                      mBuffer.append(s);
                  }
              } catch (IOException e) {
                 Log.d(TAG, mTAG + e.getMessage());
              }
              try {
                  mStream.close();
              } catch (IOException e) {
                 Log.d(TAG, mTAG + "cannot close stream", e);
              }
          }
      }
  
      private class ChildWriter extends Thread {
  
          private final OutputStream mStream;
          private final String mBuffer;
  
          ChildWriter(OutputStream os, String buf) {
              mStream = os;
              mBuffer = buf;
          }
  
          public void run() {
              int off = 0;
              byte[] buf = mBuffer.getBytes();
              try {
                  while (off < buf.length) {
                      int len = Math.min(PIPE_SIZE, buf.length - off);
                      mStream.write(buf, off, len);
                      off += len;
                  }
              } catch (IOException e) {
                 Log.d(TAG, mTAG + e.getMessage());
              }
              try {
                  mStream.close();
              } catch (IOException e) {
                 Log.d(TAG, mTAG + "cannot close stream", e);
              }
          }
      }
  
      private long mStartTime;
      private Process mChildProc;
      private ChildWriter mChildStdinWriter;
      private ChildReader mChildStdoutReader;
      private ChildReader mChildStderrReader;
      private StringBuffer mChildStdout;
      private StringBuffer mChildStderr;
      private int mExitValue;
      private long mEndTime;
  
      public ChildProcess(String[] cmdarray, String childStdin) {
  
          mStartTime = nanoTime();
          mChildStdout = new StringBuffer();
          mChildStderr = new StringBuffer();
  
          try {
              mChildProc = Runtime.getRuntime().exec(cmdarray);
              if (childStdin != null) {
                  mChildStdinWriter = new ChildWriter(mChildProc.getOutputStream(), childStdin);
                  mChildStdinWriter.start();
              }
              mChildStdoutReader = new ChildReader(mChildProc.getInputStream(), mChildStdout);
              mChildStdoutReader.start();
              mChildStderrReader = new ChildReader(mChildProc.getErrorStream(), mChildStderr);
              mChildStderrReader.start();
          } catch (IOException e) {
             Log.d(TAG, mTAG + e.getMessage(), e);
          }
      }
  
      public boolean isFinished() {
          boolean finished = true;
          if (mChildProc != null) {
              try {
                  mChildProc.exitValue();
              } catch (IllegalStateException e) {
                  finished = false;
              }
          }
          return finished;
      }
  
      public int waitFinished() {
          while (mChildProc != null) {
              try {
                  mExitValue = mChildProc.waitFor();
                  mEndTime = nanoTime();
                  mChildProc = null;
                  mChildStderrReader.join();
                  mChildStderrReader = null;
                  mChildStdoutReader.join();
                  mChildStdoutReader = null;
                  if (mChildStdinWriter != null) {
                      mChildStdinWriter.join();
                      mChildStdinWriter = null;
                  }
              } catch (InterruptedException e) {
                 Log.d(TAG, mTAG + e.getMessage(), e);
              }
          }
          return mExitValue;
      }
  
      public CommandResult getResult() {
          if (!isFinished()) {
              throw new IllegalThreadStateException("Child process running");
          }
          return new CommandResult(mStartTime, mExitValue, mChildStdout.toString(),
                  mChildStderr.toString(), mEndTime);
      }
  }
  