Skip to content

fix: replace hardcoded app ID paths with BuildConfig.APPLICATION_ID#585

Open
jeremybernstein wants to merge 1 commit intoutkarshdalal:masterfrom
jeremybernstein:jb/dynamic-appid
Open

fix: replace hardcoded app ID paths with BuildConfig.APPLICATION_ID#585
jeremybernstein wants to merge 1 commit intoutkarshdalal:masterfrom
jeremybernstein:jb/dynamic-appid

Conversation

@jeremybernstein
Copy link
Contributor

@jeremybernstein jeremybernstein commented Feb 20, 2026

Problem

/data/data/app.gamenative is hardcoded in several Java and C files. Any build variant with applicationIdSuffix (e.g. .debug, .gold) breaks:

  • Gamepad input (memory-mapped gamepad.mem files not found)
  • Wine E: drive mount
  • DXVK state cache path
  • Mediaconv dump/transcoded file paths

Fix

  • Java side: use BuildConfig.APPLICATION_ID to construct paths at runtime
  • C side (evshim.c): read new EVSHIM_DATA_DIR env var, fall back to app.gamenative

Important: imagefs rebuild required

The libevshim.so bundled in the imagefs must be rebuilt from the updated evshim.c. Without this, the evshim won't read EVSHIM_DATA_DIR and gamepad input will remain broken for non-default app IDs.

Files changed

File Change
Container.java DATA_DIR constant from BuildConfig.APPLICATION_ID; used in MEDIACONV_ENV_VARS and DEFAULT_DRIVES
DXVKHelper.java DXVK_STATE_CACHE_PATH uses imageFs.getRootDir()
WineUtils.java E: drive path and storage dir check use BuildConfig.APPLICATION_ID
WinHandler.java gamepad.mem paths derived from BuildConfig.APPLICATION_ID
BionicProgramLauncherComponent.java gamepad.mem paths + sets EVSHIM_DATA_DIR env var
evshim.c reads EVSHIM_DATA_DIR env var (fallback: app.gamenative)

Testing

  • ./gradlew compileDebugKotlin passes
  • No remaining hardcoded /data/data/app.gamenative in modified files (except comment + C fallback)

Summary by cubic

Replaced hardcoded /data/data/app.gamenative paths with BuildConfig.APPLICATION_ID and EVSHIM_DATA_DIR so build variants (e.g., .debug, .gold) work correctly. This fixes gamepad input, Wine E: drive mounts, DXVK state cache, and mediaconv paths for non-default app IDs.

  • Bug Fixes

    • Java: derive data dir from BuildConfig.APPLICATION_ID; update gamepad.mem paths, Wine E: drive, DXVK_STATE_CACHE_PATH, and mediaconv env vars.
    • C (evshim): read EVSHIM_DATA_DIR with a fallback to app.gamenative.
  • Migration

    • Rebuild imagefs to include the updated libevshim.so; without it, evshim won’t read EVSHIM_DATA_DIR and gamepad input stays broken for non-default app IDs.

Written for commit 8f1af16. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • Refactor
    • Improved application file path handling by transitioning from hardcoded directory references to dynamic, application-specific paths. This enhancement ensures more reliable file location management and better compatibility across different application instances.

Fixes #618

builds with applicationIdSuffix (.debug, .gold) break gamepad input,
Wine E: drive mount, DXVK cache, and mediaconv paths. use
BuildConfig.APPLICATION_ID / EVSHIM_DATA_DIR env var instead.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

This PR replaces hardcoded application data directory paths throughout the codebase with dynamic paths derived from BuildConfig.APPLICATION_ID, and introduces EVSHIM_DATA_DIR environment variable support for runtime configuration of the data directory.

Changes

Cohort / File(s) Summary
Dynamic Path Configuration
app/src/main/cpp/extras/evshim.c, app/src/main/java/com/winlator/container/Container.java, app/src/main/java/com/winlator/core/DXVKHelper.java, app/src/main/java/com/winlator/core/WineUtils.java, app/src/main/java/com/winlator/winhandler/WinHandler.java, app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java
Replaces hardcoded paths (e.g., /data/data/app.gamenative) with dynamic paths derived from BuildConfig.APPLICATION_ID. Updates gamepad memory file paths, app data directories, temporary directories, and DXVK cache paths. Introduces EVSHIM_DATA_DIR environment variable initialization in BionicProgramLauncherComponent.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • phobos665

Poem

🐰 Paths once carved in stone now bloom,
With CONFIG_ID lighting up the room!
From warren to warren, the bunny hops free,
No hardcoded chains—just flexibility! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: replacing hardcoded app ID paths with BuildConfig.APPLICATION_ID across multiple files to fix builds with applicationIdSuffix variants.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

