From e0059114c997f9437ed280500747c1bab23063a9 Mon Sep 17 00:00:00 2001 From: Leaf <1587968048@qq.com> Date: Mon, 13 Jul 2026 21:46:37 +0800 Subject: [PATCH 1/4] Fix AbstractMethodError crash on Android 17 IServiceConnection Android 17 (API 36) replaced the old 3-argument IServiceConnection.connected(ComponentName, IBinder, boolean) with a new 4-argument overload that adds an IBinderSession parameter, and removed the old overload entirely from the framework interface. Vector's IServiceConnection stub and the ManagerService connection implementation only declared/overrode the old 3-argument signature. When system_server dispatched the new 4-argument connected() to the parasitic manager process on Android 17, the Stub lacked the new abstract method and threw AbstractMethodError, killing the manager process. system_server then hit DeadObjectException while dispatching a broadcast to the dead process, triggering a framework restart (SYSTEM_RESTART) every time the manager was opened. Fix: - Add an IBinderSession stub (android.app.IBinderSession extends IInterface) with binderTransactionCompleted(long) and binderTransactionStarting(String):long, matching the Android 17 framework interface. - Declare both connected() overloads in the IServiceConnection stub so it compiles against Android 8.1~17 (the old overload is simply never invoked on Android 17+). - Override the new 4-argument connected() in ManagerService's connection Stub (no-op, same as the existing 3-argument override). --- .../vector/daemon/ipc/ManagerService.kt | 9 +++++ .../main/java/android/app/IBinderSession.java | 35 +++++++++++++++++++ .../java/android/app/IServiceConnection.java | 14 ++++++++ 3 files changed, 58 insertions(+) create mode 100644 hiddenapi/stubs/src/main/java/android/app/IBinderSession.java diff --git a/daemon/src/main/kotlin/org/matrix/vector/daemon/ipc/ManagerService.kt b/daemon/src/main/kotlin/org/matrix/vector/daemon/ipc/ManagerService.kt index 412165747..28f0cb50a 100644 --- a/daemon/src/main/kotlin/org/matrix/vector/daemon/ipc/ManagerService.kt +++ b/daemon/src/main/kotlin/org/matrix/vector/daemon/ipc/ManagerService.kt @@ -54,7 +54,16 @@ object ManagerService : ILSPManagerService.Stub() { IBinder.DeathRecipient { private val connection = object : android.app.IServiceConnection.Stub() { + // Android 8.1 ~ 16 override fun connected(name: ComponentName?, service: IBinder?, dead: Boolean) {} + + // Android 17+ (new signature with IBinderSession) + override fun connected( + name: ComponentName?, + service: IBinder?, + session: android.app.IBinderSession?, + dead: Boolean + ) {} } init { diff --git a/hiddenapi/stubs/src/main/java/android/app/IBinderSession.java b/hiddenapi/stubs/src/main/java/android/app/IBinderSession.java new file mode 100644 index 000000000..1dc3d5777 --- /dev/null +++ b/hiddenapi/stubs/src/main/java/android/app/IBinderSession.java @@ -0,0 +1,35 @@ +package android.app; + +import android.os.IBinder; +import android.os.IInterface; + +/** + * Stub of {@code android.app.IBinderSession} introduced in Android 17 (API 36+). + * + *
This interface is used as a parameter of the new
+ * {@link IServiceConnection#connected} overload added in Android 17. On older
+ * Android versions this class does not exist at runtime, but because the stub
+ * is only referenced from the new {@code connected} overload (which is never
+ * invoked on older versions), the absence of the runtime class is not a
+ * problem — the method is never dispatched there.
+ */
+public interface IBinderSession extends IInterface {
+
+ String DESCRIPTOR = "android.app.IBinderSession";
+
+ void binderTransactionCompleted(long transactionId);
+
+ long binderTransactionStarting(String name);
+
+ abstract class Stub extends android.os.Binder implements IBinderSession {
+
+ public static IBinderSession asInterface(IBinder obj) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IBinder asBinder() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java b/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
index a531e1bc1..4bdcf7637 100644
--- a/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
+++ b/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
@@ -6,8 +6,22 @@
import android.os.IInterface;
public interface IServiceConnection extends IInterface {
+
+ /**
+ * Old signature, used on Android 8.1 ~ 16. Removed from the framework
+ * interface in Android 17, but kept here so that code compiling against
+ * this stub can still override it (the method is simply never invoked on
+ * Android 17+).
+ */
void connected(ComponentName name, IBinder service, boolean dead);
+ /**
+ * New signature introduced in Android 17 (API 36+). On older Android
+ * versions this overload does not exist at runtime and is never invoked,
+ * so overriding it is harmless there.
+ */
+ void connected(ComponentName name, IBinder service, IBinderSession session, boolean dead);
+
abstract class Stub extends Binder implements IServiceConnection {
public static IServiceConnection asInterface(IBinder obj) {
From 73f7b331f7e8f09433133e9e4460c3649a1ea99c Mon Sep 17 00:00:00 2001
From: Leaf <1587968048@qq.com>
Date: Mon, 13 Jul 2026 21:47:04 +0800
Subject: [PATCH 2/4] Fix native version flag quoting for Windows builds
The build system passed string macros to the C/C++ compiler wrapped in
single quotes, e.g. -DVERSION_NAME='2.0' and
-DINJECTED_PACKAGE_NAME='com.android.shell'. On Linux/macOS the shell
strips the single quotes and the compiler sees a quoted string literal,
but on Windows single quotes are not shell quoting characters, so the
compiler receives -DVERSION_NAME='2.0' (a multi-character constant) or
-DINJECTED_PACKAGE_NAME='com.android.shell', causing compilation
failures:
- narrowing conversion from 'int' to 'const char*'
- expected unqualified-id / multi-character constant
Fix by passing the values as bare tokens
(-DVERSION_NAME=2.0, -DINJECTED_PACKAGE_NAME=com.android.shell) and
stringizing them at the C++ side via a STRINGIZE macro, which is robust
across Windows and Unix toolchains. Also move the stringize helper
macros out of a namespace (macros are not namespace members and cannot
be invoked with a qualified name).
---
build.gradle.kts | 2 +-
native/include/common/config.h | 9 ++++++++-
zygisk/build.gradle.kts | 4 ++--
zygisk/src/main/cpp/module.cpp | 12 ++++++++----
4 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 0b078cd04..08ecb2f86 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -102,7 +102,7 @@ subprojects {
val flags =
listOf(
"-DVERSION_CODE=${versionCodeProvider.get()}",
- "-DVERSION_NAME='\"${versionNameProvider.get()}\"'",
+ "-DVERSION_NAME=${versionNameProvider.get()}",
)
val args =
diff --git a/native/include/common/config.h b/native/include/common/config.h
index 88beeeb63..97a06461b 100644
--- a/native/include/common/config.h
+++ b/native/include/common/config.h
@@ -45,7 +45,14 @@ inline constexpr auto kLinkerPath = "/linker";
/// The version code of the library, populated by the build system.
const int kVersionCode = VERSION_CODE;
+// Stringize the VERSION_NAME token so the build system can pass it as a bare
+// token (e.g. -DVERSION_NAME=2.0) without quoting, which is fragile across
+// Windows / Unix toolchains. Macros are not namespace members, so these must
+// live at file scope.
+#define VECTOR_STRINGIZE(x) #x
+#define VECTOR_STRINGIZE_TOKEN(x) VECTOR_STRINGIZE(x)
+
/// The version name of the library, populated by the build system.
-const char *const kVersionName = VERSION_NAME;
+const char *const kVersionName = VECTOR_STRINGIZE_TOKEN(VERSION_NAME);
} // namespace vector::native
diff --git a/zygisk/build.gradle.kts b/zygisk/build.gradle.kts
index 1757ab170..be214fe55 100644
--- a/zygisk/build.gradle.kts
+++ b/zygisk/build.gradle.kts
@@ -27,9 +27,9 @@ android {
val flags =
listOf(
- "-DINJECTED_PACKAGE_NAME='\"${injectedPackageName}\"'",
+ "-DINJECTED_PACKAGE_NAME=${injectedPackageName}",
"-DINJECTED_PACKAGE_UID=${injectedPackageUid}",
- "-DMANAGER_PACKAGE_NAME='\"${defaultManagerPackageName}\"'",
+ "-DMANAGER_PACKAGE_NAME=${defaultManagerPackageName}",
)
externalNativeBuild {
diff --git a/zygisk/src/main/cpp/module.cpp b/zygisk/src/main/cpp/module.cpp
index 1692239a0..8c2b010e1 100644
--- a/zygisk/src/main/cpp/module.cpp
+++ b/zygisk/src/main/cpp/module.cpp
@@ -32,10 +32,14 @@ constexpr int SHARED_RELRO_UID = 1037;
// Android uses this to separate users. UID = AppID + UserID * 10000.
constexpr int PER_USER_RANGE = 100000;
-// Defined via CMake generated marcos
+// Defined via CMake generated marcos.
+// Package names are passed as bare tokens (no quotes) because quoting is
+// fragile across Windows / Unix toolchains; stringize them here instead.
+#define VECTOR_STR(x) #x
+#define VECTOR_STR_TOKEN(x) VECTOR_STR(x)
constexpr uid_t kHostPackageUid = INJECTED_PACKAGE_UID;
-const char *const kHostPackageName = INJECTED_PACKAGE_NAME;
-const char *const kManagerPackageName = MANAGER_PACKAGE_NAME;
+const char *const kHostPackageName = VECTOR_STR_TOKEN(INJECTED_PACKAGE_NAME);
+const char *const kManagerPackageName = VECTOR_STR_TOKEN(MANAGER_PACKAGE_NAME);
constexpr uid_t GID_INET = 3003; // Android's Internet group ID.
enum RuntimeFlags : uint32_t {
@@ -260,7 +264,7 @@ void VectorModule::preAppSpecialize(zygisk::AppSpecializeArgs *args) {
jint inet_gid = GID_INET;
env_->SetIntArrayRegion(new_gids, original_gids_count, 1, &inet_gid);
- args->nice_name = env_->NewStringUTF(INJECTED_PACKAGE_NAME);
+ args->nice_name = env_->NewStringUTF(kHostPackageName);
args->gids = new_gids;
}
}
From fc6924e5ad3c128ff1a979e7b71c514ced7d1b7a Mon Sep 17 00:00:00 2001
From: JingMatrix This interface is used as a parameter of the new
- * {@link IServiceConnection#connected} overload added in Android 17. On older
- * Android versions this class does not exist at runtime, but because the stub
- * is only referenced from the new {@code connected} overload (which is never
- * invoked on older versions), the absence of the runtime class is not a
- * problem — the method is never dispatched there.
+ * Stub of {@code android.app.IBinderSession}, added in Android 17 (API 37),
+ * where it appears as a parameter of {@link IServiceConnection#connected}.
*/
-public interface IBinderSession extends IInterface {
-
- String DESCRIPTOR = "android.app.IBinderSession";
-
- void binderTransactionCompleted(long transactionId);
-
- long binderTransactionStarting(String name);
-
- abstract class Stub extends android.os.Binder implements IBinderSession {
-
- public static IBinderSession asInterface(IBinder obj) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public IBinder asBinder() {
- throw new UnsupportedOperationException();
- }
- }
-}
+public interface IBinderSession extends IInterface {}
diff --git a/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java b/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
index 4bdcf7637..034ec8acc 100644
--- a/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
+++ b/hiddenapi/stubs/src/main/java/android/app/IServiceConnection.java
@@ -7,19 +7,10 @@
public interface IServiceConnection extends IInterface {
- /**
- * Old signature, used on Android 8.1 ~ 16. Removed from the framework
- * interface in Android 17, but kept here so that code compiling against
- * this stub can still override it (the method is simply never invoked on
- * Android 17+).
- */
+ /** Declared by the framework up to Android 16. */
void connected(ComponentName name, IBinder service, boolean dead);
- /**
- * New signature introduced in Android 17 (API 36+). On older Android
- * versions this overload does not exist at runtime and is never invoked,
- * so overriding it is harmless there.
- */
+ /** Declared by the framework from Android 17 (API 37) on. */
void connected(ComponentName name, IBinder service, IBinderSession session, boolean dead);
abstract class Stub extends Binder implements IServiceConnection {