diff --git a/index.d.ts b/index.d.ts index 8237d83..22847d3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -192,6 +192,17 @@ 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; + + /** + * 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 () { /*