public void ProcessMultiLineOutputTest() { string content = @"root 1 0 852 628 c1157816 0805d0d6 S /init root 2 0 0 0 c10589a4 00000000 S kthreadd root 3 2 0 0 c105fd59 00000000 S ksoftirqd/0"; ProcessOutputReceiver receiver = new ProcessOutputReceiver(); StringReader reader = new StringReader(content); while (reader.Peek() >= 0) { receiver.AddOutput(reader.ReadLine()); } receiver.Flush(); Assert.AreEqual(2, receiver.Processes.Count); }
public void ProcessLimitedOutputTest() { string content = @" PID USER VSZ STAT COMMAND 1 root 340 S /init 2 root 0 SW< [kthreadd]"; ProcessOutputReceiver receiver = new ProcessOutputReceiver(); StringReader reader = new StringReader(content); while (reader.Peek() >= 0) { receiver.AddOutput(reader.ReadLine()); } receiver.Flush(); Assert.AreEqual(2, receiver.Processes.Count); Assert.AreEqual("/init", receiver.Processes.First().Name); Assert.AreEqual("kthreadd", receiver.Processes.Last().Name); }
/// <summary> /// Lists all processes running on the device. /// </summary> /// <param name="device"> /// The device on which to list the processes that are running. /// </param> /// <returns> /// An <see cref="IEnumerable{AndroidProcess}"/> that will iterate over all /// processes that are currently running on the device. /// </returns> public static IEnumerable<AndroidProcess> ListProcesses(this DeviceData device) { // There are a couple of gotcha's when listing processes on an Android device. // One way would be to run ps and parse the output. However, the output of // ps differents from Android version to Android version, is not delimited, nor // entirely fixed length, and some of the fields can be empty, so it's almost impossible // to parse correctly. // // The alternative is to directly read the values in /proc/[pid], pretty much like ps // does (see https://android.googlesource.com/platform/system/core/+/master/toolbox/ps.c). // // The easiest way to do the directory listings would be to use the SyncService; unfortunately, // the sync service doesn't work very well with /proc/ so we're back to using ls and taking it // from there. List<AndroidProcess> processes = new List<AndroidProcess>(); // List all processes by doing ls /proc/. // All subfolders which are completely numeric are PIDs ConsoleOutputReceiver receiver = new ConsoleOutputReceiver(); device.ExecuteShellCommand("/system/bin/ls /proc/", receiver); Collection<int> pids = new Collection<int>(); using (StringReader reader = new StringReader(receiver.ToString())) { while (reader.Peek() > 0) { string line = reader.ReadLine(); if (!line.All(c => char.IsDigit(c))) { continue; } var pid = int.Parse(line); pids.Add(pid); } } // For each pid, we can get /proc/[pid]/stat, which contains the process information in a well-defined // format - see http://man7.org/linux/man-pages/man5/proc.5.html. // Doing cat on each file one by one takes too much time. Doing cat on all of them at the same time doesn't work // either, because the command line would be too long. // So we do it 50 processes at at time. StringBuilder catBuilder = new StringBuilder(); ProcessOutputReceiver processOutputReceiver = new ProcessOutputReceiver(); for (int i = 0; i < pids.Count; i++) { if (i % 50 == 0) { catBuilder.Clear(); catBuilder.Append("cat "); } catBuilder.Append($"/proc/{pids[i]}/stat "); if (i > 0 && (i % 50 == 0 || i == pids.Count - 1)) { device.ExecuteShellCommand(catBuilder.ToString(), processOutputReceiver); } } processOutputReceiver.Flush(); return processOutputReceiver.Processes; }
/// <summary> /// Lists all processes running on the device. /// </summary> /// <param name="device"> /// The device on which to list the processes that are running. /// </param> /// <returns> /// An <see cref="IEnumerable{AndroidProcess}"/> that will iterate over all /// processes that are currently running on the device. /// </returns> public static IEnumerable<AndroidProcess> ListProcesses(this DeviceData device) { var receiver = new ProcessOutputReceiver(); device.ExecuteShellCommand("/system/bin/ps", receiver); return receiver.Processes; }
public void ProcessOutputTest() { string output = @"USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 852 628 c1157816 0805d0d6 S /init root 2 0 0 0 c10589a4 00000000 S kthreadd root 127 2 0 0 c1052a3b 00000000 S ext4-dio-unwrit root 129 1 1572 4 c11850d6 0805f0bb S /sbin/healthd shell 145 1 1552 584 c135a860 b7649fe6 S /system/bin/sh root 146 1 4764 260 ffffffff 0806ba20 S /sbin/adbd system 452 138 511452 44104 ffffffff b765ff1b S system_server root 470 2 0 0 c1053187 00000000 S kworker/1:1H root 476 1 1544 616 c104b8ee b76b75b6 S /system/bin/sh root 478 476 1412 204 c105c979 b771a1e1 S zygotelaunch u0_a33 664 138 449648 22100 ffffffff b765ff1b S com.android.music u0_a5 698 138 451988 32252 ffffffff b765ff1b S android.process.media root 710 1 1312 416 c1157816 b7697fe6 S /system/bin/logwrapper root 715 710 1544 612 c104b8ee b76405b6 S /system/bin/sh wifi 722 715 5812 2152 c1157816 b74c2610 S /system/bin/wpa_supplicant root 731 2 0 0 c1053187 00000000 S kworker/0:1H root 754 1 1312 416 c1157816 b7719fe6 S /system/bin/logwrapper dhcp 755 754 1624 740 c1157816 b770dfe6 S /system/bin/dhcpcd u0_a4 762 138 451852 21908 ffffffff b765ff1b S com.android.dialer root 991 146 1556 696 c104b8ee b76345b6 S /system/bin/sh root 1044 991 1868 504 00000000 b76c0fe6 R ps"; ProcessOutputReceiver receiver = new ProcessOutputReceiver(); using (StringReader reader = new StringReader(output)) { while (reader.Peek() >= 0) { string line = reader.ReadLine(); receiver.AddOutput(line); } } receiver.Flush(); Assert.AreEqual(21, receiver.Processes.Count); Assert.AreEqual("/init", receiver.Processes.First().Name); Assert.AreEqual("ps", receiver.Processes.Last().Name); }