Skip to content

Stopped infinite "Handling DRM" bug#1575

Merged
utkarshdalal merged 1 commit into
masterfrom
fix-handling-drm-stuck
Jun 12, 2026
Merged

Stopped infinite "Handling DRM" bug#1575
utkarshdalal merged 1 commit into
masterfrom
fix-handling-drm-stuck

Conversation

@utkarshdalal

@utkarshdalal utkarshdalal commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Description

Sometimes we were getting stuck on Handling DRM. This fixes it by draining the logs.

Recording

Type of Change

  • Bug fix
  • Performance / stability improvement
  • Compatibility improvements
  • Other (requires prior approval)

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

Summary by cubic

Fixes an infinite "Handling DRM" hang by draining process output and shutting down Wine cleanly after interface generation. Also reduces log noise to avoid buffer buildup.

  • Bug Fixes
    • Drain stdout and stderr concurrently in ProcessHelper.execWithOutput, then join drainer threads; append stderr only when requested.
    • Run generate_interfaces_file.exe via wine cmd /c and add wineserver -k to terminate the server after execution in XServerScreen.
    • Remove noisy CPU/GPU temperature debug logs in PerformanceHudView to lower log volume.

Written for commit 832fbd0. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced Wine command execution for interface generation process with improved termination handling and cleanup procedures for stability.
  • Performance Improvements

    • Reduced excessive debug logging output from CPU and GPU temperature monitoring to improve overall system performance and log readability.
  • Refactor

    • Improved process output capture mechanism with enhanced buffering for better reliability and robustness in command execution.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors process output capture to use background drainer threads in ProcessHelper, updates Wine command invocation in XServerScreen to chain wineserver restart, and removes debug temperature logging from the PerformanceHudView.

Changes

Core utilities and UI maintenance updates

