Skip to content

customRequest 'processId' to get the debugging Java process id #399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.microsoft.java.debug.core.adapter.handler.InitializeRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.InlineValuesRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.ProcessIdHandler;
import com.microsoft.java.debug.core.adapter.handler.RefreshVariablesHandler;
import com.microsoft.java.debug.core.adapter.handler.RestartFrameHandler;
import com.microsoft.java.debug.core.adapter.handler.ScopesRequestHandler;
Expand Down Expand Up @@ -125,10 +126,11 @@ private void initialize() {
registerHandlerForDebug(new SetDataBreakpointsRequestHandler());
registerHandlerForDebug(new InlineValuesRequestHandler());
registerHandlerForDebug(new RefreshVariablesHandler());
registerHandlerForDebug(new ProcessIdHandler());

// NO_DEBUG mode only
registerHandlerForNoDebug(new DisconnectRequestWithoutDebuggingHandler());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I debug Boot App via "Debug" action i get this back:

{"processId":0,"shellProcessId":78134}

which is great.

However, when i run the app via the "Run" action i get an error back:

Error: {"name":"Error","message":"custom request failed"}

Is it possible to make it work with "Run" action?

I thought the change for this would be instead of registerHandlerForDebug(...) call registerHandler(...) but this didn't work for me and i hope also because i messed up the build...

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we can support it in "Run" as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added 'processId' request in Run action as well.

If the Run action is running with internalConsole, it works fine.

However, if the Run action is triggered on terminal shell, it may not work. In this case, Java debugger will terminate the DAP debug session early once the RunInTerminal request is responded. You may not have opportunity to call custom request to get processId.

We have a TODO task to not terminate DAP session when triggering a Run with integratedTerminal, which requires more work and may not be done right away.


registerHandlerForNoDebug(new ProcessIdHandler());
}

