Exemplo n.º 1
0
        async Task <CreateLaunchResult> CreateLaunchAsync(LaunchParams launchParams,
                                                          ICancelable cancelable, IAction action)
        {
            Task <string> sdkCompatibilityTask = CheckSdkCompatibilityAsync(
                launchParams.GameletName, launchParams.SdkVersion, launchParams.GameletSdkVersion,
                action);

            LaunchGameRequest   launchRequest = null;
            Task <ConfigStatus> parsingTask   =
                Task.Run(() => _launchGameParamsConverter.ToLaunchGameRequest(
                             launchParams, out launchRequest));

            cancelable.ThrowIfCancellationRequested();

            ConfigStatus parsingState = await parsingTask;

            if (parsingState.IsErrorLevel)
            {
                // Critical error occurred while parsing the configuration.
                // Launch can not proceed.
                throw new ConfigurationException(parsingState.ErrorMessage);
            }

            cancelable.ThrowIfCancellationRequested();
            string sdkCompatibilityMessage = await sdkCompatibilityTask;

            cancelable.ThrowIfCancellationRequested();

            var devEvent = new DeveloperLogEvent
            {
                GameLaunchData = new GameLaunchData {
                    RequestId = launchRequest.RequestId
                }
            };

            // Updating the event to record the RequestId in case LaunchGameAsync throws exception.
            action.UpdateEvent(devEvent);
            LaunchGameResponse response =
                await _gameletClient.LaunchGameAsync(launchRequest, action);

            IVsiGameLaunch vsiLaunch =
                _vsiLaunchFactory.Create(response.GameLaunchName,
                                         launchRequest.EnableDeveloperResumeOffer);

            devEvent.GameLaunchData.LaunchId = vsiLaunch.LaunchId;
            action.UpdateEvent(devEvent);
            parsingState.CompressMessages();
            return(new CreateLaunchResult(vsiLaunch, parsingState.WarningMessage,
                                          sdkCompatibilityMessage));
        }
Exemplo n.º 2
0
        public async Task SyncAsync(SshTarget target, string localPath, string remotePath,
                                    ICancelable task, bool force = false)
        {
            if (string.IsNullOrWhiteSpace(localPath))
            {
                throw new ArgumentNullException(nameof(localPath), "Local path should be specified when running ggp_rsync");
            }

            if (string.IsNullOrWhiteSpace(remotePath))
            {
                throw new ArgumentNullException(nameof(remotePath), "Remote path should be specified when running ggp_rsync");
            }

            ProcessManager   processManager = ProcessManager.CreateForCancelableTask(task);
            ProcessStartInfo startInfo      = BuildForGgpSync(target, localPath, remotePath, force);

            using (IProcess process = _remoteProcessFactory.Create(startInfo, int.MaxValue))
            {
                processManager.AddProcess(process);
                process.OutputDataReceived += (sender, args) => {
                    task.ThrowIfCancellationRequested();

                    if (string.IsNullOrWhiteSpace(args.Text))
                    {
                        return;
                    }

                    string data = args.Text.Trim();
                    task.Progress.Report(data);
                };

                process.ErrorDataReceived += (sender, args) => {
                    task.ThrowIfCancellationRequested();
                    if (string.IsNullOrWhiteSpace(args.Text))
                    {
                        return;
                    }

                    string data = args.Text;
                    throw new ProcessException(data);
                };

                await process.RunToExitWithSuccessAsync();
            }

            // Notify client if operation was cancelled.
            task.ThrowIfCancellationRequested();
        }
Exemplo n.º 3
0
        public async Task GetAsync(SshTarget target, string file, string destination,
                                   ICancelable task)
        {
            await ScpAsync(ProcessStartInfoBuilder.BuildForScpGet(file, target, destination),
                           ProcessManager.CreateForCancelableTask(task));

            // Notify client if operation was cancelled.
            task.ThrowIfCancellationRequested();
        }
