Skip to content
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 @@ -29,9 +29,12 @@
import org.robovm.compiler.config.StripArchivesConfig.StripArchivesBuilder;
import org.robovm.compiler.log.ConsoleLogger;
import org.robovm.compiler.plugin.*;
import org.robovm.compiler.target.ConsoleTarget;
import org.robovm.compiler.target.console.ConsoleTarget;
import org.robovm.compiler.target.LaunchParameters;
import org.robovm.compiler.target.ios.*;
import org.robovm.compiler.target.ios.simulator.DeviceType;
import org.robovm.compiler.target.ios.simulator.IOSSimulatorLaunchParameters;
import org.robovm.compiler.target.ios.simulator.SimCtl;
import org.robovm.compiler.util.AntPathMatcher;
import org.simpleframework.xml.Serializer;

Expand Down Expand Up @@ -1034,7 +1037,7 @@ public void launchAsyncCleanup() {
}

private static void printDeviceTypesAndExit() throws IOException {
List<DeviceType> types = DeviceType.listDeviceTypes();
List<DeviceType> types = SimCtl.list();
for (DeviceType type : types) {
System.out.println(type.getSimpleDeviceTypeId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.robovm.compiler.plugin.debug.DebuggerLaunchPlugin;
import org.robovm.compiler.plugin.invokedynamic.InvokeDynamicCompilerPlugin;
import org.robovm.compiler.plugin.objc.*;
import org.robovm.compiler.target.ConsoleTarget;
import org.robovm.compiler.target.console.ConsoleTarget;
import org.robovm.compiler.target.Target;
import org.robovm.compiler.target.framework.FrameworkTarget;
import org.robovm.compiler.target.ios.IOSTarget;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,16 @@
import org.robovm.compiler.plugin.LaunchPlugin;
import org.robovm.compiler.plugin.PluginArgument;
import org.robovm.compiler.plugin.PluginArguments;
import org.robovm.compiler.target.ConsoleTarget;
import org.robovm.compiler.target.LaunchParameters;
import org.robovm.compiler.target.Target;
import org.robovm.compiler.target.ios.IOSDeviceLaunchParameters;
import org.robovm.compiler.target.ios.IOSTarget;
import org.robovm.compiler.target.console.ConsoleLaunchParameters;
import org.robovm.compiler.target.ios.IIOSLaunchParameters;
import org.robovm.debugger.Debugger;
import org.robovm.debugger.DebuggerConfig;
import org.robovm.debugger.DebuggerException;
import org.robovm.debugger.hooks.IHooksConnection;
import org.robovm.libimobiledevice.IDeviceConnection;
import org.robovm.libimobiledevice.util.AppLauncherCallback;
import org.robovm.debugger.utils.IHooksConnectionUtils.DelegatingFuture;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -103,49 +96,22 @@ public void beforeLaunch(Config config, LaunchParameters parameters) {
builder.setLogDir(new File(logDir));
builder.setArch(DebuggerConfig.Arch.valueOf(target.getArch().getCpuArch().name()));

// make list of arguments for target
if (ConsoleTarget.TYPE.equals(target.getType())) {
// specific settings depending on launch type
if (parameters instanceof ConsoleLaunchParameters) {
File appDir = config.isSkipInstall() ? config.getTmpDir() : config.getInstallDir();
builder.setAppfile(new File(appDir, config.getExecutableName()));

File hooksPortFile;
try {
hooksPortFile = File.createTempFile("robovm-dbg-console", ".port");
builder.setHooksPortFile(hooksPortFile);
} catch (IOException e) {
throw new CompilerException("Failed to create debugger port file", e);
}

parameters.getArguments().add("-rvm:PrintDebugPort=" + hooksPortFile.getAbsolutePath());
} else if (IOSTarget.TYPE.equals(target.getType())) {
} else if (parameters instanceof IIOSLaunchParameters) {
// all ios
File appDir = new File(config.isSkipInstall() ? config.getTmpDir() : config.getInstallDir(), config.getExecutableName() + ".app");
builder.setAppfile(new File(appDir, config.getExecutableName()));

if (IOSTarget.isSimulatorArch(config.getArch())) {
// launching on simulator, it can write down port number to file on local system
File hooksPortFile;
try {
hooksPortFile = File.createTempFile("robovm-dbg-sim", ".port");
builder.setHooksPortFile(hooksPortFile);
} catch (IOException e) {
throw new CompilerException("Failed to create simulator debuuger port file", e);
}

parameters.getArguments().add("-rvm:PrintDebugPort=" + hooksPortFile.getAbsolutePath());
} else {
// launching on device
IOSDeviceLaunchParameters deviceLaunchParameters = (IOSDeviceLaunchParameters) parameters;
DebuggerLauncherCallback callback = new DebuggerLauncherCallback();
deviceLaunchParameters.setAppLauncherCallback(callback);
deviceLaunchParameters.getArguments().add("-rvm:PrintDebugPort");

// wait for hooks channel from launch callback
builder.setHooksConnection(callback);
}
} else {
throw new IllegalArgumentException("Unsupported target " + target.getType());
}

// tell launcher that debugger/hooks connection is expected
DelegatingFuture<IHooksConnection> connectionPromise = new DelegatingFuture<>();
builder.setHooksConnectionPromise(connectionPromise);
parameters.setRequestForDebuggerConnection(connectionPromise);
debuggerConfig = builder.build();
}

Expand Down Expand Up @@ -192,102 +158,4 @@ boolean argumentBoolValue(Map<String, String> arguments, String key) {

return Boolean.parseBoolean(v);
}

/**
* callback to receive hook port from device to connect debugger to.
* device will print out [DEBUG] hooks: debugPort=
* check hooks.c/_rvmHookSetupTCPChannel for details
* implements hooks connection interface to provide in and out streams
*/
private static class DebuggerLauncherCallback implements AppLauncherCallback, IHooksConnection {
private final static String tag = "[DEBUG] hooks: debugPort=";
private volatile Integer hooksPort;
private IDeviceConnection deviceConnection;
private String incompleteLine;
private AppLauncherInfo launchInfo;


@Override
public void setAppLaunchInfo(AppLauncherInfo info) {
launchInfo = info;
}

@Override
public byte[] filterOutput(byte[] data) {
if (hooksPort == null) {
// port is not received yet, keep working
String str = new String(data, StandardCharsets.UTF_8);
if (incompleteLine != null) {
str = incompleteLine + str;
incompleteLine = null;
}

int lookingPos = 0;
int newLineIdx = str.indexOf('\n');
while (newLineIdx >= 0 ) {
// get next new line
if (str.startsWith(tag, lookingPos)) {
// got it
hooksPort = Integer.parseInt(str.substring(lookingPos + tag.length(), newLineIdx).trim());
break;
} else {
// move to next line
lookingPos = newLineIdx + 1;
newLineIdx = str.indexOf('\n', newLineIdx + 1);
}
}

// keep trailing line (without eol)
if (hooksPort == null && lookingPos < str.length()) {
incompleteLine = lookingPos != 0 ? str.substring(lookingPos) : str;
}
}

return data;
}

/**
* waits till port hooks port is available and establish connection
*/
@Override
public void connect() {
try {
// FIXME: waiting for app to be deployed and prepared, its should not use TARGET_WAIT_TIMEOUT time
// and it has to be moved to pre-launch sequence
long ts = System.currentTimeMillis();
while (launchInfo == null) {
if (System.currentTimeMillis() - ts > DebuggerConfig.TARGET_DEPLOY_TIMEOUT)
throw new DebuggerException("Timeout while waiting app is deployed");
Thread.sleep(200);
}

// waiting for target to start and hooks are available
ts = System.currentTimeMillis();
while (hooksPort == null) {
if (System.currentTimeMillis() - ts > DebuggerConfig.TARGET_WAIT_TIMEOUT)
throw new DebuggerException("Timeout while waiting app is responding on device");
Thread.sleep(200);
}

deviceConnection = launchInfo.getDevice().connect(hooksPort);
} catch (InterruptedException e) {
throw new DebuggerException(e);
}
}

@Override
public void disconnect() {
deviceConnection.close();
}

@Override
public InputStream getInputStream() {
return deviceConnection.getInputStream();
}

@Override
public OutputStream getOutputStream() {
return deviceConnection.getOutputStream();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ public boolean canLaunch() {
public void prepareLaunch() throws IOException {
}

@Override
public LaunchParameters createLaunchParameters() {
return new LaunchParameters();
}

public String getInstallRelativeArchivePath(Path path) {
String name = config.getArchiveName(path);
if (path.isInBootClasspath()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,26 @@
*/
package org.robovm.compiler.target;

import org.robovm.debugger.hooks.IHooksConnection;
import org.robovm.debugger.utils.IHooksConnectionUtils.DelegatingFuture;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* Base class for parameters used to launch the app on different targets
*/
public class LaunchParameters {
private List<String> arguments = new ArrayList<>();
public abstract class LaunchParameters {
private final List<String> arguments = new ArrayList<>();
private Map<String, String> environment = null;
private File workingDirectory = new File(".");
private File stdoutFifo = null;
private File stderrFifo = null;

/// debugger support
private DelegatingFuture<IHooksConnection> requestForDebuggerConnection = null;

public List<String> getArguments() {
return arguments;
Expand Down Expand Up @@ -90,4 +97,25 @@ public File getStderrFifo() {
public void setStderrFifo(File stderrFifo) {
this.stderrFifo = stderrFifo;
}


public DelegatingFuture<IHooksConnection> getRequestForDebuggerConnection() {
return requestForDebuggerConnection;
}

/**
* Sets Future debugger will wait to retrieve debug connection to target.
* Launchers expected to take additional steps to capture information about
* connection (e.g. capture port from std output or from file)
* <p>
* If launcher is not able to provide such information or debug mode is not supported
* it should complete feature with exception
* <p>
* if `requestForDebugConnection` wasn't set -- Launcher should launch without preparing
* for debug
*/
public LaunchParameters setRequestForDebuggerConnection(DelegatingFuture<IHooksConnection> request) {
this.requestForDebuggerConnection = request;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2025 The MobiVM Contributors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.compiler.target.console;

import org.robovm.compiler.target.LaunchParameters;

/**
* Launch parameters dedicated for console tartget
*/
public class ConsoleLaunchParameters extends LaunchParameters {
}
Loading
Loading