blob: 3e2b16802bb16317e0fb644af0c30a3e00fc37c9 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ti-agent/common_helper.h"
#include <stdio.h>
#include "jni.h"
#include "openjdkjvmti/jvmti.h"
#include "ti-agent/common_load.h"
#include "utils.h"
namespace art {
bool RuntimeIsJVM;
bool IsJVM() {
return RuntimeIsJVM;
}
void SetAllCapabilities(jvmtiEnv* env) {
jvmtiCapabilities caps;
env->GetPotentialCapabilities(&caps);
env->AddCapabilities(&caps);
}
namespace common_redefine {
using RedefineDirectFunction = jvmtiError (*)(jvmtiEnv*, jclass, jint, const unsigned char*);
static void DoClassTransformation(jvmtiEnv* jvmti_env, JNIEnv* env,
jclass target,
jbyteArray class_file_bytes,
jbyteArray dex_file_bytes) {
jbyteArray desired_array = IsJVM() ? class_file_bytes : dex_file_bytes;
jint len = static_cast<jint>(env->GetArrayLength(desired_array));
const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
env->GetByteArrayElements(desired_array, nullptr));
jvmtiError res;
if (IsJVM()) {
jvmtiClassDefinition def;
def.klass = target;
def.class_byte_count = static_cast<jint>(len);
def.class_bytes = redef_bytes;
res = jvmti_env->RedefineClasses(1, &def);
} else {
RedefineDirectFunction f =
reinterpret_cast<RedefineDirectFunction>(jvmti_env->functions->reserved3);
res = f(jvmti_env, target, len, redef_bytes);
}
if (res != JVMTI_ERROR_NONE) {
printf("Redefinition failed!");
}
}
// Magic JNI export that classes can use for redefining classes.
// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env,
jclass,
jclass target,
jbyteArray class_file_bytes,
jbyteArray dex_file_bytes) {
DoClassTransformation(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
}
// Don't do anything
jint OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
void* reserved ATTRIBUTE_UNUSED) {
if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
printf("Unable to get jvmti env!\n");
return 1;
}
SetAllCapabilities(jvmti_env);
return 0;
}
} // namespace common_redefine
} // namespace art