| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| package com.mozilla.SUTAgentAndroid.service; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.BufferedReader; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.PrintWriter; |
| import java.io.RandomAccessFile; |
| import java.net.DatagramPacket; |
| import java.net.DatagramSocket; |
| import java.net.InetAddress; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import java.net.UnknownHostException; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| import java.util.TimeZone; |
| import java.util.zip.Adler32; |
| import java.util.zip.CheckedInputStream; |
| import java.util.zip.CheckedOutputStream; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| import java.util.zip.ZipInputStream; |
| import java.util.zip.ZipOutputStream; |
| |
| import org.apache.commons.net.ftp.FTP; |
| import org.apache.commons.net.ftp.FTPClient; |
| import org.apache.commons.net.ftp.FTPFile; |
| import org.apache.commons.net.ftp.FTPReply; |
| |
| import com.mozilla.SUTAgentAndroid.R; |
| import com.mozilla.SUTAgentAndroid.SUTAgentAndroid; |
| |
| import android.app.Activity; |
| import android.app.ActivityManager; |
| import android.app.AlarmManager; |
| import android.app.Notification; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.content.ActivityNotFoundException; |
| import android.content.ComponentName; |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.ContextWrapper; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ServiceInfo; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Build; |
| import android.os.Debug; |
| import android.os.Environment; |
| import android.os.StatFs; |
| import android.os.SystemClock; |
| import android.text.TextUtils; |
| import android.util.DisplayMetrics; |
| import android.util.Log; |
| import android.view.Surface; |
| import android.view.WindowManager; |
| |
| public class DoCommand { |
| |
| String lineSep = System.getProperty("line.separator"); |
| Process pProc; |
| OutputStream sutIn; |
| InputStream sutErr; |
| InputStream sutOut; |
| AlertLooperThread alrt = null; |
| ContextWrapper contextWrapper = null; |
| |
| String currentDir = "/"; |
| String sErrorPrefix = "##AGENT-WARNING## "; |
| boolean bTraceOn = false; |
| |
| String ffxProvider = "org.mozilla.ffxcp"; |
| String fenProvider = "org.mozilla.fencp"; |
| |
| private static final int DEFAULT_STARTPRG_TIMEOUT_SECONDS = 300; |
| |
| public final String prgVersion = "SUTAgentAndroid Version 1.20"; |
| |
| public enum Command |
| { |
| RUN ("run"), |
| EXEC ("exec"), |
| EXECSU ("execsu"), |
| EXECCWD ("execcwd"), |
| EXECCWDSU ("execcwdsu"), |
| EXECEXT ("execext"), |
| ENVRUN ("envrun"), |
| KILL ("kill"), |
| PS ("ps"), |
| DEVINFO ("info"), |
| OS ("os"), |
| ID ("id"), |
| UPTIME ("uptime"), |
| UPTIMEMILLIS ("uptimemillis"), |
| SUTUPTIMEMILLIS ("sutuptimemillis"), |
| SETTIME ("settime"), |
| SYSTIME ("systime"), |
| SCREEN ("screen"), |
| ROTATION ("rotation"), |
| MEMORY ("memory"), |
| POWER ("power"), |
| PROCESS ("process"), |
| SUTUSERINFO ("sutuserinfo"), |
| TEMPERATURE ("temperature"), |
| GETAPPROOT ("getapproot"), |
| TESTROOT ("testroot"), |
| ALRT ("alrt"), |
| DISK ("disk"), |
| CP ("cp"), |
| TIME ("time"), |
| HASH ("hash"), |
| CD ("cd"), |
| CAT ("cat"), |
| CWD ("cwd"), |
| MV ("mv"), |
| PUSH ("push"), |
| PULL ("pull"), |
| RM ("rm"), |
| PRUNE ("rmdr"), |
| MKDR ("mkdr"), |
| DIRWRITABLE ("dirw"), |
| ISDIR ("isdir"), |
| DEAD ("dead"), |
| MEMS ("mems"), |
| LS ("ls"), |
| TMPD ("tmpd"), |
| PING ("ping"), |
| REBT ("rebt"), |
| UNZP ("unzp"), |
| ZIP ("zip"), |
| CLOK ("clok"), |
| STAT ("stat"), |
| QUIT ("quit"), |
| EXIT ("exit"), |
| HELP ("help"), |
| FTPG ("ftpg"), |
| FTPP ("ftpp"), |
| INST ("inst"), |
| UPDT ("updt"), |
| UNINST ("uninst"), |
| UNINSTALL ("uninstall"), |
| TEST ("test"), |
| DBG ("dbg"), |
| TRACE ("trace"), |
| VER ("ver"), |
| TZGET ("tzget"), |
| TZSET ("tzset"), |
| ADB ("adb"), |
| CHMOD ("chmod"), |
| TOPACTIVITY ("activity"), |
| UNKNOWN ("unknown"); |
| |
| private final String theCmd; |
| |
| Command(String theCmd) { this.theCmd = theCmd; } |
| |
| public String theCmd() {return theCmd;} |
| |
| public static Command getCmd(String sCmd) |
| { |
| Command retCmd = UNKNOWN; |
| for (Command cmd : Command.values()) |
| { |
| if (cmd.theCmd().equalsIgnoreCase(sCmd)) |
| { |
| retCmd = cmd; |
| break; |
| } |
| } |
| return (retCmd); |
| } |
| } |
| |
| public DoCommand(ContextWrapper service) |
| { |
| this.contextWrapper = service; |
| } |
| |
| public String processCommand(String theCmdLine, PrintWriter out, BufferedInputStream in, OutputStream cmdOut) |
| { |
| String strReturn = ""; |
| Command cCmd = null; |
| Command cSubCmd = null; |
| |
| if (bTraceOn) |
| ((ASMozStub)this.contextWrapper).SendToDataChannel(theCmdLine); |
| |
| String [] Argv = parseCmdLine2(theCmdLine); |
| |
| int Argc = Argv.length; |
| |
| cCmd = Command.getCmd(Argv[0]); |
| |
| switch(cCmd) |
| { |
| case TRACE: |
| if (Argc == 2) |
| bTraceOn = (Argv[1].equalsIgnoreCase("on") ? true : false); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for trace command!"; |
| break; |
| |
| case VER: |
| strReturn = prgVersion; |
| break; |
| |
| case CLOK: |
| strReturn = GetClok(); |
| break; |
| |
| case TZGET: |
| strReturn = GetTimeZone(); |
| break; |
| |
| case TZSET: |
| if (Argc == 2) |
| strReturn = SetTimeZone(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for settz command!"; |
| break; |
| |
| case UPDT: |
| if (Argc >= 2) |
| strReturn = StrtUpdtOMatic(Argv[1], Argv[2], (Argc > 3 ? Argv[3] : null), (Argc > 4 ? Argv[4] : null)); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for updt command!"; |
| break; |
| |
| case SETTIME: |
| strReturn = SetSystemTime(Argv[1], (Argc > 2 ? Argv[2] : null), cmdOut); |
| break; |
| |
| case CWD: |
| try { |
| strReturn = new java.io.File(currentDir).getCanonicalPath(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| break; |
| |
| case CD: |
| if (Argc == 2) |
| strReturn = changeDir(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for cd command!"; |
| break; |
| |
| case LS: |
| strReturn = PrintDir(((Argc > 1) ? Argv[1] : currentDir)); |
| break; |
| |
| case GETAPPROOT: |
| if (Argc == 2) |
| strReturn = GetAppRoot(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for getapproot command!"; |
| break; |
| |
| case ISDIR: |
| if (Argc == 2) |
| strReturn = isDirectory(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for isdir command!"; |
| break; |
| |
| case TESTROOT: |
| strReturn = GetTestRoot(); |
| break; |
| |
| case DEAD: |
| if (Argc == 2) |
| strReturn = (IsProcessDead(Argv[1]) ? (Argv[1] + " is hung or unresponsive") : (Argv[1] + " is ok")); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for dead command!"; |
| break; |
| |
| case PS: |
| strReturn = GetProcessInfo(); |
| break; |
| |
| case PULL: |
| if (Argc >= 2) { |
| long lOff = 0; |
| long lLen = -1; |
| if (Argc > 2) { |
| try { |
| lOff = Long.parseLong(Argv[2].trim()); |
| } catch (NumberFormatException nfe) { |
| lOff = 0; |
| System.out.println("NumberFormatException: " + nfe.getMessage()); |
| } |
| } |
| if (Argc == 4) { |
| try { |
| lLen = Long.parseLong(Argv[3].trim()); |
| } catch (NumberFormatException nfe) { |
| lLen = -1; |
| System.out.println("NumberFormatException: " + nfe.getMessage()); |
| } |
| } |
| strReturn = Pull(Argv[1], lOff, lLen, cmdOut); |
| } else { |
| strReturn = sErrorPrefix + "Wrong number of arguments for pull command!"; |
| } |
| break; |
| |
| case PUSH: |
| if (Argc == 3) |
| { |
| long lArg = 0; |
| try |
| { |
| lArg = Long.parseLong(Argv[2].trim()); |
| } |
| catch (NumberFormatException nfe) |
| { |
| System.out.println("NumberFormatException: " + nfe.getMessage()); |
| } |
| |
| strReturn = Push(Argv[1], in, lArg); |
| } |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for push command!"; |
| break; |
| |
| case INST: |
| if (Argc >= 2) |
| strReturn = InstallApp(Argv[1], cmdOut); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for inst command!"; |
| break; |
| |
| case UNINST: |
| if (Argc >= 2) |
| strReturn = UnInstallApp(Argv[1], cmdOut, true); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for uninst command!"; |
| break; |
| |
| case UNINSTALL: |
| if (Argc >= 2) |
| strReturn = UnInstallApp(Argv[1], cmdOut, false); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for uninstall command!"; |
| break; |
| |
| case ALRT: |
| if (Argc > 1) |
| { |
| if (Argv[1].contentEquals("on")) |
| { |
| String sTitle = "Agent Alert"; |
| String sMsg = "The Agent Alert System has been activated!"; |
| if (Argc == 3) { |
| sTitle = Argv[2]; |
| sMsg = ""; |
| } else if (Argc == 4) { |
| sTitle = Argv[2]; |
| sMsg = Argv[3]; |
| } |
| StartAlert(sTitle, sMsg); |
| } |
| else |
| { |
| StopAlert(); |
| } |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for alrt command!"; |
| } |
| break; |
| |
| case REBT: |
| if (Argc >= 1) |
| strReturn = RunReboot(cmdOut, (Argc > 1 ? Argv[1] : null), (Argc > 2 ? Argv[2] : null)); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for rebt command!"; |
| // RunReboot(cmdOut); |
| break; |
| |
| case TMPD: |
| strReturn = GetTmpDir(); |
| break; |
| |
| case DEVINFO: |
| if (Argc == 1) |
| { |
| strReturn += SUTAgentAndroid.sUniqueID; |
| strReturn += "\n"; |
| strReturn += GetOSInfo(); |
| strReturn += "\n"; |
| strReturn += GetSystemTime(); |
| strReturn += "\n"; |
| strReturn += GetUptime(); |
| strReturn += "\n"; |
| strReturn += GetUptimeMillis(); |
| strReturn += "\n"; |
| strReturn += GetSutUptimeMillis(); |
| strReturn += "\n"; |
| strReturn += GetScreenInfo(); |
| strReturn += "\n"; |
| strReturn += GetRotationInfo(); |
| strReturn += "\n"; |
| strReturn += GetMemoryInfo(); |
| strReturn += "\n"; |
| strReturn += GetPowerInfo(); |
| strReturn += "\n"; |
| strReturn += GetTemperatureInfo(); |
| strReturn += "\n"; |
| strReturn += GetProcessInfo(); |
| strReturn += "\n"; |
| strReturn += GetSutUserInfo(); |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/data"); |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/system"); |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/mnt/sdcard"); |
| } |
| else |
| { |
| cSubCmd = Command.getCmd(Argv[1]); |
| switch(cSubCmd) |
| { |
| case ID: |
| strReturn = SUTAgentAndroid.sUniqueID; |
| break; |
| |
| case SCREEN: |
| strReturn = GetScreenInfo(); |
| break; |
| |
| case ROTATION: |
| strReturn = GetRotationInfo(); |
| break; |
| |
| case PROCESS: |
| strReturn = GetProcessInfo(); |
| break; |
| |
| case OS: |
| strReturn = GetOSInfo(); |
| break; |
| |
| case SYSTIME: |
| strReturn = GetSystemTime(); |
| break; |
| |
| case UPTIME: |
| strReturn = GetUptime(); |
| break; |
| |
| case UPTIMEMILLIS: |
| strReturn = GetUptimeMillis(); |
| break; |
| |
| case SUTUPTIMEMILLIS: |
| strReturn = GetSutUptimeMillis(); |
| break; |
| |
| case MEMORY: |
| strReturn = GetMemoryInfo(); |
| break; |
| |
| case POWER: |
| strReturn += GetPowerInfo(); |
| break; |
| |
| case SUTUSERINFO: |
| strReturn += GetSutUserInfo(); |
| break; |
| |
| case TEMPERATURE: |
| strReturn += GetTemperatureInfo(); |
| break; |
| |
| case DISK: |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/data"); |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/system"); |
| strReturn += "\n"; |
| strReturn += GetDiskInfo("/mnt/sdcard"); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| break; |
| |
| case STAT: |
| if (Argc == 2) |
| strReturn = StatProcess(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for ping command!"; |
| break; |
| |
| case PING: |
| if (Argc == 2) |
| strReturn = SendPing(Argv[1], cmdOut); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for ping command!"; |
| break; |
| |
| case HASH: |
| if (Argc == 2) |
| strReturn = HashFile(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for hash command!"; |
| break; |
| |
| case PRUNE: |
| if (Argc == 2) |
| strReturn = PruneDir(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for prune command!"; |
| break; |
| |
| case FTPG: |
| if (Argc == 4) |
| strReturn = FTPGetFile(Argv[1], Argv[2], Argv[3], cmdOut); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for ftpg command!"; |
| break; |
| |
| case CAT: |
| if (Argc == 2) |
| strReturn = Cat(Argv[1], cmdOut); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for cat command!"; |
| break; |
| |
| case DIRWRITABLE: |
| if (Argc == 2) |
| strReturn = IsDirWritable(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for dirwritable command!"; |
| break; |
| |
| case TIME: |
| if (Argc == 2) |
| strReturn = PrintFileTimestamp(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for time command!"; |
| break; |
| |
| case MKDR: |
| if (Argc == 2) |
| strReturn = MakeDir(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for mkdr command!"; |
| break; |
| |
| case RM: |
| if (Argc == 2) |
| strReturn = RemoveFile(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for rm command!"; |
| break; |
| |
| case MV: |
| if (Argc == 3) |
| strReturn = Move(Argv[1], Argv[2]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for mv command!"; |
| break; |
| |
| case CP: |
| if (Argc == 3) |
| strReturn = CopyFile(Argv[1], Argv[2]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for cp command!"; |
| break; |
| |
| case QUIT: |
| case EXIT: |
| strReturn = Argv[0]; |
| break; |
| |
| case DBG: |
| Debug.waitForDebugger(); |
| strReturn = "waitForDebugger on"; |
| break; |
| |
| case ADB: |
| if (Argc == 2) { |
| if (Argv[1].contains("ip") || Argv[1].contains("usb")) { |
| strReturn = SetADB(Argv[1]); |
| } else { |
| strReturn = sErrorPrefix + "Unrecognized argument for adb command!"; |
| } |
| } else { |
| strReturn = sErrorPrefix + "Wrong number of arguments for adb command!"; |
| } |
| break; |
| |
| case TEST: |
| long lFreeMemory = Runtime.getRuntime().freeMemory(); |
| long lTotMemory = Runtime.getRuntime().totalMemory(); |
| long lMaxMemory = Runtime.getRuntime().maxMemory(); |
| |
| |
| if (lFreeMemory > 0) { |
| strReturn = "Max memory: " + lMaxMemory + "\nTotal Memory: " + lTotMemory + "\nFree memory: " + lFreeMemory; |
| break; |
| } |
| |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| if (Argv[1].contains("fennec")) { |
| ffxFiles = Uri.parse("content://" + fenProvider + "/dir"); |
| } else if (Argv[1].contains("firefox")) { |
| ffxFiles = Uri.parse("content://" + ffxProvider + "/dir"); |
| } |
| |
| // Uri ffxFiles = Uri.parse("content://org.mozilla.fencp/file"); |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename", |
| "length" |
| }; |
| // String[] columns = new String[] { |
| // "_id", |
| // "chunk" |
| // }; |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| (Argc > 1 ? Argv[1] : null), // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Put the results in ascending order by name |
| /* |
| if (myCursor != null) { |
| int nRows = myCursor.getCount(); |
| String [] colNames = myCursor.getColumnNames(); |
| int nID = 0; |
| int nBytesRecvd = 0; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| nID = myCursor.getInt(0); |
| byte [] buf = myCursor.getBlob(1); |
| if (buf != null) { |
| nBytesRecvd += buf.length; |
| strReturn += new String(buf); |
| buf = null; |
| } |
| } |
| } |
| strReturn += "[eof - " + nBytesRecvd + "]"; |
| myCursor.close(); |
| } |
| |
| */ |
| if (myCursor != null) |
| { |
| int nRows = myCursor.getCount(); |
| int nID = 0; |
| String sFileName = ""; |
| long lFileSize = 0; |
| boolean bIsDir = false; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) |
| { |
| if (myCursor.moveToPosition(lcv)) |
| { |
| nID = myCursor.getInt(0); |
| bIsDir = (myCursor.getInt(1) == 1 ? true : false); |
| sFileName = myCursor.getString(2); |
| lFileSize = myCursor.getLong(3); |
| strReturn += "" + nID + "\t" + (bIsDir ? "<dir> " : " ") + sFileName + "\t" + lFileSize + "\n"; |
| } |
| } |
| myCursor.close(); |
| } |
| break; |
| |
| case EXEC: |
| case ENVRUN: |
| if (Argc >= 2) |
| { |
| String [] theArgs = new String [Argc - 1]; |
| |
| for (int lcv = 1; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - 1] = Argv[lcv]; |
| } |
| |
| strReturn = StartPrg2(theArgs, cmdOut, null, false, DEFAULT_STARTPRG_TIMEOUT_SECONDS); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case EXECSU: |
| if (Argc >= 2) |
| { |
| String [] theArgs = new String [Argc - 1]; |
| |
| for (int lcv = 1; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - 1] = Argv[lcv]; |
| } |
| |
| strReturn = StartPrg2(theArgs, cmdOut, null, true, DEFAULT_STARTPRG_TIMEOUT_SECONDS); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case EXECCWD: |
| if (Argc >= 3) |
| { |
| String [] theArgs = new String [Argc - 2]; |
| |
| for (int lcv = 2; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - 2] = Argv[lcv]; |
| } |
| |
| strReturn = StartPrg2(theArgs, cmdOut, Argv[1], false, DEFAULT_STARTPRG_TIMEOUT_SECONDS); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case EXECCWDSU: |
| if (Argc >= 3) |
| { |
| String [] theArgs = new String [Argc - 2]; |
| |
| for (int lcv = 2; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - 2] = Argv[lcv]; |
| } |
| |
| strReturn = StartPrg2(theArgs, cmdOut, Argv[1], true, DEFAULT_STARTPRG_TIMEOUT_SECONDS); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case RUN: |
| if (Argc >= 2) |
| { |
| String [] theArgs = new String [Argc - 1]; |
| |
| for (int lcv = 1; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - 1] = Argv[lcv]; |
| } |
| |
| if (Argv[1].contains("/") || Argv[1].contains("\\") || !Argv[1].contains(".")) |
| strReturn = StartPrg(theArgs, cmdOut, false, DEFAULT_STARTPRG_TIMEOUT_SECONDS); |
| else |
| strReturn = StartJavaPrg(theArgs, null); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case EXECEXT: |
| // An "extended" exec command with format: |
| // execext [su] [cwd=<path>] [t=<timeout in seconds>] arg1 ... |
| if (Argc >= 2) |
| { |
| boolean su = false; |
| String cwd = null; |
| int timeout = DEFAULT_STARTPRG_TIMEOUT_SECONDS; |
| int extra; |
| for (extra = 1; extra < Argc; extra++) |
| { |
| if (Argv[extra].equals("su")) |
| { |
| su = true; |
| } |
| else if (Argv[extra].startsWith("cwd=")) |
| { |
| cwd = Argv[extra].substring(4); |
| } |
| else if (Argv[extra].startsWith("t=")) |
| { |
| timeout = Integer.parseInt(Argv[extra].substring(2)); |
| if (timeout < 1 || timeout > 4*60*60) |
| { |
| Log.e("SUTAgentAndroid", |
| "invalid execext timeout "+Argv[extra].substring(2)+"; using default instead"); |
| timeout = DEFAULT_STARTPRG_TIMEOUT_SECONDS; |
| } |
| } |
| else |
| { |
| break; |
| } |
| } |
| |
| if (extra < Argc) |
| { |
| String [] theArgs = new String [Argc - extra]; |
| for (int lcv = extra; lcv < Argc; lcv++) |
| { |
| theArgs[lcv - extra] = Argv[lcv]; |
| } |
| |
| strReturn = StartPrg2(theArgs, cmdOut, cwd, su, timeout); |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "No regular arguments for " + Argv[0] + " command!"; |
| } |
| } |
| else |
| { |
| strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!"; |
| } |
| break; |
| |
| case KILL: |
| if (Argc == 2) |
| strReturn = KillProcess(Argv[1], cmdOut); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for kill command!"; |
| break; |
| |
| case DISK: |
| strReturn = GetDiskInfo((Argc == 2 ? Argv[1] : "/")); |
| break; |
| |
| case UNZP: |
| strReturn = Unzip(Argv[1], (Argc == 3 ? Argv[2] : "")); |
| break; |
| |
| case ZIP: |
| strReturn = Zip(Argv[1], (Argc == 3 ? Argv[2] : "")); |
| break; |
| |
| case CHMOD: |
| if (Argc == 2) |
| strReturn = ChmodDir(Argv[1]); |
| else |
| strReturn = sErrorPrefix + "Wrong number of arguments for chmod command!"; |
| break; |
| |
| case TOPACTIVITY: |
| strReturn = TopActivity(); |
| break; |
| |
| case HELP: |
| strReturn = PrintUsage(); |
| break; |
| |
| default: |
| strReturn = sErrorPrefix + "[" + Argv[0] + "] command"; |
| if (Argc > 1) |
| { |
| strReturn += " with arg(s) ="; |
| for (int lcv = 1; lcv < Argc; lcv++) |
| { |
| strReturn += " [" + Argv[lcv] + "]"; |
| } |
| } |
| strReturn += " is currently not implemented."; |
| break; |
| } |
| |
| return(strReturn); |
| } |
| |
| private void SendNotification(String tickerText, String expandedText) { |
| NotificationManager notificationManager = (NotificationManager)contextWrapper.getSystemService(Context.NOTIFICATION_SERVICE); |
| int icon = R.drawable.ateamlogo; |
| long when = System.currentTimeMillis(); |
| |
| Context context = contextWrapper.getApplicationContext(); |
| |
| // Intent to launch an activity when the extended text is clicked |
| Intent intent2 = new Intent(contextWrapper, SUTAgentAndroid.class); |
| PendingIntent launchIntent = PendingIntent.getActivity(context, 0, intent2, 0); |
| |
| Notification notification = new Notification.Builder(context) |
| .setContentTitle(tickerText) |
| .setContentText(expandedText) |
| .setSmallIcon(icon) |
| .setWhen(when) |
| .setContentIntent(launchIntent) |
| .build(); |
| |
| notification.flags |= (Notification.FLAG_INSISTENT | Notification.FLAG_AUTO_CANCEL); |
| notification.defaults |= Notification.DEFAULT_SOUND; |
| notification.defaults |= Notification.DEFAULT_VIBRATE; |
| notification.defaults |= Notification.DEFAULT_LIGHTS; |
| |
| notificationManager.notify(1959, notification); |
| } |
| |
| private void CancelNotification() |
| { |
| NotificationManager notificationManager = (NotificationManager)contextWrapper.getSystemService(Context.NOTIFICATION_SERVICE); |
| notificationManager.cancel(1959); |
| } |
| |
| public void StartAlert(String sTitle, String sMsg) |
| { |
| // start the alert message |
| SendNotification(sTitle, sMsg); |
| } |
| |
| public void StopAlert() |
| { |
| CancelNotification(); |
| } |
| |
| public String [] parseCmdLine2(String theCmdLine) |
| { |
| String cmdString; |
| String workingString; |
| String workingString2; |
| String workingString3; |
| List<String> lst = new ArrayList<String>(); |
| int nLength = 0; |
| int nFirstSpace = -1; |
| |
| // Null cmd line |
| if (theCmdLine == null) |
| { |
| String [] theArgs = new String [1]; |
| theArgs[0] = new String(""); |
| return(theArgs); |
| } |
| else |
| { |
| nLength = theCmdLine.length(); |
| nFirstSpace = theCmdLine.indexOf(' '); |
| } |
| |
| if (nFirstSpace == -1) |
| { |
| String [] theArgs = new String [1]; |
| theArgs[0] = new String(theCmdLine); |
| return(theArgs); |
| } |
| |
| // Get the command |
| cmdString = new String(theCmdLine.substring(0, nFirstSpace)); |
| lst.add(cmdString); |
| |
| // Jump past the command and trim |
| workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim(); |
| |
| while ((nLength = workingString.length()) > 0) |
| { |
| int nEnd = 0; |
| int nStart = 0; |
| |
| // if we have a quote |
| if (workingString.startsWith("\"") || workingString.startsWith("'")) |
| { |
| char quoteChar = '"'; |
| if (workingString.startsWith("\'")) |
| quoteChar = '\''; |
| |
| // point to the first non quote char |
| nStart = 1; |
| // find the matching quote |
| nEnd = workingString.indexOf(quoteChar, nStart); |
| |
| char prevChar; |
| |
| while(nEnd != -1) |
| { |
| // check to see if the quotation mark has been escaped |
| prevChar = workingString.charAt(nEnd - 1); |
| if (prevChar == '\\') |
| { |
| // if escaped, point past this quotation mark and find the next |
| nEnd++; |
| if (nEnd < nLength) |
| nEnd = workingString.indexOf(quoteChar, nEnd); |
| else |
| nEnd = -1; |
| } |
| else |
| break; |
| } |
| |
| // there isn't one |
| if (nEnd == -1) |
| { |
| // point at the quote |
| nStart = 0; |
| // so find the next space |
| nEnd = workingString.indexOf(' ', nStart); |
| // there isn't one of those either |
| if (nEnd == -1) |
| nEnd = nLength; // Just grab the rest of the cmdline |
| } |
| } |
| else // no quote so find the next space |
| { |
| nEnd = workingString.indexOf(' ', nStart); |
| // there isn't one of those |
| if (nEnd == -1) |
| nEnd = nLength; // Just grab the rest of the cmdline |
| } |
| |
| // get the substring |
| workingString2 = workingString.substring(nStart, nEnd); |
| |
| // if we have escaped quotes, convert them into standard ones |
| while (workingString2.contains("\\\"") || workingString2.contains("\\'")) |
| { |
| workingString2 = workingString2.replace("\\\"", "\""); |
| workingString2 = workingString2.replace("\\'", "'"); |
| } |
| |
| // add it to the list |
| lst.add(new String(workingString2)); |
| |
| // if we are dealing with a quote |
| if (nStart > 0) |
| nEnd++; // point past the end one |
| |
| // jump past the substring and trim it |
| workingString = (workingString.substring(nEnd)).trim(); |
| } |
| |
| // ok we're done package up the results |
| int nItems = lst.size(); |
| |
| String [] theArgs = new String [nItems]; |
| |
| for (int lcv = 0; lcv < nItems; lcv++) |
| { |
| theArgs[lcv] = lst.get(lcv); |
| } |
| |
| return(theArgs); |
| } |
| |
| public String [] parseCmdLine(String theCmdLine) { |
| String cmdString; |
| String workingString; |
| String workingString2; |
| List<String> lst = new ArrayList<String>(); |
| int nLength = 0; |
| int nFirstSpace = -1; |
| |
| // Null cmd line |
| if (theCmdLine == null) |
| { |
| String [] theArgs = new String [1]; |
| theArgs[0] = new String(""); |
| return(theArgs); |
| } |
| else |
| { |
| nLength = theCmdLine.length(); |
| nFirstSpace = theCmdLine.indexOf(' '); |
| } |
| |
| if (nFirstSpace == -1) |
| { |
| String [] theArgs = new String [1]; |
| theArgs[0] = new String(theCmdLine); |
| return(theArgs); |
| } |
| |
| // Get the command |
| cmdString = new String(theCmdLine.substring(0, nFirstSpace)); |
| lst.add(cmdString); |
| |
| // Jump past the command and trim |
| workingString = (theCmdLine.substring(nFirstSpace + 1, nLength)).trim(); |
| |
| while ((nLength = workingString.length()) > 0) |
| { |
| int nEnd = 0; |
| int nStart = 0; |
| |
| // if we have a quote |
| if (workingString.startsWith("\"")) |
| { |
| // point to the first non quote char |
| nStart = 1; |
| // find the matching quote |
| nEnd = workingString.indexOf('"', nStart); |
| // there isn't one |
| if (nEnd == -1) |
| { |
| // point at the quote |
| nStart = 0; |
| // so find the next space |
| nEnd = workingString.indexOf(' ', nStart); |
| // there isn't one of those either |
| if (nEnd == -1) |
| nEnd = nLength; // Just grab the rest of the cmdline |
| } |
| else |
| { |
| nStart = 0; |
| nEnd++; |
| } |
| } |
| else // no quote so find the next space |
| { |
| nEnd = workingString.indexOf(' ', nStart); |
| |
| // there isn't one of those |
| if (nEnd == -1) |
| nEnd = nLength; // Just grab the rest of the cmdline |
| } |
| |
| // get the substring |
| workingString2 = workingString.substring(nStart, nEnd); |
| |
| // add it to the list |
| lst.add(new String(workingString2)); |
| |
| // jump past the substring and trim it |
| workingString = (workingString.substring(nEnd)).trim(); |
| } |
| |
| int nItems = lst.size(); |
| |
| String [] theArgs = new String [nItems]; |
| |
| for (int lcv = 0; lcv < nItems; lcv++) |
| { |
| theArgs[lcv] = lst.get(lcv); |
| } |
| |
| return(theArgs); |
| } |
| |
| public String fixFileName(String fileName) |
| { |
| String sRet = ""; |
| String sTmpFileName = ""; |
| |
| sRet = fileName.replace('\\', '/'); |
| |
| if (sRet.startsWith("/")) |
| sTmpFileName = sRet; |
| else |
| sTmpFileName = currentDir + "/" + sRet; |
| |
| sRet = sTmpFileName.replace('\\', '/'); |
| sTmpFileName = sRet; |
| sRet = sTmpFileName.replace("//", "/"); |
| |
| return(sRet); |
| } |
| |
| public String AddFilesToZip(ZipOutputStream out, String baseDir, String relDir) |
| { |
| final int BUFFER = 2048; |
| String sRet = ""; |
| String curDir = ""; |
| String relFN = ""; |
| BufferedInputStream origin = null; |
| byte data[] = new byte[BUFFER]; |
| |
| if (relDir.length() > 0) |
| curDir = baseDir + "/" + relDir; |
| else |
| curDir = baseDir; |
| |
| File f = new File(curDir); |
| |
| if (f.isFile()) |
| { |
| try { |
| relFN = ((relDir.length() > 0) ? relDir + "/" + f.getName() : f.getName()); |
| System.out.println("Adding: "+relFN); |
| sRet += "Adding: "+ relFN + lineSep; |
| FileInputStream fi = new FileInputStream(curDir); |
| origin = new BufferedInputStream(fi, BUFFER); |
| ZipEntry entry = new ZipEntry(relFN); |
| out.putNextEntry(entry); |
| int count; |
| while((count = origin.read(data, 0, BUFFER)) != -1) |
| { |
| out.write(data, 0, count); |
| } |
| origin.close(); |
| } |
| catch(Exception e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return(sRet); |
| } |
| |
| String files[] = f.list(); |
| |
| if (files != null) |
| { |
| try { |
| for(int i = 0; i < files.length; i++) |
| { |
| f = new File(curDir + "/" + files[i]); |
| if (f.isDirectory()) |
| { |
| if (relDir.length() > 0) |
| sRet += AddFilesToZip(out, baseDir, relDir + "/" + files[i]); |
| else |
| sRet += AddFilesToZip(out, baseDir, files[i]); |
| } |
| else |
| { |
| relFN = ((relDir.length() > 0) ? relDir + "/" + files[i] : files[i]); |
| System.out.println("Adding: "+relFN); |
| sRet += "Adding: "+ relFN + lineSep; |
| FileInputStream fi = new FileInputStream(curDir + "/" + files[i]); |
| origin = new BufferedInputStream(fi, BUFFER); |
| ZipEntry entry = new ZipEntry(relFN); |
| out.putNextEntry(entry); |
| int count; |
| while((count = origin.read(data, 0, BUFFER)) != -1) |
| { |
| out.write(data, 0, count); |
| } |
| origin.close(); |
| } |
| } |
| } |
| catch(Exception e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| |
| return(sRet); |
| } |
| |
| public String Zip(String zipFileName, String srcName) |
| { |
| String fixedZipFileName = fixFileName(zipFileName); |
| String fixedSrcName = fixFileName(srcName); |
| String sRet = ""; |
| |
| try { |
| FileOutputStream dest = new FileOutputStream(fixedZipFileName); |
| CheckedOutputStream checksum = new CheckedOutputStream(dest, new Adler32()); |
| ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(checksum)); |
| out.setMethod(ZipOutputStream.DEFLATED); |
| |
| sRet += AddFilesToZip(out, fixedSrcName, ""); |
| |
| out.close(); |
| System.out.println("checksum: "+checksum.getChecksum().getValue()); |
| sRet += "checksum: "+checksum.getChecksum().getValue(); |
| } |
| catch(Exception e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return(sRet); |
| } |
| |
| public String Unzip(String zipFileName, String dstDirectory) |
| { |
| String sRet = ""; |
| String fixedZipFileName = fixFileName(zipFileName); |
| String fixedDstDirectory = fixFileName(dstDirectory); |
| String dstFileName = ""; |
| int nNumExtracted = 0; |
| boolean bRet = false; |
| |
| try { |
| final int BUFFER = 2048; |
| BufferedOutputStream dest = null; |
| ZipFile zipFile = new ZipFile(fixedZipFileName); |
| int nNumEntries = zipFile.size(); |
| zipFile.close(); |
| |
| FileInputStream fis = new FileInputStream(fixedZipFileName); |
| CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32()); |
| ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum)); |
| ZipEntry entry; |
| |
| byte [] data = new byte[BUFFER]; |
| |
| while((entry = zis.getNextEntry()) != null) |
| { |
| System.out.println("Extracting: " + entry); |
| int count; |
| if (fixedDstDirectory.length() > 0) |
| dstFileName = fixedDstDirectory + entry.getName(); |
| else |
| dstFileName = entry.getName(); |
| |
| String tmpDir = dstFileName.substring(0, dstFileName.lastIndexOf('/')); |
| File tmpFile = new File(tmpDir); |
| if (!tmpFile.exists()) |
| { |
| bRet = tmpFile.mkdirs(); |
| } |
| else |
| bRet = true; |
| |
| if (bRet) |
| { |
| // if we aren't just creating a directory |
| if (dstFileName.lastIndexOf('/') != (dstFileName.length() - 1)) |
| { |
| // write out the file |
| FileOutputStream fos = new FileOutputStream(dstFileName); |
| dest = new BufferedOutputStream(fos, BUFFER); |
| while ((count = zis.read(data, 0, BUFFER)) != -1) |
| { |
| dest.write(data, 0, count); |
| } |
| dest.flush(); |
| dest.close(); |
| dest = null; |
| fos.close(); |
| fos = null; |
| } |
| nNumExtracted++; |
| } |
| else |
| sRet += " - failed" + lineSep; |
| } |
| |
| data = null; |
| zis.close(); |
| System.out.println("Checksum: "+checksum.getChecksum().getValue()); |
| sRet += "Checksum: "+checksum.getChecksum().getValue(); |
| sRet += lineSep + nNumExtracted + " of " + nNumEntries + " successfully extracted"; |
| } |
| catch(Exception e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return(sRet); |
| } |
| |
| public String StatProcess(String string) |
| { |
| String sRet = ""; |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| int [] nPids = new int [1]; |
| |
| nPids[0] = Integer.parseInt(string); |
| |
| android.os.Debug.MemoryInfo[] mi = aMgr.getProcessMemoryInfo(nPids); |
| |
| sRet = "Dalvik Private Dirty pages " + mi[0].dalvikPrivateDirty + " kb\n"; |
| sRet += "Dalvik Proportional Set Size " + mi[0].dalvikPss + " kb\n"; |
| sRet += "Dalvik Shared Dirty pages " + mi[0].dalvikSharedDirty + " kb\n\n"; |
| sRet += "Native Private Dirty pages heap " + mi[0].nativePrivateDirty + " kb\n"; |
| sRet += "Native Proportional Set Size heap " + mi[0].nativePss + " kb\n"; |
| sRet += "Native Shared Dirty pages heap " + mi[0].nativeSharedDirty + " kb\n\n"; |
| sRet += "Other Private Dirty pages " + mi[0].otherPrivateDirty + " kb\n"; |
| sRet += "Other Proportional Set Size " + mi[0].otherPss + " kb\n"; |
| sRet += "Other Shared Dirty pages " + mi[0].otherSharedDirty + " kb\n\n"; |
| sRet += "Total Private Dirty Memory " + mi[0].getTotalPrivateDirty() + " kb\n"; |
| sRet += "Total Proportional Set Size Memory " + mi[0].getTotalPss() + " kb\n"; |
| sRet += "Total Shared Dirty Memory " + mi[0].getTotalSharedDirty() + " kb"; |
| |
| |
| return(sRet); |
| } |
| |
| public void FixDataLocalPermissions() |
| { |
| String chmodResult; |
| File localDir = new java.io.File("/data/local"); |
| if (!localDir.canWrite()) { |
| chmodResult = ChmodDir("/data/local"); |
| Log.i("SUTAgentAndroid", "Changed permissions on /data/local to make it writable: " + chmodResult); |
| } |
| File tmpDir = new java.io.File("/data/local/tmp"); |
| if (tmpDir.exists() && !tmpDir.isDirectory()) { |
| if (!tmpDir.delete()) { |
| Log.e("SUTAgentAndroid", "Could not delete file /data/local/tmp"); |
| } |
| } |
| if (!tmpDir.exists() && !tmpDir.mkdirs()) { |
| Log.e("SUTAgentAndroid", "Could not create directory /data/local/tmp"); |
| } |
| chmodResult = ChmodDir("/data/local/tmp"); |
| Log.i("SUTAgentAndroid", "Changed permissions on /data/local/tmp to make it writable: " + chmodResult); |
| } |
| |
| private Boolean _SetTestRoot(String testroot) |
| { |
| String isWritable = IsDirWritable(testroot); |
| if (isWritable.contains(sErrorPrefix) || isWritable.contains("is not writable")) { |
| Log.w("SUTAgentAndroid", isWritable); |
| Log.w("SUTAgentAndroid", "Unable to set device root to " + testroot); |
| return false; |
| } |
| |
| Log.i("SUTAgentAndroid", "Set device root to " + testroot); |
| SUTAgentAndroid.sTestRoot = testroot; |
| return true; |
| } |
| |
| public void SetTestRoot(String testroot) |
| { |
| Boolean success = false; |
| if (!testroot.equals("")) { |
| // Device specified the required testroot. |
| success = _SetTestRoot(testroot); |
| if (!success) { |
| Log.e("SUTAgentAndroid", "Unable to set device root to " + testroot); |
| } |
| } else { |
| // Detect the testroot. |
| // Attempt external storage. |
| success = _SetTestRoot(Environment.getExternalStorageDirectory().getAbsolutePath()); |
| if (!success) { |
| Log.e("SUTAgentAndroid", "Cannot access world writeable test root"); |
| } |
| } |
| } |
| |
| public String GetTestRoot() |
| { |
| if (SUTAgentAndroid.sTestRoot.equals("")) { |
| SetTestRoot(""); |
| } |
| return SUTAgentAndroid.sTestRoot; |
| } |
| |
| public String GetAppRoot(String AppName) |
| { |
| String sRet = sErrorPrefix + " internal error [no context]"; |
| Context ctx = contextWrapper.getApplicationContext(); |
| |
| if (ctx != null) |
| { |
| try { |
| Context appCtx = ctx.createPackageContext(AppName, 0); |
| ContextWrapper appCtxW = new ContextWrapper(appCtx); |
| sRet = appCtxW.getApplicationInfo().dataDir; |
| appCtxW = null; |
| appCtx = null; |
| ctx = null; |
| System.gc(); |
| } |
| catch (NameNotFoundException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| return(sRet); |
| } |
| |
| public String isDirectory(String sDir) |
| { |
| String sRet = sErrorPrefix + sDir + " does not exist"; |
| String tmpDir = fixFileName(sDir); |
| int nFiles = 0; |
| |
| if (tmpDir.contains("org.mozilla.fennec") || tmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (tmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename", |
| "length" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| tmpDir, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| nFiles = myCursor.getCount(); |
| |
| // If no entries the dir is empty |
| if (nFiles > 0) { |
| if (myCursor.moveToPosition(0)) { |
| sRet = ((myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) ? "TRUE" : "FALSE"); |
| } |
| } |
| myCursor.close(); |
| } |
| } else { |
| File tmpFile = new java.io.File(tmpDir); |
| |
| if (tmpFile.exists()) { |
| sRet = (tmpFile.isDirectory() ? "TRUE" : "FALSE"); |
| } |
| else { |
| try { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("ls -l " + sDir)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sRet = outThrd.strOutput; |
| if (!sRet.contains("No such file or directory") && sRet.startsWith("l")) |
| sRet = "FALSE"; |
| } |
| catch (IOException e) { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| return(sRet); |
| } |
| |
| |
| public String changeDir(String newDir) |
| { |
| String tmpDir = fixFileName(newDir); |
| String sRet = sErrorPrefix + "Couldn't change directory to " + tmpDir; |
| int nFiles = 0; |
| |
| if (tmpDir.contains("org.mozilla.fennec") || tmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (tmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| tmpDir, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| nFiles = myCursor.getCount(); |
| |
| if (nFiles > 0) { |
| if (myCursor.moveToPosition(0)) { |
| if (myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) { |
| currentDir = myCursor.getString(myCursor.getColumnIndex("filename")); |
| sRet = ""; |
| } |
| } |
| } else { |
| sRet = sErrorPrefix + tmpDir + " is not a valid directory"; |
| } |
| myCursor.close(); |
| } |
| } else { |
| File tmpFile = new java.io.File(tmpDir); |
| |
| if (tmpFile.exists()) { |
| try { |
| if (tmpFile.isDirectory()) { |
| currentDir = tmpFile.getCanonicalPath(); |
| sRet = ""; |
| } |
| else |
| sRet = sErrorPrefix + tmpDir + " is not a valid directory"; |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| return(sRet); |
| } |
| |
| static final String HEXES = "0123456789abcdef"; |
| |
| public static String getHex( byte [] raw ) |
| { |
| if ( raw == null ) |
| { |
| return null; |
| } |
| |
| final StringBuilder hex = new StringBuilder( 2 * raw.length ); |
| for ( final byte b : raw ) |
| { |
| hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); |
| } |
| return hex.toString(); |
| } |
| |
| public String HashFile(String fileName) |
| { |
| String sTmpFileName = fixFileName(fileName); |
| String sRet = sErrorPrefix + "Couldn't calculate hash for file " + sTmpFileName; |
| byte[] buffer = new byte [4096]; |
| int nRead = 0; |
| long lTotalRead = 0; |
| MessageDigest digest = null; |
| |
| try { |
| digest = java.security.MessageDigest.getInstance("MD5"); |
| } |
| catch (NoSuchAlgorithmException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "chunk" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpFileName, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| int nRows = myCursor.getCount(); |
| int nBytesRecvd = 0; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| byte [] buf = myCursor.getBlob(1); |
| if (buf != null) { |
| nBytesRecvd += buf.length; |
| digest.update(buf, 0, buf.length); |
| lTotalRead += nRead; |
| buf = null; |
| } |
| } |
| } |
| myCursor.close(); |
| byte [] hash = digest.digest(); |
| |
| sRet = getHex(hash); |
| } |
| } else { |
| try { |
| FileInputStream srcFile = new FileInputStream(sTmpFileName); |
| while((nRead = srcFile.read(buffer)) != -1) { |
| digest.update(buffer, 0, nRead); |
| lTotalRead += nRead; |
| } |
| srcFile.close(); |
| byte [] hash = digest.digest(); |
| |
| sRet = getHex(hash); |
| } |
| catch (FileNotFoundException e) { |
| sRet += " file not found"; |
| } |
| catch (IOException e) { |
| sRet += " io exception"; |
| e.printStackTrace(); |
| } |
| } |
| return(sRet); |
| } |
| |
| public String RemoveFile(String fileName) |
| { |
| String sTmpFileName = fixFileName(fileName); |
| String sRet = sErrorPrefix + "Couldn't delete file " + sTmpFileName; |
| |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| if (cr.delete(ffxFiles, sTmpFileName, null) == 1) { |
| sRet = "deleted " + sTmpFileName; |
| } |
| } else { |
| File f = new File(sTmpFileName); |
| |
| if (f.delete()) |
| sRet = "deleted " + sTmpFileName; |
| } |
| |
| return(sRet); |
| } |
| |
| public String PruneDir(String sDir) |
| { |
| String sRet = ""; |
| int nFiles = 0; |
| String sSubDir = null; |
| String sTmpDir = fixFileName(sDir); |
| |
| if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| if (cr.delete(ffxFiles, sTmpDir, null) > 0) { |
| sRet = "deleted " + sTmpDir; |
| } |
| } else { |
| File dir = new File(sTmpDir); |
| |
| if (dir.isDirectory()) { |
| sRet = "Deleting file(s) from " + sTmpDir; |
| |
| File [] files = dir.listFiles(); |
| if (files != null) { |
| if ((nFiles = files.length) > 0) { |
| for (int lcv = 0; lcv < nFiles; lcv++) { |
| if (files[lcv].isDirectory()) { |
| sSubDir = files[lcv].getAbsolutePath(); |
| sRet += "\n" + PruneDir(sSubDir); |
| } |
| else { |
| if (files[lcv].delete()) { |
| sRet += "\n\tDeleted " + files[lcv].getName(); |
| } |
| else { |
| sRet += "\n\tUnable to delete " + files[lcv].getName(); |
| } |
| } |
| } |
| } |
| else |
| sRet += "\n\t<empty>"; |
| } |
| |
| if (dir.delete()) { |
| sRet += "\nDeleting directory " + sTmpDir; |
| } |
| else { |
| sRet += "\nUnable to delete directory " + sTmpDir; |
| } |
| } |
| else { |
| sRet += sErrorPrefix + sTmpDir + " is not a directory"; |
| } |
| } |
| |
| return(sRet); |
| } |
| |
| public String PrintDir(String sDir) |
| { |
| String sRet = ""; |
| int nFiles = 0; |
| String sTmpDir = fixFileName(sDir); |
| |
| if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename", |
| "length" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpDir, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| nFiles = myCursor.getCount(); |
| |
| // If only one entry and the index is -1 this is not a directory |
| int nNdx = myCursor.getColumnIndex("_id"); |
| // If no entries the dir is empty |
| if (nFiles == 1) { |
| sRet = "<empty>"; |
| } else { |
| // Show the entries |
| for (int lcv = 1; lcv < nFiles; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| if ((lcv == 0) && (myCursor.getLong(nNdx) == -1)) { |
| sRet = sErrorPrefix + sTmpDir + " is not a directory"; |
| } else { |
| sRet += myCursor.getString(2); |
| if (lcv < (nFiles - 1)) |
| sRet += "\n"; |
| } |
| } |
| } |
| } |
| myCursor.close(); |
| } |
| } else { |
| File dir = new File(sTmpDir); |
| |
| if (dir.isDirectory()) { |
| File [] files = dir.listFiles(); |
| |
| if (files != null) { |
| if ((nFiles = files.length) > 0) { |
| for (int lcv = 0; lcv < nFiles; lcv++) { |
| sRet += files[lcv].getName(); |
| if (lcv < (nFiles - 1)) { |
| sRet += "\n"; |
| } |
| } |
| } |
| else { |
| sRet = "<empty>"; |
| } |
| } |
| } |
| else { |
| sRet = sErrorPrefix + sTmpDir + " is not a directory"; |
| } |
| } |
| return(sRet); |
| } |
| |
| public String Move(String sTmpSrcFileName, String sTmpDstFileName) { |
| String sRet = sErrorPrefix + "Could not move " + sTmpSrcFileName + " to " + sTmpDstFileName; |
| String sTmp = CopyFile(sTmpSrcFileName, sTmpDstFileName); |
| if (sTmp.contains(" copied to ")) { |
| sTmp = RemoveFile(sTmpSrcFileName); |
| if (sTmp.startsWith("deleted ")) { |
| sRet = sTmpSrcFileName + " moved to " + sTmpDstFileName; |
| } |
| } |
| |
| return(sRet); |
| } |
| |
| public String CopyFile(String sTmpSrcFileName, String sTmpDstFileName) { |
| String sRet = sErrorPrefix + "Could not copy " + sTmpSrcFileName + " to " + sTmpDstFileName; |
| ContentValues cv = null; |
| File destFile = null; |
| Uri ffxSrcFiles = null; |
| Uri ffxDstFiles = null; |
| FileInputStream srcFile = null; |
| FileOutputStream dstFile = null; |
| byte[] buffer = new byte [4096]; |
| int nRead = 0; |
| long lTotalRead = 0; |
| long lTotalWritten = 0; |
| ContentResolver crIn = null; |
| ContentResolver crOut = null; |
| |
| if (sTmpSrcFileName.contains("org.mozilla.fennec") || sTmpSrcFileName.contains("org.mozilla.firefox")) { |
| ffxSrcFiles = Uri.parse("content://" + (sTmpSrcFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| crIn = contextWrapper.getContentResolver(); |
| } else { |
| try { |
| srcFile = new FileInputStream(sTmpSrcFileName); |
| } catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| if (sTmpDstFileName.contains("org.mozilla.fennec") || sTmpDstFileName.contains("org.mozilla.firefox")) { |
| ffxDstFiles = Uri.parse("content://" + (sTmpDstFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| crOut = contextWrapper.getContentResolver(); |
| cv = new ContentValues(); |
| } else { |
| try { |
| dstFile = new FileOutputStream(sTmpDstFileName); |
| } catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| if (srcFile != null) { |
| try { |
| while((nRead = srcFile.read(buffer)) != -1) { |
| lTotalRead += nRead; |
| if (dstFile != null) { |
| dstFile.write(buffer, 0, nRead); |
| dstFile.flush(); |
| } else { |
| cv.put("length", nRead); |
| cv.put("chunk", buffer); |
| if (crOut.update(ffxDstFiles, cv, sTmpDstFileName, null) == 0) |
| break; |
| lTotalWritten += nRead; |
| } |
| } |
| |
| srcFile.close(); |
| |
| if (dstFile != null) { |
| dstFile.flush(); |
| dstFile.close(); |
| |
| destFile = new File(sTmpDstFileName); |
| lTotalWritten = destFile.length(); |
| } |
| |
| if (lTotalWritten == lTotalRead) { |
| sRet = sTmpSrcFileName + " copied to " + sTmpDstFileName; |
| } |
| else { |
| sRet = sErrorPrefix + "Failed to copy " + sTmpSrcFileName + " [length = " + lTotalWritten + "] to " + sTmpDstFileName + " [length = " + lTotalRead + "]"; |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| |
| } else { |
| String[] columns = new String[] { |
| "_id", |
| "chunk", |
| "length" |
| }; |
| |
| Cursor myCursor = crIn.query(ffxSrcFiles, |
| columns, // Which columns to return |
| sTmpSrcFileName, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| int nRows = myCursor.getCount(); |
| |
| byte [] buf = null; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| buf = myCursor.getBlob(myCursor.getColumnIndex("chunk")); |
| if (buf != null) { |
| nRead = buf.length; |
| try { |
| lTotalRead += nRead; |
| if (dstFile != null) { |
| dstFile.write(buffer, 0, nRead); |
| dstFile.flush(); |
| } else { |
| cv.put("length", nRead); |
| cv.put("chunk", buffer); |
| if (crOut.update(ffxDstFiles, cv, sTmpDstFileName, null) == 0) |
| break; |
| lTotalWritten += nRead; |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| buf = null; |
| } |
| } |
| } |
| |
| if (nRows == -1) { |
| sRet = sErrorPrefix + sTmpSrcFileName + ",-1\nNo such file or directory"; |
| } |
| else { |
| myCursor.close(); |
| |
| if (dstFile != null) { |
| try { |
| dstFile.flush(); |
| dstFile.close(); |
| |
| destFile = new File(sTmpDstFileName); |
| lTotalWritten = destFile.length(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| if (lTotalWritten == lTotalRead) { |
| sRet = sTmpSrcFileName + " copied to " + sTmpDstFileName; |
| } |
| else { |
| sRet = sErrorPrefix + "Failed to copy " + sTmpSrcFileName + " [length = " + lTotalWritten + "] to " + sTmpDstFileName + " [length = " + lTotalRead + "]"; |
| } |
| } |
| } |
| else { |
| sRet = sErrorPrefix + sTmpSrcFileName + ",-1\nUnable to access file (internal error)"; |
| } |
| } |
| |
| return (sRet); |
| } |
| |
| public String IsDirWritable(String sDir) |
| { |
| String sTmpDir = fixFileName(sDir); |
| String sRet = sErrorPrefix + "[" + sTmpDir + "] is not a directory"; |
| |
| if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename", |
| "length", |
| "writable" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpDir, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| if (myCursor.getCount() > 0) { |
| if (myCursor.moveToPosition(0)) { |
| if (myCursor.getLong(myCursor.getColumnIndex("isdir")) == 1) { |
| sRet = "[" + sTmpDir + "] " + ((myCursor.getLong(myCursor.getColumnIndex("writable")) == 1) ? "is" : "is not") + " writable"; |
| } |
| } |
| } |
| } |
| } else { |
| File dir = new File(sTmpDir); |
| |
| if (dir.isDirectory()) { |
| sRet = "[" + sTmpDir + "] " + (dir.canWrite() ? "is" : "is not") + " writable"; |
| } else { |
| sRet = sErrorPrefix + "[" + sTmpDir + "] is not a directory"; |
| } |
| } |
| return(sRet); |
| } |
| |
| public String Push(String fileName, BufferedInputStream bufIn, long lSize) |
| { |
| byte [] buffer = new byte [8192]; |
| int nRead = 0; |
| long lRead = 0; |
| String sTmpFileName = fixFileName(fileName); |
| FileOutputStream dstFile = null; |
| ContentResolver cr = null; |
| ContentValues cv = null; |
| Uri ffxFiles = null; |
| String sRet = sErrorPrefix + "Push failed!"; |
| |
| try { |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| cr = contextWrapper.getContentResolver(); |
| ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| cv = new ContentValues(); |
| } |
| else { |
| dstFile = new FileOutputStream(sTmpFileName, false); |
| } |
| |
| while((nRead != -1) && (lRead < lSize)) |
| { |
| nRead = bufIn.read(buffer); |
| if (nRead != -1) { |
| if (dstFile != null) { |
| dstFile.write(buffer, 0, nRead); |
| dstFile.flush(); |
| } |
| else { |
| cv.put("offset", lRead); |
| cv.put("length", nRead); |
| cv.put("chunk", buffer); |
| cr.update(ffxFiles, cv, sTmpFileName, null); |
| } |
| lRead += nRead; |
| } |
| } |
| |
| if (dstFile != null) { |
| dstFile.flush(); |
| dstFile.close(); |
| } |
| |
| if (lRead == lSize) { |
| sRet = HashFile(sTmpFileName); |
| } |
| } |
| catch (IOException e) { |
| e.printStackTrace(); |
| } |
| |
| buffer = null; |
| |
| return(sRet); |
| } |
| |
| public String FTPGetFile(String sServer, String sSrcFileName, String sDstFileName, OutputStream out) |
| { |
| byte[] buffer = new byte [4096]; |
| int nRead = 0; |
| long lTotalRead = 0; |
| String sRet = sErrorPrefix + "FTP Get failed for " + sSrcFileName; |
| String strRet = ""; |
| int reply = 0; |
| FileOutputStream outStream = null; |
| String sTmpDstFileName = fixFileName(sDstFileName); |
| |
| FTPClient ftp = new FTPClient(); |
| try |
| { |
| ftp.connect(sServer); |
| reply = ftp.getReplyCode(); |
| if(FTPReply.isPositiveCompletion(reply)) |
| { |
| ftp.login("anonymous", "b@t.com"); |
| reply = ftp.getReplyCode(); |
| if(FTPReply.isPositiveCompletion(reply)) |
| { |
| ftp.enterLocalPassiveMode(); |
| if (ftp.setFileType(FTP.BINARY_FILE_TYPE)) |
| { |
| File dstFile = new File(sTmpDstFileName); |
| outStream = new FileOutputStream(dstFile); |
| FTPFile [] ftpFiles = ftp.listFiles(sSrcFileName); |
| if (ftpFiles.length > 0) |
| { |
| long lFtpSize = ftpFiles[0].getSize(); |
| if (lFtpSize <= 0) |
| lFtpSize = 1; |
| |
| InputStream ftpIn = ftp.retrieveFileStream(sSrcFileName); |
| while ((nRead = ftpIn.read(buffer)) != -1) |
| { |
| lTotalRead += nRead; |
| outStream.write(buffer, 0, nRead); |
| strRet = "\r" + lTotalRead + " of " + lFtpSize + " bytes received " + ((lTotalRead * 100) / lFtpSize) + "% completed"; |
| out.write(strRet.getBytes()); |
| out.flush(); |
| } |
| ftpIn.close(); |
| @SuppressWarnings("unused") |
| boolean bRet = ftp.completePendingCommand(); |
| outStream.flush(); |
| outStream.close(); |
| strRet = ftp.getReplyString(); |
| reply = ftp.getReplyCode(); |
| } |
| else |
| { |
| strRet = sRet; |
| } |
| } |
| ftp.logout(); |
| ftp.disconnect(); |
| sRet = "\n" + strRet; |
| } |
| else |
| { |
| ftp.disconnect(); |
| System.err.println("FTP server refused login."); |
| } |
| } |
| else |
| { |
| ftp.disconnect(); |
| System.err.println("FTP server refused connection."); |
| } |
| } |
| catch (SocketException e) |
| { |
| sRet = e.getMessage(); |
| strRet = ftp.getReplyString(); |
| reply = ftp.getReplyCode(); |
| sRet += "\n" + strRet; |
| e.printStackTrace(); |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| strRet = ftp.getReplyString(); |
| reply = ftp.getReplyCode(); |
| sRet += "\n" + strRet; |
| e.printStackTrace(); |
| } |
| return (sRet); |
| } |
| |
| public String Pull(String fileName, long lOffset, long lLength, OutputStream out) |
| { |
| String sTmpFileName = fixFileName(fileName); |
| String sRet = sErrorPrefix + "Could not read the file " + sTmpFileName; |
| byte[] buffer = new byte [4096]; |
| int nRead = 0; |
| long lSent = 0; |
| |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "chunk", |
| "length" |
| }; |
| |
| String [] args = new String [2]; |
| args[0] = Long.toString(lOffset); |
| args[1] = Long.toString(lLength); |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpFileName, // Which rows to return (all rows) |
| args, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| int nRows = myCursor.getCount(); |
| long lFileLength = 0; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| if (lcv == 0) { |
| lFileLength = myCursor.getLong(2); |
| String sTmp = sTmpFileName + "," + lFileLength + "\n"; |
| try { |
| out.write(sTmp.getBytes()); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| break; |
| } |
| } |
| |
| if (lLength != 0) { |
| byte [] buf = myCursor.getBlob(1); |
| if (buf != null) { |
| nRead = buf.length; |
| try { |
| if ((lSent + nRead) <= lFileLength) { |
| out.write(buf,0,nRead); |
| lSent += nRead; |
| } |
| else { |
| nRead = (int) (lFileLength - lSent); |
| out.write(buf,0,nRead); |
| Log.d("pull warning", "more bytes read than expected"); |
| break; |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| sRet = sErrorPrefix + "Could not write to out " + sTmpFileName; |
| } |
| buf = null; |
| } |
| } |
| } |
| } |
| if (nRows == 0) { |
| String sTmp = sTmpFileName + "," + lFileLength + "\n"; |
| try { |
| out.write(sTmp.getBytes()); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| if (nRows == -1) { |
| sRet = sErrorPrefix + sTmpFileName + ",-1\nNo such file or directory"; |
| } |
| else { |
| myCursor.close(); |
| sRet = ""; |
| } |
| } |
| else { |
| sRet = sErrorPrefix + sTmpFileName + ",-1\nUnable to access file (internal error)"; |
| } |
| } |
| else { |
| try { |
| File f = new File(sTmpFileName); |
| long lFileLength = f.length(); |
| FileInputStream fin = new FileInputStream(f); |
| if (lFileLength == 0) { |
| while ((nRead = fin.read(buffer)) != -1) { |
| lFileLength += nRead; |
| } |
| fin.close(); |
| fin = new FileInputStream(f); |
| } |
| |
| // lLength == -1 return everything between lOffset and eof |
| // lLength == 0 return file length |
| // lLength > 0 return lLength bytes |
| if (lLength == -1) { |
| lFileLength = lFileLength - lOffset; |
| } else if (lLength == 0) { |
| // just return the file length |
| } else { |
| lFileLength = ((lLength <= (lFileLength - lOffset)) ? lLength : (lFileLength - lOffset)); |
| } |
| |
| String sTmp = sTmpFileName + "," + lFileLength + "\n"; |
| out.write(sTmp.getBytes()); |
| if (lLength != 0) { |
| if (lOffset > 0) { |
| fin.skip(lOffset); |
| } |
| while ((nRead = fin.read(buffer)) != -1) { |
| if ((lSent + nRead) <= lFileLength) { |
| out.write(buffer,0,nRead); |
| lSent += nRead; |
| } |
| else { |
| nRead = (int) (lFileLength - lSent); |
| out.write(buffer,0,nRead); |
| if (lLength != -1) |
| Log.d("pull warning", "more bytes read than sent"); |
| break; |
| } |
| } |
| } |
| fin.close(); |
| out.flush(); |
| sRet = ""; |
| } |
| catch (FileNotFoundException e) { |
| sRet = sErrorPrefix + sTmpFileName + ",-1\nNo such file or directory"; |
| } |
| catch (IOException e) { |
| sRet = e.toString(); |
| } |
| } |
| return (sRet); |
| } |
| |
| public String Cat(String fileName, OutputStream out) |
| { |
| String sTmpFileName = fixFileName(fileName); |
| String sRet = sErrorPrefix + "Could not read the file " + sTmpFileName; |
| byte[] buffer = new byte [4096]; |
| int nRead = 0; |
| |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = null; |
| |
| ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/file"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "chunk" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpFileName, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| int nRows = myCursor.getCount(); |
| int nBytesRecvd = 0; |
| |
| for (int lcv = 0; lcv < nRows; lcv++) { |
| if (myCursor.moveToPosition(lcv)) { |
| byte [] buf = myCursor.getBlob(1); |
| if (buf != null) { |
| nBytesRecvd += buf.length; |
| try { |
| out.write(buf); |
| sRet = ""; |
| } catch (IOException e) { |
| e.printStackTrace(); |
| sRet = sErrorPrefix + "Could not write to out " + sTmpFileName; |
| } |
| buf = null; |
| } |
| } |
| } |
| if (nRows == 0) { |
| sRet = ""; |
| } |
| |
| myCursor.close(); |
| } |
| } else { |
| try { |
| FileInputStream fin = new FileInputStream(sTmpFileName); |
| while ((nRead = fin.read(buffer)) != -1) { |
| out.write(buffer,0,nRead); |
| } |
| fin.close(); |
| out.flush(); |
| sRet = ""; |
| } |
| catch (FileNotFoundException e) { |
| sRet = sErrorPrefix + sTmpFileName + " No such file or directory"; |
| } |
| catch (IOException e) { |
| sRet = e.toString(); |
| } |
| } |
| return (sRet); |
| } |
| |
| public String MakeDir(String sDir) |
| { |
| String sTmpDir = fixFileName(sDir); |
| String sRet = sErrorPrefix + "Could not create the directory " + sTmpDir; |
| if (sTmpDir.contains("org.mozilla.fennec") || sTmpDir.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (sTmpDir.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| ContentValues cv = new ContentValues(); |
| |
| if (cr.update(ffxFiles, cv, sTmpDir, null) == 1) { |
| sRet = sDir + " successfully created"; |
| } |
| } |
| else { |
| File dir = new File(sTmpDir); |
| |
| if (dir.mkdirs()) { |
| sRet = sDir + " successfully created"; |
| } |
| } |
| |
| return (sRet); |
| } |
| // move this to SUTAgentAndroid.java |
| public String GetScreenInfo() |
| { |
| String sRet = ""; |
| DisplayMetrics metrics = new DisplayMetrics(); |
| WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE); |
| wMgr.getDefaultDisplay().getMetrics(metrics); |
| sRet = "X:" + metrics.widthPixels + " Y:" + metrics.heightPixels; |
| return (sRet); |
| } |
| // move this to SUTAgentAndroid.java |
| public int [] GetScreenXY() |
| { |
| int [] nRetXY = new int [2]; |
| DisplayMetrics metrics = new DisplayMetrics(); |
| WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE); |
| wMgr.getDefaultDisplay().getMetrics(metrics); |
| nRetXY[0] = metrics.widthPixels; |
| nRetXY[1] = metrics.heightPixels; |
| return(nRetXY); |
| } |
| |
| public String GetRotationInfo() |
| { |
| WindowManager wMgr = (WindowManager) contextWrapper.getSystemService(Context.WINDOW_SERVICE); |
| int nRotationDegrees = 0; // default |
| switch(wMgr.getDefaultDisplay().getRotation()) |
| { |
| case Surface.ROTATION_90: |
| nRotationDegrees = 90; |
| break; |
| case Surface.ROTATION_180: |
| nRotationDegrees = 180; |
| break; |
| case Surface.ROTATION_270: |
| nRotationDegrees = 270; |
| break; |
| } |
| return "ROTATION:" + nRotationDegrees; |
| } |
| |
| public String SetADB(String sWhat) { |
| String sRet = ""; |
| String sTmp = ""; |
| String sCmd; |
| |
| if (sWhat.contains("ip")) { |
| sCmd = "setprop service.adb.tcp.port 5555"; |
| } else { |
| sCmd = "setprop service.adb.tcp.port -1"; |
| } |
| |
| try { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs(sCmd)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sTmp = outThrd.strOutput; |
| Log.e("ADB", sTmp); |
| if (outThrd.nExitCode == 0) { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("stop adbd")); |
| outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sTmp = outThrd.strOutput; |
| Log.e("ADB", sTmp); |
| if (outThrd.nExitCode == 0) { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("start adbd")); |
| outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sTmp = outThrd.strOutput; |
| Log.e("ADB", sTmp); |
| if (outThrd.nExitCode == 0) { |
| sRet = "Successfully set adb to " + sWhat + "\n"; |
| } else { |
| sRet = sErrorPrefix + "Failed to start adbd\n"; |
| } |
| } else { |
| sRet = sErrorPrefix + "Failed to stop adbd\n"; |
| } |
| } else { |
| sRet = sErrorPrefix + "Failed to setprop service.adb.tcp.port 5555\n"; |
| } |
| |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| return(sRet); |
| } |
| |
| public String KillProcess(String sProcName, OutputStream out) |
| { |
| String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n"; |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses(); |
| int lcv = 0; |
| String sFoundProcName = ""; |
| int nProcs = 0; |
| boolean bFoundAppProcess = false; |
| |
| if (lProcesses != null) |
| nProcs = lProcesses.size(); |
| |
| for (lcv = 0; lcv < nProcs; lcv++) |
| { |
| if (lProcesses.get(lcv).processName.contains(sProcName)) |
| { |
| sFoundProcName = lProcesses.get(lcv).processName; |
| bFoundAppProcess = true; |
| |
| try |
| { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("kill " + lProcesses.get(lcv).pid)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(15000); |
| String sTmp = outThrd.strOutput; |
| Log.e("KILLPROCESS", sTmp); |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| if (bFoundAppProcess) |
| { |
| // Give the messages a chance to be processed |
| try { |
| Thread.sleep(2000); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| sRet = "Successfully killed " + sProcName + "\n"; |
| lProcesses = aMgr.getRunningAppProcesses(); |
| nProcs = 0; |
| if (lProcesses != null) |
| nProcs = lProcesses.size(); |
| for (lcv = 0; lcv < nProcs; lcv++) |
| { |
| if (lProcesses.get(lcv).processName.contains(sProcName)) |
| { |
| sRet = sErrorPrefix + "Unable to kill " + sProcName + " (couldn't kill " + sFoundProcName +")\n"; |
| break; |
| } |
| } |
| } |
| else |
| { |
| // To kill processes other than Java applications - processes |
| // like xpcshell - a different strategy is necessary: use ps |
| // to find the process' PID. |
| try |
| { |
| pProc = Runtime.getRuntime().exec("ps"); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(10000); |
| String sTmp = outThrd.strOutput; |
| StringTokenizer stokLines = new StringTokenizer(sTmp, "\n"); |
| while(stokLines.hasMoreTokens()) |
| { |
| String sLine = stokLines.nextToken(); |
| StringTokenizer stokColumns = new StringTokenizer(sLine, " \t\n"); |
| stokColumns.nextToken(); |
| String sPid = stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| stokColumns.nextToken(); |
| String sName = null; |
| if (stokColumns.hasMoreTokens()) |
| { |
| sName = stokColumns.nextToken(); |
| if (sName.contains(sProcName)) |
| { |
| NewKillProc(sPid, out); |
| sRet = "Successfully killed " + sName + "\n"; |
| } |
| } |
| } |
| } |
| catch (Exception e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| |
| return (sRet); |
| } |
| |
| public boolean IsProcessDead(String sProcName) |
| { |
| boolean bRet = false; |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| List <ActivityManager.ProcessErrorStateInfo> lProcesses = aMgr.getProcessesInErrorState(); |
| int lcv = 0; |
| |
| if (lProcesses != null) |
| { |
| for (lcv = 0; lcv < lProcesses.size(); lcv++) |
| { |
| if (lProcesses.get(lcv).processName.contentEquals(sProcName) && |
| lProcesses.get(lcv).condition != ActivityManager.ProcessErrorStateInfo.NO_ERROR) |
| { |
| bRet = true; |
| break; |
| } |
| } |
| } |
| |
| return (bRet); |
| } |
| |
| public String GetProcessInfo() |
| { |
| String sRet = ""; |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses(); |
| int nProcs = 0; |
| int lcv = 0; |
| String strProcName = ""; |
| int nPID = 0; |
| int nUser = 0; |
| |
| if (lProcesses != null) |
| nProcs = lProcesses.size(); |
| |
| for (lcv = 0; lcv < nProcs; lcv++) |
| { |
| strProcName = lProcesses.get(lcv).processName; |
| nPID = lProcesses.get(lcv).pid; |
| nUser = lProcesses.get(lcv).uid; |
| sRet += nUser + "\t" + nPID + "\t" + strProcName; |
| if (lcv < (nProcs - 1)) |
| sRet += "\n"; |
| } |
| |
| return (sRet); |
| } |
| |
| public String GetOSInfo() |
| { |
| String sRet = ""; |
| |
| sRet = Build.DISPLAY; |
| |
| return (sRet); |
| } |
| |
| public String GetPowerInfo() |
| { |
| String sRet = ""; |
| |
| sRet = "Power status:\n AC power " + SUTAgentAndroid.sACStatus + "\n"; |
| sRet += " Battery charge " + SUTAgentAndroid.sPowerStatus + "\n"; |
| sRet += " Remaining charge: " + SUTAgentAndroid.nChargeLevel + "%\n"; |
| sRet += " Battery Temperature: " + (((float)(SUTAgentAndroid.nBatteryTemp))/10) + " (c)\n"; |
| return (sRet); |
| } |
| |
| public String GetSutUserInfo() |
| { |
| String sRet = ""; |
| try { |
| // based on patch in https://bugzilla.mozilla.org/show_bug.cgi?id=811763 |
| Context context = contextWrapper.getApplicationContext(); |
| Object userManager = context.getSystemService("user"); |
| if (userManager != null) { |
| // if userManager is non-null that means we're running on 4.2+ and so the rest of this |
| // should just work |
| Object userHandle = android.os.Process.class.getMethod("myUserHandle", (Class[])null).invoke(null); |
| Object userSerial = userManager.getClass().getMethod("getSerialNumberForUser", userHandle.getClass()).invoke(userManager, userHandle); |
| sRet += "User Serial:" + userSerial.toString(); |
| } |
| } catch (Exception e) { |
| // Guard against any unexpected failures |
| e.printStackTrace(); |
| } |
| |
| return sRet; |
| } |
| |
| public String GetTemperatureInfo() |
| { |
| String sTempVal = "unknown"; |
| String sDeviceFile = "/sys/bus/platform/devices/temp_sensor_hwmon.0/temp1_input"; |
| try { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("cat " + sDeviceFile)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| String output = outThrd.strOutput; |
| // this only works on pandas (with the temperature sensors turned |
| // on), other platforms we just get a file not found error... we'll |
| // just return "unknown" for that case |
| try { |
| sTempVal = String.valueOf(Integer.parseInt(output.trim()) / 1000.0); |
| } catch (NumberFormatException e) { |
| // not parsed! probably not a panda |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| |
| return "Temperature: " + sTempVal; |
| } |
| |
| public String GetDiskInfo(String sPath) |
| { |
| String sRet = ""; |
| StatFs statFS = new StatFs(sPath); |
| |
| long nBlockCount = statFS.getBlockCount(); |
| long nBlockSize = statFS.getBlockSize(); |
| long nBlocksAvail = statFS.getAvailableBlocks(); |
| // Free is often the same as Available, but can include reserved |
| // blocks that are not available to normal applications. |
| // long nBlocksFree = statFS.getFreeBlocks(); |
| |
| sRet = sPath + ": " + (nBlockCount * nBlockSize) + " total, " + (nBlocksAvail * nBlockSize) + " available"; |
| |
| return (sRet); |
| } |
| |
| public String GetMemoryInfo() |
| { |
| String sRet = "PA:" + GetMemoryConfig() + ", FREE: " + GetMemoryUsage(); |
| return (sRet); |
| } |
| |
| public long GetMemoryConfig() |
| { |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); |
| aMgr.getMemoryInfo(outInfo); |
| long lMem = outInfo.availMem; |
| |
| return (lMem); |
| } |
| |
| public long GetMemoryUsage() |
| { |
| |
| String load = ""; |
| try { |
| RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r"); |
| load = reader.readLine(); // Read in the MemTotal |
| load = reader.readLine(); // Read in the MemFree |
| } catch (IOException ex) { |
| return (0); |
| } |
| |
| String[] toks = load.split(" "); |
| int i = 1; |
| for (i=1; i < toks.length; i++) { |
| String val = toks[i].trim(); |
| if (!val.equals("")) { |
| break; |
| } |
| } |
| if (i <= toks.length) { |
| long lMem = Long.parseLong(toks[i].trim()); |
| return (lMem * 1024); |
| } |
| return (0); |
| } |
| |
| public String UpdateCallBack(String sFileName) |
| { |
| String sRet = sErrorPrefix + "No file specified"; |
| String sIP = ""; |
| String sPort = ""; |
| int nEnd = 0; |
| int nStart = 0; |
| |
| if ((sFileName == null) || (sFileName.length() == 0)) |
| return(sRet); |
| |
| Context ctx = contextWrapper.getApplicationContext(); |
| try { |
| FileInputStream fis = ctx.openFileInput(sFileName); |
| int nBytes = fis.available(); |
| if (nBytes > 0) |
| { |
| byte [] buffer = new byte [nBytes + 1]; |
| int nRead = fis.read(buffer, 0, nBytes); |
| fis.close(); |
| ctx.deleteFile(sFileName); |
| if (nRead > 0) |
| { |
| String sBuffer = new String(buffer); |
| nEnd = sBuffer.indexOf(','); |
| if (nEnd > 0) |
| { |
| sIP = (sBuffer.substring(0, nEnd)).trim(); |
| nStart = nEnd + 1; |
| nEnd = sBuffer.indexOf('\r', nStart); |
| if (nEnd > 0) |
| { |
| sPort = (sBuffer.substring(nStart, nEnd)).trim(); |
| Thread.sleep(5000); |
| sRet = RegisterTheDevice(sIP, sPort, sBuffer.substring(nEnd + 1)); |
| } |
| } |
| } |
| } |
| } |
| catch (FileNotFoundException e) |
| { |
| sRet = sErrorPrefix + "Nothing to do"; |
| } |
| catch (IOException e) |
| { |
| sRet = sErrorPrefix + "Couldn't send info to " + sIP + ":" + sPort; |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| return(sRet); |
| } |
| |
| public String RegisterTheDevice(String sSrvr, String sPort, String sData) |
| { |
| String sRet = ""; |
| String line = ""; |
| |
| // Debug.waitForDebugger(); |
| |
| if (sSrvr != null && sPort != null && sData != null) |
| { |
| try |
| { |
| int nPort = Integer.parseInt(sPort); |
| Socket socket = new Socket(sSrvr, nPort); |
| PrintWriter out = new PrintWriter(socket.getOutputStream(), false); |
| BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); |
| out.println(sData); |
| if ( out.checkError() == false ) |
| { |
| socket.setSoTimeout(30000); |
| while (socket.isInputShutdown() == false) |
| { |
| line = in.readLine(); |
| |
| if (line != null) |
| { |
| line = line.toLowerCase(); |
| sRet += line; |
| // ok means we're done |
| if (line.contains("ok")) |
| break; |
| } |
| else |
| { |
| // end of stream reached |
| break; |
| } |
| } |
| } |
| out.close(); |
| in.close(); |
| socket.close(); |
| } |
| catch(NumberFormatException e) |
| { |
| sRet += "reg NumberFormatException thrown [" + e.getLocalizedMessage() + "]"; |
| e.printStackTrace(); |
| } |
| catch (UnknownHostException e) |
| { |
| sRet += "reg UnknownHostException thrown [" + e.getLocalizedMessage() + "]"; |
| e.printStackTrace(); |
| } |
| catch (IOException e) |
| { |
| sRet += "reg IOException thrown [" + e.getLocalizedMessage() + "]"; |
| e.printStackTrace(); |
| } |
| } |
| return(sRet); |
| } |
| |
| public String GetTimeZone() |
| { |
| String sRet = ""; |
| TimeZone tz; |
| |
| tz = TimeZone.getDefault(); |
| Date now = new Date(); |
| sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG); |
| |
| return(sRet); |
| } |
| |
| public String SetTimeZone(String sTimeZone) |
| { |
| String sRet = "Unable to set timezone to " + sTimeZone; |
| TimeZone tz = null; |
| AlarmManager amgr = null; |
| |
| if ((sTimeZone.length() > 0) && (sTimeZone.startsWith("GMT"))) |
| { |
| amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE); |
| if (amgr != null) |
| amgr.setTimeZone(sTimeZone); |
| } |
| else |
| { |
| String [] zoneNames = TimeZone.getAvailableIDs(); |
| int nNumMatches = zoneNames.length; |
| int lcv = 0; |
| |
| for (lcv = 0; lcv < nNumMatches; lcv++) |
| { |
| if (zoneNames[lcv].equalsIgnoreCase(sTimeZone)) |
| break; |
| } |
| |
| if (lcv < nNumMatches) |
| { |
| amgr = (AlarmManager) contextWrapper.getSystemService(Context.ALARM_SERVICE); |
| if (amgr != null) |
| amgr.setTimeZone(zoneNames[lcv]); |
| } |
| } |
| |
| if (amgr != null) |
| { |
| tz = TimeZone.getDefault(); |
| Date now = new Date(); |
| sRet = tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG); |
| } |
| |
| return(sRet); |
| } |
| |
| public String GetSystemTime() |
| { |
| String sRet = ""; |
| Calendar cal = Calendar.getInstance(); |
| SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); |
| sRet = sdf.format(cal.getTime()); |
| |
| return (sRet); |
| } |
| |
| public String SetSystemTime(String sDate, String sTime, OutputStream out) { |
| String sRet = ""; |
| String sM = ""; |
| String sMillis = ""; |
| |
| if (((sDate != null) && (sTime != null)) && |
| (sDate.contains("/") || sDate.contains(".")) && |
| (sTime.contains(":"))) { |
| int year = Integer.parseInt(sDate.substring(0,4)); |
| int month = Integer.parseInt(sDate.substring(5,7)); |
| int day = Integer.parseInt(sDate.substring(8,10)); |
| |
| int hour = Integer.parseInt(sTime.substring(0,2)); |
| int mins = Integer.parseInt(sTime.substring(3,5)); |
| int secs = Integer.parseInt(sTime.substring(6,8)); |
| |
| Calendar cal = new GregorianCalendar(TimeZone.getDefault()); |
| cal.set(year, month - 1, day, hour, mins, secs); |
| long lMillisecs = cal.getTime().getTime(); |
| |
| sM = Long.toString(lMillisecs); |
| sMillis = sM.substring(0, sM.length() - 3) + "." + sM.substring(sM.length() - 3); |
| |
| } else { |
| sRet += "Invalid argument(s)"; |
| } |
| |
| // if we have an argument |
| if (sMillis.length() > 0) { |
| try { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("date -u " + sMillis)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(10000); |
| sRet += GetSystemTime(); |
| } catch (IOException e) { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| return (sRet); |
| } |
| |
| public String GetClok() |
| { |
| long lMillisecs = System.currentTimeMillis(); |
| String sRet = ""; |
| |
| if (lMillisecs > 0) |
| sRet = Long.toString(lMillisecs); |
| |
| return(sRet); |
| } |
| |
| public String GetUptime() |
| { |
| String sRet = ""; |
| long lHold = 0; |
| long lUptime = SystemClock.elapsedRealtime(); |
| int nDays = 0; |
| int nHours = 0; |
| int nMinutes = 0; |
| int nSecs = 0; |
| int nMilliseconds = 0; |
| |
| if (lUptime > 0) |
| { |
| nDays = (int)(lUptime / (24L * 60L * 60L * 1000L)); |
| lHold = lUptime % (24L * 60L * 60L * 1000L); |
| nHours = (int)(lHold / (60L * 60L * 1000L)); |
| lHold %= 60L * 60L * 1000L; |
| nMinutes = (int)(lHold / (60L * 1000L)); |
| lHold %= 60L * 1000L; |
| nSecs = (int)(lHold / 1000L); |
| nMilliseconds = (int)(lHold % 1000); |
| sRet = "" + nDays + " days " + nHours + " hours " + nMinutes + " minutes " + nSecs + " seconds " + nMilliseconds + " ms"; |
| } |
| |
| return (sRet); |
| } |
| |
| public String GetUptimeMillis() |
| { |
| return Long.toString(SystemClock.uptimeMillis()); |
| } |
| |
| public String GetSutUptimeMillis() |
| { |
| long now = System.currentTimeMillis(); |
| return "SUTagent running for "+Long.toString(now - SUTAgentAndroid.nCreateTimeMillis)+" ms"; |
| } |
| |
| public String NewKillProc(String sProcId, OutputStream out) |
| { |
| String sRet = ""; |
| |
| try |
| { |
| pProc = Runtime.getRuntime().exec("kill "+sProcId); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return(sRet); |
| } |
| |
| public String SendPing(String sIPAddr, OutputStream out) |
| { |
| String sRet = ""; |
| String [] theArgs = new String [4]; |
| |
| theArgs[0] = "ping"; |
| theArgs[1] = "-c"; |
| theArgs[2] = "3"; |
| theArgs[3] = sIPAddr; |
| |
| try |
| { |
| pProc = Runtime.getRuntime().exec(theArgs); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| if (out == null) |
| sRet = outThrd.strOutput; |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return (sRet); |
| } |
| |
| public String GetTmpDir() |
| { |
| String sRet = ""; |
| Context ctx = contextWrapper.getApplicationContext(); |
| File dir = ctx.getFilesDir(); |
| ctx = null; |
| try { |
| sRet = dir.getCanonicalPath(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| return(sRet); |
| } |
| |
| public String PrintFileTimestamp(String sFile) |
| { |
| String sRet = ""; |
| String sTmpFileName = fixFileName(sFile); |
| long lModified = -1; |
| |
| if (sTmpFileName.contains("org.mozilla.fennec") || sTmpFileName.contains("org.mozilla.firefox")) { |
| ContentResolver cr = contextWrapper.getContentResolver(); |
| Uri ffxFiles = Uri.parse("content://" + (sTmpFileName.contains("fennec") ? fenProvider : ffxProvider) + "/dir"); |
| |
| String[] columns = new String[] { |
| "_id", |
| "isdir", |
| "filename", |
| "length", |
| "ts" |
| }; |
| |
| Cursor myCursor = cr.query( ffxFiles, |
| columns, // Which columns to return |
| sTmpFileName, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| null); // Order clause (none) |
| if (myCursor != null) { |
| if (myCursor.getCount() > 0) { |
| if (myCursor.moveToPosition(0)) { |
| lModified = myCursor.getLong(myCursor.getColumnIndex("ts")); |
| } |
| } |
| myCursor.close(); |
| } |
| } |
| else { |
| File theFile = new File(sTmpFileName); |
| |
| if (theFile.exists()) { |
| lModified = theFile.lastModified(); |
| } |
| } |
| |
| if (lModified != -1) { |
| Date dtModified = new Date(lModified); |
| SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); |
| sRet = "Last modified: " + sdf.format(dtModified); |
| } |
| else { |
| sRet = sErrorPrefix + "[" + sTmpFileName + "] doesn't exist"; |
| } |
| |
| return(sRet); |
| } |
| |
| public String GetIniData(String sSection, String sKey, String sFile) |
| { |
| String sRet = ""; |
| String sComp = ""; |
| String sLine = ""; |
| boolean bFound = false; |
| BufferedReader in = null; |
| String sTmpFileName = fixFileName(sFile); |
| |
| try { |
| in = new BufferedReader(new FileReader(sTmpFileName)); |
| sComp = "[" + sSection + "]"; |
| while ((sLine = in.readLine()) != null) |
| { |
| if (sLine.equalsIgnoreCase(sComp)) |
| { |
| bFound = true; |
| break; |
| } |
| } |
| |
| if (bFound) |
| { |
| sComp = (sKey + " =").toLowerCase(); |
| while ((sLine = in.readLine()) != null) |
| { |
| if (sLine.toLowerCase().contains(sComp)) |
| { |
| String [] temp = null; |
| temp = sLine.split("="); |
| if (temp != null) |
| { |
| if (temp.length > 1) |
| sRet = temp[1].trim(); |
| } |
| break; |
| } |
| } |
| } |
| in.close(); |
| } |
| catch (FileNotFoundException e) |
| { |
| sComp = e.toString(); |
| } |
| catch (IOException e) |
| { |
| sComp = e.toString(); |
| } |
| return (sRet); |
| } |
| |
| public String RunReboot(OutputStream out, String sCallBackIP, String sCallBackPort) |
| { |
| String sRet = ""; |
| Context ctx = contextWrapper.getApplicationContext(); |
| |
| try { |
| if ((sCallBackIP != null) && (sCallBackPort != null) && |
| (sCallBackIP.length() > 0) && (sCallBackPort.length() > 0)) { |
| FileOutputStream fos = ctx.openFileOutput("update.info", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); |
| String sBuffer = sCallBackIP + "," + sCallBackPort + "\rSystem rebooted\r"; |
| fos.write(sBuffer.getBytes()); |
| fos.flush(); |
| fos.close(); |
| fos = null; |
| } |
| } catch (FileNotFoundException e) { |
| sRet = sErrorPrefix + "Callback file creation error [rebt] call failed " + e.getMessage(); |
| e.printStackTrace(); |
| } catch (IOException e) { |
| sRet = sErrorPrefix + "Callback file error [rebt] call failed " + e.getMessage(); |
| e.printStackTrace(); |
| } |
| |
| try { |
| // Tell all of the data channels we are rebooting |
| ((ASMozStub)this.contextWrapper).SendToDataChannel("Rebooting ..."); |
| |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("reboot")); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(10000); |
| } catch (IOException e) { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| |
| return (sRet); |
| } |
| |
| private String [] getSuArgs(String cmdString) |
| { |
| String [] theArgs = new String [3]; |
| theArgs[0] = "su"; |
| theArgs[1] = "-c"; |
| // as a security measure, ICS and later resets LD_LIBRARY_PATH. reset |
| // it here when executing the command |
| theArgs[2] = "LD_LIBRARY_PATH=/vendor/lib:/system/lib " + cmdString; |
| return theArgs; |
| } |
| |
| public String UnInstallApp(String sApp, OutputStream out, boolean reboot) |
| { |
| String sRet = ""; |
| |
| try |
| { |
| if (reboot == true) { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("pm uninstall " + sApp + ";reboot;exit")); |
| } else { |
| pProc = Runtime.getRuntime().exec(this.getSuArgs("pm uninstall " + sApp + ";exit")); |
| } |
| |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| try { |
| outThrd.joinAndStopRedirect(60000); |
| int nRet = pProc.exitValue(); |
| sRet = "\nuninst complete [" + nRet + "]"; |
| } |
| catch (IllegalThreadStateException itse) { |
| itse.printStackTrace(); |
| sRet = "\nuninst command timed out"; |
| } |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return (sRet); |
| } |
| |
| public String InstallApp(String sApp, OutputStream out) |
| { |
| String sRet = ""; |
| File srcFile = new File(sApp); |
| |
| try |
| { |
| // on android 4.2 and above, we want to pass the "-d" argument to pm so that version |
| // downgrades are allowed... (option unsupported in earlier versions) |
| String sPmCmd; |
| |
| if (android.os.Build.VERSION.SDK_INT >= 17) { // JELLY_BEAN_MR1 |
| sPmCmd = "pm install -r -d " + sApp + " Cleanup;exit"; |
| } else { |
| sPmCmd = "pm install -r " + sApp + " Cleanup;exit"; |
| } |
| pProc = Runtime.getRuntime().exec(this.getSuArgs(sPmCmd)); |
| RedirOutputThread outThrd3 = new RedirOutputThread(pProc, out); |
| outThrd3.start(); |
| try { |
| outThrd3.joinAndStopRedirect(60000); |
| int nRet3 = pProc.exitValue(); |
| if (nRet3 == 0) { |
| sRet = "\ninstallation complete [0]\n"; |
| } |
| else { |
| sRet = "\nFailure pm install [" + nRet3 + "]\n"; |
| } |
| } |
| catch (IllegalThreadStateException itse) { |
| itse.printStackTrace(); |
| sRet = "\nFailure pm install command timed out\n"; |
| } |
| try { |
| out.write(sRet.getBytes()); |
| out.flush(); |
| } |
| catch (IOException e1) |
| { |
| e1.printStackTrace(); |
| } |
| } |
| catch (IOException e) |
| { |
| sRet = e.getMessage(); |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| } |
| |
| return (sRet); |
| } |
| |
| public String StrtUpdtOMatic(String sPkgName, String sPkgFileName, String sCallBackIP, String sCallBackPort) |
| { |
| String sRet = ""; |
| |
| Context ctx = contextWrapper.getApplicationContext(); |
| PackageManager pm = ctx.getPackageManager(); |
| |
| Intent prgIntent = new Intent(); |
| prgIntent.setPackage("com.mozilla.watcher"); |
| |
| try { |
| PackageInfo pi = pm.getPackageInfo("com.mozilla.watcher", PackageManager.GET_SERVICES | PackageManager.GET_INTENT_FILTERS); |
| ServiceInfo [] si = pi.services; |
| for (int i = 0; i < si.length; i++) |
| { |
| ServiceInfo s = si[i]; |
| if (s.name.length() > 0) |
| { |
| prgIntent.setClassName(s.packageName, s.name); |
| break; |
| } |
| } |
| } |
| catch (NameNotFoundException e) |
| { |
| e.printStackTrace(); |
| sRet = sErrorPrefix + "watcher is not properly installed"; |
| return(sRet); |
| } |
| |
| prgIntent.putExtra("command", "updt"); |
| prgIntent.putExtra("pkgName", sPkgName); |
| prgIntent.putExtra("pkgFile", sPkgFileName); |
| prgIntent.putExtra("reboot", true); |
| |
| try |
| { |
| if ((sCallBackIP != null) && (sCallBackPort != null) && |
| (sCallBackIP.length() > 0) && (sCallBackPort.length() > 0)) |
| { |
| FileOutputStream fos = ctx.openFileOutput("update.info", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); |
| String sBuffer = sCallBackIP + "," + sCallBackPort + "\rupdate started " + sPkgName + " " + sPkgFileName + "\r"; |
| fos.write(sBuffer.getBytes()); |
| fos.flush(); |
| fos.close(); |
| fos = null; |
| prgIntent.putExtra("outFile", ctx.getFilesDir() + "/update.info"); |
| } |
| else { |
| if (prgIntent.hasExtra("outFile")) { |
| System.out.println("outFile extra unset from intent"); |
| prgIntent.removeExtra("outFile"); |
| } |
| } |
| |
| ComponentName cn = contextWrapper.startService(prgIntent); |
| if (cn != null) |
| sRet = "exit"; |
| else |
| sRet = sErrorPrefix + "Unable to use watcher service"; |
| } |
| catch(ActivityNotFoundException anf) |
| { |
| sRet = sErrorPrefix + "Activity Not Found Exception [updt] call failed"; |
| anf.printStackTrace(); |
| } |
| catch (FileNotFoundException e) |
| { |
| sRet = sErrorPrefix + "File creation error [updt] call failed"; |
| e.printStackTrace(); |
| } |
| catch (IOException e) |
| { |
| sRet = sErrorPrefix + "File error [updt] call failed"; |
| e.printStackTrace(); |
| } |
| |
| ctx = null; |
| |
| return (sRet); |
| } |
| |
| public String StartJavaPrg(String [] sArgs, Intent preIntent) |
| { |
| String sRet = ""; |
| String sArgList = ""; |
| String sUrl = ""; |
| // String sRedirFileName = ""; |
| Intent prgIntent = null; |
| |
| Context ctx = contextWrapper.getApplicationContext(); |
| PackageManager pm = ctx.getPackageManager(); |
| |
| if (preIntent == null) |
| prgIntent = new Intent(); |
| else |
| prgIntent = preIntent; |
| |
| prgIntent.setPackage(sArgs[0]); |
| prgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| |
| // Get the main activity for this package |
| try { |
| final ComponentName c = pm.getLaunchIntentForPackage(sArgs[0]).getComponent(); |
| prgIntent.setClassName(c.getPackageName(), c.getClassName()); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| return "Unable to find main activity for package: " + sArgs[0]; |
| } |
| |
| if (sArgs.length > 1) |
| { |
| if (sArgs[0].contains("android.browser")) |
| prgIntent.setAction(Intent.ACTION_VIEW); |
| else |
| prgIntent.setAction(Intent.ACTION_MAIN); |
| |
| if (sArgs[0].contains("fennec") || sArgs[0].contains("firefox")) |
| { |
| sArgList = ""; |
| sUrl = ""; |
| |
| for (int lcv = 1; lcv < sArgs.length; lcv++) |
| { |
| if (sArgs[lcv].contains("://")) |
| { |
| prgIntent.setAction(Intent.ACTION_VIEW); |
| sUrl = sArgs[lcv]; |
| } |
| else |
| { |
| if (sArgs[lcv].equals(">")) |
| { |
| lcv++; |
| if (lcv < sArgs.length) |
| lcv++; |
| // sRedirFileName = sArgs[lcv++]; |
| } |
| else |
| sArgList += " " + sArgs[lcv]; |
| } |
| } |
| |
| if (sArgList.length() > 0) |
| prgIntent.putExtra("args", sArgList.trim()); |
| |
| if (sUrl.length() > 0) |
| prgIntent.setData(Uri.parse(sUrl.trim())); |
| } |
| else |
| { |
| for (int lcv = 1; lcv < sArgs.length; lcv++) |
| sArgList += " " + sArgs[lcv]; |
| |
| prgIntent.setData(Uri.parse(sArgList.trim())); |
| } |
| } |
| else |
| { |
| prgIntent.setAction(Intent.ACTION_MAIN); |
| } |
| |
| try |
| { |
| contextWrapper.startActivity(prgIntent); |
| FindProcThread findProcThrd = new FindProcThread(contextWrapper, sArgs[0]); |
| findProcThrd.start(); |
| findProcThrd.join(7000); |
| if (!findProcThrd.bFoundIt && !findProcThrd.bStillRunning) { |
| sRet = "Unable to start " + sArgs[0] + ""; |
| } |
| } |
| catch(ActivityNotFoundException anf) |
| { |
| anf.printStackTrace(); |
| } |
| catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| |
| ctx = null; |
| return (sRet); |
| } |
| |
| public String StartPrg(String [] progArray, OutputStream out, boolean startAsRoot, int timeoutSeconds) |
| { |
| String sRet = ""; |
| int lcv = 0; |
| |
| try { |
| if (startAsRoot) |
| { |
| // we need to requote the program string here, in case |
| // there's spaces or other characters which need quoting |
| // before being passed to su |
| List<String> quotedProgList = new ArrayList<String>(); |
| for (String arg : progArray) |
| { |
| String quotedArg = arg; |
| quotedArg = quotedArg.replace("\"", "\\\""); |
| quotedArg = quotedArg.replace("\'", "\\\'"); |
| if (quotedArg.contains(" ")) |
| { |
| quotedArg = "\"" + quotedArg + "\""; |
| } |
| quotedProgList.add(quotedArg); |
| } |
| pProc = Runtime.getRuntime().exec(this.getSuArgs(TextUtils.join(" ", quotedProgList))); |
| } |
| else |
| { |
| pProc = Runtime.getRuntime().exec(progArray); |
| } |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| try { |
| outThrd.join(timeoutSeconds * 1000); |
| int nRetCode = pProc.exitValue(); |
| sRet = "return code [" + nRetCode + "]"; |
| } |
| catch (IllegalThreadStateException itse) { |
| } |
| outThrd.stopRedirect(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| sRet = "Timed out!"; |
| } |
| |
| return (sRet); |
| } |
| |
| public String StartPrg2(String [] progArray, OutputStream out, String cwd, boolean startAsRoot, int timeoutSeconds) |
| { |
| String sRet = ""; |
| |
| int nArraySize = 0; |
| int nArgs = progArray.length - 1; // 1st arg is the environment string |
| int lcv = 0; |
| int temp = 0; |
| |
| String sEnvString = progArray[0]; |
| |
| if (!sEnvString.contains("=") && (sEnvString.length() > 0)) |
| { |
| if (sEnvString.contains("/") || sEnvString.contains("\\") || !sEnvString.contains(".")) |
| sRet = StartPrg(progArray, out, startAsRoot, timeoutSeconds); |
| else |
| sRet = StartJavaPrg(progArray, null); |
| return(sRet); |
| } |
| |
| // Set up command line args stripping off the environment string |
| String [] theArgs = new String [nArgs]; |
| for (lcv = 0; lcv < nArgs; lcv++) |
| { |
| theArgs[lcv] = progArray[lcv + 1]; |
| } |
| |
| try |
| { |
| String [] envStrings = sEnvString.split(","); |
| Map<String, String> newEnv = new HashMap<String, String>(); |
| |
| for (lcv = 0; lcv < envStrings.length; lcv++) |
| { |
| temp = envStrings[lcv].indexOf("="); |
| if (temp > 0) |
| { |
| newEnv.put( envStrings[lcv].substring(0, temp), |
| envStrings[lcv].substring(temp + 1, envStrings[lcv].length())); |
| } |
| } |
| |
| Map<String, String> sysEnv = System.getenv(); |
| |
| nArraySize = sysEnv.size(); |
| |
| for (Map.Entry<String, String> entry : newEnv.entrySet()) |
| { |
| if (!sysEnv.containsKey(entry.getKey())) |
| { |
| nArraySize++; |
| } |
| } |
| |
| String[] envArray = new String[nArraySize]; |
| |
| int i = 0; |
| int offset; |
| String sKey = ""; |
| String sValue = ""; |
| |
| for (Map.Entry<String, String> entry : sysEnv.entrySet()) |
| { |
| sKey = entry.getKey(); |
| if (newEnv.containsKey(sKey)) |
| { |
| sValue = newEnv.get(sKey); |
| if ((offset = sValue.indexOf("$" + sKey)) != -1) |
| { |
| envArray[i++] = sKey + |
| "=" + |
| sValue.substring(0, offset) + |
| entry.getValue() + |
| sValue.substring(offset + sKey.length() + 1); |
| } |
| else |
| envArray[i++] = sKey + "=" + sValue; |
| newEnv.remove(sKey); |
| } |
| else |
| envArray[i++] = entry.getKey() + "=" + entry.getValue(); |
| } |
| |
| for (Map.Entry<String, String> entry : newEnv.entrySet()) |
| { |
| envArray[i++] = entry.getKey() + "=" + entry.getValue(); |
| } |
| |
| if (theArgs[0].contains("/") || theArgs[0].contains("\\") || !theArgs[0].contains(".")) |
| { |
| if (cwd != null) |
| { |
| File f = new File(cwd); |
| pProc = Runtime.getRuntime().exec(theArgs, envArray, f); |
| } |
| else |
| { |
| pProc = Runtime.getRuntime().exec(theArgs, envArray); |
| } |
| |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, out); |
| outThrd.start(); |
| |
| try { |
| outThrd.join(timeoutSeconds * 1000); |
| int nRetCode = pProc.exitValue(); |
| sRet = "return code [" + nRetCode + "]"; |
| } |
| catch (IllegalThreadStateException itse) { |
| } |
| outThrd.stopRedirect(); |
| } |
| else |
| { |
| Intent preIntent = new Intent(); |
| for (lcv = 0; lcv < envArray.length; lcv++) |
| { |
| preIntent.putExtra("env" + lcv, envArray[lcv]); |
| } |
| sRet = StartJavaPrg(theArgs, preIntent); |
| } |
| } |
| catch(UnsupportedOperationException e) |
| { |
| if (e != null) |
| e.printStackTrace(); |
| } |
| catch(ClassCastException e) |
| { |
| if (e != null) |
| e.printStackTrace(); |
| } |
| catch(IllegalArgumentException e) |
| { |
| if (e != null) |
| e.printStackTrace(); |
| } |
| catch(NullPointerException e) |
| { |
| if (e != null) |
| e.printStackTrace(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (InterruptedException e) |
| { |
| e.printStackTrace(); |
| sRet = "Timed out!"; |
| } |
| |
| return (sRet); |
| } |
| |
| public String ChmodDir(String sDir) |
| { |
| String sRet = ""; |
| int nFiles = 0; |
| String sSubDir = null; |
| String sTmpDir = fixFileName(sDir); |
| |
| File dir = new File(sTmpDir); |
| |
| if (dir.isDirectory()) { |
| sRet = "Changing permissions for " + sTmpDir; |
| |
| File [] files = dir.listFiles(); |
| if (files != null) { |
| if ((nFiles = files.length) > 0) { |
| for (int lcv = 0; lcv < nFiles; lcv++) { |
| if (files[lcv].isDirectory()) { |
| sSubDir = files[lcv].getAbsolutePath(); |
| sRet += "\n" + ChmodDir(sSubDir); |
| } |
| else { |
| // set the new file's permissions to rwxrwxrwx, if possible |
| try { |
| Process pProc = Runtime.getRuntime().exec(this.getSuArgs("chmod 777 "+files[lcv])); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sRet += "\n\tchmod " + files[lcv].getName() + " ok"; |
| } catch (InterruptedException e) { |
| sRet += "\n\ttimeout waiting for chmod " + files[lcv].getName(); |
| } catch (IOException e) { |
| sRet += "\n\tunable to chmod " + files[lcv].getName(); |
| } |
| } |
| } |
| } |
| else |
| sRet += "\n\t<empty>"; |
| } |
| } |
| |
| // set the new directory's (or file's) permissions to rwxrwxrwx, if possible |
| try { |
| Process pProc = Runtime.getRuntime().exec(this.getSuArgs("chmod 777 "+sTmpDir)); |
| RedirOutputThread outThrd = new RedirOutputThread(pProc, null); |
| outThrd.start(); |
| outThrd.joinAndStopRedirect(5000); |
| sRet += "\n\tchmod " + sTmpDir + " ok"; |
| } catch (InterruptedException e) { |
| sRet += "\n\ttimeout waiting for chmod " + sTmpDir; |
| } catch (IOException e) { |
| sRet += "\n\tunable to chmod " + sTmpDir; |
| } |
| |
| return(sRet); |
| } |
| |
| public String TopActivity() |
| { |
| String sRet = ""; |
| ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE); |
| List< ActivityManager.RunningTaskInfo > taskInfo = null; |
| ComponentName componentInfo = null; |
| if (aMgr != null) |
| { |
| taskInfo = aMgr.getRunningTasks(1); |
| } |
| if (taskInfo != null) |
| { |
| // topActivity: "The activity component at the top of the history stack of the task. |
| // This is what the user is currently doing." |
| componentInfo = taskInfo.get(0).topActivity; |
| } |
| if (componentInfo != null) |
| { |
| sRet = componentInfo.getPackageName(); |
| } |
| return(sRet); |
| } |
| |
| private String PrintUsage() |
| { |
| String sRet = |
| "run [cmdline] - start program no wait\n" + |
| "exec [env pairs] [cmdline] - start program no wait optionally pass env\n" + |
| " key=value pairs (comma separated)\n" + |
| "execcwd <dir> [env pairs] [cmdline] - start program from specified directory\n" + |
| "execsu [env pairs] [cmdline] - start program as privileged user\n" + |
| "execcwdsu <dir> [env pairs] [cmdline] - start program from specified directory as privileged user\n" + |
| "execext [su] [cwd=<dir>] [t=<timeout>] [env pairs] [cmdline] - start program with extended options\n" + |
| "kill [program name] - kill program no path\n" + |
| "killall - kill all processes started\n" + |
| "ps - list of running processes\n" + |
| "info - list of device info\n" + |
| " [os] - os version for device\n" + |
| " [id] - unique identifier for device\n" + |
| " [uptime] - uptime for device\n" + |
| " [uptimemillis] - uptime for device in milliseconds\n" + |
| " [sutuptimemillis] - uptime for SUT in milliseconds\n" + |
| " [systime] - current system time\n" + |
| " [screen] - width, height and bits per pixel for device\n" + |
| " [memory] - physical, free, available, storage memory\n" + |
| " for device\n" + |
| " [processes] - list of running processes see 'ps'\n" + |
| "alrt [on/off] - start or stop sysalert behavior\n" + |
| "disk [arg] - prints disk space info\n" + |
| "cp file1 file2 - copy file1 to file2\n" + |
| "time file - timestamp for file\n" + |
| "hash file - generate hash for file\n" + |
| "cd directory - change cwd\n" + |
| "cat file - cat file\n" + |
| "cwd - display cwd\n" + |
| "mv file1 file2 - move file1 to file2\n" + |
| "push filename - push file to device\n" + |
| "rm file - delete file\n" + |
| "rmdr directory - delete directory even if not empty\n" + |
| "mkdr directory - create directory\n" + |
| "dirw directory - tests whether the directory is writable\n" + |
| "isdir directory - test whether the directory exists\n" + |
| "chmod directory|file - change permissions of directory and contents (or file) to 777\n" + |
| "stat processid - stat process\n" + |
| "dead processid - print whether the process is alive or hung\n" + |
| "mems - dump memory stats\n" + |
| "ls - print directory\n" + |
| "tmpd - print temp directory\n" + |
| "ping [hostname/ipaddr] - ping a network device\n" + |
| "unzp zipfile destdir - unzip the zipfile into the destination dir\n" + |
| "zip zipfile src - zip the source file/dir into zipfile\n" + |
| "rebt - reboot device\n" + |
| "inst /path/filename.apk - install the referenced apk file\n" + |
| "uninst packagename - uninstall the referenced package and reboot\n" + |
| "uninstall packagename - uninstall the referenced package without a reboot\n" + |
| "updt pkgname pkgfile - unpdate the referenced package\n" + |
| "clok - the current device time expressed as the" + |
| " number of millisecs since epoch\n" + |
| "settime date time - sets the device date and time\n" + |
| " (YYYY/MM/DD HH:MM:SS)\n" + |
| "tzset timezone - sets the device timezone format is\n" + |
| " GMTxhh:mm x = +/- or a recognized Olsen string\n" + |
| "tzget - returns the current timezone set on the device\n" + |
| "rebt - reboot device\n" + |
| "adb ip|usb - set adb to use tcp/ip on port 5555 or usb\n" + |
| "activity - print package name of top (foreground) activity\n" + |
| "quit - disconnect SUTAgent\n" + |
| "exit - close SUTAgent\n" + |
| "ver - SUTAgent version\n" + |
| "help - you're reading it"; |
| return (sRet); |
| } |
| } |