From 7fcad2ddfbaae862d150430b27674606ebca299e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 12 Sep 2026 15:52:54 -0700 Subject: Proven on a phone: woken from a cold stop in four seconds. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole chain, on real hardware, with the shipping APK installed: am broadcast → PushReceiver → expedited job → off-screen WebView → v3.coinos.io/?wake= → the wallet restored from its vault → CoinosHost.done() 15:49:52.341 schedule -> 1 15:49:52.390 job started (49ms later) 15:49:56.602 finishing (page said so) Four and a bit seconds from a force-stopped app to the page reporting it had dealt with the payload — not the timeout, the page. A notify payload raised the right notification too ("You were paid", "New message"), and the wallet it woke was one imported into the WebView build minutes earlier, restored from the vault in a process that had been killed. The payload no longer goes to logcat. It carries the user's push, and anything with ADB can read that. Unproven, and the one link I couldn't close here: the distributor handshake. There's no UnifiedPush distributor on this phone, so every push above was a broadcast I sent by hand — which is exactly what a distributor sends, but it isn't the same as watching ntfy do it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx --- .../app/src/webview/java/io/coinos/app/Wake.java | 4 +--- .../app/src/webview/java/io/coinos/app/WakeJob.java | 4 +++- static/graphene.apk | Bin 38908 -> 38840 bytes 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/app/src/webview/java/io/coinos/app/Wake.java b/android/app/src/webview/java/io/coinos/app/Wake.java index 82fc16f..bb5d4e9 100644 --- a/android/app/src/webview/java/io/coinos/app/Wake.java +++ b/android/app/src/webview/java/io/coinos/app/Wake.java @@ -31,9 +31,7 @@ final class Wake { } else { b.setOverrideDeadline(0); } - int r = js.schedule(b.build()); - android.util.Log.i("coinos", "wake: schedule -> " + r); - return r == JobScheduler.RESULT_SUCCESS; + return js.schedule(b.build()) == JobScheduler.RESULT_SUCCESS; } catch (Exception e) { android.util.Log.w("coinos", "wake: schedule failed: " + e); // out of expedited quota, or a manufacturer being creative: the diff --git a/android/app/src/webview/java/io/coinos/app/WakeJob.java b/android/app/src/webview/java/io/coinos/app/WakeJob.java index c866c33..a6cb1a2 100644 --- a/android/app/src/webview/java/io/coinos/app/WakeJob.java +++ b/android/app/src/webview/java/io/coinos/app/WakeJob.java @@ -39,7 +39,9 @@ public class WakeJob extends JobService { public boolean onStartJob(JobParameters p) { params = p; String payload = p.getExtras() == null ? null : p.getExtras().getString("payload"); - android.util.Log.i("coinos", "wake: job started, payload=" + payload); + // no payload in the log: it carries the user's push, and logcat is read + // by anything with ADB + android.util.Log.i("coinos", "wake: job started"); web = new WebView(this); WebSettings s = web.getSettings(); diff --git a/static/graphene.apk b/static/graphene.apk index 49f0fc5..29ca693 100644 Binary files a/static/graphene.apk and b/static/graphene.apk differ -- cgit v1.2.3