Skip to content

Fix two crashes that prevent a fresh install from launching - #123

Open
mengelh wants to merge 1 commit into
OpenIPC:masterfrom
mengelh:fix-launch-crashes
Open

mengelh wants to merge 1 commit into
OpenIPC:masterfrom
mengelh:fix-launch-crashes

Conversation

@mengelh

@mengelh mengelh commented Sep 9, 2026

Copy link
Copy Markdown
Contributor
  1. UnsatisfiedLinkError: libusb1.0.so / libsodium.so / libopus.so are
    linked into libWfbngRtl8812.so and libVideoNative.so via absolute
    paths in each module's CMakeLists.txt, but nothing placed them
    under a jniLibs source set, so AGP never packaged them into the
    APK and the dynamic linker couldn't find them at runtime. Only
    surfaces on a genuinely fresh install/device with no cached APK
    already carrying them (e.g. from a properly configured CI/release
    build) to mask the gap. Fixed by adding the prebuilt libraries
    (already present in each module's src/main/cpp/libs//) to a
    standard src/main/jniLibs// source set for both modules.

  2. SIGABRT in Aggregator::Aggregator ("Unable to open gs.key") /
    USB adapter lock false-refusal: WfbngLink.hpp/.cpp hardcoded both
    the gs.key path and the USB advisory lock directory as
    /data/user/0/com.openipc.pixelpilot/..., which is only correct for
    the default applicationId running as Android's default user (id
    0). Under a different applicationId (a fork/rebrand) or a
    non-default user profile (secondary user, work profile, Samsung
    Secure Folder, ...), that path doesn't exist, so opening gs.key
    fails outright, and the USB lock (see UsbDeviceLock.h) either
    silently degrades to no exclusivity or -- once the directory
    happens to resolve to a stale lock from an earlier process -- falsely
    reports "in use". Fixed by resolving both from
    Context.getFilesDir() via JNI once in the constructor instead.

Verified on-device (Galaxy Tab S7 FE, RTL8812AU): a fresh install now
launches and opens the USB adapter successfully
("USB adapter locked for exclusive access") instead of crashing
or falsely refusing the adapter.

🤖 Generated with Claude Code

1. UnsatisfiedLinkError: libusb1.0.so / libsodium.so / libopus.so are
   linked into libWfbngRtl8812.so and libVideoNative.so via absolute
   paths in each module's CMakeLists.txt, but nothing placed them
   under a jniLibs source set, so AGP never packaged them into the
   APK and the dynamic linker couldn't find them at runtime. Only
   surfaces on a genuinely fresh install/device with no cached APK
   already carrying them (e.g. from a properly configured CI/release
   build) to mask the gap. Fixed by adding the prebuilt libraries
   (already present in each module's src/main/cpp/libs/<abi>/) to a
   standard src/main/jniLibs/<abi>/ source set for both modules.

2. SIGABRT in Aggregator::Aggregator ("Unable to open gs.key") /
   USB adapter lock false-refusal: WfbngLink.hpp/.cpp hardcoded both
   the gs.key path and the USB advisory lock directory as
   /data/user/0/com.openipc.pixelpilot/..., which is only correct for
   the default applicationId running as Android's default user (id
   0). Under a different applicationId (a fork/rebrand) or a
   non-default user profile (secondary user, work profile, Samsung
   Secure Folder, ...), that path doesn't exist, so opening gs.key
   fails outright, and the USB lock (see UsbDeviceLock.h) either
   silently degrades to no exclusivity or -- once the directory
   happens to resolve to a stale lock from an earlier process -- falsely
   reports "in use". Fixed by resolving both from
   Context.getFilesDir() via JNI once in the constructor instead.

Verified on-device (Galaxy Tab S7 FE, RTL8812AU): a fresh install now
launches and opens the USB adapter successfully
("USB adapter <id> locked for exclusive access") instead of crashing
or falsely refusing the adapter.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

