The app hands its log to Dev Updater on the phone, not through ai-server
Iris's call once the upload route was working: put it in Dev Updater properly. So the app now exposes its own ring through a ContentProvider at `<applicationId>.devlog` -- Dev Updater's contract, written down in that project's README, not something invented here -- and Dev Updater's phone app reads it on the same device and forwards it to its own build machine. No tunnel, no token, no second enrolment, and any app that server delivers can implement the same and get the same Runtime tab. `DevLogProvider.java` plus `devlog.rs` are the platform glue only: a flat `String[]` across JNI, a `MatrixCursor` on the Java side, and `nativeReady` telling Rust the authority the provider actually registered, so the Diagnostics pane can name somewhere a reader can query rather than composing a guess. `LogRing::newest_seq()` is the one addition in `client-core`: an in-memory ring starts again at zero, so it is what lets a reader notice the process restarted instead of silently skipping everything since. Deleted with it, so there is one mechanism: `client_core::log_upload`, `POST /client-log` on ai-server, the `AI_APP_LOG_*` baking (which left `build.rs` with nothing to do), and the uploader on both Android clients. Kept: the ring, `RingLogger`, `install_process_logger`, and the Diagnostics line -- whose second half is now `devlog provider: content://<authority>`. Verified end to end on this checkout's emulator: iris's own `iris::android::view` startup lines read out of the provider by the shell, forwarded by Dev Updater's Runtime tab, and served back from `GET /apps/android-app/components/app/logs?kind=runtime`. A component whose package has no provider says so in as many words. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e10582a2cd
commit
06b8a1f4b0
15 files changed
+618
-842
No files matched your search
+61
-2
@@ -46,7 +46,61 @@ marked **DEFERRED** are ones the agent chose not to decide alone.
|
||||
unaffected (still resolves monospace correctly, confirmed unchanged).
|
||||
docs/RUST.md's "Platform fonts (2026-09-07)" has the full account.
|
||||
|
||||
## 2026-09-07 (how a phone log reaches Iris)
|
||||
## 2026-09-07 (a phone log reaches Iris through Dev Updater's own tab)
|
||||
|
||||
**Supersedes the "how a phone log reaches Iris" entry below, same day.**
|
||||
Iris's call once the route was working: put it in Dev Updater properly
|
||||
rather than smuggling the lines through `ai-server`'s log.
|
||||
|
||||
- **The app exposes its own log on the device, and Dev Updater reads it
|
||||
there.** A `ContentProvider` at `<applicationId>.devlog`, one table of
|
||||
lines queried with `?since=<seq>` so a poll is incremental, plus a
|
||||
`status` row (`held`, `dropped`, `newest_seq`). Dev Updater's phone app
|
||||
polls it while the component's **Runtime** tab is open and forwards what
|
||||
is new to its own build machine, into that APK component's runtime log
|
||||
-- so the same tab renders both kinds and the history outlives the
|
||||
phone. No tunnel, no token, no second enrolment: the two apps are on the
|
||||
same phone.
|
||||
|
||||
**It is a contract, not a feature for iris.** Written down in
|
||||
dev-updater's `README.md` ("An app's own log"), so any app that server
|
||||
delivers gets the tab by implementing it; the Compose app in `app/` can
|
||||
do the same later. That is the reason it beat the route below on its
|
||||
second look -- the earlier one only ever worked for the one project that
|
||||
had a server, and put a phone's lines under a *different component* than
|
||||
the one they came from.
|
||||
|
||||
- **Read access is `protectionLevel="normal"`, and that is a real trade.**
|
||||
`signature` is what this wants and is not available: Dev Updater and the
|
||||
apps it delivers are built on one machine but signed with different
|
||||
locally generated keys, so a signature permission would be held by
|
||||
nothing at all. What `normal` costs is that any app on that phone which
|
||||
requests `dev.updater.permission.READ_DEVLOG` by name can read another
|
||||
app's dev log. Accepted because these are development builds on a
|
||||
development phone and the alternative was no log; stated in the manifest
|
||||
beside the declaration and in dev-updater's README so it is not
|
||||
rediscovered as a surprise.
|
||||
|
||||
- **The provider polls rather than notifying.** `notifyChange` was not
|
||||
implemented: the ring is filled by a `log::Log` backend on whatever
|
||||
thread logged, and giving that a route to a `ContentProvider` means
|
||||
plumbing a callback through `client-core` for every platform. Dev
|
||||
Updater's contract therefore says it polls (about a second, only while
|
||||
the tab is open), which is what keeps implementing the contract cheap --
|
||||
a provider that does notify loses nothing.
|
||||
|
||||
- **What was deleted, so there is one mechanism**: `client-core`'s
|
||||
`log_upload` module, `POST /client-log` on `ai-server`, the
|
||||
`AI_APP_LOG_HOST`/`_PORT`/`_TOKEN` baking in `iris/android-app/build.rs`
|
||||
(which left that file with nothing to do, so it is gone too), and the
|
||||
uploader fields on both Android clients. Kept: the ring, `RingLogger`,
|
||||
`install_process_logger`, and the Diagnostics line counting what is
|
||||
held. The upload-status line there is now **"devlog provider:
|
||||
content://<authority>"** -- named from what the provider registered
|
||||
rather than composed from the package here, so a screenshot of that pane
|
||||
is evidence the contract is live and says which package's log it is.
|
||||
|
||||
## 2026-09-07 (how a phone log reaches Iris) -- superseded, see above
|
||||
|
||||
- **The app sends its own log to `ai-server`, and Dev Updater shows it as
|
||||
`ai-server`'s runtime log.** Iris has no `adb`/`logcat` on her phone, and
|
||||
@@ -60,7 +114,9 @@ marked **DEFERRED** are ones the agent chose not to decide alone.
|
||||
component. So **no change to Dev Updater at all** -- one route on
|
||||
`ai-server`, and the client in `client-core`.
|
||||
|
||||
**Rejected: posting to Dev Updater's own server** (the first candidate).
|
||||
**Rejected: posting to Dev Updater's own server** (the first candidate,
|
||||
and what the entry above went on to build -- the estimate below was
|
||||
right about the work and wrong about it being too much).
|
||||
It would need a new authenticated *write* route on a TLS surface whose
|
||||
module doc says every route on it "is, or decides, the bytes that get
|
||||
handed to `REQUEST_INSTALL_PACKAGES` next"; a per-app device-log store;
|
||||
@@ -90,6 +146,9 @@ marked **DEFERRED** are ones the agent chose not to decide alone.
|
||||
|
||||
- **The destination is baked in at build time, from the build machine's
|
||||
own files** (`AI_APP_LOG_HOST`/`_PORT`/`_TOKEN` plus the pinned CA) --
|
||||
*gone; the provider above replaced it.* What is worth keeping from it is
|
||||
the reason it went: an APK good only for the server that built it cannot
|
||||
be built in this VM for Iris's phone, which is the case that mattered.
|
||||
all three or none, never two. The same trust boundary the transcript
|
||||
config and the Compose APK's CA already use: nothing secret is
|
||||
committed, and an APK is good for the server that built it. A build told
|
||||
|
||||
Reference in new issue
Block a user