Skip to content

chore: cleanup for android on bridge reload#30

Merged
santhoshvai merged 8 commits intomasterfrom
cleanup-on-bridge-reload
Apr 15, 2026
Merged

chore: cleanup for android on bridge reload#30
santhoshvai merged 8 commits intomasterfrom
cleanup-on-bridge-reload

Conversation

@santhoshvai
Copy link
Copy Markdown
Member

@santhoshvai santhoshvai commented Apr 14, 2026

  • PeerConnectionFactory on Android wraps a C++ pointer via JNI. The Java wrapper has no finalize() — GC reclaims the Java object but the native factory and its 3 threads (network/worker/signaling) leak on every bridge reload. In this PR. we add the teardown for native factory on bridge reload.
  • iOS is unaffected — RTCPeerConnectionFactory uses unique_ptr C++ members that auto-destruct when ARC releases the ObjC object.

Summary by CodeRabbit

  • Bug Fixes

    • Improved shutdown cleanup to fully dispose media tracks, streams, and adapters, reducing memory leaks and stopping periodic adapter timers.
    • Prevented screen-sharing from starting after the module has been disposed, returning a clear error instead.
    • Strengthened error handling and logging around synchronous cleanup to avoid silent failures.
  • Chores

    • Bumped package version.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

Warning

Rate limit exceeded

@santhoshvai has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 56 minutes and 7 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 56 minutes and 7 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 42fd8c5a-ba0b-4ca8-a833-b6cff9c8703b

📥 Commits

Reviewing files that changed from the base of the PR and between 4bf4f73 and 9594dd3.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • package.json
📝 Walkthrough

Walkthrough

Added explicit disposal flows: new invalidate() on WebRTCModule runs synchronous cleanup via executor; GetUserMediaImpl can dispose all tracked tracks and prevents screen capture after factory disposal; PeerConnectionObserver and VideoTrackAdapter receive additional adapter/ timer cleanup.

Changes

Cohort / File(s) Summary
Track Cleanup
android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
Added disposeAllTracks() to iterate and dispose each TrackPrivate with per-entry exception logging and clear tracks. createScreenStream() now rejects/clears displayMediaPromise early when webRTCModule.mFactory is null.
Module Invalidation
android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
Added public void invalidate() override that submits a synchronous cleanup task: disposes mPeerConnectionObservers, disposes local MediaStreams and their tracks, calls getUserMediaImpl.disposeAllTracks(), disposes and nulls mFactory, and logs InterruptedException/ExecutionException before calling super.invalidate().
Observer & Adapter Disposal
android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java, android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java
PeerConnectionObserver.dispose() now calls videoTrackAdapters.dispose() in addition to peerConnection.dispose(). VideoTrackAdapter gained dispose() which cancels its shared Timer.
Metadata
package.json
Bumped package version from 137.1.4-alpha.5 to 137.1.4-alpha.7.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant WRM as WebRTCModule
    participant Exec as ThreadUtils Executor
    participant GMI as GetUserMediaImpl
    participant PCO as PeerConnectionObserver
    participant MS as MediaStream
    participant Fac as PeerConnectionFactory

    App->>WRM: invalidate()
    WRM->>Exec: submit cleanup task (blocking .get())
    Exec-->>WRM: task executes
    rect rgba(100,150,200,0.5)
        WRM->>PCO: for each observer -> dispose()
        PCO-->>WRM: observer disposed
    end
    rect rgba(150,100,200,0.5)
        WRM->>GMI: disposeAllTracks()
        GMI->>GMI: iterate and dispose each TrackPrivate
        GMI-->>WRM: tracks cleared
    end
    rect rgba(200,150,100,0.5)
        WRM->>MS: for each local stream -> remove tracks & dispose stream
        MS-->>WRM: streams disposed
    end
    rect rgba(150,200,100,0.5)
        WRM->>Fac: dispose() and set null
        Fac-->>WRM: factory disposed
    end
    WRM->>WRM: super.invalidate()
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nudge each track to say goodbye,
Timers hush, adapters softly die.
Observers fold, the factory goes dim,
Streams drift off on a moonlit whim—
A rabbit hops home; the module sleeps, slim.

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: cleanup for android on bridge reload' accurately describes the main objective of the PR: adding teardown/cleanup for Android's native PeerConnectionFactory when the bridge reloads.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cleanup-on-bridge-reload

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
Copy Markdown

