Skip to content

Commit d0259c1

Browse files
committed
android: lazily init app in localAPI Request to fix cold-start crash
A localAPI request issued from a cold-started process (e.g. UseExitNodeWorker, kicked off by IPNReceiver) reads Request's lateinit `app` before the backend has been initialized, crashing the process with UninitializedPropertyAccessException. Resolve the app lazily via App.get() in execute(), matching the lazy init that Client already uses.
1 parent 76b307f commit d0259c1

1 file changed

Lines changed: 13 additions & 0 deletions

File tree

  • android/src/main/java/com/tailscale/ipn/ui/localapi

android/src/main/java/com/tailscale/ipn/ui/localapi/Client.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,24 @@ class Request<T>(
306306
fun setApp(newApp: libtailscale.Application) {
307307
app = newApp
308308
}
309+
310+
// Returns the libtailscale app, initializing the backend on demand. A localAPI request can be
311+
// issued from a cold-started process (e.g. UseExitNodeWorker, kicked off by IPNReceiver) that
312+
// never went through App.get(), so setApp() may not have run yet. Resolving lazily here mirrors
313+
// Client's own lazy `app` and avoids crashing the process with an
314+
// UninitializedPropertyAccessException.
315+
private fun resolveApp(): libtailscale.Application {
316+
if (!::app.isInitialized) {
317+
app = App.get().getLibtailscaleApp()
318+
}
319+
return app
320+
}
309321
}
310322

311323
@OptIn(ExperimentalSerializationApi::class)
312324
fun execute() {
313325
scope.launch(Dispatchers.IO) {
326+
val app = resolveApp()
314327
TSLog.d(TAG, "Executing request:${method}:${fullPath} on app $app")
315328
try {
316329
val resp =

0 commit comments

Comments
 (0)