Layer / File(s) Summary
Process output capture via background drainer threads
app/src/main/java/com/winlator/core/ProcessHelper.java
ProcessHelper.execWithOutput() now uses dedicated background drainer threads for stdout and stderr that append to StringBuilders, replacing inline stream reading. Process waits for exit, streams close, threads join with timeout, and output builds from accumulated buffers.
Wine interface generation command wrapping
app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt
unpackExecutableFile updates the genCmd string to wrap generate_interfaces_file.exe execution in wine cmd /c and chain wineserver -k restart via shell operator &, instead of invoking the executable directly.
Performance HUD temperature logging removal
app/src/main/java/app/gamenative/ui/widget/PerformanceHudView.kt
readCpuTempC() and readGpuTempC() remove conditional Timber.d debug logs that reported temperature readings and source selection, now returning only the computed temperature without diagnostic logging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through code so clean,
Background threads now gather the scene,
Wine commands restart with flair,
And logs of heat fade in the air.
Maintenance done with grace and care!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: stopping an infinite 'Handling DRM' bug, which directly aligns with the primary objective of this changeset.
Description check ✅ Passed The description covers all required template sections with substantive content: clear problem statement, bug fix type selected, and all checklist items completed. However, the recording section is left empty despite being checked off.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-handling-drm-stuck

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt`:
- Line 4145: The generated command concatenates relDllPath unquoted into genCmd
in XServerScreen.kt causing breakage when the DLL path contains spaces or
metacharacters; change the construction of genCmd (the variable using "wine cmd
/c ... generate_interfaces_file.exe A:\\...") to wrap the A:\... argument in
properly escaped quotes and escape any embedded quotes in relDllPath (e.g.,
replace " with \") so the cmd /c payload receives a single quoted path token;
update the string building around genCmd (and any helper that constructs this
payload) to produce ...generate_interfaces_file.exe "A:\<escaped relDllPath>"...
so wineserver -k remains outside the inner quoted argument.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee05d8df-88fb-4ed4-ae42-b07b1ec6726e

📥 Commits

Reviewing files that changed from the base of the PR and between 3b72ac7 and 832fbd0.

📒 Files selected for processing (3)
  • app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt
  • app/src/main/java/app/gamenative/ui/widget/PerformanceHudView.kt
  • app/src/main/java/com/winlator/core/ProcessHelper.java
💤 Files with no reviewable changes (1)
  • app/src/main/java/app/gamenative/ui/widget/PerformanceHudView.kt

val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
if (origDll.exists()) {
val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Quote and escape the DLL path inside the cmd /c payload.

At Line 4145, relDllPath is concatenated unquoted into wine cmd /c "...". If the path contains spaces (or cmd metacharacters), generate_interfaces_file.exe parsing breaks and may execute unintended fragments. Wrap the A:\... argument in quotes and escape embedded quotes.

Suggested patch
-                                val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
+                                val dllPathArg = relDllPath
+                                    .replace('/', '\\')
+                                    .replace("\"", "\\\"")
+                                val genCmd =
+                                    "wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
val dllPathArg = relDllPath
.replace('/', '\\')
.replace("\"", "\\\"")
val genCmd =
"wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt` at line
4145, The generated command concatenates relDllPath unquoted into genCmd in
XServerScreen.kt causing breakage when the DLL path contains spaces or
metacharacters; change the construction of genCmd (the variable using "wine cmd
/c ... generate_interfaces_file.exe A:\\...") to wrap the A:\... argument in
properly escaped quotes and escape any embedded quotes in relDllPath (e.g.,
replace " with \") so the cmd /c payload receives a single quoted path token;
update the string building around genCmd (and any helper that constructs this
payload) to produce ...generate_interfaces_file.exe "A:\<escaped relDllPath>"...
so wineserver -k remains outside the inner quoted argument.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt">

<violation number="1" location="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt:4145">
P2: The `relDllPath` is interpolated unquoted inside the `cmd /c "..."` payload. If the DLL path contains spaces or cmd metacharacters (e.g., `&`, `^`, `"`), the command will break or execute unintended fragments. Wrap the `A:\...` argument in escaped quotes and escape any embedded quotes in the path.</violation>

<violation number="2" location="app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt:4145">
P2: `&` runs commands sequentially in cmd — if `generate_interfaces_file.exe` hangs, `wineserver -k` never executes</violation>
</file>

<file name="app/src/main/java/com/winlator/core/ProcessHelper.java">

<violation number="1" location="app/src/main/java/com/winlator/core/ProcessHelper.java:253">
P1: Streams are closed before drainer threads finish, which can truncate captured output/logs.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment on lines +253 to +256
try { stdoutStream.close(); } catch (IOException ignored) {}
try { stderrStream.close(); } catch (IOException ignored) {}
stdoutDrainer.join(5_000);
stderrDrainer.join(5_000);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Streams are closed before drainer threads finish, which can truncate captured output/logs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/winlator/core/ProcessHelper.java, line 253:

<comment>Streams are closed before drainer threads finish, which can truncate captured output/logs.</comment>

<file context>
@@ -221,45 +224,43 @@ public static String execWithOutput(String command, String[] envp, File workingD
-            // Process has already exited (we drained its stdout to EOF).
-            // waitFor() reaps the OS process-table entry.
             process.waitFor();
+            try { stdoutStream.close(); } catch (IOException ignored) {}
+            try { stderrStream.close(); } catch (IOException ignored) {}
+            stdoutDrainer.join(5_000);
</file context>
Suggested change
try { stdoutStream.close(); } catch (IOException ignored) {}
try { stderrStream.close(); } catch (IOException ignored) {}
stdoutDrainer.join(5_000);
stderrDrainer.join(5_000);
stdoutDrainer.join(5_000);
stderrDrainer.join(5_000);

val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
if (origDll.exists()) {
val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The relDllPath is interpolated unquoted inside the cmd /c "..." payload. If the DLL path contains spaces or cmd metacharacters (e.g., &, ^, "), the command will break or execute unintended fragments. Wrap the A:\... argument in escaped quotes and escape any embedded quotes in the path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt, line 4145:

<comment>The `relDllPath` is interpolated unquoted inside the `cmd /c "..."` payload. If the DLL path contains spaces or cmd metacharacters (e.g., `&`, `^`, `"`), the command will break or execute unintended fragments. Wrap the `A:\...` argument in escaped quotes and escape any embedded quotes in the path.</comment>

<file context>
@@ -4142,7 +4142,7 @@ private fun unpackExecutableFile(
                             val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
                             if (origDll.exists()) {
-                                val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
+                                val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
                                 Timber.i("Running generate_interfaces_file $genCmd")
                                 val genOutput = guestProgramLauncherComponent.execShellCommand(genCmd)
</file context>
Suggested change
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
val dllPathArg = relDllPath
.replace('/', '\\')
.replace("\"", "\\\"")
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe \\\"A:\\$dllPathArg\\\" & wineserver -k\""

val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
if (origDll.exists()) {
val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: & runs commands sequentially in cmd — if generate_interfaces_file.exe hangs, wineserver -k never executes

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt, line 4145:

<comment>`&` runs commands sequentially in cmd — if `generate_interfaces_file.exe` hangs, `wineserver -k` never executes</comment>

<file context>
@@ -4142,7 +4142,7 @@ private fun unpackExecutableFile(
                             val origDll = File("${imageFs.wineprefix}/dosdevices/a:/$relDllPath")
                             if (origDll.exists()) {
-                                val genCmd = "wine z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\')
+                                val genCmd = "wine cmd /c \"z:\\generate_interfaces_file.exe A:\\" + relDllPath.replace('/', '\\') + " & wineserver -k\""
                                 Timber.i("Running generate_interfaces_file $genCmd")
                                 val genOutput = guestProgramLauncherComponent.execShellCommand(genCmd)
</file context>

@utkarshdalal utkarshdalal merged commit bd2c180 into master Jun 12, 2026
3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 12, 2026
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant