//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public object StartWithoutDebugging(int launchOptions, LaunchConfiguration launchConfig, LaunchProps [] launchProps, IDictionary<string, string> projectProperties) { LoggingUtils.PrintFunction (); if (launchConfig == null) { throw new ArgumentNullException ("launchConfig"); } if (launchProps == null) { throw new ArgumentNullException ("launchProps"); } if (projectProperties == null) { throw new ArgumentNullException ("projectProperties"); } try { // // Refresh ADB service and evaluate a list of connected devices or emulators. // AndroidAdb.Refresh (); AndroidDevice debuggingDevice = GetPrioritisedConnectedDevice (); if (debuggingDevice == null) { 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 nonDebuglaunchSettings; } catch (Exception e) { LoggingUtils.HandleException (e); throw; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public object StartWithDebugging(int launchOptions, LaunchConfiguration launchConfig, LaunchProps [] launchProps, IDictionary<string, string> projectProperties) { LoggingUtils.PrintFunction (); if (launchConfig == null) { throw new ArgumentNullException ("launchConfig"); } if (launchProps == null) { throw new ArgumentNullException ("launchProps"); } if (projectProperties == null) { throw new ArgumentNullException ("projectProperties"); } try { // // Refresh ADB service and evaluate a list of connected devices or emulators. // AndroidAdb.Refresh (); AndroidDevice debuggingDevice = GetPrioritisedConnectedDevice (); if (debuggingDevice == null) { throw new InvalidOperationException ("No device/emulator found or connected. Check status using \"adb devices\"."); } // // Enforce required device/emulator properties. // foreach (LaunchProps 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 { string [] 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 (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 { string [] deviceDateOutput = debuggingDevice.Shell ("date", "-u").Replace ("\r", "").Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string debuggingDeviceUtcTimestamp = deviceDateOutput [0]; string [] 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; LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "Current UTC time on '{0}': {1}", debuggingDevice.ID, debuggingDeviceUtcTime.ToString ()), false)); LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "Current UTC time on '{0}': {1}", System.Environment.MachineName, thisMachineUtcTime.ToString ()), false)); LoggingUtils.RequireOk (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 { string [] extendedLsOutput = debuggingDevice.Shell ("ls -l", path).Replace ("\r", "").Split (new char [] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string [] 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; LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "'{0}' was last modified on '{1}' at: {2}.", launchConfig ["PackageName"], debuggingDevice.ID, debuggingDeviceUtcTimeAtLastModification.ToString ()), false)); LoggingUtils.RequireOk (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)); LoggingUtils.RequireOk (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) { LoggingUtils.RequireOk (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 { LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate ("Skipping up-to-date check.", false)); } if (!appIsInstalled || appIsOutOfDate) { LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "Installing '{0}' to '{1}'...", launchConfig ["PackageName"], debuggingDevice.ID), false)); InstallApplicationAsync (debuggingDevice, launchConfig); LoggingUtils.RequireOk (m_debugConnectionService.LaunchDialogUpdate (string.Format (CultureInfo.InvariantCulture, "'{0}' installed successfully.", launchConfig ["PackageName"]), false)); } else { LoggingUtils.RequireOk (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; } catch (Exception e) { LoggingUtils.HandleException (e); throw; } }