From 747f3c6d2a33f3c9cf75741a659e976e3207bfc4 Mon Sep 17 00:00:00 2001 From: pwrwpw <113509866+pwrwpw@users.noreply.github.com> Date: Tue, 29 Sep 2026 12:31:47 +0900 Subject: [PATCH 1/2] feat(moq-tokio,moq-ffi)!: always log to logcat on Android --- .github/workflows/android.yml | 10 ++++++++-- rs/justfile | 5 ++++- rs/moq-ffi/Cargo.toml | 1 - rs/moq-tokio/Cargo.toml | 3 +-- rs/moq-tokio/src/log.rs | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 9ff35d7e967..3ff0710a545 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -11,9 +11,13 @@ name: Android # recipe is still `just rs android`, so a local run and this one compile the # same thing, and rust-toolchain.toml still pins the compiler. # +# It also builds moq-ffi and asserts the `.so` imports `__android_log_*`, so a +# build that stops linking logcat fails here. +# # Narrow trigger, like wasm.yml. The filter is moq-video's in-repo dependency -# graph (`cargo metadata`, normal dependencies), plus the files that decide how -# it is built. A crate added to that graph has to be added here too. +# graph (`cargo metadata`, normal dependencies), plus moq-ffi and moq-tokio, which +# own the logcat link, and the files that decide how it is built. A crate added +# to that graph has to be added here too. permissions: contents: read @@ -25,6 +29,8 @@ on: types: [opened, synchronize, reopened, closed] paths: - "rs/moq-video/**" + - "rs/moq-ffi/**" + - "rs/moq-tokio/**" - "rs/moq-mux/**" - "rs/moq-net/**" - "rs/moq-nvenc/**" diff --git a/rs/justfile b/rs/justfile index c583c4e7393..c50f01c3e18 100644 --- a/rs/justfile +++ b/rs/justfile @@ -127,10 +127,13 @@ capture-test *args: # than a denying clippy: the capture plumbing is dead on a target without a # capture backend. -# Compile the Android backends, which the host-target check skips. +# Compile the Android backends, which the host-target check skips, and assert the +# moq-ffi library links logcat: `Log::init` is silent on Android without it. [positional-arguments] android *args: cargo ndk -t arm64-v8a --platform 26 check --locked -p moq-video --all-targets "$@" + cargo ndk -t arm64-v8a --platform 26 -o target/android-jni build --locked -p moq-ffi "$@" + nm -D --undefined-only target/android-jni/arm64-v8a/libmoq_ffi.so | grep -q __android_log_ # moq-wasm's crate root is `#![cfg(target_arch = "wasm32")]`, so only a wasm32 # build sees the code. Not to be confused with `just js wasm`, which builds the diff --git a/rs/moq-ffi/Cargo.toml b/rs/moq-ffi/Cargo.toml index c6205452571..b8c5b07544a 100644 --- a/rs/moq-ffi/Cargo.toml +++ b/rs/moq-ffi/Cargo.toml @@ -26,7 +26,6 @@ crate-type = ["staticlib", "cdylib"] # They are unavailable on wasm32 regardless: the browser encodes via WebCodecs. default = ["audio", "video"] -android-logcat = ["moq-tokio/android-logcat"] audio = ["dep:moq-audio"] video = ["dep:moq-video", "dep:pollster"] diff --git a/rs/moq-tokio/Cargo.toml b/rs/moq-tokio/Cargo.toml index 4e1042c5183..70c7c759a7a 100644 --- a/rs/moq-tokio/Cargo.toml +++ b/rs/moq-tokio/Cargo.toml @@ -45,7 +45,6 @@ tcp = ["_transport", "dep:qmux", "dep:dns-lookup"] # inspection on accept. Pulls in `tcp` (shares qmux's stream transport). uds = ["tcp", "qmux/uds"] ring = ["_certs", "rustls/ring", "rcgen/ring", "web-transport-moq?/ring"] -android-logcat = ["dep:tracing-android"] [dependencies] bytes = "1" @@ -98,7 +97,7 @@ x509-parser = "0.18" # `tls::init_android`); jni is the bridge. Until init runs, verification falls # back to the bundled Mozilla roots. jni = "0.22" -tracing-android = { version = "0.2", optional = true } +tracing-android = "0.2" webpki-roots = "1" [target.'cfg(unix)'.dependencies] diff --git a/rs/moq-tokio/src/log.rs b/rs/moq-tokio/src/log.rs index 2e47016ade9..ddf33bbcbe1 100644 --- a/rs/moq-tokio/src/log.rs +++ b/rs/moq-tokio/src/log.rs @@ -66,7 +66,7 @@ impl Log { // On Android, route logs to logcat so they can be inspected via ADB/Android Studio. // Everywhere else, format to stderr. - #[cfg(all(target_os = "android", feature = "android-logcat"))] + #[cfg(target_os = "android")] let registry = { let logcat_layer = tracing_android::layer("MoQNative") .map_err(|e| crate::Error::Logcat(std::sync::Arc::new(e)))? @@ -74,7 +74,7 @@ impl Log { registry.with(logcat_layer) }; - #[cfg(not(all(target_os = "android", feature = "android-logcat")))] + #[cfg(not(target_os = "android"))] let registry = { let fmt_layer = tracing_subscriber::fmt::layer() .with_writer(std::io::stderr) From 59c16290ac71770fdf5da8e0e4c9ba1d184accb8 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Wed, 30 Sep 2026 22:13:44 -0700 Subject: [PATCH 2/2] quest: finish android-logcat Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 1 - quest/m1/android-logcat.md | 41 -------------------------------------- 2 files changed, 42 deletions(-) delete mode 100644 quest/m1/android-logcat.md diff --git a/quest/m1/README.md b/quest/m1/README.md index dbd3d4780ff..681654ad77f 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -31,7 +31,6 @@ QUIC studies there on that rule. - [Merge queue](/quest/m1/merge-queue.md) - the required checks run on `merge_group`, so a stale green check can no longer break main - [Binding audio delay](/quest/m1/binding-surface.md) - moq-ffi and every wrapper configure and observe audio playout delay - [FFI shape](/quest/m1/ffi-shape/README.md) - the bindings mirror Rust's layers: net at the root, then media, json, flate, audio, and video namespaces built from the handle below -- [Android logcat](/quest/m1/android-logcat.md) - on dev, Android builds always log to logcat and the `android-logcat` feature is gone - [Raw stream codes](/quest/m1/raw-stream-codes.md) - raw QUIC stream resets and stops carry the application's code, not an HTTP/3-mapped one - [IETF drain before close](/quest/m1/ietf-drain-before-close.md) - moq-transport sessions deliver finished tracks before a graceful close, as moq-lite does - [Close waits for the tail](/quest/m1/close-tail.md) - on lite-07, `close()` returns `Ok` only after each subscriber FINs its Subscribe Stream, having read the track to its end diff --git a/quest/m1/android-logcat.md b/quest/m1/android-logcat.md deleted file mode 100644 index 233f09e880f..00000000000 --- a/quest/m1/android-logcat.md +++ /dev/null @@ -1,41 +0,0 @@ -# [XS] Android logs always go to logcat - -## Goal - -On dev, `moq_tokio::Log::init` sends logs to logcat on every Android build, so -the published Kotlin and Dart bindings (and libmoq) stop losing every Rust log -to stderr, which Android app processes discard. The `android-logcat` Cargo -feature is gone from `moq-tokio` and `moq-ffi`. - -## Plan - -Today the logcat layer in `rs/moq-tokio/src/log.rs` is gated on -`all(target_os = "android", feature = "android-logcat")`, and no shipped build -enables the feature: libmoq has no `[features]`, and `rs/moq-ffi/build.sh`, the -Dart build hook, and the release workflows build Android without it. The -published `dev.moq:moq-ffi-android` 0.4.8 does not link `liblog`. - -Decided (maintainer, 2026-09-30): gate the layer on `target_os = "android"` -alone and delete the feature, rather than wire it through every build, so no -Android consumer has to know to turn it on. Logging stays opt-in at runtime, -since `Log::init` runs only when the app calls it. Removing a feature from -published crates is a break, so this targets dev; no no-op feature is kept. - -- `tracing-android` becomes a plain dependency under the existing - `cfg(target_os = "android")` target table in `rs/moq-tokio/Cargo.toml`; it - must stay target-gated because `android_log-sys` links `liblog` - unconditionally. -- Fix the `Log::init` doc comment, which already claims logcat. -- Leave the `rs/moq-native` tombstone alone. -- Regression check: the Android CI workflow builds moq-ffi for one Android - target and asserts the `.so` imports `__android_log_*`. - -The reporter ([#4456](https://github.com/moq-dev/moq/issues/4456)) has this -working locally and offered the PR. - -Public API: breaking on dev, the `android-logcat` feature is removed from -`moq-tokio` and `moq-ffi`. Wire: none. - -## Closes - -- [#4456](https://github.com/moq-dev/moq/issues/4456) - Rust logs never reach logcat on Android