//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected DebuggeePort CreatePort(IDebugPortRequest2 portRequest) { AndroidAdb.Refresh(); string requestPortName; LoggingUtils.RequireOk(portRequest.GetPortName(out requestPortName)); AndroidDevice device = AndroidAdb.GetConnectedDeviceById(requestPortName); return(new DebuggeePort(this, device)); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Task <DebugLaunchSettings> StartWithoutDebugging(int launchOptions, LaunchConfiguration launchConfig, ICollection <LaunchProps> launchProps, IDictionary <string, string> projectProperties) { LoggingUtils.PrintFunction(); if (launchConfig == null) { throw new ArgumentNullException(nameof(launchConfig)); } if (launchProps == null) { throw new ArgumentNullException(nameof(launchProps)); } if (projectProperties == null) { throw new ArgumentNullException(nameof(projectProperties)); } // // Refresh ADB service and evaluate a list of connected devices or emulators. // AndroidAdb.Refresh(); AndroidDevice debuggingDevice = GetPrioritisedConnectedDevice() ?? throw new InvalidOperationException("No device/emulator found or connected. Check status using \"adb devices\"."); // // Construct VS launch settings to debug or attach to the specified target application. // launchOptions |= (int)DebugLaunchOptions.Silent; DebugLaunchSettings nonDebuglaunchSettings = new DebugLaunchSettings((DebugLaunchOptions)launchOptions); nonDebuglaunchSettings.LaunchDebugEngineGuid = new Guid("8310DAF9-1043-4C8E-85A0-FF68896E1922"); nonDebuglaunchSettings.PortSupplierGuid = new Guid("3AEE417F-E5F9-4B89-BC31-20534C99B7F5"); nonDebuglaunchSettings.PortName = debuggingDevice.ID; nonDebuglaunchSettings.Options = launchConfig.ToString(); nonDebuglaunchSettings.Executable = launchConfig ["TargetApk"]; nonDebuglaunchSettings.LaunchOperation = DebugLaunchOperation.Custom; return(Task.FromResult(nonDebuglaunchSettings)); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public object StartWithoutDebugging(int launchOptionsFlags, LaunchConfiguration launchConfig, LaunchProps [] launchProps, IDictionary <string, string> projectProperties) { LoggingUtils.PrintFunction(); try { // // Refresh ADB service and evaluate a list of connected devices or emulators. // AndroidAdb.Refresh(); AndroidDevice debuggingDevice = GetPriortisedConnectedDevice(); if (debuggingDevice == null) { throw new InvalidOperationException("No device/emulator found or connected. Check status via 'adb devices'."); } // // Construct VS launch settings to debug or attach to the specified target application. // launchOptionsFlags |= (int)DebugLaunchOptions.Silent; DebugLaunchSettings nonDebuglaunchSettings = new DebugLaunchSettings((DebugLaunchOptions)launchOptionsFlags); nonDebuglaunchSettings.LaunchDebugEngineGuid = new Guid("8310DAF9-1043-4C8E-85A0-FF68896E1922"); nonDebuglaunchSettings.PortSupplierGuid = new Guid("3AEE417F-E5F9-4B89-BC31-20534C99B7F5"); nonDebuglaunchSettings.PortName = debuggingDevice.ID; nonDebuglaunchSettings.Options = launchConfig.ToString(); nonDebuglaunchSettings.Executable = launchConfig ["TargetApk"]; nonDebuglaunchSettings.LaunchOperation = DebugLaunchOperation.Custom; return(nonDebuglaunchSettings); } catch (Exception e) { LoggingUtils.HandleException(e); throw; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int EnumPersistedPorts(BSTR_ARRAY PortNames, out IEnumDebugPorts2 ppEnum) { // // This method retrieves an object that allows enumeration of the list of persisted ports. // LoggingUtils.PrintFunction(); try { #if false AndroidAdb.Refresh(); if (PortNames.dwCount > 0) { // TODO: This conversion process is tricky, and still broken. _BSTR_ARRAY portNames = (_BSTR_ARRAY)Marshal.PtrToStructure(PortNames.Members, typeof(_BSTR_ARRAY)); for (int i = 0; i < PortNames.dwCount; ++i) { IDebugPort2 ppPort; AndroidDevice device = AndroidAdb.GetConnectedDeviceById(portNames.Members [i]); LoggingUtils.RequireOk(AddPort(new DevicePortRequest(device), out ppPort)); } } #endif LoggingUtils.RequireOk(EnumPorts(out ppEnum)); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); ppEnum = null; return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int EnumPorts(out IEnumDebugPorts2 ppEnum) { // // Retrieves a list of all the ports supplied by a port supplier. // LoggingUtils.PrintFunction(); try { AndroidAdb.Refresh(); AndroidDevice [] connectedDevices = AndroidAdb.GetConnectedDevices(); foreach (AndroidDevice device in connectedDevices) { IDebugPort2 ppPort; LoggingUtils.RequireOk(AddPort(new DevicePortRequest(device), out ppPort)); } IDebugPort2 [] ports = new IDebugPort2 [m_registeredPorts.Count]; m_registeredPorts.Values.CopyTo(ports, 0); ppEnum = new DebugPortEnumerator(ports); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); ppEnum = null; return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public async Task <DebugLaunchSettings> StartWithDebugging(int launchOptions, LaunchConfiguration launchConfig, ICollection <LaunchProps> launchProps, IDictionary <string, string> projectProperties) { LoggingUtils.PrintFunction(); if (launchConfig == null) { throw new ArgumentNullException(nameof(launchConfig)); } if (launchProps == null) { throw new ArgumentNullException(nameof(launchProps)); } if (projectProperties == null) { throw new ArgumentNullException(nameof(projectProperties)); } // // Refresh ADB service and evaluate a list of connected devices or emulators. // AndroidAdb.Refresh(); AndroidDevice debuggingDevice = GetPrioritisedConnectedDevice() ?? throw new InvalidOperationException("No device/emulator found or connected. Check status using \"adb devices\"."); // // Enforce required device/emulator properties. // foreach (var prop in launchProps) { debuggingDevice.Shell("setprop", string.Format(CultureInfo.InvariantCulture, "{0} {1}", prop.Item1, prop.Item2)); } // // Construct VS launch settings to debug or attach to the specified target application. // bool shouldAttach = false; #if false AndroidProcess [] debuggingDeviceProcesses = debuggingDevice.GetProcesses(); foreach (AndroidProcess process in debuggingDeviceProcesses) { if (process.Name.Equals(applicationPackageName)) { shouldAttach = true; break; } } #endif launchOptions |= (int)DebugLaunchOptions.Silent; DebugLaunchSettings debugLaunchSettings = new DebugLaunchSettings((DebugLaunchOptions)launchOptions); debugLaunchSettings.LaunchDebugEngineGuid = new Guid("8310DAF9-1043-4C8E-85A0-FF68896E1922"); debugLaunchSettings.PortSupplierGuid = new Guid("3AEE417F-E5F9-4B89-BC31-20534C99B7F5"); debugLaunchSettings.PortName = debuggingDevice.ID; debugLaunchSettings.Options = launchConfig.ToString(); if (shouldAttach) { debugLaunchSettings.Executable = launchConfig ["PackageName"]; debugLaunchSettings.LaunchOperation = DebugLaunchOperation.AlreadyRunning; } else { // // Determine whether the application is currently installed, and if it is; // check last modified date to ensure we don't re-installed unchanged binaries. // bool upToDateCheck = launchConfig ["UpToDateCheck"].Equals("true"); bool appIsInstalled = false; bool appIsOutOfDate = true; if (upToDateCheck) { FileInfo targetApkFileInfo = new FileInfo(launchConfig ["TargetApk"]); try { var adbPmPathOutput = debuggingDevice.Shell("pm", "path " + launchConfig ["PackageName"]).Replace("\r", "").Split(new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in adbPmPathOutput) { if (line.StartsWith("package:", StringComparison.OrdinalIgnoreCase)) { appIsInstalled = true; LoggingUtils.RequireOk(await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' already installed on target '{1}'.", launchConfig ["PackageName"], debuggingDevice.ID), false)); string path = line.Substring("package:".Length); // // Get the target device/emulator's UTC current time. // // This is done by specifying the '-u' argument to 'date'. Despite this though, // the returned string will always claim to be in GMT: // // i.e: "Fri Jan 9 14:35:23 GMT 2015" // DateTime debuggingDeviceUtcTime; try { var deviceDateOutput = debuggingDevice.Shell("date", "-u").Replace("\r", "").Split(new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string debuggingDeviceUtcTimestamp = deviceDateOutput [0]; var debuggingDeviceUtcTimestampComponents = debuggingDeviceUtcTimestamp.Split(new char [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); debuggingDeviceUtcTimestampComponents [4] = "-00:00"; if (!DateTime.TryParseExact(string.Join(" ", debuggingDeviceUtcTimestampComponents), "ddd MMM d HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out debuggingDeviceUtcTime)) { break; } debuggingDeviceUtcTime = debuggingDeviceUtcTime.ToUniversalTime(); } catch (Exception e) { throw new InvalidOperationException("Failed to evaluate device local time.", e); } // // Convert current device/emulator time to UTC, and probe the working machine's time too. // DateTime thisMachineUtcTime = DateTime.UtcNow; TimeSpan thisMachineUtcVersusDeviceUtc = debuggingDeviceUtcTime - thisMachineUtcTime; await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "Current UTC time on '{0}': {1}", debuggingDevice.ID, debuggingDeviceUtcTime.ToString()), false); await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "Current UTC time on '{0}': {1}", System.Environment.MachineName, thisMachineUtcTime.ToString()), false); await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "Difference in UTC time between '{0}' and '{1}': {2}", System.Environment.MachineName, debuggingDevice.ID, thisMachineUtcVersusDeviceUtc.ToString()), false); // // Check the last modified date; ls output currently uses this format: // // -rw-r--r-- system system 11533274 2015-01-09 13:47 com.example.native_activity-2.apk // DateTime lastModifiedTimestampDeviceLocalTime; try { var extendedLsOutput = debuggingDevice.Shell("ls -l", path).Replace("\r", "").Split(new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); var extendedLsOutputComponents = extendedLsOutput [0].Split(new char [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string date = extendedLsOutputComponents [4]; string time = extendedLsOutputComponents [5]; if (!DateTime.TryParseExact(date + " " + time, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out lastModifiedTimestampDeviceLocalTime)) { break; } } catch (Exception e) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Failed to evaluate device local modified time of: {0}", path), e); } // // Calculate how long ago the APK was changed, according to the device's local time. // TimeSpan timeSinceLastModification = debuggingDeviceUtcTime - lastModifiedTimestampDeviceLocalTime; DateTime debuggingDeviceUtcTimeAtLastModification = debuggingDeviceUtcTime - timeSinceLastModification; DateTime thisMachineUtcTimeAtLastModification = thisMachineUtcTime - timeSinceLastModification; await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' was last modified on '{1}' at: {2}.", launchConfig ["PackageName"], debuggingDevice.ID, debuggingDeviceUtcTimeAtLastModification.ToString()), false); await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "{0} (on {1}) was around {2} (on {3}).", debuggingDeviceUtcTimeAtLastModification.ToString(), debuggingDevice.ID, thisMachineUtcTimeAtLastModification.ToString(), System.Environment.MachineName), false); await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' was last modified on '{1}' at: {2}.", Path.GetFileName(targetApkFileInfo.FullName), System.Environment.MachineName, targetApkFileInfo.LastWriteTime.ToString()), false); if ((targetApkFileInfo.LastWriteTime + thisMachineUtcVersusDeviceUtc) > thisMachineUtcTimeAtLastModification) { await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' was determined to be out-of-date. Reinstalling...", launchConfig ["PackageName"]), false); } else { appIsOutOfDate = false; } break; } } } catch (Exception) { appIsInstalled = false; } } else { await m_debugConnectionService.LaunchDialogUpdate("Skipping up-to-date check.", false); } if (!appIsInstalled || appIsOutOfDate) { await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "Installing '{0}' to '{1}'...", launchConfig ["PackageName"], debuggingDevice.ID), false); InstallApplicationAsync(debuggingDevice, launchConfig); await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' installed successfully.", launchConfig ["PackageName"]), false); } else { await m_debugConnectionService.LaunchDialogUpdate(string.Format(CultureInfo.InvariantCulture, "'{0}' on '{1}' is up-to-date. Skipping installation...", launchConfig ["PackageName"], debuggingDevice.ID), false); } debugLaunchSettings.Executable = launchConfig ["TargetApk"]; debugLaunchSettings.LaunchOperation = DebugLaunchOperation.Custom; } return(debugLaunchSettings); }