Fix root mode default installer - #87
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe changes move root-service binding onto the Android main thread and expand hidden-API exemptions used during privileged service binding and default-installer setup on Android P and above. ChangesRoot privileged service binding fix
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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/pwhs/universalinstaller/presentation/install/controller/FullInstallerBackendFactory.kt`:
- Around line 267-272: Close the cancellation window around the posted
RootService.bind call in FullInstallerBackendFactory’s binding flow. The issue
is that the Handler.post block can still run after the coroutine has been
cancelled or timed out, causing a late bind after cleanup; update the logic to
guard the posted runnable with the coroutine state and skip RootService.bind
when the continuation is no longer active, using the existing cont/connection
setup to ensure unbind and bind stay in sync.
🪄 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: 5a4133e7-b581-478c-a341-7b2e7edd856f
📒 Files selected for processing (2)
app/src/main/java/app/pwhs/universalinstaller/presentation/install/controller/FullInstallerBackendFactory.ktapp/src/main/java/app/pwhs/universalinstaller/privileged/PrivilegedRootService.kt
| android.os.Handler(android.os.Looper.getMainLooper()).post { | ||
| try { | ||
| RootService.bind(intent, connection) | ||
| } catch (t: Throwable) { | ||
| if (cont.isActive) cont.resumeWithException(t) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Close the cancellation window before the posted bind runs.
If this coroutine is cancelled or times out before the main-thread runnable executes, Line 265 unbinds a connection that has not been bound yet, then Line 269 can still bind afterward. That can leave a root service connection cached from an already-cancelled request.
Proposed fix
- cont.invokeOnCancellation {
- runCatching { RootService.unbind(connection) }
- }
- android.os.Handler(android.os.Looper.getMainLooper()).post {
+ val mainHandler = android.os.Handler(android.os.Looper.getMainLooper())
+ val bindRunnable = Runnable {
+ if (!cont.isActive) return@Runnable
try {
RootService.bind(intent, connection)
} catch (t: Throwable) {
if (cont.isActive) cont.resumeWithException(t)
}
}
+ cont.invokeOnCancellation {
+ mainHandler.removeCallbacks(bindRunnable)
+ mainHandler.post {
+ runCatching { RootService.unbind(connection) }
+ }
+ }
+ if (!mainHandler.post(bindRunnable) && cont.isActive) {
+ cont.resumeWithException(IllegalStateException("Failed to post RootService.bind to main thread"))
+ }📝 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.
| android.os.Handler(android.os.Looper.getMainLooper()).post { | |
| try { | |
| RootService.bind(intent, connection) | |
| } catch (t: Throwable) { | |
| if (cont.isActive) cont.resumeWithException(t) | |
| } | |
| val mainHandler = android.os.Handler(android.os.Looper.getMainLooper()) | |
| val bindRunnable = Runnable { | |
| if (!cont.isActive) return@Runnable | |
| try { | |
| RootService.bind(intent, connection) | |
| } catch (t: Throwable) { | |
| if (cont.isActive) cont.resumeWithException(t) | |
| } | |
| } | |
| cont.invokeOnCancellation { | |
| mainHandler.removeCallbacks(bindRunnable) | |
| mainHandler.post { | |
| runCatching { RootService.unbind(connection) } | |
| } | |
| } | |
| if (!mainHandler.post(bindRunnable) && cont.isActive) { | |
| cont.resumeWithException(IllegalStateException("Failed to post RootService.bind to main thread")) | |
| } |
🤖 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/pwhs/universalinstaller/presentation/install/controller/FullInstallerBackendFactory.kt`
around lines 267 - 272, Close the cancellation window around the posted
RootService.bind call in FullInstallerBackendFactory’s binding flow. The issue
is that the Handler.post block can still run after the coroutine has been
cancelled or timed out, causing a late bind after cleanup; update the logic to
guard the posted runnable with the coroutine state and skip RootService.bind
when the continuation is no longer active, using the existing cont/connection
setup to ensure unbind and bind stay in sync.
This PR fixes #85 by ensuring
RootService.bind()is called on the main thread and addingHiddenApiBypassforIPackageManagerandServiceManagerin the root process.Summary by CodeRabbit