Skip to content
Open
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
45 changes: 44 additions & 1 deletion app/src/main/java/com/winlator/XServerDisplayActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,43 @@ private void exit() {
AppUtils.restartApplication(this);
}

private void showCrashDialog(int exitCode) {
String signalName = getSignalName(exitCode);
String exitInfo = "Exit code: " + exitCode + (signalName != null ? " (" + signalName + ")" : "");

ArrayList<String> logLines = ProcessHelper.getCrashLogSnapshot();
StringBuilder logText = new StringBuilder();
logText.append(exitInfo).append("\n\n");
if (logLines.isEmpty()) {
logText.append("No debug output captured.\nEnable Wine debug or Box86/64 logs in Settings for more detail.");
} else {
logText.append("Last ").append(logLines.size()).append(" lines of output:\n\n");
for (String line : logLines) logText.append(line).append("\n");
}

ContentDialog dialog = new ContentDialog(this);
dialog.setTitle(getString(R.string.process_crashed));
dialog.setCancelable(false);
dialog.setMessage(logText.toString());
dialog.setOnConfirmCallback(this::exit);
dialog.show();
}

private static String getSignalName(int exitCode) {
if (exitCode < 128) return null;
switch (exitCode - 128) {
case 4: return "Illegal instruction";
case 6: return "Aborted";
case 7: return "Bus error";
case 8: return "Floating point exception";
case 9: return "Killed";
case 11: return "Segmentation fault";
case 13: return "Broken pipe";
case 15: return "Terminated";
default: return "Signal " + (exitCode - 128);
}
}

private void setupWineSystemFiles() {
String appVersion = String.valueOf(AppUtils.getVersionCode(this));
String imgVersion = String.valueOf(imageFs.getVersion());
Expand Down Expand Up @@ -449,7 +486,13 @@ else if (audioDriver.equals("pulseaudio")) {
}

guestProgramLauncherComponent.setEnvVars(envVars);
guestProgramLauncherComponent.setTerminationCallback((status) -> exit());
guestProgramLauncherComponent.setTerminationCallback((status) -> {
if (status != 0) {
runOnUiThread(() -> showCrashDialog(status));
} else {
exit();
}
});
environment.addComponent(guestProgramLauncherComponent);

if (isGenerateWineprefix()) generateWineprefix();
Expand Down
24 changes: 20 additions & 4 deletions app/src/main/java/com/winlator/core/ProcessHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public abstract class ProcessHelper {
private static final ArrayList<Callback<String>> debugCallbacks = new ArrayList<>();
private static final byte SIGCONT = 18;
private static final byte SIGSTOP = 19;
private static final int CRASH_LOG_BUFFER_SIZE = 200;
private static final ArrayList<String> crashLogBuffer = new ArrayList<>();

public static void suspendProcess(int pid) {
Process.sendSignal(pid, SIGSTOP);
Expand Down Expand Up @@ -46,10 +48,8 @@ public static int exec(String command, String[] envp, File workingDir, Callback<
pid = pidField.getInt(process);
pidField.setAccessible(false);

if (!debugCallbacks.isEmpty()) {
createDebugThread(process.getInputStream());
createDebugThread(process.getErrorStream());
}
createDebugThread(process.getInputStream());
createDebugThread(process.getErrorStream());

if (terminationCallback != null) createWaitForThread(process, terminationCallback);
}
Expand All @@ -63,6 +63,10 @@ private static void createDebugThread(final InputStream inputStream) {
String line;
while ((line = reader.readLine()) != null) {
if (PRINT_DEBUG) System.out.println(line);
synchronized (crashLogBuffer) {
crashLogBuffer.add(line);
while (crashLogBuffer.size() > CRASH_LOG_BUFFER_SIZE) crashLogBuffer.remove(0);
}
synchronized (debugCallbacks) {
if (!debugCallbacks.isEmpty()) {
for (Callback<String> callback : debugCallbacks) callback.call(line);
Expand Down Expand Up @@ -102,6 +106,18 @@ public static void removeDebugCallback(Callback<String> callback) {
}
}

public static ArrayList<String> getCrashLogSnapshot() {
synchronized (crashLogBuffer) {
return new ArrayList<>(crashLogBuffer);
}
}

public static void clearCrashLog() {
synchronized (crashLogBuffer) {
crashLogBuffer.clear();
}
}

public static String[] splitCommand(String command) {
ArrayList<String> result = new ArrayList<>();
boolean startedQuotes = false;
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,5 @@
<string name="msg_warning_install_wine">Warning: Installing a new version of Wine is recommended for testing purposes only.</string>
<string name="startup_selection">Startup Selection</string>
<string name="wine_debug_channel">Wine Debug Channel</string>
<string name="process_crashed">Process Crashed</string>
</resources>