From ed77923f414dc6eebff93a0e91697a1225b78bf4 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Thu, 6 Aug 2026 14:14:43 +0200 Subject: [PATCH] Bypass the SystemUI notification flags on Android 15 too Constructing a Notification on Android 16 reads an aconfig flag of the systemui container, and the daemon cannot serve that read: it holds an ActivityThread but no application record, so the settings provider is refused it and the constructor throws SecurityException. Setting systemui_is_cached ahead of the first read avoids it. The gate has been SDK_INT == 36 since the Kotlin refactor. It was originally >= VANILLA_ICE_CREAM, because Xiaomi shipped the change on Android 15 without the SDK level, which is #96 and now #880 again. Android 17 drops the read, so the test now spans 35 to 36. --- .../matrix/vector/daemon/utils/Workarounds.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/daemon/src/main/kotlin/org/matrix/vector/daemon/utils/Workarounds.kt b/daemon/src/main/kotlin/org/matrix/vector/daemon/utils/Workarounds.kt index fcaa9afa0..11408df79 100644 --- a/daemon/src/main/kotlin/org/matrix/vector/daemon/utils/Workarounds.kt +++ b/daemon/src/main/kotlin/org/matrix/vector/daemon/utils/Workarounds.kt @@ -38,9 +38,24 @@ fun IUserManager.getRealUsers(): List { return users } -/** Android 16 DP1 SystemUI FeatureFlag and Notification Builder workaround. */ +/** + * Notification.Builder workaround for the SystemUI feature flags. + * + * Android 16 reads an aconfig flag from the `systemui` container while constructing a + * `Notification`, and the generated `FeatureFlagsImpl` only reads it once, guarded by + * `systemui_is_cached`. The read goes out to `content://settings/config`, which the daemon cannot + * reach: it has an ActivityThread but no application record, so the system refuses it a provider + * and the constructor throws `SecurityException`. Setting the guard leaves the flags at their + * defaults and skips the read entirely. + * + * The read belongs to Android 16 and is gone again in Android 17, where the constructor sets the + * fields unconditionally. It reaches Android 15 all the same, on vendor builds that took the change + * without taking the SDK level: #96 and #880 are both Xiaomi HyperOS on 15. The test therefore + * spans the versions where the field can exist rather than naming one, and a device that never had + * it fails with a `ClassNotFoundException` that is ignored. + */ fun applyNotificationWorkaround() { - if (Build.VERSION.SDK_INT == 36) { + if (Build.VERSION.SDK_INT in Build.VERSION_CODES.VANILLA_ICE_CREAM..36) { runCatching { val feature = Class.forName("android.app.FeatureFlagsImpl") val field = feature.getDeclaredField("systemui_is_cached").apply { isAccessible = true }