@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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java`:
- Around line 358-359: When detecting webRTCModule.mFactory == null in the
onServiceConnected guard, reject and clear any pending display-media request
before returning: if webRTCModule.displayMediaPromise (or the field holding the
pending promise from getDisplayMedia()) is non-null, call its reject/resolve
with an appropriate error (e.g., "Operation aborted" or the same error used
elsewhere), then set webRTCModule.displayMediaPromise = null (and clear any
related state like a pending displayMediaStreamId) so the pending
getDisplayMedia() call is settled and future calls won't hit "Another operation
is pending."; keep this logic immediately before the existing return in
GetUserMediaImpl where mFactory is checked.

In `@android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java`:
- Around line 147-155: The loop that disposes localStreams in
WebRTCModule.dispose is unguarded and a thrown exception from any
stream.dispose() can abort remaining teardowns and prevent localStreams.clear()
and mFactory.dispose(); fix by wrapping each stream.dispose() call in a
try/catch (catch Throwable) and log the exception using the same
log-and-continue pattern used elsewhere (e.g., PeerConnection teardown), so the
loop continues for all entries, and ensure that after the loop
localStreams.clear() and the existing mFactory disposal still execute.
🪄 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: 9db95331-1170-476b-9fae-897602a33a43

📥 Commits

Reviewing files that changed from the base of the PR and between 13da032 and d004e93.

📒 Files selected for processing (2)
  • android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java

Comment thread android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java Outdated
Comment thread android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java Outdated
Copy link
Copy Markdown

@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 (1)
android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java (1)

288-297: Use a snapshot when disposing tracks to avoid fail-fast iteration issues.

disposeAllTracks() currently iterates the live map while invoking dispose(). If disposal indirectly mutates tracks, teardown can fail with ConcurrentModificationException.

Proposed defensive change
 void disposeAllTracks() {
-        for (Map.Entry<String, TrackPrivate> entry : tracks.entrySet()) {
+        for (Map.Entry<String, TrackPrivate> entry : new ArrayList<>(tracks.entrySet())) {
             try {
                 entry.getValue().dispose();
             } catch (Exception e) {
                 Log.w(TAG, "disposeAllTracks: error disposing " + entry.getKey(), e);
             }
         }
         tracks.clear();
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java` around
lines 288 - 297, disposeAllTracks currently iterates the live tracks map and
calls TrackPrivate.dispose(), which may mutate the tracks map and cause
ConcurrentModificationException; fix by iterating over a snapshot of the entries
(e.g., copy tracks.entrySet() into a new list) and call
entry.getValue().dispose() against that snapshot, still catching exceptions per
entry, and then clear the original tracks map once iteration completes to ensure
safe teardown.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java`:
- Around line 288-297: disposeAllTracks currently iterates the live tracks map
and calls TrackPrivate.dispose(), which may mutate the tracks map and cause
ConcurrentModificationException; fix by iterating over a snapshot of the entries
(e.g., copy tracks.entrySet() into a new list) and call
entry.getValue().dispose() against that snapshot, still catching exceptions per
entry, and then clear the original tracks map once iteration completes to ensure
safe teardown.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b5424c14-30d4-4e20-901d-1042e4b07a87

📥 Commits

Reviewing files that changed from the base of the PR and between 6c593e0 and 4bf4f73.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java

@santhoshvai santhoshvai merged commit 5e8cf5f into master Apr 15, 2026
4 checks passed
@santhoshvai santhoshvai deleted the cleanup-on-bridge-reload branch April 15, 2026 13:44
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