Cleanup of redefinition testing

Move redefine logic into a single common function and perform some
other cleanup.

Test: mma -j40 test-art-host
Change-Id: I8618bda4f392b683ce198374066e356b87578e7b
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
new file mode 100644
index 0000000..3e2b168
--- /dev/null
+++ b/test/ti-agent/common_helper.cc
@@ -0,0 +1,91 @@
+/*
+ * 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
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 84997f3..76543fe 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -18,9 +18,19 @@
 #define ART_TEST_TI_AGENT_COMMON_HELPER_H_
 
 #include "jni.h"
+#include "openjdkjvmti/jvmti.h"
 #include "ScopedLocalRef.h"
 
 namespace art {
+namespace common_redefine {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+}  // namespace common_redefine
+
+extern bool RuntimeIsJVM;
+
+bool IsJVM();
 
 template <typename T>
 static jobjectArray CreateObjectArray(JNIEnv* env,
@@ -53,11 +63,7 @@
   return ret.release();
 }
 
-static void SetAllCapabilities(jvmtiEnv* env) {
-  jvmtiCapabilities caps;
-  env->GetPotentialCapabilities(&caps);
-  env->AddCapabilities(&caps);
-}
+void SetAllCapabilities(jvmtiEnv* env);
 
 }  // namespace art
 
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index a959482..2795cbc 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -23,9 +23,9 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "common_load.h"
+#include "common_helper.h"
 
 #include "901-hello-ti-agent/basics.h"
-#include "902-hello-transformation/transform.h"
 #include "903-hello-tagging/tagging.h"
 #include "904-object-allocation/tracking.h"
 #include "905-object-free/tracking_free.h"
@@ -54,7 +54,7 @@
 // A list of all the agents we have for testing.
 AgentLib agents[] = {
   { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
-  { "902-hello-transformation", Test902HelloTransformation::OnLoad, nullptr },
+  { "902-hello-transformation", common_redefine::OnLoad, nullptr },
   { "903-hello-tagging", Test903HelloTagging::OnLoad, nullptr },
   { "904-object-allocation", Test904ObjectAllocation::OnLoad, nullptr },
   { "905-object-free", Test905ObjectFree::OnLoad, nullptr },
@@ -95,6 +95,10 @@
   return true;
 }
 
+static void SetIsJVM(char* options) {
+  RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
+}
+
 extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
   char* remaining_options = nullptr;
   char* name_option = nullptr;
@@ -112,6 +116,7 @@
     printf("agent: %s does not include an OnLoad method.\n", name_option);
     return -3;
   }
+  SetIsJVM(remaining_options);
   return lib->load(vm, remaining_options, reserved);
 }
 
@@ -132,6 +137,7 @@
     printf("agent: %s does not include an OnAttach method.\n", name_option);
     return -3;
   }
+  SetIsJVM(remaining_options);
   return lib->attach(vm, remaining_options, reserved);
 }