PR Summary by Qodo

Resolve native key and USB lock paths from the app context

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Resolve the native key path from the running app’s files directory to support alternate packages
 and user profiles.
• Use that directory for USB advisory locks to avoid incorrect adapter refusals.
• The supplied diff does not include the native-library packaging fix described in the PR text.
Diagram

graph TD
  A["Android Context"] --> B["JNI resolver"] --> C["WfbngLink paths"] --> D["Key aggregators"]
  C --> E["USB advisory lock"]
Loading
High-Level Assessment

Resolving the directory once from the existing Android context fits both native consumers and avoids package- and user-specific assumptions. Passing the path separately to each consumer would add plumbing without a clear benefit. The claimed jniLibs packaging fix is absent from the supplied diff, so confirm it is included before treating both reported crashes as fixed.

Files changed (2) +36 / -3

Bug fix (2) +36 / -3
WfbngLink.cppResolve and reuse the app-specific files directory +28/-2

Resolve and reuse the app-specific files directory

• Adds a JNI helper that reads Context.getFilesDir() during construction. The resulting directory supplies the gs.key path for aggregators and replaces the hardcoded USB lock directory in run().

app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp

WfbngLink.hppStore resolved native filesystem paths +8/-1

Store resolved native filesystem paths

• Replaces the hardcoded key-path member with strings for the runtime files directory and derived key path.

app/wfbngrtl8812/src/main/cpp/WfbngLink.hpp

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Library callers can hit a native crash 🐞 Bug ☼ Reliability
Description
resolveFilesDir passes context and each returned JNI object into subsequent calls without
checking for null values or pending exceptions. A caller constructing WfbNgLink with a null
context now reaches GetObjectClass and continues through invalid JNI results, potentially aborting
initialization instead of reporting a controlled Java error.
Code

app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[R56-58]

+    jclass contextClass = env->GetObjectClass(context);
+    jmethodID getFilesDirMethod = env->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");
+    jobject filesDir = env->CallObjectMethod(context, getFilesDirMethod);
Evidence
The public Java constructor forwards its context directly to native initialization, which constructs
WfbngLink; the new constructor path immediately calls resolveFilesDir. That resolver
dereferences the context and results without null or exception checks, whereas the sole
in-repository production caller currently happens to pass a valid Activity.

app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java[53-55]
app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[55-66]
app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[369-373]
app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[368-372]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new files-directory resolver dereferences the constructor's `Context` without validating it and continues after JNI lookup or invocation failures. This can turn a null context or pending Java exception into an uncontrolled native failure.
## Issue Context
`WfbNgLink` exposes a public constructor that forwards its argument directly to `nativeInitialize`. Validate the context before native initialization and stop immediately after any JNI exception or null result, preferably by throwing a clear Java exception rather than continuing with invalid JNI values.
## Fix Focus Areas
- app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[55-66]
- app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java[53-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: Auto: ⚖️ Balanced: Native JNI initialization affects fresh-install startup and needs careful validation.

Grey Divider

Tip of the day
💡 Did you know, you can move or hide resolved findings to focus on what still needs action

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 06f85fe ⚖️ Balanced

Results up to commit 06f85fe


🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)


Remediation recommended
1. Library callers can hit a native crash 🐞 Bug ☼ Reliability
Description
resolveFilesDir passes context and each returned JNI object into subsequent calls without
checking for null values or pending exceptions. A caller constructing WfbNgLink with a null
context now reaches GetObjectClass and continues through invalid JNI results, potentially aborting
initialization instead of reporting a controlled Java error.
Code

app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[R56-58]

+    jclass contextClass = env->GetObjectClass(context);
+    jmethodID getFilesDirMethod = env->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");
+    jobject filesDir = env->CallObjectMethod(context, getFilesDirMethod);
Evidence
The public Java constructor forwards its context directly to native initialization, which constructs
WfbngLink; the new constructor path immediately calls resolveFilesDir. That resolver
dereferences the context and results without null or exception checks, whereas the sole
in-repository production caller currently happens to pass a valid Activity.

