//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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 static SyncRedirectProcess AdbCommand(AndroidDevice target, string command, string arguments) { LoggingUtils.Print(string.Format("[AndroidDevice] AdbCommand: Target={0} Cmd={1} Args={2}", target.ID, command, arguments)); SyncRedirectProcess adbCommand = new SyncRedirectProcess(AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", string.Format("-s {0} {1} {2}", target.ID, command, arguments)); return(adbCommand); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static SyncRedirectProcess AdbCommand(string command, string arguments) { LoggingUtils.Print(string.Format("[AndroidDevice] AdbCommand: Cmd={0} Args={1}", command, arguments)); var adbCommand = new SyncRedirectProcess(AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", string.Format("{0} {1}", command, arguments)); return(adbCommand); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static SyncRedirectProcess AdbCommand(AndroidDevice target, string command, string arguments) { LoggingUtils.Print (string.Format ("[AndroidDevice] AdbCommand: Target={0} Cmd={1} Args={2}", target.ID, command, arguments)); SyncRedirectProcess adbCommand = new SyncRedirectProcess (AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", string.Format ("-s {0} {1} {2}", target.ID, command, arguments)); return adbCommand; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 static string GetElfSectionData(string objDumpTool, string elfBinary, string sectionName) { if (string.IsNullOrWhiteSpace(objDumpTool) || !File.Exists(objDumpTool)) { throw new ArgumentException("Could not find required objdump tool. Expected: " + objDumpTool); } if (string.IsNullOrWhiteSpace(elfBinary) || !File.Exists(elfBinary)) { throw new ArgumentException("Could not find required ELF binary. Expected: " + elfBinary); } if (string.IsNullOrWhiteSpace(sectionName)) { throw new ArgumentNullException("sectionName"); } using (SyncRedirectProcess dumpSection = new SyncRedirectProcess(objDumpTool, string.Format("-s -j {0} {1}", sectionName, elfBinary))) { int exitCode = dumpSection.StartAndWaitForExit(); if (exitCode == 0) { StringBuilder dumpContent = new StringBuilder(); string dumpRegExPattern = " ([0-9a-fA-F]+) (?<block_a>[0-9a-fA-F]*) (?<block_b>[0-9a-fA-F]*) (?<block_c>[0-9a-fA-F]*) (?<block_d>[0-9a-fA-F]*)"; Regex regExMatcher = new Regex(dumpRegExPattern, RegexOptions.Compiled); MatchCollection regExMatches = regExMatcher.Matches(dumpSection.StandardOutput); string [] blockIds = { "${block_a}", "${block_b}", "${block_c}", "${block_d}" }; foreach (Match match in regExMatches) { foreach (string block in blockIds) { string blockData = match.Result(block); if (!string.IsNullOrWhiteSpace(blockData)) { for (int i = 0; i < blockData.Length; i += 2) { string hexComponent = blockData.Substring(i, 2); dumpContent.Append(Convert.ToChar(Convert.ToUInt32(hexComponent, 16))); } } } } return(dumpContent.ToString()); } } return(null); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 LaunchConfiguration GetLaunchConfigurationFromProjectProperties(IDictionary<string, string> projectProperties) { LoggingUtils.PrintFunction (); // // Retrieve standard project macro values, and determine the preferred debugger configuration. // string projectTargetName = EvaluateProjectProperty (projectProperties, "ConfigurationGeneral", "TargetName"); string projectProjectDir = EvaluateProjectProperty (projectProperties, "ConfigurationGeneral", "ProjectDir"); string debuggerMode = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigMode"); string debuggerTargetApk = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigTargetApk"); string debuggerUpToDateCheck = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigUpToDateCheck"); string debuggerLaunchActivity = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigLaunchActivity"); string debuggerDebugMode = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigDebugMode"); string debuggerOpenGlTrace = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigOpenGlTrace"); string debuggerKeepAppData = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigKeepAppData"); string debuggerInstallerPackage = EvaluateProjectProperty (projectProperties, "AndroidPlusPlusDebugger", "DebuggerConfigInstallerPackage"); if (string.IsNullOrEmpty (debuggerMode)) { debuggerMode = "Custom"; } else if (debuggerMode.Equals ("vs-android")) { // // Support for vs-android. // string antBuildPath = EvaluateProjectProperty (projectProperties, "AntBuild", "AntBuildPath"); string antBuildType = EvaluateProjectProperty (projectProperties, "AntBuild", "AntBuildType"); string antBuildXml = Path.Combine (antBuildPath, "build.xml"); XmlDocument buildXmlDocument = new XmlDocument (); buildXmlDocument.Load (antBuildXml); string antBuildXmlProjectName = buildXmlDocument.DocumentElement.GetAttribute ("name"); debuggerTargetApk = Path.Combine (antBuildPath, "bin", string.Format (CultureInfo.InvariantCulture, "{0}-{1}.apk", antBuildXmlProjectName, antBuildType)); } // // Ensure the provided target APK is found and absolute. // if (string.IsNullOrEmpty (debuggerTargetApk)) { throw new FileNotFoundException ("Could not locate target application. Empty path provided."); } else if (!Path.IsPathRooted (debuggerTargetApk) && !string.IsNullOrWhiteSpace (projectProjectDir)) { debuggerTargetApk = Path.Combine (projectProjectDir, debuggerTargetApk); } if (!Path.IsPathRooted (debuggerTargetApk)) { throw new InvalidOperationException ("Could not evaluate an absolute path to the target application. Tried: " + debuggerTargetApk); } debuggerTargetApk = Path.GetFullPath (debuggerTargetApk); // normalises relative paths. if (!File.Exists (debuggerTargetApk)) { throw new FileNotFoundException ("Could not find required target application. Expected: " + debuggerTargetApk); } // // Find the selected Android SDK (and associated build-tools) deployment. // string androidSdkRoot = EvaluateProjectProperty (projectProperties, "ConfigurationGeneral", "AndroidSdkRoot"); if (string.IsNullOrWhiteSpace (androidSdkRoot)) { throw new DirectoryNotFoundException ("Could not locate Android SDK. \"AndroidSdkRoot\" property is empty."); } else if (!Directory.Exists (androidSdkRoot)) { throw new DirectoryNotFoundException ("Could not locate Android SDK. \"AndroidSdkRoot\" property references a directory which does not exist. Expected: " + androidSdkRoot); } string androidSdkBuildToolsVersion = EvaluateProjectProperty (projectProperties, "ConfigurationGeneral", "AndroidSdkBuildToolsVersion"); string androidSdkBuildToolsPath = Path.Combine (androidSdkRoot, "build-tools", androidSdkBuildToolsVersion); if (!Directory.Exists (androidSdkBuildToolsPath)) { throw new DirectoryNotFoundException (string.Format (CultureInfo.CurrentCulture, "Could not locate Android SDK build-tools (v{0}). Expected: {1}", androidSdkBuildToolsVersion, androidSdkBuildToolsPath)); } // // Spawn a AAPT.exe instance to gain some extra information about the APK we are trying to load. // string applicationPackageName = string.Empty; string applicationLaunchActivity = string.Empty; string aaptToolPath = Path.Combine (androidSdkBuildToolsPath, "aapt.exe"); if (!File.Exists (aaptToolPath)) { throw new FileNotFoundException ("Could not locate AAPT tool (under Android SDK build-tools).", aaptToolPath); } using (SyncRedirectProcess getApkDetails = new SyncRedirectProcess (aaptToolPath, "dump --values badging " + PathUtils.SantiseWindowsPath (debuggerTargetApk))) { int exitCode = getApkDetails.StartAndWaitForExit (); if (exitCode != 0) { throw new InvalidOperationException ("AAPT failed to dump required application badging information. Exit-code: " + exitCode); } string [] apkDetails = getApkDetails.StandardOutput.Replace ("\r", "").Split (new char [] { '\n' }); foreach (string singleLine in apkDetails) { if (singleLine.StartsWith ("package: ", StringComparison.OrdinalIgnoreCase)) { // // Retrieve package name from format: "package: name='com.example.hellogdbserver' versionCode='1' versionName='1.0'" // string [] packageData = singleLine.Substring ("package: ".Length).Split (' '); foreach (string data in packageData) { if (data.StartsWith ("name=", StringComparison.OrdinalIgnoreCase)) { applicationPackageName = data.Substring ("name=".Length).Trim ('\''); } } } else if (singleLine.StartsWith ("launchable-activity: ", StringComparison.OrdinalIgnoreCase)) { string [] launchActivityData = singleLine.Substring ("launchable-activity: ".Length).Split (' '); foreach (string data in launchActivityData) { if (data.StartsWith ("name=", StringComparison.OrdinalIgnoreCase)) { applicationLaunchActivity = data.Substring ("name=".Length).Trim ('\''); } } } } } // // If a specific launch activity was not requested, ensure that the default one is referenced. // if (string.IsNullOrEmpty (debuggerLaunchActivity)) { debuggerLaunchActivity = applicationLaunchActivity; } LaunchConfiguration launchConfig = new LaunchConfiguration (); launchConfig ["TargetApk"] = debuggerTargetApk; launchConfig ["UpToDateCheck"] = debuggerUpToDateCheck; launchConfig ["PackageName"] = applicationPackageName; launchConfig ["LaunchActivity"] = debuggerLaunchActivity; launchConfig ["DebugMode"] = debuggerDebugMode; launchConfig ["OpenGlTrace"] = debuggerOpenGlTrace; launchConfig ["KeepAppData"] = debuggerKeepAppData; launchConfig ["InstallerPackage"] = debuggerInstallerPackage; return launchConfig; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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 static void Refresh () { LoggingUtils.PrintFunction (); lock (m_updateLockMutex) { // // Start an ADB instance, if required. // using (SyncRedirectProcess adbStartServer = new SyncRedirectProcess (AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", "start-server")) { adbStartServer.StartAndWaitForExit (30000); } using (SyncRedirectProcess adbDevices = new SyncRedirectProcess (AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", "devices")) { adbDevices.StartAndWaitForExit (30000); // // Parse 'devices' output, skipping headers and potential 'start-server' output. // Dictionary<string, string> currentAdbDevices = new Dictionary<string, string> (); LoggingUtils.Print (string.Format ("[AndroidAdb] Devices output: {0}", adbDevices.StandardOutput)); if (!String.IsNullOrEmpty (adbDevices.StandardOutput)) { string [] deviceOutputLines = adbDevices.StandardOutput.Replace ("\r", "").Split (new char [] { '\n' }); foreach (string line in deviceOutputLines) { if (Regex.IsMatch (line, "^[A-Za-z0-9.:\\-]+[\t][a-z]+$")) { string [] segments = line.Split (new char [] { '\t' }); string deviceName = segments [0]; string deviceType = segments [1]; currentAdbDevices.Add (deviceName, deviceType); } } } // // First identify any previously tracked devices which aren't in 'devices' output. // HashSet<string> disconnectedDevices = new HashSet<string> (); foreach (string key in m_connectedDevices.Keys) { string deviceName = (string) key; if (!currentAdbDevices.ContainsKey (deviceName)) { disconnectedDevices.Add (deviceName); } } // // Identify whether any devices have changed state; connected/persisted/disconnected. // foreach (KeyValuePair <string, string> devicePair in currentAdbDevices) { string deviceName = devicePair.Key; string deviceType = devicePair.Value; if (deviceType.Equals ("offline")) { disconnectedDevices.Add (deviceName); } else if (deviceType.Equals ("unauthorized")) { // User needs to allow USB debugging. } else { AndroidDevice connectedDevice; if (m_connectedDevices.TryGetValue (deviceName, out connectedDevice)) { // // Device is pervasive. Refresh internal properties. // LoggingUtils.Print (string.Format ("[AndroidAdb] Device pervaded: {0} - {1}", deviceName, deviceType)); connectedDevice.Refresh (); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DevicePervasive (connectedDevice); } } else { // // Device connected. // LoggingUtils.Print (string.Format ("[AndroidAdb] Device connected: {0} - {1}", deviceName, deviceType)); connectedDevice = new AndroidDevice (deviceName); connectedDevice.Refresh (); m_connectedDevices.Add (deviceName, connectedDevice); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DeviceConnected (connectedDevice); } } } } // // Finally, handle device disconnection. // foreach (string deviceName in disconnectedDevices) { AndroidDevice disconnectedDevice; if (m_connectedDevices.TryGetValue (deviceName, out disconnectedDevice)) { LoggingUtils.Print (string.Format ("[AndroidAdb] Device disconnected: {0}", deviceName)); m_connectedDevices.Remove (deviceName); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DeviceDisconnected (disconnectedDevice); } } } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static void Refresh() { LoggingUtils.PrintFunction(); lock (m_updateLockMutex) { // // Start an ADB instance, if required. // using (SyncRedirectProcess adbStartServer = new SyncRedirectProcess(AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", "start-server")) { adbStartServer.StartAndWaitForExit(30000); } using (SyncRedirectProcess adbDevices = new SyncRedirectProcess(AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", "devices")) { adbDevices.StartAndWaitForExit(30000); // // Parse 'devices' output, skipping headers and potential 'start-server' output. // Dictionary <string, string> currentAdbDevices = new Dictionary <string, string> (); LoggingUtils.Print(string.Concat("[AndroidAdb] Devices output: ", adbDevices.StandardOutput)); if (!String.IsNullOrEmpty(adbDevices.StandardOutput)) { string [] deviceOutputLines = adbDevices.StandardOutput.Replace("\r", "").Split(new char [] { '\n' }); foreach (string line in deviceOutputLines) { if (Regex.IsMatch(line, "^[A-Za-z0-9.:\\-]+[\t][A-Za-z]+$")) { string [] segments = line.Split(new char [] { '\t' }); string deviceName = segments [0]; string deviceType = segments [1]; currentAdbDevices.Add(deviceName, deviceType); } } } // // First identify any previously tracked devices which aren't in 'devices' output. // HashSet <string> disconnectedDevices = new HashSet <string> (); foreach (string key in m_connectedDevices.Keys) { string deviceName = (string)key; if (!currentAdbDevices.ContainsKey(deviceName)) { disconnectedDevices.Add(deviceName); } } // // Identify whether any devices have changed state; connected/persisted/disconnected. // foreach (KeyValuePair <string, string> devicePair in currentAdbDevices) { string deviceName = devicePair.Key; string deviceType = devicePair.Value; if (deviceType.Equals("offline", StringComparison.InvariantCultureIgnoreCase)) { disconnectedDevices.Add(deviceName); } else if (deviceType.Equals("unauthorized", StringComparison.InvariantCultureIgnoreCase)) { // User needs to allow USB debugging. } else { AndroidDevice connectedDevice; if (m_connectedDevices.TryGetValue(deviceName, out connectedDevice)) { // // Device is pervasive. Refresh internal properties. // LoggingUtils.Print(string.Format("[AndroidAdb] Device pervaded: {0} - {1}", deviceName, deviceType)); connectedDevice.Refresh(); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DevicePervasive(connectedDevice); } } else { // // Device connected. // LoggingUtils.Print(string.Format("[AndroidAdb] Device connected: {0} - {1}", deviceName, deviceType)); connectedDevice = new AndroidDevice(deviceName); connectedDevice.Refresh(); m_connectedDevices.Add(deviceName, connectedDevice); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DeviceConnected(connectedDevice); } } } } // // Finally, handle device disconnection. // foreach (string deviceName in disconnectedDevices) { AndroidDevice disconnectedDevice; if (m_connectedDevices.TryGetValue(deviceName, out disconnectedDevice)) { LoggingUtils.Print(string.Concat("[AndroidAdb] Device disconnected: ", deviceName)); m_connectedDevices.Remove(deviceName); foreach (IStateListener deviceListener in m_registeredDeviceStateListeners) { deviceListener.DeviceDisconnected(disconnectedDevice); } } } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 static string GetElfSectionData (string objDumpTool, string elfBinary, string sectionName) { if (string.IsNullOrWhiteSpace (objDumpTool) || !File.Exists (objDumpTool)) { throw new ArgumentException ("Could not find required objdump tool. Expected: " + objDumpTool); } if (string.IsNullOrWhiteSpace (elfBinary) || !File.Exists (elfBinary)) { throw new ArgumentException ("Could not find required ELF binary. Expected: " + elfBinary); } if (string.IsNullOrWhiteSpace (sectionName)) { throw new ArgumentNullException ("sectionName"); } using (SyncRedirectProcess dumpSection = new SyncRedirectProcess (objDumpTool, string.Format ("-s -j {0} {1}", sectionName, elfBinary))) { int exitCode = dumpSection.StartAndWaitForExit (); if (exitCode == 0) { StringBuilder dumpContent = new StringBuilder (); string dumpRegExPattern = " ([0-9a-fA-F]+) (?<block_a>[0-9a-fA-F]*) (?<block_b>[0-9a-fA-F]*) (?<block_c>[0-9a-fA-F]*) (?<block_d>[0-9a-fA-F]*)"; Regex regExMatcher = new Regex (dumpRegExPattern, RegexOptions.Compiled); MatchCollection regExMatches = regExMatcher.Matches (dumpSection.StandardOutput); string [] blockIds = { "${block_a}", "${block_b}", "${block_c}", "${block_d}" }; foreach (Match match in regExMatches) { foreach (string block in blockIds) { string blockData = match.Result (block); if (!string.IsNullOrWhiteSpace (blockData)) { for (int i = 0; i < blockData.Length; i += 2) { string hexComponent = blockData.Substring (i, 2); dumpContent.Append (Convert.ToChar (Convert.ToUInt32 (hexComponent, 16))); } } } } return dumpContent.ToString (); } } return null; }