From f1a4b8231e0f9e2083739779de67fb0b936b6ce2 Mon Sep 17 00:00:00 2001 From: mbricchi Date: Tue, 16 Jul 2024 15:46:32 +0200 Subject: [PATCH 1/2] android: Fix Java.choose() on newer ART APEXes Equivalent to the system version on Android 14. --- lib/android.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/android.js b/lib/android.js index 06b2adc..bdf1ace 100644 --- a/lib/android.js +++ b/lib/android.js @@ -618,6 +618,7 @@ function _getArtRuntimeSpec (api) { const apiLevel = getAndroidApiLevel(); const codename = getAndroidCodename(); + const isApiLevel34OrApexEquivalent = Module.findExportByName('libart.so', '_ZN3art7AppInfo29GetPrimaryApkReferenceProfileEv') !== null; let spec = null; @@ -645,7 +646,7 @@ function _getArtRuntimeSpec (api) { const threadListOffset = internTableOffset - pointerSize; let heapOffset; - if (apiLevel >= 34) { + if (isApiLevel34OrApexEquivalent) { heapOffset = threadListOffset - (9 * pointerSize); } else if (apiLevel >= 24) { heapOffset = threadListOffset - (8 * pointerSize); From f2c614adaa90cdd442fbcbebdf768f896ee03c6e Mon Sep 17 00:00:00 2001 From: mbricchi Date: Wed, 17 Jul 2024 22:02:30 +0200 Subject: [PATCH 2/2] android: Properly handle the CMC GC strategy - With Google Play System Updates the base version of libart may differ from the Android version. For example, an Android 12 system could be using libart equivalent to the system version on Android 14. - The function we were hooking in the MarkCompact GC was not the right spot to update the class pointers, causing crashes after some time. Fixes #323, for real this time. --- lib/android.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/android.js b/lib/android.js index bdf1ace..d696b89 100644 --- a/lib/android.js +++ b/lib/android.js @@ -1808,6 +1808,9 @@ on_leave_gc_concurrent_copying_copying_phase (GumInvocationContext * ic) Gc: { copyingPhase: { onLeave: cm.on_leave_gc_concurrent_copying_copying_phase + }, + runFlip: { + onEnter: cm.on_leave_gc_concurrent_copying_copying_phase } } } @@ -1885,19 +1888,22 @@ function ensureArtKnowsHowToHandleReplacementMethods (vm) { const apiLevel = getAndroidApiLevel(); - let exportName = null; - if (apiLevel > 28) { - exportName = '_ZN3art2gc9collector17ConcurrentCopying12CopyingPhaseEv'; - } else if (apiLevel > 22) { - exportName = '_ZN3art2gc9collector17ConcurrentCopying12MarkingPhaseEv'; - } - - if (exportName !== null) { - Interceptor.attach(Module.getExportByName('libart.so', exportName), artController.hooks.Gc.copyingPhase); + const mayUseCollector = (apiLevel > 28) + ? new NativeFunction(Module.getExportByName('libart.so', '_ZNK3art2gc4Heap15MayUseCollectorENS0_13CollectorTypeE'), 'bool', ['pointer', 'int']) + : () => false; + const kCollectorTypeCMC = 3; - const collectorCMC = Module.findExportByName('libart.so', '_ZN3art2gc9collector11MarkCompact15CompactionPhaseEv'); - if (collectorCMC !== null) { - Interceptor.attach(collectorCMC, artController.hooks.Gc.copyingPhase); + if (mayUseCollector(getApi().artHeap, kCollectorTypeCMC)) { + Interceptor.attach(Module.getExportByName('libart.so', '_ZN3art6Thread15RunFlipFunctionEPS0_b'), artController.hooks.Gc.runFlip); + } else { + let exportName = null; + if (apiLevel > 28) { + exportName = '_ZN3art2gc9collector17ConcurrentCopying12CopyingPhaseEv'; + } else if (apiLevel > 22) { + exportName = '_ZN3art2gc9collector17ConcurrentCopying12MarkingPhaseEv'; + } + if (exportName !== null) { + Interceptor.attach(Module.getExportByName('libart.so', exportName), artController.hooks.Gc.copyingPhase); } } }