Runs on the UI thread after {@link #doInBackground}. The + * specified result is the value returned by {@link #doInBackground}.
+ * + *This method won't be invoked if the task was cancelled.
+ * + * You MUST @Override this method if you don't need the result + * then you should consider using a new Thread implentation instead + * + * @param result The result of the operation computed by {@link #doInBackground}. + */ + @Override + protected abstract void onPostExecute(String result); +} diff --git a/src/com/SecUpwN/AIMSICD/cmdprocessor/CMDProcessor.java b/src/com/SecUpwN/AIMSICD/cmdprocessor/CMDProcessor.java new file mode 100644 index 000000000..222b69698 --- /dev/null +++ b/src/com/SecUpwN/AIMSICD/cmdprocessor/CMDProcessor.java @@ -0,0 +1,81 @@ +/** 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 com.SecUpwN.AIMSICD.cmdprocessor; + +import android.util.Log; + +public final class CMDProcessor { + private static final String TAG = "AIMSICD_CMDProcessor"; + + public CMDProcessor() { + + } + + /* Run a system command with full redirection */ + public static ChildProcess startSysCmd(String[] cmdarray, String childStdin) { + return new ChildProcess(cmdarray, childStdin); + } + + public static CommandResult runSysCmd(String[] cmdarray, String childStdin) { + ChildProcess proc = startSysCmd(cmdarray, childStdin); + proc.waitFinished(); + return proc.getResult(); + } + + public static ChildProcess startShellCommand(String cmd) { + String[] cmdarray = new String[3]; + cmdarray[0] = "sh"; + cmdarray[1] = "-c"; + cmdarray[2] = cmd; + return startSysCmd(cmdarray, null); + } + + public static CommandResult runShellCommand(String cmd) { + ChildProcess proc = startShellCommand(cmd); + proc.waitFinished(); + return proc.getResult(); + } + + public static ChildProcess startSuCommand(String cmd) { + String[] cmdarray = new String[3]; + cmdarray[0] = "su"; + cmdarray[1] = "-c"; + cmdarray[2] = cmd; + return startSysCmd(cmdarray, null); + } + + public static CommandResult runSuCommand(String cmd) { + ChildProcess proc = startSuCommand(cmd); + proc.waitFinished(); + return proc.getResult(); + } + + public static boolean canSU() { + CommandResult r = runShellCommand("id"); + StringBuilder out = new StringBuilder(0); + out.append(r.getStdout()); + out.append(" ; "); + out.append(r.getStderr()); + Log.d(TAG, "canSU() su[" + r.getExitValue() + "]: " + out); + return r.success(); + } +} diff --git a/src/com/SecUpwN/AIMSICD/cmdprocessor/ChildProcess.java b/src/com/SecUpwN/AIMSICD/cmdprocessor/ChildProcess.java new file mode 100644 index 000000000..6bd2a1184 --- /dev/null +++ b/src/com/SecUpwN/AIMSICD/cmdprocessor/ChildProcess.java @@ -0,0 +1,165 @@ +/** 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 com.SecUpwN.AIMSICD.cmdprocessor; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import static java.lang.System.nanoTime; + +public class ChildProcess { + private String TAG = getClass().getSimpleName(); + + private static final int PIPE_SIZE = 1024; + + private class ChildReader extends Thread { + InputStream mStream; + 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) { + // Ignore + } + try { + mStream.close(); + } catch (IOException e) { + // Ignore + } + } + } + + private class ChildWriter extends Thread { + OutputStream mStream; + 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) { + // Ignore + } + try { + mStream.close(); + } catch (IOException e) { + // Ignore + } + } + } + + 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(); + try { + mChildProc = Runtime.getRuntime().exec(cmdarray); + if (childStdin != null) { + mChildStdinWriter = new ChildWriter(mChildProc.getOutputStream(), childStdin); + mChildStdinWriter.start(); + } + mChildStdout = new StringBuffer(); + mChildStdoutReader = new ChildReader(mChildProc.getInputStream(), mChildStdout); + mChildStdoutReader.start(); + mChildStderr = new StringBuffer(); + mChildStderrReader = new ChildReader(mChildProc.getErrorStream(), mChildStderr); + mChildStderrReader.start(); + } catch (IOException e) { + // XXX: log + } + } + + 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) { + // Ignore + } + } + return mExitValue; + } + + public CommandResult getResult() { + if (!isFinished()) { + throw new IllegalThreadStateException("Child process running"); + } + return new CommandResult( + mStartTime, + mExitValue, + mChildStdout.toString(), + mChildStderr.toString(), + mEndTime); + } +} diff --git a/src/com/SecUpwN/AIMSICD/cmdprocessor/CommandResult.java b/src/com/SecUpwN/AIMSICD/cmdprocessor/CommandResult.java new file mode 100644 index 000000000..55a27b20f --- /dev/null +++ b/src/com/SecUpwN/AIMSICD/cmdprocessor/CommandResult.java @@ -0,0 +1,193 @@ +/** 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 com.SecUpwN.AIMSICD.cmdprocessor; + +import android.os.Environment; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +@SuppressWarnings("AccessOfSystemProperties") +public class CommandResult implements Parcelable { + private final String TAG = "AIMSICD_CommandResult"; + private final long mStartTime; + private final int mExitValue; + private final String mStdout; + private final String mStderr; + private final long mEndTime; + + public CommandResult(long startTime, + int exitValue, + String stdout, + String stderr, + long endTime) { + mStartTime = startTime; + mExitValue = exitValue; + mStdout = stdout; + mStderr = stderr; + mEndTime = endTime; + + Log.d(TAG, "Time to execute: " + (mEndTime - mStartTime) + " ns (nanoseconds)"); + // this is set last so log from here + checkForErrors(); + } + + // pretty much just forward the constructor from parcelable to our main + // loading constructor + @SuppressWarnings("CastToConcreteClass") + public CommandResult(Parcel inParcel) { + this(inParcel.readLong(), + inParcel.readInt(), + inParcel.readString(), + inParcel.readString(), + inParcel.readLong()); + } + + public boolean success() { + return (mExitValue == 0); + } + + public long getEndTime() { + return mEndTime; + } + + public String getStderr() { + return new String(mStderr); + } + + public String getStdout() { + return new String(mStdout); + } + + public Integer getExitValue() { + return mExitValue; + } + + public long getStartTime() { + return mStartTime; + } + + @SuppressWarnings("UnnecessaryExplicitNumericCast") + private void checkForErrors() { + if (mExitValue != 0 + || !"".equals(mStderr.trim())) { + // don't log the commands that failed + // because the cpu was offline + boolean skipOfflineCpu = + // if core is off locking fails + mStderr.contains("chmod: /sys/devices/system/cpu/cpu") + // if core is off applying cpu freqs fails + || mStderr.contains(": can't create /sys/devices/system/cpu/cpu"); + String lineEnding = System.getProperty("line.separator"); + FileWriter errorWriter = null; + try { + File errorLogFile = new File( + Environment.getExternalStorageDirectory() + + "/AIMSICD/error.txt"); + if (!errorLogFile.exists()) { + errorLogFile.createNewFile(); + } + errorWriter = new FileWriter(errorLogFile, true); + // only log the cpu state as offline while writing + if (skipOfflineCpu) { + errorWriter.write(lineEnding); + errorWriter.write("Attempted to write to an offline cpu core (ignore me)."); + } else { + errorWriter.write(TAG + " shell error detected!"); + errorWriter.write(lineEnding); + errorWriter.write("CommandResult {" + this.toString() + '}'); + errorWriter.write(lineEnding); + } + errorWriter.write(lineEnding); + } catch (IOException e) { + Log.e(TAG, "Failed to write command result to error file", e); + } finally { + if (errorWriter != null) { + try { + errorWriter.close(); + } catch (IOException ignored) { + // let it go + } + } + } + } + } + + // implement parcelable + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeLong(mStartTime); + parcel.writeInt(mExitValue); + parcel.writeString(mStdout); + parcel.writeString(mStderr); + parcel.writeLong(mEndTime); + } + + @Override + public String toString() { + return "CommandResult{" + + ", mStartTime=" + mStartTime + + ", mExitValue=" + mExitValue + + ", stdout='" + mStdout + "'" + + ", stderr='" + mStderr + "'" + + ", mEndTime=" + mEndTime + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof CommandResult)) { + return false; + } + + CommandResult that = (CommandResult) o; + + return (mStartTime == that.mStartTime && + mExitValue == that.mExitValue && + mStdout == that.mStdout && + mStderr == that.mStderr && + mEndTime == that.mEndTime); + } + + @Override + public int hashCode() { + int result = 0; + result = 31 * result + (int) (mStartTime ^ (mStartTime >>> 32)); + result = 31 * result + mExitValue; + result = 31 * result + (mStdout != null ? mStdout.hashCode() : 0); + result = 31 * result + (mStderr != null ? mStderr.hashCode() : 0); + result = 31 * result + (int) (mEndTime ^ (mEndTime >>> 32)); + return result; + } +} diff --git a/src/com/SecUpwN/AIMSICD/cmdprocessor/Helpers.java b/src/com/SecUpwN/AIMSICD/cmdprocessor/Helpers.java new file mode 100644 index 000000000..ad9a83314 --- /dev/null +++ b/src/com/SecUpwN/AIMSICD/cmdprocessor/Helpers.java @@ -0,0 +1,424 @@ +/** 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 com.SecUpwN.AIMSICD.cmdprocessor; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.util.Log; +import android.widget.Toast; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; + +import static com.SecUpwN.AIMSICD.cmdprocessor.CMDProcessor.*; + +public class Helpers { + private static final String BUILD_PROP = "/system/build.prop"; + // don't show unavoidable warnings + @SuppressWarnings({ + "UnusedDeclaration", + "MethodWithMultipleReturnPoints", + "ReturnOfNull", + "NestedAssignment", + "DynamicRegexReplaceableByCompiledPattern", + "BreakStatement" + }) + + // avoids hardcoding the tag + private static final String TAG = "AIMSICD_Helpers"; + + public Helpers() { + // dummy constructor + } + + public static String convertStreamToString(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + + return sb.toString(); + } + + public static String getStringFromFile(String filePath) throws Exception { + File fl = new File(filePath); + FileInputStream fin = new FileInputStream(fl); + String ret = convertStreamToString(fin); + fin.close(); + + return ret; + } + + public static Boolean hasBuildPropValue(String buildProp) throws Exception { + Boolean has = false; + String buildprop = ""; + buildprop = getStringFromFile(BUILD_PROP); + if (buildprop.matches(buildProp + "=.+$")) + has = true; + return has; + } + + /** + * Checks device for SuperUser permission + * + * @return If SU was granted or denied + */ + @SuppressWarnings("MethodWithMultipleReturnPoints") + public static boolean checkSu() { + if (!new File("/system/bin/su").exists() + && !new File("/system/xbin/su").exists()) { + Log.e(TAG, "su binary does not exist!!!"); + return false; // tell caller to bail... + } + try { + if (runSuCommand("ls /data/app-private").success()) { + Log.i(TAG, " SU exists and we have permission"); + return true; + } else { + Log.i(TAG, " SU exists but we don't have permission"); + return false; + } + } catch (NullPointerException e) { + Log.e(TAG, "NullPointer throw while looking for su binary", e); + return false; + } + } + + /** + * Checks to see if Busybox is installed in "/system/" + * + * @return If busybox exists + */ + public static boolean checkBusybox() { + if (!new File("/system/bin/busybox").exists() + && !new File("/system/xbin/busybox").exists()) { + Log.e(TAG, "Busybox not in xbin or bin!"); + return false; + } + try { + if (!runSuCommand("busybox mount").success()) { + Log.e(TAG, "Busybox is there but it is borked! "); + return false; + } + } catch (NullPointerException e) { + Log.e(TAG, "NullpointerException thrown while testing busybox", e); + return false; + } + return true; + } + + public static String[] getMounts(CharSequence path) { + BufferedReader bufferedReader = null; + try { + bufferedReader = new BufferedReader(new FileReader("/proc/mounts"), 256); + String line; + while ((line = bufferedReader.readLine()) != null) { + if (line.contains(path)) { + return line.split(" "); + } + } + } catch (FileNotFoundException ignored) { + Log.d(TAG, "/proc/mounts does not exist"); + } catch (IOException ignored) { + Log.d(TAG, "Error reading /proc/mounts"); + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException ignored) { + // ignored + } + } + } + return null; + } + + public static boolean getMount(String mount) { + String[] mounts = getMounts("/system"); + if (mounts != null && mounts.length >= 3) { + String device = mounts[0]; + String path = mounts[1]; + String point = mounts[2]; + String preferredMountCmd = "mount -o " + mount + ",remount -t " + point + ' ' + device + ' ' + path; + if (runSuCommand(preferredMountCmd).success()) { + return true; + } + } + String fallbackMountCmd = "busybox mount -o remount," + mount + " /system"; + return runSuCommand(fallbackMountCmd).success(); + } + + public static String readOneLine(String fname) { + BufferedReader br = null; + String line = null; + try { + br = new BufferedReader(new FileReader(fname), 1024); + line = br.readLine(); + } catch (FileNotFoundException ignored) { + Log.d(TAG, "File was not found! trying via shell..."); + return readFileViaShell(fname, true); + } catch (IOException e) { + Log.d(TAG, "IOException while reading system file", e); + return readFileViaShell(fname, true); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ignored) { + // failed to close reader + } + } + } + return line; + } + + public static String readFileViaShell(String filePath, boolean useSu) { + String command = "cat " + filePath; + return useSu ? runSuCommand(command).getStdout() + : runShellCommand(command).getStdout(); + } + + public static boolean writeOneLine(String filename, String value) { + FileWriter fileWriter = null; + try { + fileWriter = new FileWriter(filename); + fileWriter.write(value); + } catch (IOException e) { + String Error = "Error writing { " + value + " } to file: " + filename; + Log.e(TAG, Error, e); + return false; + } finally { + if (fileWriter != null) { + try { + fileWriter.close(); + } catch (IOException ignored) { + // failed to close writer + } + } + } + return true; + } + + public static String[] getAvailableIOSchedulers() { + String[] schedulers = null; + String[] aux = readStringArray("/sys/block/mmcblk0/queue/scheduler"); + if (aux != null) { + schedulers = new String[aux.length]; + for (int i = 0; i < aux.length; i++) { + schedulers[i] = aux[i].charAt(0) == '[' + ? aux[i].substring(1, aux[i].length() - 1) + : aux[i]; + } + } + return schedulers; + } + + private static String[] readStringArray(String fname) { + String line = readOneLine(fname); + if (line != null) { + return line.split(" "); + } + return null; + } + + public static String getIOScheduler() { + String scheduler = null; + String[] schedulers = readStringArray("/sys/block/mmcblk0/queue/scheduler"); + if (schedulers != null) { + for (String s : schedulers) { + if (s.charAt(0) == '[') { + scheduler = s.substring(1, s.length() - 1); + break; + } + } + } + return scheduler; + } + + /** + * Long toast message + * + * @param context Application Context + * @param msg Message to send + */ + public static void msgLong(Context context, String msg) { + if (context != null && msg != null) { + Toast.makeText(context, msg.trim(), Toast.LENGTH_LONG).show(); + } + } + + /** + * Short toast message + * + * @param context Application Context + * @param msg Message to send + */ + public static void msgShort(Context context, String msg) { + if (context != null && msg != null) { + Toast.makeText(context, msg.trim(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * Long toast message + * + * @param context Application Context + * @param msg Message to send + */ + public static void sendMsg(Context context, String msg) { + if (context != null && msg != null) { + msgLong(context, msg); + } + } + + /** + * Return a timestamp + * + * @param context Application Context + */ + @SuppressWarnings("UnnecessaryFullyQualifiedName") + public static String getTimestamp(Context context) { + String timestamp = "unknown"; + Date now = new Date(); + java.text.DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context); + java.text.DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context); + timestamp = dateFormat.format(now) + ' ' + timeFormat.format(now); + return timestamp; + } + + public static boolean isPackageInstalled(String packageName, PackageManager pm) { + try { + String mVersion = pm.getPackageInfo(packageName, 0).versionName; + if (mVersion == null) { + return false; + } + } catch (PackageManager.NameNotFoundException notFound) { + Log.e(TAG, "Package could not be found!", notFound); + return false; + } + return true; + } + + public static void restartSystemUI() { + startSuCommand("pkill -TERM -f com.android.systemui"); + } + + public static void setSystemProp(String prop, String val) { + startSuCommand("setprop " + prop + " " + val); + } + + public static String getSystemProp(Context context, String prop, String def) { + String result = null; + try { + result = SystemPropertiesReflection.get(context, prop); + } catch (IllegalArgumentException iae) { + Log.e(TAG, "Failed to get prop: " + prop); + } + return result == null ? def : result; + } + + // If the value is empty or null, fallback to the second property if there's one + public static String getPropWithFallback(Context context, String[] props, String def) { + String value = ""; + for (String prop : props) { + value = Helpers.getSystemProp(context, prop, def); + if (!value.equals("")) { + return value; + } + } + return ""; + } + + public static String toMHz(String mhzString) { + return new StringBuilder().append(Integer.valueOf(mhzString) / 1000) + .append(" MHz").toString(); + } + + public static int getNumOfCpus() { + int numOfCpu = 1; + String numOfCpus = Helpers.readOneLine("/sys/devices/system/cpu/present"); + String[] cpuCount = numOfCpus.split("-"); + if (cpuCount.length > 1) { + try { + int cpuStart = Integer.parseInt(cpuCount[0]); + int cpuEnd = Integer.parseInt(cpuCount[1]); + + numOfCpu = cpuEnd - cpuStart + 1; + + if (numOfCpu < 0) + numOfCpu = 1; + } catch (NumberFormatException ex) { + numOfCpu = 1; + } + } + return numOfCpu; + } + + public static ArrayList