From 846d8f18d1400417cd7a8422957c922edc8a5dea Mon Sep 17 00:00:00 2001 From: Siberia_1337 Date: Sun, 5 Apr 2026 15:09:07 +0800 Subject: [PATCH] Fix Android 16 ART Java bridge fast-path detection --- lib/android.js | 9 ++++++++- lib/class-model.js | 25 +++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/android.js b/lib/android.js index 11daebe..c0d6982 100644 --- a/lib/android.js +++ b/lib/android.js @@ -1149,7 +1149,14 @@ export function getArtClassSpec (vm) { } } if (offsetCopiedMethods === -1) { - throw new Error('Unable to find copied methods in java/lang/Thread; please file a bug'); + /* + * Android 16 ART no longer exposes a nearby field whose raw value + * matches the methods_ array length for java/lang/Thread. The class + * model derives the actual method count from the methods_ array header, + * so keep a stable placeholder offset here instead of aborting bridge + * initialization on newer ART builds. + */ + offsetCopiedMethods = offsetMethods; } spec = { diff --git a/lib/class-model.js b/lib/class-model.js index 28b68b0..0d4f055 100644 --- a/lib/class-model.js +++ b/lib/class-model.js @@ -313,8 +313,12 @@ model_new (jclass class_handle, guint field_array_cursor; gboolean merged_fields = art_api.class_offset_sfields == 0; - elements = read_art_array (class_object, art_api.class_offset_methods, sizeof (gsize), NULL); - n = *(guint16 *) (class_object + art_api.class_offset_copied_methods_offset); + /* + * On newer ART builds, copied_methods_offset_ is no longer a reliable + * proxy for the total number of ArtMethod entries. The methods_ array + * header already carries the authoritative length, so use that directly. + */ + elements = read_art_array (class_object, art_api.class_offset_methods, sizeof (gsize), &n); for (i = 0; i != n; i++) { jmethodID id; @@ -333,7 +337,12 @@ model_new (jclass class_handle, method = to_reflected_method (env, class_handle, id, is_static); name = call_object_method (env, method, java_api.method.get_name); name_str = get_string_utf_chars (env, name, NULL); - modifiers = access_flags & 0xffff; + /* + * ART access_flags are no longer a safe source of Java-level modifiers + * on Android 16. Query the reflected Method object instead so static + * methods like Thread.currentThread() keep their correct dispatch kind. + */ + modifiers = call_int_method (env, method, java_api.method.get_modifiers); model_add_method (model, name_str, id, modifiers); @@ -369,7 +378,11 @@ model_new (jclass class_handle, field = to_reflected_field (env, class_handle, id, is_static); name = call_object_method (env, field, java_api.field.get_name); name_str = get_string_utf_chars (env, name, NULL); - modifiers = access_flags & 0xffff; + /* + * Keep field modifiers aligned with the reflected Java view for the + * same reason as methods: raw ART flags are no longer sufficient. + */ + modifiers = call_int_method (env, field, java_api.field.get_modifiers); model_add_field (model, name_str, id, modifiers); @@ -613,8 +626,8 @@ collect_matching_class_methods (ArtClassVisitor * self, class_name_length = strlen (class_name); seen_method_names = ctx->include_signature ? NULL : g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - elements = read_art_array (klass, art_api.class_offset_methods, sizeof (gsize), NULL); - n = *(guint16 *) ((gpointer) klass + art_api.class_offset_copied_methods_offset); + /* Keep enumeration aligned with the authoritative methods_ array length. */ + elements = read_art_array (klass, art_api.class_offset_methods, sizeof (gsize), &n); for (i = 0; i != n; i++) { ArtMethod * method;