From 31d40f5043ea0016e13afa38e1b58a9e7df2cb67 Mon Sep 17 00:00:00 2001 From: Electric1447 Date: Mon, 20 Apr 2026 20:39:57 +0300 Subject: [PATCH 1/2] Exported deoptimizeMethod for type script bindings --- index.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/index.d.ts b/index.d.ts index 8237d83..7758375 100644 --- a/index.d.ts +++ b/index.d.ts @@ -192,6 +192,12 @@ declare module "frida-java-bridge" { */ function deoptimizeBootImage(): void; + /** + * Deoptimizes a method / constructor in case hooked callee is not called + * because of inline. + */ + function deoptimizeMethod(method: Method): void; + const vm: VM; /** From 9f340dd3be84c8dda89364c687556887e8310db7 Mon Sep 17 00:00:00 2001 From: Electric1447 Date: Mon, 20 Apr 2026 20:43:28 +0300 Subject: [PATCH 2/2] add art::Instrumentation::IsDeoptimized to api --- index.d.ts | 5 +++++ index.js | 7 ++++++- lib/android.js | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 7758375..22847d3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -198,6 +198,11 @@ declare module "frida-java-bridge" { */ function deoptimizeMethod(method: Method): void; + /** + * Return whether a method is deoptimized. + */ + function isDeoptimized(method: Method): boolean; + const vm: VM; /** diff --git a/index.js b/index.js index ad0a05c..38f9dea 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,8 @@ import { backtrace, deoptimizeEverything, deoptimizeBootImage, - deoptimizeMethod + deoptimizeMethod, + isDeoptimized } from './lib/android.js'; import ClassFactory from './lib/class-factory.js'; import ClassModel from './lib/class-model.js'; @@ -524,6 +525,10 @@ class Runtime { return deoptimizeMethod(vm, vm.getEnv(), method); } + isDeoptimized (method) { + return isDeoptimized(method); + } + _checkAvailable () { if (!this.available) { throw new Error('Java API not available'); diff --git a/lib/android.js b/lib/android.js index 11daebe..6f72729 100644 --- a/lib/android.js +++ b/lib/android.js @@ -311,6 +311,7 @@ function _getApi () { }, _ZN3art7Runtime19DeoptimizeBootImageEv: ['art::Runtime::DeoptimizeBootImage', 'void', ['pointer']], _ZN3art15instrumentation15Instrumentation10DeoptimizeEPNS_9ArtMethodE: ['art::Instrumentation::Deoptimize', 'void', ['pointer', 'pointer']], + _ZN3art15instrumentation15Instrumentation13IsDeoptimizedEPNS_9ArtMethodE: ['art::Instrumentation::IsDeoptimized', 'bool', ['pointer', 'pointer']], // Android >= 11 _ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID: ['art::jni::JniIdManager::DecodeMethodId', 'pointer', ['pointer', 'pointer']], @@ -368,6 +369,7 @@ function _getApi () { '_ZN3art15instrumentation15Instrumentation20DeoptimizeEverythingEv', '_ZN3art7Runtime19DeoptimizeBootImageEv', '_ZN3art15instrumentation15Instrumentation10DeoptimizeEPNS_9ArtMethodE', + '_ZN3art15instrumentation15Instrumentation13IsDeoptimizedEPNS_9ArtMethodE', '_ZN3art3Dbg9StartJdwpEv', '_ZN3art3Dbg8GoActiveEv', '_ZN3art3Dbg21RequestDeoptimizationERKNS_21DeoptimizationRequestE', @@ -4057,6 +4059,21 @@ function requestDeoptimization (vm, env, kind, method) { }); } +export function isDeoptimized (method) { + const api = getApi(); + + if (getAndroidApiLevel() < 24) { + throw new Error('This API is only available on Android >= 7.0'); + } + + const instrumentation = api.artInstrumentation; + if (instrumentation === null) { + throw new Error('Unable to find Instrumentation class in ART; please file a bug'); + } + + return !!api['art::Instrumentation::IsDeoptimized'](instrumentation, method); +} + class JdwpSession { constructor () { /*