1 issue found across 6 files

Prompt for AI agents (all 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/com/winlator/core/WineUtils.java">

<violation number="1" location="app/src/main/java/com/winlator/core/WineUtils.java:41">
P2: Existing containers with an E: drive already set will not be migrated to the new BuildConfig.APPLICATION_ID path, leaving stale E: mappings from the old hardcoded app ID.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}
if (!currentDrives.contains("E:")) {
missingDrives += "E:/data/data/app.gamenative/storage";
missingDrives += "E:/data/data/" + app.gamenative.BuildConfig.APPLICATION_ID + "/storage";
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 20, 2026

Choose a reason for hiding this comment

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

P2: Existing containers with an E: drive already set will not be migrated to the new BuildConfig.APPLICATION_ID path, leaving stale E: mappings from the old hardcoded app ID.

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/WineUtils.java, line 41:

<comment>Existing containers with an E: drive already set will not be migrated to the new BuildConfig.APPLICATION_ID path, leaving stale E: mappings from the old hardcoded app ID.</comment>

<file context>
@@ -38,7 +38,7 @@ public static void createDosdevicesSymlinks(Container container) {
             }
             if (!currentDrives.contains("E:")) {
-                missingDrives += "E:/data/data/app.gamenative/storage";
+                missingDrives += "E:/data/data/" + app.gamenative.BuildConfig.APPLICATION_ID + "/storage";
             }
             String updatedDrives = missingDrives + currentDrives;
</file context>
Fix with Cubic

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (6)
app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java (2)

186-194: Move tmpDir after imageFs is available and derive from it.

tmpDir is computed at line 186 before context (line 205) and imageFs (line 206) are obtained, forcing use of the hardcoded /data/data/ prefix. Moving the computation a few lines down allows using imageFs.getRootDir(), which is context-aware and consistent with how DXVKHelper.java now derives its paths.

♻️ Proposed fix

Move tmpDir below line 206 and derive from imageFs:

-        String tmpDir = "/data/data/" + BuildConfig.APPLICATION_ID + "/files/imagefs/tmp";
-        for (int i = 0; i < enabledPlayerCount; i++) {
         ...
         Context context = environment.getContext();
         ImageFs imageFs = ImageFs.find(context);
         File rootDir = imageFs.getRootDir();
+        String tmpDir = imageFs.getRootDir().getPath() + "/tmp";
+        for (int i = 0; i < enabledPlayerCount; i++) {

Note: imageFs.getRootDir().getPath() + "/tmp" resolves to <filesDir>/imagefs/tmp, which equals the current hardcoded value.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java`
around lines 186 - 194, tmpDir is computed too early using a hardcoded
/data/data/... path; move its declaration in BionicProgramLauncherComponent
below where context and imageFs are obtained (after imageFs is available) and
derive tmpDir from imageFs by using imageFs.getRootDir().getPath() + "/tmp" so
the path is context-aware and consistent with DXVKHelper.java's approach; update
any references to the old tmpDir variable accordingly.

306-306: EVSHIM_DATA_DIR should also use a context-derived path.

"/data/data/" + BuildConfig.APPLICATION_ID hardcodes the /data/data/ prefix. At this point in the code context is available (line 205), so context.getFilesDir().getParentFile().getPath() returns the correct app data directory for all Android users.

♻️ Proposed fix
-        envVars.put("EVSHIM_DATA_DIR", "/data/data/" + BuildConfig.APPLICATION_ID);
+        envVars.put("EVSHIM_DATA_DIR", context.getFilesDir().getParentFile().getPath());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java`
at line 306, EVSHIM_DATA_DIR is set with a hardcoded "/data/data/" prefix;
change the assignment in BionicProgramLauncherComponent where envVars is
populated to derive the app data directory from the available context (use
context.getFilesDir().getParentFile().getPath()) instead of concatenating
BuildConfig.APPLICATION_ID, so envVars.put("EVSHIM_DATA_DIR", ...) uses the
context-derived path; ensure you reference the existing envVars map and keep
BuildConfig.APPLICATION_ID out of the path composition.
app/src/main/java/com/winlator/core/WineUtils.java (1)

41-53: Add import app.gamenative.BuildConfig for consistency.

Both lines use the fully-qualified app.gamenative.BuildConfig.APPLICATION_ID inline. Every other file changed in this PR (Container.java, WinHandler.java, BionicProgramLauncherComponent.java) imports BuildConfig at the top. Using the short name is cleaner and consistent.

♻️ Proposed change

Add to imports:

+import app.gamenative.BuildConfig;

Then simplify the usage:

-                missingDrives += "E:/data/data/" + app.gamenative.BuildConfig.APPLICATION_ID + "/storage";
+                missingDrives += "E:/data/data/" + BuildConfig.APPLICATION_ID + "/storage";
-            if (!linkTarget.isDirectory() && path.endsWith("/" + app.gamenative.BuildConfig.APPLICATION_ID + "/storage")) {
+            if (!linkTarget.isDirectory() && path.endsWith("/" + BuildConfig.APPLICATION_ID + "/storage")) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/winlator/core/WineUtils.java` around lines 41 - 53, The
file WineUtils.java is using the fully-qualified
app.gamenative.BuildConfig.APPLICATION_ID inline; add an import for
app.gamenative.BuildConfig at the top of the file and replace occurrences of the
fully-qualified name with the short BuildConfig.APPLICATION_ID to match other
changed files (e.g., references in the string concatenation when computing
missingDrives and the path check inside the loop over
container.drivesIterator()); update all instances in WineUtils (used near
container.setDrives/Log.d and the linkTarget path.endsWith check) to use
BuildConfig.APPLICATION_ID.
app/src/main/java/com/winlator/winhandler/WinHandler.java (1)

523-535: Prefer activity.getFilesDir() over the hardcoded /data/data/ prefix.

activity (a Context) is already set in the constructor. Using getFilesDir() is more robust — it returns the correct path for all Android users (primary and secondary), whereas the hardcoded /data/data/ prefix is only correct for user 0.

♻️ Proposed fix
-            String tmpDir = "/data/data/" + BuildConfig.APPLICATION_ID + "/files/imagefs/tmp";
+            String tmpDir = activity.getFilesDir().getPath() + "/imagefs/tmp";

This renders the import app.gamenative.BuildConfig (line 48) removable if not needed elsewhere.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/winlator/winhandler/WinHandler.java` around lines 523 -
535, Replace the hardcoded tmpDir construction that uses
"/data/data/"+BuildConfig.APPLICATION_ID with a path built from the Activity
context: use activity.getFilesDir() (e.g. activity.getFilesDir().getPath() +
"/imagefs/tmp") when computing tmpDir so p1_mem_path, extra_mem_path and
subsequent file operations (p1_memFile, RandomAccessFile, gamepadBuffer,
extraGamepadBuffers) use the correct per-user files directory; ensure parent
directories are still created with getParentFile().mkdirs(); after this change
you can remove the now-unused BuildConfig import if it isn’t referenced
elsewhere.
app/src/main/cpp/extras/evshim.c (1)

169-179: LGTM — consider checking snprintf return for truncation.

The EVSHIM_DATA_DIR env-var path is correct; the fallback default aligns with the PR description. One minor robustness note: snprintf is not checked for truncation. If data_dir were unusually long, path would be silently truncated and open() would fail with ENOENT, which is already caught and logged at line 186. So the failure mode is safe, but an explicit guard would be cleaner.

♻️ Proposed guard
+        int written = snprintf(path, sizeof path,
-        snprintf(path, sizeof path,
                 "%s/files/imagefs/tmp/gamepad%s.mem",
                 data_dir,
                 (i == 0) ? "" : (char[2]){'0' + i, '\0'});
+        if (written < 0 || (size_t)written >= sizeof path) {
+            LOGE("P%d: path truncated, skipping\n", i);
+            continue;
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/cpp/extras/evshim.c` around lines 169 - 179, Check the return
value of snprintf when writing into path and handle truncation/errors: after the
call to snprintf(path, sizeof path, "%s/files/imagefs/tmp/gamepad%s.mem",
data_dir, (i == 0) ? "" : (char[2]){'0' + i, '\0'}) inspect the int result (rv);
if rv < 0 or rv >= (int)sizeof(path) treat it as an error (log via the same
logger used elsewhere, skip this player or fail gracefully) instead of relying
on open() to report ENOENT, so the code using data_dir/path and the per-player
loop over players detects and handles truncated paths explicitly.
app/src/main/java/com/winlator/container/Container.java (1)

26-58: Note: /data/data/ prefix is hardcoded in static constants.

Since Container is a data class with no Context, using BuildConfig.APPLICATION_ID is the correct approach and DATA_DIR is the right abstraction. However, the hardcoded /data/data/ prefix will be incorrect for apps installed under a secondary Android user profile (where the correct prefix is /data/user/{userId}/). This limitation is not new — the old hardcoded string had the same issue — but worth noting since context-based derivation is now used inconsistently across the codebase.

Where Context is unavailable (static constants), this is accepted. For places that do have Context (see WinHandler.java, BionicProgramLauncherComponent.java), context.getFilesDir() should be preferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/winlator/container/Container.java` around lines 26 -
58, DATA_DIR is built with a hardcoded "/data/data/" prefix which fails for
secondary Android users; change DATA_DIR from a compile-time static constant to
a runtime value derived from a Context (e.g., provide
Container.getDataDir(Context) or a lazy-initializer that uses
context.getFilesDir()/context.getDataDir()), and update dependent constants that
rely on it (MEDIACONV_ENV_VARS and DEFAULT_DRIVES) to be generated at runtime
via that getter; also update places that already have a Context (WinHandler,
BionicProgramLauncherComponent) to call context.getFilesDir() (or getDataDir())
instead of using Container.DATA_DIR so all file paths use the correct per-user
directory.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/src/main/cpp/extras/evshim.c`:
- Around line 169-179: Check the return value of snprintf when writing into path
and handle truncation/errors: after the call to snprintf(path, sizeof path,
"%s/files/imagefs/tmp/gamepad%s.mem", data_dir, (i == 0) ? "" : (char[2]){'0' +
i, '\0'}) inspect the int result (rv); if rv < 0 or rv >= (int)sizeof(path)
treat it as an error (log via the same logger used elsewhere, skip this player
or fail gracefully) instead of relying on open() to report ENOENT, so the code
using data_dir/path and the per-player loop over players detects and handles
truncated paths explicitly.

In `@app/src/main/java/com/winlator/container/Container.java`:
- Around line 26-58: DATA_DIR is built with a hardcoded "/data/data/" prefix
which fails for secondary Android users; change DATA_DIR from a compile-time
static constant to a runtime value derived from a Context (e.g., provide
Container.getDataDir(Context) or a lazy-initializer that uses
context.getFilesDir()/context.getDataDir()), and update dependent constants that
rely on it (MEDIACONV_ENV_VARS and DEFAULT_DRIVES) to be generated at runtime
via that getter; also update places that already have a Context (WinHandler,
BionicProgramLauncherComponent) to call context.getFilesDir() (or getDataDir())
instead of using Container.DATA_DIR so all file paths use the correct per-user
directory.

In `@app/src/main/java/com/winlator/core/WineUtils.java`:
- Around line 41-53: The file WineUtils.java is using the fully-qualified
app.gamenative.BuildConfig.APPLICATION_ID inline; add an import for
app.gamenative.BuildConfig at the top of the file and replace occurrences of the
fully-qualified name with the short BuildConfig.APPLICATION_ID to match other
changed files (e.g., references in the string concatenation when computing
missingDrives and the path check inside the loop over
container.drivesIterator()); update all instances in WineUtils (used near
container.setDrives/Log.d and the linkTarget path.endsWith check) to use
BuildConfig.APPLICATION_ID.

In `@app/src/main/java/com/winlator/winhandler/WinHandler.java`:
- Around line 523-535: Replace the hardcoded tmpDir construction that uses
"/data/data/"+BuildConfig.APPLICATION_ID with a path built from the Activity
context: use activity.getFilesDir() (e.g. activity.getFilesDir().getPath() +
"/imagefs/tmp") when computing tmpDir so p1_mem_path, extra_mem_path and
subsequent file operations (p1_memFile, RandomAccessFile, gamepadBuffer,
extraGamepadBuffers) use the correct per-user files directory; ensure parent
directories are still created with getParentFile().mkdirs(); after this change
you can remove the now-unused BuildConfig import if it isn’t referenced
elsewhere.

In
`@app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java`:
- Around line 186-194: tmpDir is computed too early using a hardcoded
/data/data/... path; move its declaration in BionicProgramLauncherComponent
below where context and imageFs are obtained (after imageFs is available) and
derive tmpDir from imageFs by using imageFs.getRootDir().getPath() + "/tmp" so
the path is context-aware and consistent with DXVKHelper.java's approach; update
any references to the old tmpDir variable accordingly.
- Line 306: EVSHIM_DATA_DIR is set with a hardcoded "/data/data/" prefix; change
the assignment in BionicProgramLauncherComponent where envVars is populated to
derive the app data directory from the available context (use
context.getFilesDir().getParentFile().getPath()) instead of concatenating
BuildConfig.APPLICATION_ID, so envVars.put("EVSHIM_DATA_DIR", ...) uses the
context-derived path; ensure you reference the existing envVars map and keep
BuildConfig.APPLICATION_ID out of the path composition.

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.

Hardcoded /data/data/app.gamenative paths break variant builds

1 participant