RootService.bindOrTask() can leave RootServiceManager in a stale pending state if the returned startup task fails before the root service process broadcasts back.
Observed with libsu 6.0.0.
The rough sequence is:
- Call
RootService.bindOrTask(intent, executor, connection).
RootServiceManager.createBindTask(...) queues a pending bind task and sets the remote/daemon en-route flag.
- Caller runs the returned
Shell.Task.
- Shell startup or task execution fails before the root service manager broadcast is received.
- For example,
Shell.getShell() can fail before shell.execTask(task) runs.
- This is also relevant to
RootService.bind(), because it runs the returned task internally.
- No
ServiceConnection callback is delivered.
- The pending task and en-route flag remain in
RootServiceManager.
- A later bind attempt can see startup as already en route, return no new startup task, and wait indefinitely.
In librootkotlinx we worked around this by using bindOrTask() instead of bind(), running the returned task ourselves, and reflectively cleaning up RootServiceManager.pendingTasks plus the corresponding REMOTE_EN_ROUTE / DAEMON_EN_ROUTE flag if startup fails before the broadcast arrives.
That workaround is intentionally narrow, but this looks like state that libsu should own. RootService.bind() also appears to make the failure harder to observe because its internal task runner catches/logs IOException from execTask() instead of reporting failure through the bind path.
Expected behavior:
If root-service startup fails before the service manager broadcast completes, libsu should clear the pending bind task and en-route flag, and ideally report the failure through a callback or another observable failure path. At minimum, later bind attempts should not be blocked by stale pending state from the failed startup.
Possible fix direction:
Make the startup task failure-aware/cancellable, or have RootService.bind() / the internal task runner notify RootServiceManager when Shell.getShell() or shell.execTask(task) fails before the service is connected.
RootService.bindOrTask()can leaveRootServiceManagerin a stale pending state if the returned startup task fails before the root service process broadcasts back.Observed with libsu
6.0.0.The rough sequence is:
RootService.bindOrTask(intent, executor, connection).RootServiceManager.createBindTask(...)queues a pending bind task and sets the remote/daemon en-route flag.Shell.Task.Shell.getShell()can fail beforeshell.execTask(task)runs.RootService.bind(), because it runs the returned task internally.ServiceConnectioncallback is delivered.RootServiceManager.In librootkotlinx we worked around this by using
bindOrTask()instead ofbind(), running the returned task ourselves, and reflectively cleaning upRootServiceManager.pendingTasksplus the correspondingREMOTE_EN_ROUTE/DAEMON_EN_ROUTEflag if startup fails before the broadcast arrives.That workaround is intentionally narrow, but this looks like state that libsu should own.
RootService.bind()also appears to make the failure harder to observe because its internal task runner catches/logsIOExceptionfromexecTask()instead of reporting failure through the bind path.Expected behavior:
If root-service startup fails before the service manager broadcast completes, libsu should clear the pending bind task and en-route flag, and ideally report the failure through a callback or another observable failure path. At minimum, later bind attempts should not be blocked by stale pending state from the failed startup.
Possible fix direction:
Make the startup task failure-aware/cancellable, or have
RootService.bind()/ the internal task runner notifyRootServiceManagerwhenShell.getShell()orshell.execTask(task)fails before the service is connected.