app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java[53-55]
app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[55-66]
app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[369-373]
app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[368-372]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new files-directory resolver dereferences the constructor's `Context` without validating it and continues after JNI lookup or invocation failures. This can turn a null context or pending Java exception into an uncontrolled native failure.

## Issue Context
`WfbNgLink` exposes a public constructor that forwards its argument directly to `nativeInitialize`. Validate the context before native initialization and stop immediately after any JNI exception or null result, preferably by throwing a clear Java exception rather than continuing with invalid JNI values.

## Fix Focus Areas
- app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[55-66]
- app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java[53-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Context sources
Review mode: ⚖️ Balanced: This changes native JNI path resolution and USB locking behavior on critical startup and device-profile paths, so it warrants a careful single-pass review.

Grey Divider

Qodo Logo

Comment on lines +56 to +58
jclass contextClass = env->GetObjectClass(context);
jmethodID getFilesDirMethod = env->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");
jobject filesDir = env->CallObjectMethod(context, getFilesDirMethod);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Library callers can hit a native crash 🐞 Bug ☼ Reliability

resolveFilesDir passes context and each returned JNI object into subsequent calls without
checking for null values or pending exceptions. A caller constructing WfbNgLink with a null
context now reaches GetObjectClass and continues through invalid JNI results, potentially aborting
initialization instead of reporting a controlled Java error.
Agent Prompt
## Issue description
The new files-directory resolver dereferences the constructor's `Context` without validating it and continues after JNI lookup or invocation failures. This can turn a null context or pending Java exception into an uncontrolled native failure.

## Issue Context
`WfbNgLink` exposes a public constructor that forwards its argument directly to `nativeInitialize`. Validate the context before native initialization and stop immediately after any JNI exception or null result, preferably by throwing a clear Java exception rather than continuing with invalid JNI values.

## Fix Focus Areas
- app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp[55-66]
- app/wfbngrtl8812/src/main/java/com/openipc/wfbngrtl8812/WfbNgLink.java[53-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@josephnef josephnef closed this Oct 18, 2026
@josephnef josephnef reopened this Oct 18, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 06f85fe

@josephnef josephnef left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, the two halves of this need different answers.

Part 2, resolving the files dir from Context: yes, please keep it. The hard-coded /data/user/0/com.openipc.pixelpilot/... for both gs.key and devourer's lock dir was a documented gotcha (it is in CLAUDE.md) and this is the right fix: AggregatorUDPv4 and TxArgs already take std::string paths, so the type change is clean. Two small asks there: check the JNI results for null and pending exceptions in resolveFilesDir (Qodo's note, and it keeps a library consumer from crashing with a bare Context), and the lock dir comment can drop the "resolved in the constructor" cross-reference now that the member name says it.

Part 1, the jniLibs copies: I cannot reproduce the problem and would rather not take 8 MB of duplicated binaries. Both APKs that CI produces today already contain libusb1.0.so, libsodium.so and libopus.so for both ABIs (checked with unzip -l on the debug artifact from the reopened run and on the latest release APK). AGP 8.5 packages shared libraries that a CMake target links by absolute path, which is why the existing src/main/cpp/libs/<abi>/ setup works. If your fresh-install UnsatisfiedLinkError came from an Android Studio build, can you say which AGP / Studio version and whether useLegacyPackaging was in effect? If there is a real configuration that drops them, the fix should be sourceSets.main.jniLibs.srcDirs pointing at the existing cpp/libs directories rather than a second copy of the files.

CI note: format, host test, debug APK and emulator smoke are all green on this branch.

So: drop the four jniLibs/ binaries (or replace with srcDirs plus the evidence), add the null checks, and this is good to merge.

This branch has not been deployed

No deployments
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.

2 participants