Beispiel #1
0
        private LaunchOptions SetupForDebuggingWorker(CancellationToken token)
        {
            CancellationTokenRegistration onCancelRegistration = token.Register(() =>
            {
                _gdbServerExecCancellationSource.Cancel();
            });

            using (onCancelRegistration)
            {
                // TODO: Adb exception messages should be improved. Example, if ADB is not started, this is returned:
                //    +		[libadb.AdbException]	{"Could not connect to the adb.exe server. See InnerException for details."}	libadb.AdbException
                // 'See InnerException for details.' should not be there. It should just add the inner exception message:
                //    [System.Net.Sockets.SocketException]	{"No connection could be made because the target machine actively refused it 127.0.0.1:5037"}	System.Net.Sockets.SocketException

                Device device = null;
                string workingDirectory = null;
                string gdbServerRemotePath = null;
                string gdbServerSocketDescription = null;
                string exePath = null;
                Task taskGdbServer = null;
                int gdbPortNumber = 0;
                int progressCurrentIndex = 0;
                int progressStepCount = 0;

                List<NamedAction> actions = new List<NamedAction>();

                actions.Add(new NamedAction(LauncherResources.Step_ResolveInstallPaths, () =>
                {
                    _installPaths = InstallPaths.Resolve(token, _launchOptions, Logger);
                }));

                actions.Add(new NamedAction(LauncherResources.Step_ConnectToDevice, () =>
                {
                    Adb adb;
                    try
                    {
                        adb = new Adb(_installPaths.SDKRoot);
                    }
                    catch (ArgumentException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.InvalidAndroidSDK, string.Format(CultureInfo.CurrentCulture, LauncherResources.Error_InvalidAndroidSDK, _installPaths.SDKRoot));
                    }

                    try
                    {
                        adb.Start();
                        device = adb.GetDeviceById(_launchOptions.DeviceId);

                        // There is a rare case, which we have seen it a few times now with the Android emulator where the device will be initially
                        // in the offline state. But after a very short amount of time it comes online. Retry waiting for this.
                        if (device.GetState().HasFlag(DeviceState.Offline))
                        {
                            // Add in an extra progress step and update the dialog
                            progressStepCount++;

                            _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, LauncherResources.Step_WaitingForDeviceToComeOnline);
                            progressCurrentIndex++;

                            const int waitTimePerIteration = 50;
                            const int maxTries = 5000 / waitTimePerIteration; // We will wait for up to 5 seconds

                            // NOTE: libadb has device discovery built in which we could allegedly use instead of a retry loop,
                            // but I couldn't get this to work (though the problem is so rare, I had a lot of trouble testing it), so just using
                            // a retry loop.
                            for (int cTry = 0; true; cTry++)
                            {
                                if (cTry == maxTries)
                                {
                                    throw new LauncherException(Telemetry.LaunchFailureCode.DeviceOffline, LauncherResources.Error_DeviceOffline);
                                }

                                // Sleep for a little while unless this operation is canceled
                                if (token.WaitHandle.WaitOne(waitTimePerIteration))
                                {
                                    throw new OperationCanceledException();
                                }

                                if (!device.GetState().HasFlag(DeviceState.Offline))
                                {
                                    break; // we are no longer offline
                                }
                            }
                        }
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }
                }));

                actions.Add(new NamedAction(LauncherResources.Step_InspectingDevice, () =>
                {
                    try
                    {
                        DeviceAbi[] allowedAbis;
                        switch (_launchOptions.TargetArchitecture)
                        {
                            case TargetArchitecture.ARM:
                                allowedAbis = new DeviceAbi[] { DeviceAbi.armeabi, DeviceAbi.armeabiv7a };
                                break;

                            case TargetArchitecture.ARM64:
                                allowedAbis = new DeviceAbi[] { DeviceAbi.arm64v8a };
                                break;

                            case TargetArchitecture.X86:
                                allowedAbis = new DeviceAbi[] { DeviceAbi.x86 };
                                break;

                            case TargetArchitecture.X64:
                                allowedAbis = new DeviceAbi[] { DeviceAbi.x64 };
                                break;

                            default:
                                Debug.Fail("New target architucture support added without updating this code???");
                                throw new InvalidOperationException();
                        }

                        if (!DoesDeviceSupportAnyAbi(device, allowedAbis))
                        {
                            throw GetBadDeviceAbiException(device.Abi);
                        }

                        if (_launchOptions.TargetArchitecture == TargetArchitecture.ARM && device.IsEmulator)
                        {
                            _isUsingArmEmulator = true;
                        }

                        _shell = device.Shell;
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }

                    VerifySdkVersion();

                    if (_targetEngine == TargetEngine.Native)
                    {
                        string pwdCommand = string.Concat("run-as ", _launchOptions.Package, " /system/bin/sh -c pwd");
                        ExecCommand(pwdCommand);
                        workingDirectory = PwdOutputParser.ExtractWorkingDirectory(_shell.Out, _launchOptions.Package);
                        gdbServerRemotePath = GetGdbServerPath(workingDirectory, device);

                        KillOldInstances(gdbServerRemotePath);
                    }
                }));

                if (!_launchOptions.IsAttach)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_StartingApp, () =>
                    {
                        string activateCommand = string.Concat("am start -D -n ", _launchOptions.Package, "/", _launchOptions.LaunchActivity);
                        ExecCommand(activateCommand);
                        ValidateActivityManagerOutput(activateCommand, _shell.Out);
                    }));
                }

                actions.Add(new NamedAction(LauncherResources.Step_GettingAppProcessId, () =>
                {
                    _appProcessId = GetAppProcessId();
                }));

                if (_targetEngine == TargetEngine.Native)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_StartGDBServer, () =>
                    {
                        // We will default to using a unix socket with gdbserver as this is what the ndk-gdb script uses. Though we have seen
                        // some machines where this doesn't work and we fall back to TCP instead.
                        const bool useUnixSocket = true;

                        taskGdbServer = StartGdbServer(gdbServerRemotePath, workingDirectory, useUnixSocket, out gdbServerSocketDescription);
                    }));
                }

                actions.Add(new NamedAction(LauncherResources.Step_PortForwarding, () =>
                {
                    // TODO: Use a dynamic socket
                    gdbPortNumber = 5039;
                    _jdbPortNumber = 65534;

                    if (_targetEngine == TargetEngine.Native)
                    {
                        device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", gdbPortNumber), gdbServerSocketDescription);
                    }

                    device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", _jdbPortNumber), string.Format(CultureInfo.InvariantCulture, "jdwp:{0}", _appProcessId));
                }));

                if (_targetEngine == TargetEngine.Native)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_DownloadingFiles, () =>
                    {
                        //pull binaries from the emulator/device
                        var fileSystem = device.FileSystem;

                        string app_process_suffix = String.Empty;
                        switch (_launchOptions.TargetArchitecture)
                        {
                            case TargetArchitecture.X86:
                            case TargetArchitecture.ARM:
                                app_process_suffix = "32";
                                break;
                            case TargetArchitecture.X64:
                            case TargetArchitecture.ARM64:
                                app_process_suffix = "64";
                                break;
                            default:
                                Debug.Fail("Unsupported Target Architecture!");
                                break;
                        }

                        string app_process = String.Concat("app_process", app_process_suffix);
                        exePath = Path.Combine(_launchOptions.IntermediateDirectory, app_process);

                        bool retry = false;
                        try
                        {
                            fileSystem.Download(@"/system/bin/" + app_process, exePath, true);
                        }
                        catch (AdbException) when (String.Compare(app_process_suffix, "32", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // Older devices don't have an 'app_process32', only an 'app_process', so retry
                            // NOTE: libadb doesn't have an error code property to verify that this is caused
                            // by the file not being found.
                            retry = true;
                        }

                        if (retry)
                        {
                            app_process = "app_process";
                            exePath = Path.Combine(_launchOptions.IntermediateDirectory, app_process);
                            fileSystem.Download(@"/system/bin/app_process", exePath, true);
                        }

                        //on 64 bit, 'linker64' is the 64bit version and 'linker' is the 32 bit version
                        string suffix64bit = String.Empty;
                        if (_launchOptions.TargetArchitecture == TargetArchitecture.X64 || _launchOptions.TargetArchitecture == TargetArchitecture.ARM64)
                        {
                            suffix64bit = "64";
                        }

                        string linker = String.Concat("linker", suffix64bit);
                        fileSystem.Download(String.Concat(@"/system/bin/", linker), Path.Combine(_launchOptions.IntermediateDirectory, linker), true);

                        //on 64 bit, libc.so lives in /system/lib64/, on 32 bit it lives in simply /system/lib/
                        fileSystem.Download(@"/system/lib" + suffix64bit + "/libc.so", Path.Combine(_launchOptions.IntermediateDirectory, "libc.so"), true);
                    }));
                }

                progressStepCount = actions.Count;

                foreach (NamedAction namedAction in actions)
                {
                    token.ThrowIfCancellationRequested();

                    _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, namedAction.Name);
                    progressCurrentIndex++;
                    namedAction.Action();
                }

                _waitLoop.SetProgress(progressStepCount, progressStepCount, string.Empty);

                if (_targetEngine == TargetEngine.Native && taskGdbServer.IsCompleted)
                {
                    token.ThrowIfCancellationRequested();
                    throw new LauncherException(Telemetry.LaunchFailureCode.GDBServerFailed, LauncherResources.Error_GDBServerFailed);
                }

                if (_launchOptions.LogcatServiceId != Guid.Empty)
                {
                    _eventCallback.OnCustomDebugEvent(_launchOptions.LogcatServiceId, new Guid(LogcatServiceMessage_SourceId), LogcatServiceMessage_NewProcess, _appProcessId, null);
                }

                LaunchOptions launchOptions = null;
                if (_targetEngine == TargetEngine.Native)
                {
                    launchOptions = new LocalLaunchOptions(_installPaths.GDBPath, string.Format(CultureInfo.InvariantCulture, ":{0}", gdbPortNumber), 0, null);
                    launchOptions.ExePath = exePath;
                }
                else
                {
                    launchOptions = new JavaLaunchOptions(_launchOptions.JVMHost, _launchOptions.JVMPort, _launchOptions.SourceRoots, _launchOptions.Package);
                }

                launchOptions.AdditionalSOLibSearchPath = _launchOptions.AdditionalSOLibSearchPath;
                launchOptions.AbsolutePrefixSOLibSearchPath = _launchOptions.AbsolutePrefixSOLibSearchPath;

                // The default ABI is 'Cygwin' in the Android NDK >= r11 for Windows.
                launchOptions.SetupCommands = new ReadOnlyCollection<LaunchCommand>( new LaunchCommand[]
                {
                    new LaunchCommand("-gdb-set osabi GNU/Linux")
                });

                launchOptions.TargetArchitecture = _launchOptions.TargetArchitecture;
                launchOptions.WorkingDirectory = _launchOptions.IntermediateDirectory;

                launchOptions.DebuggerMIMode = MIMode.Gdb;

                launchOptions.VisualizerFile = "Microsoft.Android.natvis";
                launchOptions.WaitDynamicLibLoad = _launchOptions.WaitDynamicLibLoad;

                return launchOptions;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Resolves the various file paths used by the AndroidDebugLauncher and returns an initialized InstallPaths object
        /// </summary>
        /// <param name="token">token to check for cancelation</param>
        /// <param name="launchOptions">[Required] launch options object</param>
        /// <returns>[Required] Created InstallPaths object</returns>
        public static InstallPaths Resolve(CancellationToken token, AndroidLaunchOptions launchOptions)
        {
            var result = new InstallPaths();

            if (launchOptions.SDKRoot != null)
            {
                result.SDKRoot = launchOptions.SDKRoot;
            }
            else
            {
                result.SDKRoot = GetDirectoryFromRegistry(@"SOFTWARE\Android SDK Tools", "Path", checkBothBitnesses: true, externalProductName: LauncherResources.ProductName_NDK);
            }

            string ndkRoot = launchOptions.NDKRoot;

            if (ndkRoot == null)
            {
                ndkRoot = GetDirectoryFromRegistry(RegistryRoot.Value + @"\Setup\VS\SecondaryInstaller\AndroidNDK", "NDK_HOME", checkBothBitnesses: false, externalProductName: LauncherResources.ProductName_SDK);
            }

            string ndkReleaseVersionFile = Path.Combine(ndkRoot, "RELEASE.TXT");

            if (!File.Exists(ndkReleaseVersionFile))
            {
                ThrowExternalFileNotFoundException(ndkReleaseVersionFile, LauncherResources.ProductName_NDK);
            }

            NdkReleaseId ndkReleaseId;

            NdkReleaseId.TryParseFile(ndkReleaseVersionFile, out ndkReleaseId);
            MICore.Logger.WriteLine("Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);

            string targetArchitectureName;

            NDKToolChainFilePath[] possibleGDBPaths;
            switch (launchOptions.TargetArchitecture)
            {
            case MICore.TargetArchitecture.X86:
                targetArchitectureName = "x86";
                possibleGDBPaths       = NDKToolChainFilePath.x86_GDBPaths();
                break;

            case MICore.TargetArchitecture.X64:
                targetArchitectureName = "x64";
                possibleGDBPaths       = NDKToolChainFilePath.x64_GDBPaths();
                break;

            case MICore.TargetArchitecture.ARM:
                targetArchitectureName = "arm";
                possibleGDBPaths       = NDKToolChainFilePath.ARM_GDBPaths();
                break;

            case MICore.TargetArchitecture.ARM64:
                targetArchitectureName = "arm64";
                possibleGDBPaths       = NDKToolChainFilePath.ARM64_GDBPaths();
                break;

            default:
                Debug.Fail("Should be impossible");
                throw new InvalidOperationException();
            }

            NDKToolChainFilePath matchedPath;

            result.GDBPath = GetNDKFilePath(
                string.Concat("Android-", targetArchitectureName, "-GDBPath"),
                ndkRoot,
                possibleGDBPaths,
                out matchedPath
                );
            if (launchOptions.TargetArchitecture == MICore.TargetArchitecture.X86 && matchedPath != null)
            {
                var r10b = new NdkReleaseId(10, 'b', true);

                // Before r10b, the 'windows-x86_64' ndk didn't support x86 debugging
                if (ndkReleaseId.IsValid && ndkReleaseId.CompareVersion(r10b) < 0 && matchedPath.PartialFilePath.Contains(@"\windows-x86_64\"))
                {
                    throw new LauncherException(Telemetry.LaunchFailureCode.NoReport, LauncherResources.Error_64BitNDKNotSupportedForX86);
                }
            }

            token.ThrowIfCancellationRequested();

            return(result);
        }
Beispiel #3
0
        private LaunchOptions SetupForDebuggingWorker(CancellationToken token)
        {
            CancellationTokenRegistration onCancelRegistration = token.Register(() =>
            {
                _gdbServerExecCancellationSource.Cancel();
            });

            using (onCancelRegistration)
            {
                // TODO: Adb exception messages should be improved. Example, if ADB is not started, this is returned:
                //    +		[libadb.AdbException]	{"Could not connect to the adb.exe server. See InnerException for details."}	libadb.AdbException
                // 'See InnerException for details.' should not be there. It should just add the inner exception message:
                //    [System.Net.Sockets.SocketException]	{"No connection could be made because the target machine actively refused it 127.0.0.1:5037"}	System.Net.Sockets.SocketException

                Device device                     = null;
                string workingDirectory           = null;
                string gdbServerRemotePath        = null;
                string gdbServerSocketDescription = null;
                string exePath                    = null;
                Task   taskGdbServer              = null;
                int    gdbPortNumber              = 0;
                int    progressCurrentIndex       = 0;
                int    progressStepCount          = 0;

                List <NamedAction> actions = new List <NamedAction>();

                actions.Add(new NamedAction(LauncherResources.Step_ResolveInstallPaths, () =>
                {
                    _installPaths = InstallPaths.Resolve(token, _launchOptions);
                }));

                actions.Add(new NamedAction(LauncherResources.Step_ConnectToDevice, () =>
                {
                    Adb adb;
                    try
                    {
                        adb = new Adb(_installPaths.SDKRoot);
                    }
                    catch (ArgumentException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.InvalidAndroidSDK, string.Format(CultureInfo.CurrentCulture, LauncherResources.Error_InvalidAndroidSDK, _installPaths.SDKRoot));
                    }

                    try
                    {
                        adb.Start();
                        device = adb.GetDeviceById(_launchOptions.DeviceId);

                        // There is a rare case, which we have seen it a few times now with the Android emulator where the device will be initially
                        // in the offline state. But after a very short amount of time it comes online. Retry waiting for this.
                        if (device.GetState().HasFlag(DeviceState.Offline))
                        {
                            // Add in an extra progress step and update the dialog
                            progressStepCount++;

                            _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, LauncherResources.Step_WaitingForDeviceToComeOnline);
                            progressCurrentIndex++;

                            const int waitTimePerIteration = 50;
                            const int maxTries             = 5000 / waitTimePerIteration; // We will wait for up to 5 seconds

                            // NOTE: libadb has device discovery built in which we could allegedly use instead of a retry loop,
                            // but I couldn't get this to work (though the problem is so rare, I had a lot of trouble testing it), so just using
                            // a retry loop.
                            for (int cTry = 0; true; cTry++)
                            {
                                if (cTry == maxTries)
                                {
                                    throw new LauncherException(Telemetry.LaunchFailureCode.DeviceOffline, LauncherResources.Error_DeviceOffline);
                                }

                                // Sleep for a little while unless this operation is canceled
                                if (token.WaitHandle.WaitOne(waitTimePerIteration))
                                {
                                    throw new OperationCanceledException();
                                }

                                if (!device.GetState().HasFlag(DeviceState.Offline))
                                {
                                    break; // we are no longer offline
                                }
                            }
                        }
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }
                }));

                actions.Add(new NamedAction(LauncherResources.Step_InspectingDevice, () =>
                {
                    try
                    {
                        DeviceAbi[] allowedAbis;
                        switch (_launchOptions.TargetArchitecture)
                        {
                        case TargetArchitecture.ARM:
                            allowedAbis = new DeviceAbi[] { DeviceAbi.armeabi, DeviceAbi.armeabiv7a };
                            break;

                        case TargetArchitecture.ARM64:
                            allowedAbis = new DeviceAbi[] { DeviceAbi.arm64v8a };
                            break;

                        case TargetArchitecture.X86:
                            allowedAbis = new DeviceAbi[] { DeviceAbi.x86 };
                            break;

                        case TargetArchitecture.X64:
                            allowedAbis = new DeviceAbi[] { DeviceAbi.x64 };
                            break;

                        default:
                            Debug.Fail("New target architucture support added without updating this code???");
                            throw new InvalidOperationException();
                        }

                        if (!DoesDeviceSupportAnyAbi(device, allowedAbis))
                        {
                            throw GetBadDeviceAbiException(device.Abi);
                        }

                        if (_launchOptions.TargetArchitecture == TargetArchitecture.ARM && device.IsEmulator)
                        {
                            _isUsingArmEmulator = true;
                        }

                        _shell = device.Shell;
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }

                    VerifySdkVersion();

                    if (_targetEngine == TargetEngine.Native)
                    {
                        string pwdCommand = string.Concat("run-as ", _launchOptions.Package, " /system/bin/sh -c pwd");
                        ExecCommand(pwdCommand);
                        workingDirectory    = PwdOutputParser.ExtractWorkingDirectory(_shell.Out, _launchOptions.Package);
                        gdbServerRemotePath = GetGdbServerPath(workingDirectory);

                        KillOldInstances(gdbServerRemotePath);
                    }
                }));

                if (!_launchOptions.IsAttach)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_StartingApp, () =>
                    {
                        string activateCommand = string.Concat("am start -D -n ", _launchOptions.Package, "/", _launchOptions.LaunchActivity);
                        ExecCommand(activateCommand);
                        ValidateActivityManagerOutput(activateCommand, _shell.Out);
                    }));
                }

                actions.Add(new NamedAction(LauncherResources.Step_GettingAppProcessId, () =>
                {
                    _appProcessId = GetAppProcessId();
                }));

                if (_targetEngine == TargetEngine.Native)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_StartGDBServer, () =>
                    {
                        // We will default to using a unix socket with gdbserver as this is what the ndk-gdb script uses. Though we have seen
                        // some machines where this doesn't work and we fall back to TCP instead.
                        const bool useUnixSocket = true;

                        taskGdbServer = StartGdbServer(gdbServerRemotePath, workingDirectory, useUnixSocket, out gdbServerSocketDescription);
                    }));
                }

                actions.Add(new NamedAction(LauncherResources.Step_PortForwarding, () =>
                {
                    // TODO: Use a dynamic socket
                    gdbPortNumber  = 5039;
                    _jdbPortNumber = 65534;

                    if (_targetEngine == TargetEngine.Native)
                    {
                        device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", gdbPortNumber), gdbServerSocketDescription);
                    }


                    device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", _jdbPortNumber), string.Format(CultureInfo.InvariantCulture, "jdwp:{0}", _appProcessId));
                }));

                if (_targetEngine == TargetEngine.Native)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_DownloadingFiles, () =>
                    {
                        //pull binaries from the emulator/device
                        var fileSystem = device.FileSystem;

                        string app_process_suffix = String.Empty;
                        switch (_launchOptions.TargetArchitecture)
                        {
                        case TargetArchitecture.X86:
                        case TargetArchitecture.ARM:
                            app_process_suffix = "32";
                            break;

                        case TargetArchitecture.X64:
                        case TargetArchitecture.ARM64:
                            app_process_suffix = "64";
                            break;

                        default:
                            Debug.Fail("Unsupported Target Architecture!");
                            break;
                        }

                        string app_process = String.Concat("app_process", app_process_suffix);
                        exePath            = Path.Combine(_launchOptions.IntermediateDirectory, app_process);

                        bool retry = false;
                        try
                        {
                            fileSystem.Download(@"/system/bin/" + app_process, exePath, true);
                        }
                        catch (AdbException) when(String.Compare(app_process_suffix, "32", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // Older devices don't have an 'app_process32', only an 'app_process', so retry
                            // NOTE: libadb doesn't have an error code property to verify that this is caused
                            // by the file not being found.
                            retry = true;
                        }

                        if (retry)
                        {
                            app_process = "app_process";
                            exePath     = Path.Combine(_launchOptions.IntermediateDirectory, app_process);
                            fileSystem.Download(@"/system/bin/app_process", exePath, true);
                        }

                        //on 64 bit, 'linker64' is the 64bit version and 'linker' is the 32 bit version
                        string suffix64bit = String.Empty;
                        if (_launchOptions.TargetArchitecture == TargetArchitecture.X64 || _launchOptions.TargetArchitecture == TargetArchitecture.ARM64)
                        {
                            suffix64bit = "64";
                        }

                        string linker = String.Concat("linker", suffix64bit);
                        fileSystem.Download(String.Concat(@"/system/bin/", linker), Path.Combine(_launchOptions.IntermediateDirectory, linker), true);

                        //on 64 bit, libc.so lives in /system/lib64/, on 32 bit it lives in simply /system/lib/
                        fileSystem.Download(@"/system/lib" + suffix64bit + "/libc.so", Path.Combine(_launchOptions.IntermediateDirectory, "libc.so"), true);
                    }));
                }

                progressStepCount = actions.Count;

                foreach (NamedAction namedAction in actions)
                {
                    token.ThrowIfCancellationRequested();

                    _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, namedAction.Name);
                    progressCurrentIndex++;
                    namedAction.Action();
                }

                _waitLoop.SetProgress(progressStepCount, progressStepCount, string.Empty);

                if (_targetEngine == TargetEngine.Native && taskGdbServer.IsCompleted)
                {
                    token.ThrowIfCancellationRequested();
                    throw new LauncherException(Telemetry.LaunchFailureCode.GDBServerFailed, LauncherResources.Error_GDBServerFailed);
                }

                if (_launchOptions.LogcatServiceId != Guid.Empty)
                {
                    _eventCallback.OnCustomDebugEvent(_launchOptions.LogcatServiceId, new Guid(LogcatServiceMessage_SourceId), LogcatServiceMessage_NewProcess, _appProcessId, null);
                }

                LaunchOptions launchOptions = null;
                if (_targetEngine == TargetEngine.Native)
                {
                    launchOptions         = new LocalLaunchOptions(_installPaths.GDBPath, string.Format(CultureInfo.InvariantCulture, ":{0}", gdbPortNumber));
                    launchOptions.ExePath = exePath;
                }
                else
                {
                    launchOptions = new JavaLaunchOptions(_launchOptions.JVMHost, _launchOptions.JVMPort, _launchOptions.SourceRoots, _launchOptions.Package);
                }

                launchOptions.AdditionalSOLibSearchPath = _launchOptions.AdditionalSOLibSearchPath;
                launchOptions.TargetArchitecture        = _launchOptions.TargetArchitecture;
                launchOptions.WorkingDirectory          = _launchOptions.IntermediateDirectory;

                launchOptions.DebuggerMIMode = MIMode.Gdb;

                launchOptions.VisualizerFile = "Microsoft.Android.natvis";

                return(launchOptions);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Resolves the various file paths used by the AndroidDebugLauncher and returns an initialized InstallPaths object
        /// </summary>
        /// <param name="token">token to check for cancelation</param>
        /// <param name="launchOptions">[Required] launch options object</param>
        /// <returns>[Required] Created InstallPaths object</returns>
        public static InstallPaths Resolve(CancellationToken token, AndroidLaunchOptions launchOptions, MICore.Logger logger)
        {
            var result = new InstallPaths();

            if (launchOptions.SDKRoot != null)
            {
                result.SDKRoot = launchOptions.SDKRoot;
            }
            else
            {
                result.SDKRoot = GetDirectoryFromRegistry(@"SOFTWARE\Android SDK Tools", "Path", checkBothBitnesses: true, externalProductName: LauncherResources.ProductName_SDK);
            }

            string ndkRoot = launchOptions.NDKRoot;
            if (ndkRoot == null)
            {
                ndkRoot = GetDirectoryFromRegistry(RegistryRoot.Value + @"\Setup\VS\SecondaryInstaller\AndroidNDK", "NDK_HOME", checkBothBitnesses: false, externalProductName: LauncherResources.ProductName_NDK);
            }

            string ndkReleaseVersionFile = Path.Combine(ndkRoot, "RELEASE.TXT");
            if (!File.Exists(ndkReleaseVersionFile))
            {
                ThrowExternalFileNotFoundException(ndkReleaseVersionFile, LauncherResources.ProductName_NDK);
            }

            NdkReleaseId ndkReleaseId;
            NdkReleaseId.TryParseFile(ndkReleaseVersionFile, out ndkReleaseId);
            logger.WriteLine("Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);

            string targetArchitectureName;
            NDKToolChainFilePath[] possibleGDBPaths;
            switch (launchOptions.TargetArchitecture)
            {
                case MICore.TargetArchitecture.X86:
                    targetArchitectureName = "x86";
                    possibleGDBPaths = NDKToolChainFilePath.x86_GDBPaths();
                    break;

                case MICore.TargetArchitecture.X64:
                    targetArchitectureName = "x64";
                    possibleGDBPaths = NDKToolChainFilePath.x64_GDBPaths();
                    break;

                case MICore.TargetArchitecture.ARM:
                    targetArchitectureName = "arm";
                    possibleGDBPaths = NDKToolChainFilePath.ARM_GDBPaths();
                    break;

                case MICore.TargetArchitecture.ARM64:
                    targetArchitectureName = "arm64";
                    possibleGDBPaths = NDKToolChainFilePath.ARM64_GDBPaths();
                    break;

                default:
                    Debug.Fail("Should be impossible");
                    throw new InvalidOperationException();
            }

            NDKToolChainFilePath matchedPath;
            result.GDBPath = GetNDKFilePath(
                string.Concat("Android-", targetArchitectureName, "-GDBPath"),
                ndkRoot,
                possibleGDBPaths,
                out matchedPath
                );
            if (launchOptions.TargetArchitecture == MICore.TargetArchitecture.X86 && matchedPath != null)
            {
                var r10b = new NdkReleaseId(10, 'b', true);

                // Before r10b, the 'windows-x86_64' ndk didn't support x86 debugging
                if (ndkReleaseId.IsValid && ndkReleaseId.CompareVersion(r10b) < 0 && matchedPath.PartialFilePath.Contains(@"\windows-x86_64\"))
                {
                    throw new LauncherException(Telemetry.LaunchFailureCode.NoReport, LauncherResources.Error_64BitNDKNotSupportedForX86);
                }
            }

            token.ThrowIfCancellationRequested();

            return result;
        }
Beispiel #5
0
        /// <summary>
        /// Resolves the various file paths used by the AndroidDebugLauncher and returns an initialized InstallPaths object
        /// </summary>
        /// <param name="token">token to check for cancelation</param>
        /// <param name="launchOptions">[Required] launch options object</param>
        /// <returns>[Required] Created InstallPaths object</returns>
        public static InstallPaths Resolve(CancellationToken token, AndroidLaunchOptions launchOptions, MICore.Logger logger)
        {
            var result = new InstallPaths();

            if (launchOptions.SDKRoot != null)
            {
                result.SDKRoot = launchOptions.SDKRoot;
            }
            else
            {
                result.SDKRoot = GetDirectoryFromRegistry(@"SOFTWARE\Android SDK Tools", "Path", checkBothBitnesses: true, externalProductName: LauncherResources.ProductName_SDK);
            }

            string ndkRoot = launchOptions.NDKRoot;

            if (ndkRoot == null)
            {
                ndkRoot = GetDirectoryFromRegistry(RegistryRoot.Value + @"\Setup\VS\SecondaryInstaller\AndroidNDK", "NDK_HOME", checkBothBitnesses: false, externalProductName: LauncherResources.ProductName_NDK);
            }

            NdkReleaseId ndkReleaseId            = new NdkReleaseId();
            string       ndkReleaseVersionFile   = Path.Combine(ndkRoot, "RELEASE.TXT");
            string       ndkSourcePropertiesFile = Path.Combine(ndkRoot, "source.properties");

            // NDK releases >= r11 have a source.properties file
            if (File.Exists(ndkSourcePropertiesFile))
            {
                NdkReleaseId.TryParsePropertiesFile(ndkSourcePropertiesFile, out ndkReleaseId);
            }
            // NDK releases < r11 have a RELEASE.txt file
            else if (File.Exists(ndkReleaseVersionFile))
            {
                NdkReleaseId.TryParseFile(ndkReleaseVersionFile, out ndkReleaseId);
            }
            else
            {
                ThrowExternalFileNotFoundException(ndkReleaseVersionFile, LauncherResources.ProductName_NDK);
            }

            logger.WriteLine("Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);

            // 32 vs 64-bit doesn't matter when comparing
            var r11 = new NdkReleaseId(11, 'a');
            // In NDK r11 and later, gdb is multi-arch and there's only one binary
            // in the prebuilt directory
            bool usePrebuiltGDB = ndkReleaseId.CompareVersion(r11) >= 0;
            IEnumerable <INDKFilePath> prebuiltGDBPath = NDKPrebuiltFilePath.GDBPaths();

            string targetArchitectureName;
            IEnumerable <INDKFilePath> possibleGDBPaths;

            switch (launchOptions.TargetArchitecture)
            {
            case MICore.TargetArchitecture.X86:
                targetArchitectureName = "x86";
                possibleGDBPaths       = usePrebuiltGDB ? prebuiltGDBPath: NDKToolChainFilePath.x86_GDBPaths();
                break;

            case MICore.TargetArchitecture.X64:
                targetArchitectureName = "x64";
                possibleGDBPaths       = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.x64_GDBPaths();
                break;

            case MICore.TargetArchitecture.ARM:
                targetArchitectureName = "arm";
                possibleGDBPaths       = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.ARM_GDBPaths();
                break;

            case MICore.TargetArchitecture.ARM64:
                targetArchitectureName = "arm64";
                possibleGDBPaths       = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.ARM64_GDBPaths();
                break;

            default:
                Debug.Fail("Should be impossible");
                throw new InvalidOperationException();
            }

            INDKFilePath matchedPath;

            result.GDBPath = GetNDKFilePath(
                string.Concat("Android-", targetArchitectureName, "-GDBPath"),
                ndkRoot,
                possibleGDBPaths,
                out matchedPath
                );
            if (launchOptions.TargetArchitecture == MICore.TargetArchitecture.X86 && matchedPath != null)
            {
                var r10b = new NdkReleaseId(10, 'b');

                // Before r10b, the 'windows-x86_64' ndk didn't support x86 debugging
                if (ndkReleaseId.IsValid && ndkReleaseId.CompareVersion(r10b) < 0 && matchedPath.PartialFilePath.Contains(@"\windows-x86_64\"))
                {
                    throw new LauncherException(Telemetry.LaunchFailureCode.NoReport, LauncherResources.Error_64BitNDKNotSupportedForX86);
                }
            }

            token.ThrowIfCancellationRequested();

            return(result);
        }
Beispiel #6
0
        private LocalLaunchOptions SetupForDebuggingWorker(CancellationToken token)
        {
            CancellationTokenRegistration onCancelRegistration = token.Register(() =>
            {
                _gdbServerExecCancellationSource.Cancel();
            });

            using (onCancelRegistration)
            {
                // TODO: Adb exception messages should be improved. Example, if ADB is not started, this is returned:
                //    +		[libadb.AdbException]	{"Could not connect to the adb.exe server. See InnerException for details."}	libadb.AdbException
                // 'See InnerException for details.' should not be there. It should just add the inner exception message:
                //    [System.Net.Sockets.SocketException]	{"No connection could be made because the target machine actively refused it 127.0.0.1:5037"}	System.Net.Sockets.SocketException

                Device device = null;
                string workingDirectory = null;
                string gdbServerRemotePath = null;
                string gdbServerSocketDescription = null;
                Task taskGdbServer = null;
                int gdbPortNumber = 0;
                int progressCurrentIndex = 0;
                int progressStepCount = 0;

                List<NamedAction> actions = new List<NamedAction>();

                actions.Add(new NamedAction(LauncherResources.Step_ResolveInstallPaths, () =>
                {
                    _installPaths = InstallPaths.Resolve(token, _launchOptions);
                }));

                actions.Add(new NamedAction(LauncherResources.Step_ConnectToDevice, () =>
                {
                    Adb adb;
                    try
                    {
                        adb = new Adb(_installPaths.SDKRoot);
                    }
                    catch (ArgumentException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.InvalidAndroidSDK, string.Format(CultureInfo.CurrentCulture, LauncherResources.Error_InvalidAndroidSDK, _installPaths.SDKRoot));
                    }

                    try
                    {
                        adb.Start();
                        device = adb.GetDeviceById(_launchOptions.DeviceId);

                        // There is a rare case, which we have seen it a few times now with the Android emulator where the device will be initially
                        // in the offline state. But after a very short amount of time it comes online. Retry waiting for this.
                        if (device.GetState().HasFlag(DeviceState.Offline))
                        {
                            // Add in an extra progress step and update the dialog
                            progressStepCount++;

                            _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, LauncherResources.Step_WaitingForDeviceToComeOnline);
                            progressCurrentIndex++;

                            const int waitTimePerIteration = 50;
                            const int maxTries = 5000 / waitTimePerIteration; // We will wait for up to 5 seconds

                            // NOTE: libadb has device discovery built in which we could allegedly use instead of a retry loop,
                            // but I couldn't get this to work (though the problem is so rare, I had a lot of trouble testing it), so just using
                            // a retry loop.
                            for (int cTry = 0; true; cTry++)
                            {
                                if (cTry == maxTries)
                                {
                                    throw new LauncherException(Telemetry.LaunchFailureCode.DeviceOffline, LauncherResources.Error_DeviceOffline);
                                }

                                // Sleep for a little while unless this operation is canceled
                                if (token.WaitHandle.WaitOne(waitTimePerIteration))
                                {
                                    throw new OperationCanceledException();
                                }

                                if (!device.GetState().HasFlag(DeviceState.Offline))
                                {
                                    break; // we are no longer offline
                                }
                            }
                        }
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }
                }));

                actions.Add(new NamedAction(LauncherResources.Step_InspectingDevice, () =>
                {
                    try
                    {
                        DeviceAbi deviceAbi = device.Abi;
                        if (deviceAbi == DeviceAbi.unknown)
                            deviceAbi = device.Abi2;

                        switch (_launchOptions.TargetArchitecture)
                        {
                            case TargetArchitecture.ARM:
                                if (deviceAbi != DeviceAbi.armeabi && deviceAbi != DeviceAbi.armeabiv7a)
                                {
                                    throw GetBadDeviceAbiException(deviceAbi);
                                }
                                break;

                            case TargetArchitecture.X86:
                                if (deviceAbi != DeviceAbi.x86)
                                {
                                    throw GetBadDeviceAbiException(deviceAbi);
                                }
                                break;

                            default:
                                Debug.Fail("New target architucture support added without updating this code???");
                                throw new InvalidOperationException();
                        }

                        if (_launchOptions.TargetArchitecture == TargetArchitecture.ARM && device.IsEmulator)
                        {
                            _isUsingArmEmulator = true;
                        }

                        _shell = device.Shell;
                    }
                    catch (AdbException)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.DeviceNotResponding, LauncherResources.Error_DeviceNotResponding);
                    }

                    VerifySdkVersion();

                    string pwdCommand = string.Concat("run-as ", _launchOptions.Package, " /system/bin/sh -c pwd");
                    ExecCommand(pwdCommand);
                    workingDirectory = ParsePwdOutput(_shell.Out);

                    // Kill old processes to make sure we aren't confused and think an old process is still arround
                    gdbServerRemotePath = workingDirectory + "/lib/gdbserver";
                    KillOldInstances(gdbServerRemotePath);

                    string lsCommand = string.Format(CultureInfo.InvariantCulture, "ls {0}", gdbServerRemotePath);
                    string output = ExecCommand(lsCommand);
                    if (string.Compare(output, gdbServerRemotePath, StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        throw new LauncherException(Telemetry.LaunchFailureCode.NoGdbServer, string.Format(CultureInfo.CurrentCulture, LauncherResources.Error_NoGdbServer, gdbServerRemotePath));
                    }
                }));

                if (!_launchOptions.IsAttach)
                {
                    actions.Add(new NamedAction(LauncherResources.Step_StartingApp, () =>
                    {
                        string activateCommand = string.Concat("am start -D -n ", _launchOptions.Package, "/", _launchOptions.LaunchActivity);
                        ExecCommand(activateCommand);
                        ValidateActivityManagerOutput(activateCommand, _shell.Out);
                    }));
                }

                actions.Add(new NamedAction(LauncherResources.Step_GettingAppProcessId, () =>
                {
                    _appProcessId = GetAppProcessId();
                }));

                actions.Add(new NamedAction(LauncherResources.Step_StartGDBServer, () =>
                {
                    // We will default to using a unix socket with gdbserver as this is what the ndk-gdb script uses. Though we have seen
                    // some machines where this doesn't work and we fall back to TCP instead.
                    const bool useUnixSocket = true;

                    taskGdbServer = StartGdbServer(gdbServerRemotePath, workingDirectory, useUnixSocket, out gdbServerSocketDescription);
                }));

                actions.Add(new NamedAction(LauncherResources.Step_PortForwarding, () =>
                {
                    // TODO: Use a dynamic socket
                    gdbPortNumber = 5039;
                    _jdbPortNumber = 65534;

                    device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", gdbPortNumber), gdbServerSocketDescription);
                    if (!_launchOptions.IsAttach)
                    {
                        device.Forward(string.Format(CultureInfo.InvariantCulture, "tcp:{0}", _jdbPortNumber), string.Format(CultureInfo.InvariantCulture, "jdwp:{0}", _appProcessId));
                    }
                }));

                actions.Add(new NamedAction(LauncherResources.Step_DownloadingFiles, () =>
                {
                    //pull binaries from the emulator/device
                    var fileSystem = device.FileSystem;

                    fileSystem.Download(@"/system/bin/app_process", Path.Combine(_launchOptions.IntermediateDirectory, "app_process"), true);
                    fileSystem.Download(@"/system/bin/linker", Path.Combine(_launchOptions.IntermediateDirectory, "linker"), true);
                    fileSystem.Download(@"/system/lib/libc.so", Path.Combine(_launchOptions.IntermediateDirectory, "libc.so"), true);
                }));

                progressStepCount = actions.Count;

                foreach (NamedAction namedAction in actions)
                {
                    token.ThrowIfCancellationRequested();

                    _waitLoop.SetProgress(progressStepCount, progressCurrentIndex, namedAction.Name);
                    progressCurrentIndex++;
                    namedAction.Action();
                }

                _waitLoop.SetProgress(progressStepCount, progressStepCount, string.Empty);

                if (taskGdbServer.IsCompleted)
                {
                    token.ThrowIfCancellationRequested();
                    throw new LauncherException(Telemetry.LaunchFailureCode.GDBServerFailed, LauncherResources.Error_GDBServerFailed);
                }

                if (_launchOptions.LogcatServiceId != Guid.Empty)
                {
                    _eventCallback.OnCustomDebugEvent(_launchOptions.LogcatServiceId, new Guid(LogcatServiceMessage_SourceId), LogcatServiceMessage_NewProcess, _appProcessId, null);
                }

                var launchOptions = new LocalLaunchOptions(_installPaths.GDBPath, string.Format(CultureInfo.InvariantCulture, ":{0}", gdbPortNumber));
                launchOptions.AdditionalSOLibSearchPath = _launchOptions.AdditionalSOLibSearchPath;
                launchOptions.TargetArchitecture = _launchOptions.TargetArchitecture;
                launchOptions.WorkingDirectory = _launchOptions.IntermediateDirectory;
                launchOptions.ExePath = Path.Combine(_launchOptions.IntermediateDirectory, "app_process");
                launchOptions.DebuggerMIMode = MIMode.Gdb;
                launchOptions.VisualizerFile = "Microsoft.Android.natvis";

                return launchOptions;
            }
        }
Beispiel #7
0
        /// <summary>
        /// Resolves the various file paths used by the AndroidDebugLauncher and returns an initialized InstallPaths object
        /// </summary>
        /// <param name="token">token to check for cancelation</param>
        /// <param name="launchOptions">[Required] launch options object</param>
        /// <returns>[Required] Created InstallPaths object</returns>
        public static InstallPaths Resolve(CancellationToken token, AndroidLaunchOptions launchOptions, MICore.Logger logger)
        {
            var result = new InstallPaths();

            if (launchOptions.SDKRoot != null)
            {
                result.SDKRoot = launchOptions.SDKRoot;
            }
            else
            {
                result.SDKRoot = GetDirectoryFromRegistry(@"SOFTWARE\Android SDK Tools", "Path", checkBothBitnesses: true, externalProductName: LauncherResources.ProductName_SDK);
            }

            string ndkRoot = launchOptions.NDKRoot;
            if (ndkRoot == null)
            {
                ndkRoot = GetDirectoryFromRegistry(RegistryRoot.Value + @"\Setup\VS\SecondaryInstaller\AndroidNDK", "NDK_HOME", checkBothBitnesses: false, externalProductName: LauncherResources.ProductName_NDK);
            }

            NdkReleaseId ndkReleaseId = new NdkReleaseId();
            string ndkReleaseVersionFile = Path.Combine(ndkRoot, "RELEASE.TXT");
            string ndkSourcePropertiesFile = Path.Combine(ndkRoot, "source.properties");

            // NDK releases >= r11 have a source.properties file
            if (File.Exists(ndkSourcePropertiesFile))
            {
                NdkReleaseId.TryParsePropertiesFile(ndkSourcePropertiesFile, out ndkReleaseId);
            }
            // NDK releases < r11 have a RELEASE.txt file
            else if (File.Exists(ndkReleaseVersionFile))
            {
                NdkReleaseId.TryParseFile(ndkReleaseVersionFile, out ndkReleaseId);
            }
            else
            {
                ThrowExternalFileNotFoundException(ndkReleaseVersionFile, LauncherResources.ProductName_NDK);
            }

            logger.WriteLine("Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);

            // 32 vs 64-bit doesn't matter when comparing
            var r11 = new NdkReleaseId(11, 'a');
            // In NDK r11 and later, gdb is multi-arch and there's only one binary
            // in the prebuilt directory
            bool usePrebuiltGDB = ndkReleaseId.CompareVersion(r11) >= 0;
            IEnumerable<INDKFilePath> prebuiltGDBPath = NDKPrebuiltFilePath.GDBPaths();

            string targetArchitectureName = launchOptions.TargetArchitecture.ToNDKArchitectureName();
            IEnumerable<INDKFilePath> possibleGDBPaths;

            switch (launchOptions.TargetArchitecture)
            {
                case MICore.TargetArchitecture.X86:
                    possibleGDBPaths = usePrebuiltGDB ? prebuiltGDBPath: NDKToolChainFilePath.x86_GDBPaths();
                    break;

                case MICore.TargetArchitecture.X64:
                    possibleGDBPaths = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.x64_GDBPaths();
                    break;

                case MICore.TargetArchitecture.ARM:
                    possibleGDBPaths = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.ARM_GDBPaths();
                    break;

                case MICore.TargetArchitecture.ARM64:
                    possibleGDBPaths = usePrebuiltGDB ? prebuiltGDBPath : NDKToolChainFilePath.ARM64_GDBPaths();
                    break;

                default:
                    Debug.Fail("Should be impossible");
                    throw new InvalidOperationException();
            }

            INDKFilePath gdbMatchedPath;
            result.GDBPath = GetNDKFilePath(
                string.Concat("Android-", targetArchitectureName, "-GDBPath"),
                ndkRoot,
                possibleGDBPaths,
                out gdbMatchedPath
                );
            if (launchOptions.TargetArchitecture == MICore.TargetArchitecture.X86 && gdbMatchedPath != null)
            {
                var r10b = new NdkReleaseId(10, 'b');

                // Before r10b, the 'windows-x86_64' ndk didn't support x86 debugging
                if (ndkReleaseId.IsValid && ndkReleaseId.CompareVersion(r10b) < 0 && gdbMatchedPath.PartialFilePath.Contains(@"\windows-x86_64\"))
                {
                    throw new LauncherException(Telemetry.LaunchFailureCode.NoReport, LauncherResources.Error_64BitNDKNotSupportedForX86);
                }
            }

            IEnumerable<INDKFilePath> gdbServerPath = NDKPrebuiltFilePath.GDBServerPaths(targetArchitectureName);
            INDKFilePath gdbServerMatchedPath;
            result.GDBServerPath = GetNDKFilePath(
                string.Concat("Android-", targetArchitectureName, "-GDBServerPath"),
                ndkRoot,
                gdbServerPath,
                out gdbServerMatchedPath // not used
                );

            token.ThrowIfCancellationRequested();

            return result;
        }