Exemplo n.º 4
0
 /// <summary>
 /// Run action repeatedly until it returns true, sleeping for the retry delay between
 /// retry attempts.
 /// </summary>
 /// <remarks>The action is attempted at least once, even if the timeout has been
 /// exceeded.
 /// </remarks>
 /// <exception cref="System.TimeoutException">Thrown when timer elapsed
 /// time exceeds the timeout.
 /// </exception>
 /// <exception  cref="OperationCanceledException">Thrown when the task is canceled while
 /// sleeping.
 /// </exception>
 static void RetryWithTimeout(ICancelable task, Func <bool> action, TimeSpan retryDelay,
                              TimeSpan timeout, Stopwatch timer)
 {
     while (!action())
     {
         if (timer.Elapsed > timeout)
         {
             throw new TimeoutException($"Timeout exceeded: {timeout.TotalMilliseconds}ms");
         }
         Trace.WriteLine($"Retrying in {retryDelay.TotalMilliseconds}ms");
         Thread.Sleep((int)retryDelay.TotalMilliseconds);
         task.ThrowIfCancellationRequested();
     }
 }
Exemplo n.º 5
0
        // Polling statuses until we see RunningGame or GameLaunchEnded. IncompleteLaunch,
        // ReadyToPlay and DelayedLaunch are transitioning states.
        async Task PollForLaunchStatusAsync(ICancelable task, IAction action)
        {
            int maxPollCount = (_isDeveloperResumeOfferEnabled
                ? _pollingTimeoutResumeOfferMs
                : _pollingTimeoutMs) / _pollDelayMs;
            int currentPollCount = 0;
            var devEvent         = new DeveloperLogEvent
            {
                GameLaunchData = new GameLaunchData {
                    LaunchId = LaunchId
                }
            };

            action.UpdateEvent(devEvent);
            while (++currentPollCount <= maxPollCount)
            {
                task.ThrowIfCancellationRequested();
                GgpGrpc.Models.GameLaunch launch = await GetLaunchStateAsync(action);

                if (launch.GameLaunchState == GameLaunchState.RunningGame)
                {
                    return;
                }

                if (launch.GameLaunchState == GameLaunchState.GameLaunchEnded)
                {
                    string error =
                        LaunchUtils.GetEndReason(launch.GameLaunchEnded, launch.GameletName);
                    devEvent.GameLaunchData.EndReason = (int)launch.GameLaunchEnded.EndReason;
                    action.UpdateEvent(devEvent);
                    throw new GameLaunchFailError(error);
                }

                await Task.Delay(_pollDelayMs);
            }

            if (currentPollCount > maxPollCount)
            {
                throw new TimeoutException(ErrorStrings.LaunchEndedTimeout);
            }
        }
Exemplo n.º 6
0
        public async Task <DeleteLaunchResult> WaitUntilGameLaunchEndedAsync(
            string gameLaunchName, ICancelable task, IAction action)
        {
            GgpGrpc.Models.GameLaunch launch =
                await _gameletClient.GetGameLaunchStateAsync(gameLaunchName, action);

            int maxPollCount     = _pollingTimeoutMs / _pollDelayMs;
            int currentPollCount = 0;

            while (launch.GameLaunchState != GameLaunchState.GameLaunchEnded &&
                   ++currentPollCount <= maxPollCount)
            {
                task.ThrowIfCancellationRequested();
                await Task.Delay(_pollDelayMs);

                launch = await _gameletClient.GetGameLaunchStateAsync(gameLaunchName, action);
            }

            return(new DeleteLaunchResult(
                       launch, launch.GameLaunchState == GameLaunchState.GameLaunchEnded));
        }
