//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void SetupPortForwarding () { // // Setup network redirection. // LoggingUtils.PrintFunction (); StringBuilder forwardArgsBuilder = new StringBuilder (); forwardArgsBuilder.AppendFormat ("tcp:{0} ", Port); if (!string.IsNullOrWhiteSpace (Socket)) { forwardArgsBuilder.AppendFormat ("localfilesystem:{0}/{1}", Process.DataDirectory, Socket); } else { forwardArgsBuilder.AppendFormat ("tcp:{0} ", Port); } using (SyncRedirectProcess adbPortForward = AndroidAdb.AdbCommand (Process.HostDevice, "forward", forwardArgsBuilder.ToString ())) { adbPortForward.StartAndWaitForExit (); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public string Push(string localPath, string remotePath) { LoggingUtils.PrintFunction(); try { int exitCode = -1; using (SyncRedirectProcess process = AndroidAdb.AdbCommand(this, "push", string.Format("{0} {1}", PathUtils.QuoteIfNeeded(localPath), remotePath))) { exitCode = process.StartAndWaitForExit(); if (exitCode != 0) { throw new InvalidOperationException(string.Format("[push] returned error code: {0}", exitCode)); } return(process.StandardOutput); } } catch (Exception e) { LoggingUtils.HandleException(e); throw new InvalidOperationException("[push] failed", e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public string Shell(string command, string arguments, int timeout = 30000) { LoggingUtils.PrintFunction(); try { int exitCode = -1; using (SyncRedirectProcess process = AndroidAdb.AdbCommand(this, "shell", string.Format("{0} {1}", command, arguments))) { exitCode = process.StartAndWaitForExit(timeout); if (exitCode != 0) { throw new InvalidOperationException(string.Format("[shell:{0}] returned error code: {1}", command, exitCode)); } return(process.StandardOutput); } } catch (Exception e) { LoggingUtils.HandleException(e); throw new InvalidOperationException(string.Format("[shell:{0}] failed", command), e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void ClearPortForwarding() { // // Clear network redirection. // LoggingUtils.PrintFunction(); StringBuilder forwardArgsBuilder = new StringBuilder(); forwardArgsBuilder.AppendFormat("--remove tcp:{0}", Port); using SyncRedirectProcess adbPortForward = AndroidAdb.AdbCommand(Process.HostDevice, "forward", forwardArgsBuilder.ToString()); adbPortForward.StartAndWaitForExit(1000); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void SetupPortForwarding() { // // Setup network redirection. // LoggingUtils.PrintFunction(); StringBuilder forwardArgsBuilder = new StringBuilder(); forwardArgsBuilder.AppendFormat("tcp:{0} jdwp:{1}", Port, Process.Pid); using (SyncRedirectProcess adbPortForward = AndroidAdb.AdbCommand(Process.HostDevice, "forward", forwardArgsBuilder.ToString())) { adbPortForward.StartAndWaitForExit(1000); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void Start() { LoggingUtils.PrintFunction(); // // Check the target 'gdbserver' binary exits on target device/emulator. // string gdbServerPath = string.Empty; List <string> potentialGdbServerPaths = new List <string> (); foreach (string libraryPath in m_gdbSetup.Process.NativeLibraryAbiPaths) { potentialGdbServerPaths.Add(string.Format("{0}/gdbserver", libraryPath)); } potentialGdbServerPaths.Add(string.Format("{0}/gdbserver", m_gdbSetup.Process.NativeLibraryPath)); foreach (string path in potentialGdbServerPaths) { using (SyncRedirectProcess checkGdbServer = AndroidAdb.AdbCommand(m_gdbSetup.Process.HostDevice, "shell", "ls " + path)) { int exitCode = checkGdbServer.StartAndWaitForExit(1000); if ((exitCode == 0) && !checkGdbServer.StandardOutput.ToLower().Contains("no such file")) { gdbServerPath = path; break; } } } if (string.IsNullOrWhiteSpace(gdbServerPath)) { // TODO: Push the required gdbserver binary, so we can attach to any app. throw new InvalidOperationException(string.Format("Failed to locate required 'gdbserver' binary on device ({0}).", m_gdbSetup.Process.HostDevice.ID)); } KillActiveGdbServerSessions(); // // Construct a adaptive command line based on GdbSetup requirements. // StringBuilder commandLineArgumentsBuilder = new StringBuilder(); commandLineArgumentsBuilder.AppendFormat("run-as {0} {1} ", m_gdbSetup.Process.Name, gdbServerPath); if (!string.IsNullOrWhiteSpace(m_gdbSetup.Socket)) { commandLineArgumentsBuilder.AppendFormat("+{0} ", m_gdbSetup.Socket); } commandLineArgumentsBuilder.Append("--attach "); if (string.IsNullOrWhiteSpace(m_gdbSetup.Socket)) // Don't need a host if we have a bound socket? { commandLineArgumentsBuilder.AppendFormat("{0}:{1} ", m_gdbSetup.Host, m_gdbSetup.Port); } commandLineArgumentsBuilder.Append(m_gdbSetup.Process.Pid); // // Launch 'gdbserver' and wait for output to determine success. // Stopwatch waitForConnectionTimer = new Stopwatch(); waitForConnectionTimer.Start(); m_gdbServerAttached = new ManualResetEvent(false); m_gdbServerInstance = AndroidAdb.AdbCommandAsync(m_gdbSetup.Process.HostDevice, "shell", commandLineArgumentsBuilder.ToString()); m_gdbServerInstance.Start(this); LoggingUtils.Print(string.Format("[GdbServer] Waiting to attach...")); uint timeout = 5000; bool responseSignaled = false; while ((!responseSignaled) && (waitForConnectionTimer.ElapsedMilliseconds < timeout)) { responseSignaled = m_gdbServerAttached.WaitOne(0); if (!responseSignaled) { Thread.Sleep(100); } } if (!responseSignaled) { throw new TimeoutException("Timed out waiting for GdbServer to execute."); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public string Pull(string remotePath, string localPath) { LoggingUtils.PrintFunction(); try { // // Check if the remote path is a symbolic link, and adjust the target file. // (ADB Pull doesn't follow these links) // try { string readlink = Shell("readlink", remotePath).Replace("\r", "").Replace("\n", ""); if (readlink.StartsWith("/")) // absolute path link { remotePath = readlink; } else // relative path link { int i = remotePath.LastIndexOf('/'); if (i != -1) { string parentPath = remotePath.Substring(0, i); string file = remotePath.Substring(i + 1); remotePath = parentPath + '/' + file; } } } catch (Exception) { // Ignore. Not a relative link. } // // Pull the requested file. // int exitCode = -1; using (SyncRedirectProcess process = AndroidAdb.AdbCommand(this, "pull", string.Format("{0} {1}", remotePath, PathUtils.QuoteIfNeeded(localPath)))) { exitCode = process.StartAndWaitForExit(); if (exitCode != 0) { throw new InvalidOperationException(string.Format("[pull] returned error code: {0}", exitCode)); } return(process.StandardOutput); } } catch (Exception e) { LoggingUtils.HandleException(e); throw new InvalidOperationException("[pull] failed", e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void Start() { LoggingUtils.PrintFunction(); // // Check the target 'gdbserver' binary exits on target device/emulator. // string gdbServerPath = string.Empty; List <string> potentialGdbServerPaths = new List <string> (); foreach (string libraryPath in m_gdbSetup.Process.NativeLibraryAbiPaths) { potentialGdbServerPaths.Add(string.Format("{0}/gdbserver", libraryPath)); } potentialGdbServerPaths.Add(string.Format("{0}/gdbserver", m_gdbSetup.Process.NativeLibraryPath)); foreach (string path in potentialGdbServerPaths) { try { string ls = m_gdbSetup.Process.HostDevice.Shell("ls", path); if (ls.ToLowerInvariant().Contains("no such file")) { throw new DirectoryNotFoundException(path); } gdbServerPath = path; break; } catch (Exception) { // Ignore. } } // // If we can't find a bundled 'gdbserver' binary, attempt to find one in the NDK. // if (string.IsNullOrWhiteSpace(gdbServerPath)) { foreach (string path in m_gdbSetup.Process.NativeLibraryAbiPaths) { try { string shortAbi = path.Substring(path.LastIndexOf('/') + 1); string local = Path.Combine(AndroidSettings.NdkRoot, string.Format(@"prebuilt\android-{0}\gdbserver\gdbserver", shortAbi)); string remote = string.Format("/data/local/tmp/gdbserver-{0}", shortAbi); m_gdbSetup.Process.HostDevice.Push(local, remote); } catch (Exception e) { LoggingUtils.HandleException(e); } } } if (string.IsNullOrWhiteSpace(gdbServerPath)) { throw new InvalidOperationException(string.Format("Failed to locate required 'gdbserver' binary on device ({0}).", m_gdbSetup.Process.HostDevice.ID)); } KillActiveGdbServerSessions(); // // Construct a adaptive command line based on GdbSetup requirements. // StringBuilder commandLineArgumentsBuilder = new StringBuilder(); commandLineArgumentsBuilder.AppendFormat("run-as {0} {1} ", m_gdbSetup.Process.Name, gdbServerPath); if (!string.IsNullOrWhiteSpace(m_gdbSetup.Socket)) { commandLineArgumentsBuilder.AppendFormat("+{0} ", m_gdbSetup.Socket); } commandLineArgumentsBuilder.Append("--attach "); if (string.IsNullOrWhiteSpace(m_gdbSetup.Socket)) // Don't need a host if we have a bound socket? { commandLineArgumentsBuilder.AppendFormat("{0}:{1} ", m_gdbSetup.Host, m_gdbSetup.Port); } commandLineArgumentsBuilder.Append(m_gdbSetup.Process.Pid); // // Launch 'gdbserver' and wait for output to determine success. // Stopwatch waitForConnectionTimer = new Stopwatch(); waitForConnectionTimer.Start(); m_gdbServerAttached = new ManualResetEvent(false); m_gdbServerInstance = AndroidAdb.AdbCommandAsync(m_gdbSetup.Process.HostDevice, "shell", commandLineArgumentsBuilder.ToString()); m_gdbServerInstance.Start(this); LoggingUtils.Print(string.Format("[GdbServer] Waiting to attach...")); uint timeout = 5000; bool responseSignaled = false; while ((!responseSignaled) && (waitForConnectionTimer.ElapsedMilliseconds < timeout)) { responseSignaled = m_gdbServerAttached.WaitOne(0); if (!responseSignaled) { Thread.Sleep(100); } } if (!responseSignaled) { throw new TimeoutException("Timed out waiting for GdbServer to execute."); } }