class
ArtMethodMangler {
constructor (opaqueMethodId) {
const
methodId = unwrapMethodId(opaqueMethodId);
this
.methodId = methodId;
this
.originalMethod =
null
;
this
.hookedMethodId = methodId;
this
.replacementMethodId =
null
;
this
.interceptor =
null
;
}
replace (impl, isInstanceMethod, argTypes, vm, api) {
const
{ kAccCompileDontBother, artNterpEntryPoint } = api;
this
.originalMethod = fetchArtMethod(
this
.methodId, vm);
const
originalFlags =
this
.originalMethod.accessFlags;
if
((originalFlags & kAccXposedHookedMethod) !==
0
&& xposedIsSupported()) {
const
hookInfo =
this
.originalMethod.jniCode;
this
.hookedMethodId = hookInfo.add(
2
* pointerSize).readPointer();
this
.originalMethod = fetchArtMethod(
this
.hookedMethodId, vm);
}
const
{ hookedMethodId } =
this
;
const
replacementMethodId = cloneArtMethod(hookedMethodId, vm);
this
.replacementMethodId = replacementMethodId;
patchArtMethod(replacementMethodId, {
jniCode: impl,
accessFlags: ((originalFlags & ~(kAccCriticalNative | kAccFastNative | kAccNterpEntryPointFastPathFlag)) | kAccNative | kAccCompileDontBother) >>>
0
,
quickCode: api.artClassLinker.quickGenericJniTrampoline,
interpreterCode: api.artInterpreterToCompiledCodeBridge
}, vm);
let hookedMethodRemovedFlags = kAccFastInterpreterToInterpreterInvoke | kAccSingleImplementation | kAccNterpEntryPointFastPathFlag;
if
((originalFlags & kAccNative) ===
0
) {
hookedMethodRemovedFlags |= kAccSkipAccessChecks;
}
patchArtMethod(hookedMethodId, {
accessFlags: ((originalFlags & ~(hookedMethodRemovedFlags)) | kAccCompileDontBother) >>>
0
}, vm);
const
quickCode =
this
.originalMethod.quickCode;
if
(artNterpEntryPoint !== undefined && quickCode.equals(artNterpEntryPoint)) {
patchArtMethod(hookedMethodId, {
quickCode: api.artQuickToInterpreterBridge
}, vm);
}
if
(!isArtQuickEntrypoint(quickCode)) {
const
interceptor =
new
ArtQuickCodeInterceptor(quickCode);
interceptor.activate(vm);
this
.interceptor = interceptor;
}
artController.replacedMethods.set(hookedMethodId, replacementMethodId);
notifyArtMethodHooked(hookedMethodId, vm);
}
···
}