private void registerHandlerForDebug(IDebugRequestHandler handler) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public class DebugAdapterContext implements IDebugAdapterContext {
private Path classpathJar = null;
private Path argsfile = null;

private long shellProcessId = -1;
private long processId = -1;

private IdCollection<String> sourceReferences = new IdCollection<>();
private RecyclableObjectPool<Long, Object> recyclableIdPool = new RecyclableObjectPool<>();
private IVariableFormatter variableFormatter = VariableFormatterFactory.createVariableFormatter();
Expand Down Expand Up @@ -326,4 +329,24 @@ public IBreakpointManager getBreakpointManager() {
public IStepResultManager getStepResultManager() {
return stepResultManager;
}

@Override
public long getProcessId() {
return this.processId;
}

@Override
public long getShellProcessId() {
return this.shellProcessId;
}

@Override
public void setProcessId(long processId) {
this.processId = processId;
}

@Override
public void setShellProcessId(long shellProcessId) {
this.shellProcessId = shellProcessId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,12 @@ public interface IDebugAdapterContext {
IBreakpointManager getBreakpointManager();

IStepResultManager getStepResultManager();

void setShellProcessId(long shellProcessId);

long getShellProcessId();

void setProcessId(long processId);

long getProcessId();
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ protected CompletableFuture<Response> handleLaunchCommand(Arguments arguments, R
}

return launch(launchArguments, response, context).thenCompose(res -> {
long processId = context.getProcessId();
long shellProcessId = context.getShellProcessId();
if (context.getDebuggeeProcess() != null) {
processId = context.getDebuggeeProcess().pid();
}

// If processId or shellProcessId exist, send a notification to client.
if (processId > 0 || shellProcessId > 0) {
context.getProtocolServer().sendEvent(new Events.ProcessIdNotification(processId, shellProcessId));
}

LaunchUtils.releaseTempLaunchFile(context.getClasspathJar());
LaunchUtils.releaseTempLaunchFile(context.getArgsfile());
if (res.success) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.commons.lang3.SystemUtils;

import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.DebugException;
import com.microsoft.java.debug.core.DebugSession;
Expand All @@ -45,6 +46,7 @@
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
import com.microsoft.java.debug.core.protocol.Requests.RunInTerminalRequestArguments;
import com.microsoft.java.debug.core.protocol.Responses.RunInTerminalResponseBody;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
Expand Down Expand Up @@ -102,6 +104,14 @@ public CompletableFuture<Response> launchInTerminal(LaunchArguments launchArgume
if (runResponse != null) {
if (runResponse.success) {
try {
try {
RunInTerminalResponseBody terminalResponse = JsonUtils.fromJson(
JsonUtils.toJson(runResponse.body), RunInTerminalResponseBody.class);
context.setProcessId(terminalResponse.processId);
context.setShellProcessId(terminalResponse.shellProcessId);
} catch (JsonSyntaxException e) {
logger.severe("Failed to resolve runInTerminal response: " + e.toString());
}
VirtualMachine vm = listenConnector.accept(args);
vmHandler.connectVirtualMachine(vm);
context.setDebugSession(new DebugSession(vm));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.logging.Logger;

import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.DebugException;
import com.microsoft.java.debug.core.adapter.ErrorCode;
Expand All @@ -33,6 +34,7 @@
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Requests.LaunchArguments;
import com.microsoft.java.debug.core.protocol.Requests.RunInTerminalRequestArguments;
import com.microsoft.java.debug.core.protocol.Responses.RunInTerminalResponseBody;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.VMStartException;

Expand Down Expand Up @@ -112,8 +114,19 @@ public CompletableFuture<Response> launchInTerminal(LaunchArguments launchArgume
context.getProtocolServer().sendRequest(request, RUNINTERMINAL_TIMEOUT).whenComplete((runResponse, ex) -> {
if (runResponse != null) {
if (runResponse.success) {
// Without knowing the pid, debugger has lost control of the process.
// So simply send `terminated` event to end the session.
try {
RunInTerminalResponseBody terminalResponse = JsonUtils.fromJson(
JsonUtils.toJson(runResponse.body), RunInTerminalResponseBody.class);
context.setProcessId(terminalResponse.processId);
context.setShellProcessId(terminalResponse.shellProcessId);
} catch (JsonSyntaxException e) {
logger.severe("Failed to resolve runInTerminal response: " + e.toString());
}

// TODO: Since the RunInTerminal request will return the pid or parent shell
// pid now, the debugger is able to use this pid to monitor the lifecycle
// of the running Java process. There is no need to terminate the debug
// session early here.
context.getProtocolServer().sendEvent(new Events.TerminatedEvent());
resultFuture.complete(response);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2022 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter.handler;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Responses.ProcessIdResponseBody;

public class ProcessIdHandler implements IDebugRequestHandler {
@Override
public List<Command> getTargetCommands() {
return Arrays.asList(Command.PROCESSID);
}

@Override
public CompletableFuture<Response> handle(Command command, Arguments arguments, Response response,
IDebugAdapterContext context) {
long processId = context.getProcessId();
long shellProcessId = context.getShellProcessId();
if (context.getDebuggeeProcess() != null) {
processId = context.getDebuggeeProcess().pid();
}

response.body = new ProcessIdResponseBody(processId, shellProcessId);
return CompletableFuture.completedFuture(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,26 @@ public InvalidatedEvent(InvalidatedAreas area, int frameId) {
this.frameId = frameId;
}
}

public static class ProcessIdNotification extends DebugEvent {
/**
* The process ID.
*/
public long processId = -1;
/**
* The process ID of the terminal shell if the process is running in a terminal shell.
*/
public long shellProcessId = -1;

public ProcessIdNotification(long processId) {
super("processid");
this.processId = processId;
}

public ProcessIdNotification(long processId, long shellProcessId) {
super("processid");
this.processId = processId;
this.shellProcessId = shellProcessId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ public static enum Command {
PAUSEOTHERS("pauseOthers", ThreadOperationArguments.class),
INLINEVALUES("inlineValues", InlineValuesArguments.class),
REFRESHVARIABLES("refreshVariables", RefreshVariablesArguments.class),
PROCESSID("processId", Arguments.class),
UNSUPPORTED("", Arguments.class);

private String command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,34 @@ public InitializeResponseBody(Types.Capabilities capabilities) {
}
}

public static class RunInTerminalResponseBody extends ResponseBody {
public int processId;
public static class ProcessIdResponseBody extends ResponseBody {
/**
* The process ID.
*/
public long processId = -1;
/**
* The process ID of the terminal shell if the process is running in a terminal shell.
*/
public long shellProcessId = -1;

public ProcessIdResponseBody(long processId) {
this.processId = processId;
}

public RunInTerminalResponseBody(int processId) {
public ProcessIdResponseBody(long processId, long shellProcessId) {
this.processId = processId;
this.shellProcessId = shellProcessId;
}
}

public static class RunInTerminalResponseBody extends ProcessIdResponseBody {

public RunInTerminalResponseBody(long processId) {
super(processId);
}

public RunInTerminalResponseBody(long processId, long shellProcessId) {
super(processId, shellProcessId);
}
}

Expand Down