//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public AndroidProcess(AndroidDevice device, string name, uint pid, uint ppid, string user) { if (device == null) { throw new ArgumentNullException("device"); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (string.IsNullOrEmpty(user)) { throw new ArgumentNullException("user"); } HostDevice = device; Name = name; Pid = pid; ParentPid = ppid; User = user; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public AndroidProcess (AndroidDevice device, string name, uint pid, uint ppid, string user) { if (device == null) { throw new ArgumentNullException ("device"); } if (string.IsNullOrEmpty (name)) { throw new ArgumentNullException ("name"); } if (string.IsNullOrEmpty (user)) { throw new ArgumentNullException ("user"); } HostDevice = device; Name = name; Pid = pid; ParentPid = ppid; User = user; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 AsyncRedirectProcess AdbCommandAsync(AndroidDevice target, string command, string arguments) { LoggingUtils.Print(string.Format("[AndroidDevice] AdbCommandAsync: Target={0} Cmd={1} Args={2}", target.ID, command, arguments)); AsyncRedirectProcess adbCommand = new AsyncRedirectProcess(AndroidSettings.SdkRoot + @"\platform-tools\adb.exe", string.Format("-s {0} {1} {2}", target.ID, command, arguments)); return(adbCommand); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool IsDeviceConnected(AndroidDevice queryDevice) { LoggingUtils.PrintFunction(); lock (m_updateLockMutex) { return(m_connectedDevices.ContainsKey(queryDevice.ID)); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static AndroidDevice [] GetConnectedDevices() { lock (m_updateLockMutex) { AndroidDevice [] deviceArray = new AndroidDevice [m_connectedDevices.Count]; m_connectedDevices.Values.CopyTo(deviceArray, 0); return(deviceArray); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static AndroidDevice GetConnectedDeviceById(string id) { AndroidDevice device = null; lock (m_updateLockMutex) { m_connectedDevices.TryGetValue(id, out device); } return(device); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 bool IsDeviceConnected (AndroidDevice queryDevice) { LoggingUtils.PrintFunction (); lock (m_updateLockMutex) { return m_connectedDevices.ContainsKey (queryDevice.ID); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static AndroidDevice [] GetConnectedDevices () { lock (m_updateLockMutex) { AndroidDevice [] deviceArray = new AndroidDevice [m_connectedDevices.Count]; m_connectedDevices.Values.CopyTo (deviceArray, 0); return deviceArray; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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); } } } } } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void InstallApplicationAsync(AndroidDevice debuggingDevice, LaunchConfiguration launchConfig) { // // Asynchronous installation process, so the UI can be updated appropriately. // LoggingUtils.PrintFunction (); ManualResetEvent installCompleteEvent = new ManualResetEvent (false); Exception installFailedException = null; System.Threading.Thread asyncInstallApplicationThread = new System.Threading.Thread (delegate () { try { string targetLocalApk = launchConfig ["TargetApk"]; string targetRemoteTemporaryPath = "/data/local/tmp"; string targetRemoteTemporaryFile = targetRemoteTemporaryPath + '/' + Path.GetFileName (targetLocalApk); bool keepData = launchConfig ["KeepAppData"].Equals ("true"); string installerPackage = launchConfig ["InstallerPackage"]; // // Construct 'am install' arguments for installing the application in a manner compatible with GDB. // // Note: Installations to /mnt/asec/ cause 'run-as' to fail regarding permissions. // StringBuilder installArgsBuilder = new StringBuilder (); installArgsBuilder.Append ("-f "); // install package on internal flash. (required for debugging) if (keepData) { installArgsBuilder.Append ("-r "); // reinstall an existing app, keeping its data. } if (!string.IsNullOrWhiteSpace (installerPackage)) { installArgsBuilder.Append (string.Format (CultureInfo.InvariantCulture, "-i {0} ", installerPackage)); } installArgsBuilder.Append (targetRemoteTemporaryFile); // // Explicitly install the target APK using 'pm' tool, as this allows more customisation. // // 1) APKs must already be on the device for this tool to work. We push these manually. // // 2) Installations can fail for various reasons; errors are reported thusly: // pkg: /data/local/tmp/hello-gdbserver-Debug.apk // Failure [INSTALL_FAILED_INVALID_URI] // m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "[adb:push] {0} {1}", targetLocalApk, targetRemoteTemporaryPath), false); debuggingDevice.Push (targetLocalApk, targetRemoteTemporaryPath); m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "[adb:shell:pm] {0} {1}", "install", installArgsBuilder.ToString ()), false); string installReport = debuggingDevice.Shell ("pm", "install " + installArgsBuilder.ToString (), int.MaxValue); if (!installReport.Contains ("Success")) { string sanitisedFailure = installReport; throw new InvalidOperationException (string.Format (CultureInfo.InvariantCulture, "[adb:shell:pm] install failed: {0}", sanitisedFailure)); } m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "[adb:shell:rm] {0}", targetRemoteTemporaryFile), false); debuggingDevice.Shell ("rm", targetRemoteTemporaryFile); } catch (Exception e) { LoggingUtils.HandleException (e); installFailedException = e; throw; } finally { installCompleteEvent.Set (); } }); asyncInstallApplicationThread.Start (); while (!installCompleteEvent.WaitOne (0)) { Application.DoEvents (); System.Threading.Thread.Sleep (100); } if (installFailedException != null) { throw installFailedException; } }
public DebuggerLogcatEvent (AndroidDevice device) { HostDevice = device; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool IsDeviceConnected(AndroidDevice queryDevice) { return(m_connectedDevices.ContainsKey(queryDevice.ID)); }