Exemplo n.º 7
0
        public async Task <ILldbAttachedProgram> LaunchAsync(
            ICancelable task, IDebugProcess2 process, Guid programId, uint?attachPid,
            DebuggerOptions.DebuggerOptions debuggerOptions, HashSet <string> libPaths,
            GrpcConnection grpcConnection, int localDebuggerPort, string targetIpAddress,
            int targetPort, IDebugEventCallback2 callback)
        {
            var       launchSucceeded = false;
            Stopwatch launchTimer     = Stopwatch.StartNew();


            // This should be the first request to the DebuggerGrpcServer.  Providing a retry wait
            // time allows us to connect to a DebuggerGrpcServer that is slow to start. Note that
            // we postpone sourcing .lldbinit until we are done with our initialization so that
            // the users can override our defaults.
            var lldbDebugger =
                _lldbDebuggerFactory.Create(grpcConnection, false, TimeSpan.FromSeconds(10));

            if (lldbDebugger == null)
            {
                throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToCreateDebugger);
            }

            if (debuggerOptions[DebuggerOption.CLIENT_LOGGING] == DebuggerOptionState.ENABLED)
            {
                lldbDebugger.EnableLog("lldb", new List <string> {
                    "default", "module"
                });

                // TODO: Disable 'dwarf' logs until we can determine why this
                // causes LLDB to hang.
                // lldbDebugger.EnableLog("dwarf", new List<string> { "default" });
            }

            if (_fastExpressionEvaluation)
            {
                lldbDebugger.EnableFastExpressionEvaluation();
            }

            lldbDebugger.SetDefaultLLDBSettings();

            // Apply .lldbinit after we set our settings so that the user can override our
            // defaults with a custom .lldbinit.
            LoadLocalLldbInit(lldbDebugger);

            // Add exec search paths, so that LLDB can find the executable and any dependent
            // libraries.  If LLDB is able to find the files locally, it won't try to download
            // them from the remote server, saving valuable time on attach.
            foreach (string path in libPaths)
            {
                lldbDebugger.SetLibrarySearchPath(path);
            }

            lldbDebugger.SetAsync(true);

            SbPlatform lldbPlatform;

            switch (_launchOption)
            {
            case LaunchOption.AttachToGame:
            // Fall through.
            case LaunchOption.LaunchGame:
                lldbPlatform = CreateRemotePlatform(grpcConnection, lldbDebugger);
                if (lldbPlatform == null)
                {
                    throw new AttachException(VSConstants.E_FAIL,
                                              ErrorStrings.FailedToCreateLldbPlatform);
                }
                task.ThrowIfCancellationRequested();
                Trace.WriteLine("Attempting to connect debugger");
                task.Progress.Report("Connecting to debugger");

                string connectRemoteUrl      = $"{_lldbConnectUrl}:{localDebuggerPort}";
                string connectRemoteArgument =
                    CreateConnectRemoteArgument(connectRemoteUrl, targetIpAddress, targetPort);

                SbPlatformConnectOptions lldbConnectOptions =
                    _lldbPlatformConnectOptionsFactory.Create(connectRemoteArgument);

                IAction debugerWaitAction =
                    _actionRecorder.CreateToolAction(ActionType.DebugWaitDebugger);

                bool TryConnectRemote()
                {
                    if (lldbPlatform.ConnectRemote(lldbConnectOptions).Success())
                    {
                        return(true);
                    }

                    VerifyGameIsReady(debugerWaitAction);
                    return(false);
                }

                try
                {
                    debugerWaitAction.Record(() => RetryWithTimeout(
                                                 task, TryConnectRemote, _launchRetryDelay,
                                                 _launchTimeout, launchTimer));
                }
                catch (TimeoutException e)
                {
                    throw new AttachException(
                              VSConstants.E_ABORT,
                              ErrorStrings.FailedToConnectDebugger(lldbConnectOptions.GetUrl()), e);
                }
                Trace.WriteLine("LLDB successfully connected");
                break;

            case LaunchOption.AttachToCore:
                lldbPlatform = _lldbPlatformFactory.Create(_localLldbPlatformName, grpcConnection);
                if (lldbPlatform == null)
                {
                    throw new AttachException(VSConstants.E_FAIL,
                                              ErrorStrings.FailedToCreateLldbPlatform);
                }
                break;

            default:
                throw new AttachException(VSConstants.E_ABORT, ErrorStrings.InvalidLaunchOption(
                                              _launchOption.ToString()));
            }

            lldbDebugger.SetSelectedPlatform(lldbPlatform);

            task.ThrowIfCancellationRequested();
            task.Progress.Report("Debugger is attaching (this can take a while)");

            RemoteTarget lldbTarget = null;

            if (_launchOption == LaunchOption.LaunchGame &&
                !string.IsNullOrEmpty(_executableFullPath))
            {
                var createExecutableTargetAction =
                    _actionRecorder.CreateToolAction(ActionType.DebugCreateExecutableTarget);
                createExecutableTargetAction.Record(
                    () => lldbTarget = CreateTarget(lldbDebugger, _executableFullPath));
            }
            else
            {
                lldbTarget = CreateTarget(lldbDebugger, "");
            }

            var lldbListener = CreateListener(grpcConnection);

            // This is required to catch breakpoint change events.
            lldbTarget.AddListener(lldbListener, EventType.STATE_CHANGED);
            var listenerSubscriber = new LldbListenerSubscriber(lldbListener);
            var eventHandler       = new EventHandler <FileUpdateReceivedEventArgs>(
                (s, e) => ListenerSubscriberOnFileUpdateReceived(task, e));

            listenerSubscriber.FileUpdateReceived += eventHandler;
            listenerSubscriber.Start();

            try
            {
                if (_launchOption == LaunchOption.AttachToCore)
                {
                    var       loadCoreAction      = _actionRecorder.CreateToolAction(ActionType.DebugLoadCore);
                    SbProcess lldbDebuggerProcess = null;
                    loadCoreAction.Record(() =>
                                          lldbDebuggerProcess = LoadCore(lldbTarget, loadCoreAction));

                    await _taskContext.Factory.SwitchToMainThreadAsync();

                    return(_attachedProgramFactory.Create(
                               process, programId, _debugEngine, callback, lldbDebugger, lldbTarget,
                               listenerSubscriber, lldbDebuggerProcess,
                               lldbDebugger.GetCommandInterpreter(), true, new NullExceptionManager(),
                               _moduleSearchLogHolder, remotePid: 0));
                }

                // Get process ID.
                uint processId = 0;
                switch (_launchOption)
                {
                case LaunchOption.AttachToGame:
                    if (!attachPid.HasValue)
                    {
                        throw new AttachException(VSConstants.E_ABORT,
                                                  ErrorStrings.FailedToRetrieveProcessId);
                    }

                    processId = attachPid.Value;
                    break;

                case LaunchOption.LaunchGame:
                    // Since we have no way of knowing when the remote process actually
                    // starts, try a few times to get the pid.

                    IAction debugWaitAction =
                        _actionRecorder.CreateToolAction(ActionType.DebugWaitProcess);

                    bool TryGetRemoteProcessId()
                    {
                        if (GetRemoteProcessId(_executableFileName, lldbPlatform, out processId))
                        {
                            return(true);
                        }

                        VerifyGameIsReady(debugWaitAction);
                        return(false);
                    }

                    try
                    {
                        debugWaitAction.Record(() => RetryWithTimeout(
                                                   task, TryGetRemoteProcessId, _launchRetryDelay,
                                                   _launchTimeout, launchTimer));
                    }
                    catch (TimeoutException e)
                    {
                        throw new AttachException(VSConstants.E_ABORT,
                                                  ErrorStrings.FailedToRetrieveProcessId, e);
                    }

                    break;
                }

                Trace.WriteLine("Attaching to pid " + processId);
                var debugAttachAction = _actionRecorder.CreateToolAction(ActionType.DebugAttach);

                SbProcess debuggerProcess = null;
                debugAttachAction.Record(() => {
                    var moduleFileLoadRecorder =
                        _moduleFileLoadRecorderFactory.Create(debugAttachAction);
                    moduleFileLoadRecorder.RecordBeforeLoad(Array.Empty <SbModule>());

                    debuggerProcess = lldbTarget.AttachToProcessWithID(lldbListener, processId,
                                                                       out SbError lldbError);
                    if (lldbError.Fail())
                    {
                        throw new AttachException(
                            VSConstants.E_ABORT,
                            GetLldbAttachErrorDetails(lldbError, lldbPlatform, processId));
                    }

                    RecordModules(lldbTarget, moduleFileLoadRecorder);
                });

                var exceptionManager = _exceptionManagerFactory.Create(debuggerProcess);

                await _taskContext.Factory.SwitchToMainThreadAsync();

                ILldbAttachedProgram attachedProgram = _attachedProgramFactory.Create(
                    process, programId, _debugEngine, callback, lldbDebugger, lldbTarget,
                    listenerSubscriber, debuggerProcess, lldbDebugger.GetCommandInterpreter(),
                    false, exceptionManager, _moduleSearchLogHolder, processId);
                launchSucceeded = true;
                return(attachedProgram);
            }
            finally
            {
                // clean up the SBListener subscriber
                listenerSubscriber.FileUpdateReceived -= eventHandler;
                // stop the SBListener subscriber completely if the game failed to launch
                if (!launchSucceeded)
                {
                    listenerSubscriber.Stop();
                }
            }
        }
