//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public JdbSetup(AndroidProcess process) { LoggingUtils.PrintFunction(); Process = process; Host = "localhost"; Port = 65534; string sanitisedDeviceId = Process.HostDevice.ID.Replace(':', '-'); CacheDirectory = string.Format(@"{0}\Android++\Cache\{1}\{2}", Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), sanitisedDeviceId, Process.Name); Directory.CreateDirectory(CacheDirectory); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public JdbSetup (AndroidProcess process) { LoggingUtils.PrintFunction (); Process = process; Host = "localhost"; Port = 65534; string sanitisedDeviceId = Process.HostDevice.ID.Replace (':', '-'); CacheDirectory = string.Format (@"{0}\Android++\Cache\{1}\{2}", Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), sanitisedDeviceId, Process.Name); Directory.CreateDirectory (CacheDirectory); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void KillActiveGdbServerSessions() { LoggingUtils.PrintFunction(); // // Killing GDB server instances requires use of run-as [package-name], // but it's very difficult to get the parent package of lib/gdbserver as the PPID // will always refer to the zygote. This hack uses the sand-boxed 'user' to try all combinations. // m_gdbSetup.Process.HostDevice.Refresh(); uint [] activeDevicePids = m_gdbSetup.Process.HostDevice.GetActivePids(); List <AndroidProcess> activeGdbProcesses = new List <AndroidProcess> (); foreach (uint pid in activeDevicePids) { AndroidProcess process = m_gdbSetup.Process.HostDevice.GetProcessFromPid(pid); if (process.Name.Contains("lib/gdbserver")) { activeGdbProcesses.Add(process); } } foreach (AndroidProcess gdbProcess in activeGdbProcesses) { foreach (uint pid in activeDevicePids) { AndroidProcess process = m_gdbSetup.Process.HostDevice.GetProcessFromPid(pid); if ((gdbProcess != process) && (gdbProcess.User.Equals(process.User))) { LoggingUtils.Print(string.Format("[GdbServer] Attempting to terminate existing GDB debugging session: {0} ({1}).", gdbProcess.Name, gdbProcess.Pid)); m_gdbSetup.Process.HostDevice.Shell("run-as", string.Format("{0} kill -9 {1}", process.Name, gdbProcess.Pid)); } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public GdbSetup (AndroidProcess process, string gdbToolPath) { LoggingUtils.PrintFunction (); Process = process; Host = "localhost"; Port = 5039; if (!Process.HostDevice.IsOverWiFi) { Socket = "debug-socket"; } string sanitisedDeviceId = Process.HostDevice.ID.Replace (':', '-'); CacheDirectory = string.Format (@"{0}\Android++\Cache\{1}\{2}", Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), sanitisedDeviceId, Process.Name); Directory.CreateDirectory (CacheDirectory); CacheSysRoot = Path.Combine (CacheDirectory, "sysroot"); Directory.CreateDirectory (CacheSysRoot); SymbolDirectories = new HashSet<string> (); GdbToolPath = gdbToolPath; GdbToolArguments = "--interpreter=mi "; if (!File.Exists (gdbToolPath)) { throw new FileNotFoundException ("Could not find requested GDB instance. Expected: " + gdbToolPath); } // // Spawn an initial GDB instance to evaluate the client version. // GdbToolVersionMajor = 1; GdbToolVersionMinor = 0; using (SyncRedirectProcess gdbProcess = new SyncRedirectProcess (GdbToolPath, "--version")) { gdbProcess.StartAndWaitForExit (); string [] versionDetails = gdbProcess.StandardOutput.Replace ("\r", "").Split (new char [] { '\n' }); string versionPrefix = "GNU gdb (GDB) "; for (int i = 0; i < versionDetails.Length; ++i) { if (versionDetails [i].StartsWith (versionPrefix)) { string gdbVersion = versionDetails [i].Substring (versionPrefix.Length); ; string [] gdbVersionComponents = gdbVersion.Split ('.'); if (gdbVersionComponents.Length > 0) { GdbToolVersionMajor = int.Parse (gdbVersionComponents [0]); } if (gdbVersionComponents.Length > 1) { GdbToolVersionMinor = int.Parse (gdbVersionComponents [1]); } break; } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public GdbSetup(AndroidProcess process, string gdbToolPath) { LoggingUtils.PrintFunction (); Process = process; Host = "localhost"; Port = 5039; if (!Process.HostDevice.IsOverWiFi) { Socket = "debug-socket"; } string sanitisedDeviceId = Process.HostDevice.ID.Replace (':', '-'); CacheDirectory = string.Format (@"{0}\Android++\Cache\{1}\{2}", Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), sanitisedDeviceId, Process.Name); Directory.CreateDirectory (CacheDirectory); CacheSysRoot = Path.Combine (CacheDirectory, "sysroot"); Directory.CreateDirectory (CacheSysRoot); SymbolDirectories = new HashSet<string> (); GdbToolPath = gdbToolPath; GdbToolArguments = "--interpreter=mi "; if (!File.Exists (gdbToolPath)) { throw new FileNotFoundException ("Could not find requested GDB instance. Expected: " + gdbToolPath); } // // Spawn an initial GDB instance to evaluate the client version. // GdbToolVersionMajor = 1; GdbToolVersionMinor = 0; using (SyncRedirectProcess gdbProcess = new SyncRedirectProcess (GdbToolPath, "--version")) { gdbProcess.StartAndWaitForExit (); string [] versionDetails = gdbProcess.StandardOutput.Replace ("\r", "").Split (new char [] { '\n' }); string versionPrefix = "GNU gdb (GDB) "; for (int i = 0; i < versionDetails.Length; ++i) { if (versionDetails [i].StartsWith (versionPrefix)) { string gdbVersion = versionDetails [i].Substring (versionPrefix.Length); ; string [] gdbVersionComponents = gdbVersion.Split ('.'); if (gdbVersionComponents.Length > 0) { GdbToolVersionMajor = int.Parse (gdbVersionComponents [0]); } if (gdbVersionComponents.Length > 1) { GdbToolVersionMinor = int.Parse (gdbVersionComponents [1]); } break; } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void RefreshProcesses (uint processIdFilter = 0) { // // Skip the first line, and read in tab-separated process data. // LoggingUtils.PrintFunction (); string deviceProcessList = Shell ("ps", string.Format ("-t {0}", ((processIdFilter == 0) ? "" : processIdFilter.ToString ()))); if (!String.IsNullOrEmpty (deviceProcessList)) { string [] processesOutputLines = deviceProcessList.Replace ("\r", "").Split (new char [] { '\n' }); string processesRegExPattern = @"(?<user>[^ ]+)[ ]*(?<pid>[0-9]+)[ ]*(?<ppid>[0-9]+)[ ]*(?<vsize>[0-9]+)[ ]*(?<rss>[0-9]+)[ ]*(?<wchan>[^ ]+)[ ]*(?<pc>[A-Za-z0-9]+)[ ]*(?<s>[^ ]+)[ ]*(?<name>[^\r\n]+)"; Regex regExMatcher = new Regex (processesRegExPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); m_deviceProcessesByPid.Clear (); m_devicePidsByName.Clear (); m_devicePidsByPpid.Clear (); for (uint i = 1; i < processesOutputLines.Length; ++i) { if (!String.IsNullOrEmpty (processesOutputLines [i])) { Match regExLineMatches = regExMatcher.Match (processesOutputLines [i]); string processUser = regExLineMatches.Result ("${user}"); uint processPid = uint.Parse (regExLineMatches.Result ("${pid}")); uint processPpid = uint.Parse (regExLineMatches.Result ("${ppid}")); uint processVsize = uint.Parse (regExLineMatches.Result ("${vsize}")); uint processRss = uint.Parse (regExLineMatches.Result ("${rss}")); string processWchan = regExLineMatches.Result ("${wchan}"); string processPc = regExLineMatches.Result ("${pc}"); string processPcS = regExLineMatches.Result ("${s}"); string processName = regExLineMatches.Result ("${name}"); AndroidProcess process = new AndroidProcess (this, processName, processPid, processPpid, processUser); m_deviceProcessesByPid [processPid] = process; // // Add new process to a fast-lookup collection organised by process name. // HashSet<uint> processPidsList; if (!m_devicePidsByName.TryGetValue (processName, out processPidsList)) { processPidsList = new HashSet<uint> (); } if (!processPidsList.Contains (processPid)) { processPidsList.Add (processPid); } m_devicePidsByName [processName] = processPidsList; // // Check whether this process is sibling of another; keep ppids-pid relationships tracked. // HashSet<uint> processPpidSiblingList; if (!m_devicePidsByPpid.TryGetValue (processPpid, out processPpidSiblingList)) { processPpidSiblingList = new HashSet<uint> (); } if (!processPpidSiblingList.Contains (process.Pid)) { processPpidSiblingList.Add (process.Pid); } m_devicePidsByPpid [processPpid] = processPpidSiblingList; } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void RefreshProcesses(uint processIdFilter = 0) { // // Skip the first line, and read in tab-separated process data. // LoggingUtils.PrintFunction(); string deviceProcessList = Shell("ps", string.Format("-t {0}", ((processIdFilter == 0) ? "" : processIdFilter.ToString()))); if (!String.IsNullOrEmpty(deviceProcessList)) { string [] processesOutputLines = deviceProcessList.Replace("\r", "").Split(new char [] { '\n' }); string processesRegExPattern = @"(?<user>[^ ]+)[ ]*(?<pid>[0-9]+)[ ]*(?<ppid>[0-9]+)[ ]*(?<vsize>[0-9]+)[ ]*(?<rss>[0-9]+)[ ]*(?<wchan>[^ ]+)[ ]*(?<pc>[A-Za-z0-9]+)[ ]*(?<s>[^ ]+)[ ]*(?<name>[^\r\n]+)"; Regex regExMatcher = new Regex(processesRegExPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); m_deviceProcessesByPid.Clear(); m_devicePidsByName.Clear(); m_devicePidsByPpid.Clear(); for (uint i = 1; i < processesOutputLines.Length; ++i) { if (!String.IsNullOrEmpty(processesOutputLines [i])) { Match regExLineMatches = regExMatcher.Match(processesOutputLines [i]); string processUser = regExLineMatches.Result("${user}"); uint processPid = uint.Parse(regExLineMatches.Result("${pid}")); uint processPpid = uint.Parse(regExLineMatches.Result("${ppid}")); uint processVsize = uint.Parse(regExLineMatches.Result("${vsize}")); uint processRss = uint.Parse(regExLineMatches.Result("${rss}")); string processWchan = regExLineMatches.Result("${wchan}"); string processPc = regExLineMatches.Result("${pc}"); string processPcS = regExLineMatches.Result("${s}"); string processName = regExLineMatches.Result("${name}"); AndroidProcess process = new AndroidProcess(this, processName, processPid, processPpid, processUser); m_deviceProcessesByPid [processPid] = process; // // Add new process to a fast-lookup collection organised by process name. // HashSet <uint> processPidsList; if (!m_devicePidsByName.TryGetValue(processName, out processPidsList)) { processPidsList = new HashSet <uint> (); } if (!processPidsList.Contains(processPid)) { processPidsList.Add(processPid); } m_devicePidsByName [processName] = processPidsList; // // Check whether this process is sibling of another; keep ppids-pid relationships tracked. // HashSet <uint> processPpidSiblingList; if (!m_devicePidsByPpid.TryGetValue(processPpid, out processPpidSiblingList)) { processPpidSiblingList = new HashSet <uint> (); } if (!processPpidSiblingList.Contains(process.Pid)) { processPpidSiblingList.Add(process.Pid); } m_devicePidsByPpid [processPpid] = processPpidSiblingList; } } } }