Exemplo n.º 8
0
        public async Task <int> LoadModuleFilesAsync(
            IList <SbModule> modules, SymbolInclusionSettings symbolSettings, bool useSymbolStores,
            ICancelable task, IModuleFileLoadMetricsRecorder moduleFileLoadRecorder)
        {
            if (modules == null)
            {
                throw new ArgumentNullException(nameof(modules));
            }

            if (task == null)
            {
                throw new ArgumentNullException(nameof(task));
            }

            if (moduleFileLoadRecorder == null)
            {
                throw new ArgumentNullException(nameof(moduleFileLoadRecorder));
            }

            // Add some metrics to the event proto before attempting to load symbols, so that they
            // are still recorded if the task is aborted or cancelled.
            moduleFileLoadRecorder.RecordBeforeLoad(modules);

            int result = VSConstants.S_OK;

            for (int i = 0; i < modules.Count; ++i)
            {
                SbModule   module    = modules[i];
                TextWriter searchLog = new StringWriter();
                string     name      = module.GetPlatformFileSpec()?.GetFilename() ?? "<unknown>";

                try
                {
                    task.ThrowIfCancellationRequested();

                    if (SkipModule(name, symbolSettings))
                    {
                        await searchLog.WriteLineAsync(
                            SymbolInclusionSettings.ModuleExcludedMessage);

                        continue;
                    }

                    task.Progress.Report($"Loading binary for {name} ({i}/{modules.Count})");

                    (SbModule newModule, bool ok) =
                        await _binaryLoader.LoadBinaryAsync(module, searchLog);

                    if (!ok)
                    {
                        result = VSConstants.E_FAIL;
                        continue;
                    }
                    module = newModule;

                    task.ThrowIfCancellationRequested();
                    task.Progress.Report($"Loading symbols for {name} ({i}/{modules.Count})");
                    var loaded =
                        await _symbolLoader.LoadSymbolsAsync(module, searchLog, useSymbolStores);

                    if (!loaded)
                    {
                        result = VSConstants.E_FAIL;
                        continue;
                    }
                }
                finally
                {
                    _moduleSearchLogHolder.SetSearchLog(module, searchLog.ToString());
                    modules[i] = module;
                }
            }

            moduleFileLoadRecorder.RecordAfterLoad(modules);

            return(result);
        }