1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "common_helper.h"
18 
19 #include <cstdio>
20 #include <deque>
21 #include <map>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 #include "jni.h"
27 #include "jvmti.h"
28 
29 #include "jvmti_helper.h"
30 #include "test_env.h"
31 
32 namespace art {
33 
34 enum class RedefineType {
35   kNormal,
36   kStructural,
37 };
38 
39 static void SetupCommonRedefine();
40 static void SetupCommonRetransform(RedefineType type);
41 static void SetupCommonTransform();
42 template <bool is_redefine>
throwCommonRedefinitionError(jvmtiEnv * jvmti,JNIEnv * env,jint num_targets,jclass * target,jvmtiError res)43 static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
44                                          JNIEnv* env,
45                                          jint num_targets,
46                                          jclass* target,
47                                          jvmtiError res) {
48   // Get the last error message which might give more details on what went wrong.
49   using GetLastError = jvmtiError (*)(jvmtiEnv* env, char** msg);
50   GetLastError get_last_error =
51       GetExtensionFunction<GetLastError>(env, jvmti, "com.android.art.misc.get_last_error_message");
52   char* error_msg = nullptr;
53   if (get_last_error != nullptr) {
54     get_last_error(jvmti_env, &error_msg);
55   }
56 
57   std::stringstream err;
58   char* error = nullptr;
59   jvmti->GetErrorName(res, &error);
60   err << "Failed to " << (is_redefine ? "redefine" : "retransform") << " class";
61   if (num_targets > 1) {
62     err << "es";
63   }
64   err << " <";
65   for (jint i = 0; i < num_targets; i++) {
66     char* signature = nullptr;
67     char* generic = nullptr;
68     jvmti->GetClassSignature(target[i], &signature, &generic);
69     if (i != 0) {
70       err << ", ";
71     }
72     err << signature;
73     jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
74     jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
75   }
76   err << "> due to " << error;
77   if (error_msg != nullptr) {
78     err << " (" << error_msg << ")";
79   }
80   std::string message = err.str();
81   jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
82   jvmti->Deallocate(reinterpret_cast<unsigned char*>(error_msg));
83   env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
84 }
85 
86 #define CONFIGURATION_COMMON_REDEFINE 0
87 #define CONFIGURATION_COMMON_RETRANSFORM 1
88 #define CONFIGURATION_COMMON_TRANSFORM 2
89 #define CONFIGURATION_STRUCTURAL_TRANSFORM 3
90 
Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv *,jclass,jint type)91 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*,
92                                                                                    jclass,
93                                                                                    jint type) {
94   switch (type) {
95     case CONFIGURATION_COMMON_REDEFINE: {
96       SetupCommonRedefine();
97       return;
98     }
99     case CONFIGURATION_COMMON_RETRANSFORM: {
100       SetupCommonRetransform(RedefineType::kNormal);
101       return;
102     }
103     case CONFIGURATION_COMMON_TRANSFORM: {
104       SetupCommonTransform();
105       return;
106     }
107     case CONFIGURATION_STRUCTURAL_TRANSFORM: {
108       SetupCommonRetransform(RedefineType::kStructural);
109       return;
110     }
111     default: {
112       LOG(FATAL) << "Unknown test configuration: " << type;
113     }
114   }
115 }
116 
117 template<RedefineType kType>
SupportsAndIsJVM()118 static bool SupportsAndIsJVM() {
119   if constexpr (kType == RedefineType::kStructural) {
120     return false;
121   } else {
122     return IsJVM();
123   }
124 }
125 
126 
127 namespace common_redefine {
128 
129 template <RedefineType kType>
CallRedefineEntrypoint(JNIEnv * env,jvmtiEnv * jvmti,jint num_defs,const jvmtiClassDefinition * defs)130 static jvmtiError CallRedefineEntrypoint(JNIEnv* env,
131                                          jvmtiEnv* jvmti,
132                                          jint num_defs,
133                                          const jvmtiClassDefinition* defs) {
134   decltype(jvmti->functions->RedefineClasses) entrypoint = nullptr;
135   if constexpr (kType == RedefineType::kNormal) {
136     entrypoint = jvmti->functions->RedefineClasses;
137   } else {
138     entrypoint = GetExtensionFunction<decltype(entrypoint)>(
139         env, jvmti_env, "com.android.art.class.structurally_redefine_classes");
140   }
141   if (entrypoint == nullptr) {
142     LOG(INFO) << "Could not find entrypoint!";
143     return JVMTI_ERROR_NOT_AVAILABLE;
144   }
145   return entrypoint(jvmti, num_defs, defs);
146 }
147 
throwRedefinitionError(jvmtiEnv * jvmti,JNIEnv * env,jint num_targets,jclass * target,jvmtiError res)148 static void throwRedefinitionError(jvmtiEnv* jvmti,
149                                    JNIEnv* env,
150                                    jint num_targets,
151                                    jclass* target,
152                                    jvmtiError res) {
153   return throwCommonRedefinitionError<true>(jvmti, env, num_targets, target, res);
154 }
155 
156 template<RedefineType kType>
DoMultiClassRedefine(jvmtiEnv * jvmti_env,JNIEnv * env,jint num_redefines,jclass * targets,jbyteArray * class_file_bytes,jbyteArray * dex_file_bytes)157 static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
158                                  JNIEnv* env,
159                                  jint num_redefines,
160                                  jclass* targets,
161                                  jbyteArray* class_file_bytes,
162                                  jbyteArray* dex_file_bytes) {
163   std::vector<jvmtiClassDefinition> defs;
164   for (jint i = 0; i < num_redefines; i++) {
165     jbyteArray desired_array = SupportsAndIsJVM<kType>() ? class_file_bytes[i] : dex_file_bytes[i];
166     jint len = static_cast<jint>(env->GetArrayLength(desired_array));
167     const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
168         env->GetByteArrayElements(desired_array, nullptr));
169     defs.push_back({targets[i], static_cast<jint>(len), redef_bytes});
170   }
171   jvmtiError res = CallRedefineEntrypoint<kType>(env, jvmti_env, num_redefines, defs.data());
172   if (res != JVMTI_ERROR_NONE) {
173     throwRedefinitionError(jvmti_env, env, num_redefines, targets, res);
174   }
175 }
176 
177 template<RedefineType kType>
DoClassRedefine(jvmtiEnv * jvmti_env,JNIEnv * env,jclass target,jbyteArray class_file_bytes,jbyteArray dex_file_bytes)178 static void DoClassRedefine(jvmtiEnv* jvmti_env,
179                             JNIEnv* env,
180                             jclass target,
181                             jbyteArray class_file_bytes,
182                             jbyteArray dex_file_bytes) {
183   return DoMultiClassRedefine<kType>(jvmti_env, env, 1, &target, &class_file_bytes, &dex_file_bytes);
184 }
185 
186 extern "C" JNIEXPORT jboolean JNICALL
Java_art_Redefinition_isStructurallyModifiable(JNIEnv * env,jclass,jclass target)187 Java_art_Redefinition_isStructurallyModifiable(JNIEnv* env, jclass, jclass target) {
188   using ArtCanStructurallyRedefineClass =
189       jvmtiError (*)(jvmtiEnv * env, jclass k, jboolean * result);
190   ArtCanStructurallyRedefineClass can_redef = GetExtensionFunction<ArtCanStructurallyRedefineClass>(
191       env, jvmti_env, "com.android.art.class.is_structurally_modifiable_class");
192   if (can_redef == nullptr || env->ExceptionCheck()) {
193     return false;
194   }
195   jboolean result = false;
196   JvmtiErrorToException(env, jvmti_env, can_redef(jvmti_env, target, &result));
197   return result;
198 }
199 
Java_art_Redefinition_doCommonStructuralClassRedefinition(JNIEnv * env,jclass,jclass target,jbyteArray dex_file_bytes)200 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonStructuralClassRedefinition(
201     JNIEnv* env, jclass, jclass target, jbyteArray dex_file_bytes) {
202   DoClassRedefine<RedefineType::kStructural>(jvmti_env, env, target, nullptr, dex_file_bytes);
203 }
204 
205 // Magic JNI export that classes can use for redefining classes.
206 // To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
Java_art_Redefinition_doCommonClassRedefinition(JNIEnv * env,jclass,jclass target,jbyteArray class_file_bytes,jbyteArray dex_file_bytes)207 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition(
208     JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) {
209   DoClassRedefine<RedefineType::kNormal>(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
210 }
211 
212 // Magic JNI export that classes can use for redefining classes.
213 // To use classes should declare this as a native function with signature
214 // ([Ljava/lang/Class;[[B[[B)V
Java_art_Redefinition_doCommonMultiStructuralClassRedefinition(JNIEnv * env,jclass,jobjectArray targets,jobjectArray dex_file_bytes)215 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiStructuralClassRedefinition(
216     JNIEnv* env,
217     jclass,
218     jobjectArray targets,
219     jobjectArray dex_file_bytes) {
220   std::vector<jclass> classes;
221   std::vector<jbyteArray> class_files;
222   std::vector<jbyteArray> dex_files;
223   jint len = env->GetArrayLength(targets);
224   if (len != env->GetArrayLength(dex_file_bytes)) {
225     env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
226                   "the three array arguments passed to this function have different lengths!");
227     return;
228   }
229   for (jint i = 0; i < len; i++) {
230     classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
231     dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
232     class_files.push_back(nullptr);
233   }
234   return DoMultiClassRedefine<RedefineType::kStructural>(jvmti_env,
235                                                          env,
236                                                          len,
237                                                          classes.data(),
238                                                          class_files.data(),
239                                                          dex_files.data());
240 }
241 
242 // Magic JNI export that classes can use for redefining classes.
243 // To use classes should declare this as a native function with signature
244 // ([Ljava/lang/Class;[[B[[B)V
Java_art_Redefinition_doCommonMultiClassRedefinition(JNIEnv * env,jclass,jobjectArray targets,jobjectArray class_file_bytes,jobjectArray dex_file_bytes)245 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition(
246     JNIEnv* env,
247     jclass,
248     jobjectArray targets,
249     jobjectArray class_file_bytes,
250     jobjectArray dex_file_bytes) {
251   std::vector<jclass> classes;
252   std::vector<jbyteArray> class_files;
253   std::vector<jbyteArray> dex_files;
254   jint len = env->GetArrayLength(targets);
255   if (len != env->GetArrayLength(class_file_bytes) || len != env->GetArrayLength(dex_file_bytes)) {
256     env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
257                   "the three array arguments passed to this function have different lengths!");
258     return;
259   }
260   for (jint i = 0; i < len; i++) {
261     classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
262     dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
263     class_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(class_file_bytes, i)));
264   }
265   return DoMultiClassRedefine<RedefineType::kNormal>(jvmti_env,
266                                                      env,
267                                                      len,
268                                                      classes.data(),
269                                                      class_files.data(),
270                                                      dex_files.data());
271 }
272 
273 // Get all capabilities except those related to retransformation.
OnLoad(JavaVM * vm,char * options,void * reserved)274 jint OnLoad(JavaVM* vm,
275             [[maybe_unused]] char* options,
276             [[maybe_unused]] void* reserved) {
277   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
278     printf("Unable to get jvmti env!\n");
279     return 1;
280   }
281   SetupCommonRedefine();
282   return 0;
283 }
284 
285 }  // namespace common_redefine
286 
287 namespace common_retransform {
288 
289 struct CommonTransformationResult {
290   std::vector<unsigned char> class_bytes;
291   std::vector<unsigned char> dex_bytes;
292 
CommonTransformationResultart::common_retransform::CommonTransformationResult293   CommonTransformationResult(size_t class_size, size_t dex_size)
294       : class_bytes(class_size), dex_bytes(dex_size) {}
295 
296   CommonTransformationResult() = default;
297   CommonTransformationResult(CommonTransformationResult&&) = default;
298   CommonTransformationResult(CommonTransformationResult&) = default;
299 };
300 
301 // Map from class name to transformation result.
302 std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
303 bool gPopTransformations = true;
304 
Java_art_Redefinition_addCommonTransformationResult(JNIEnv * env,jclass,jstring class_name,jbyteArray class_array,jbyteArray dex_array)305 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult(
306     JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) {
307   const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
308   std::string name_str(name_chrs);
309   env->ReleaseStringUTFChars(class_name, name_chrs);
310   CommonTransformationResult trans(env->GetArrayLength(class_array),
311                                    env->GetArrayLength(dex_array));
312   if (env->ExceptionOccurred()) {
313     return;
314   }
315   env->GetByteArrayRegion(class_array,
316                           0,
317                           env->GetArrayLength(class_array),
318                           reinterpret_cast<jbyte*>(trans.class_bytes.data()));
319   if (env->ExceptionOccurred()) {
320     return;
321   }
322   env->GetByteArrayRegion(dex_array,
323                           0,
324                           env->GetArrayLength(dex_array),
325                           reinterpret_cast<jbyte*>(trans.dex_bytes.data()));
326   if (env->ExceptionOccurred()) {
327     return;
328   }
329   if (gTransformations.find(name_str) == gTransformations.end()) {
330     std::deque<CommonTransformationResult> list;
331     gTransformations[name_str] = std::move(list);
332   }
333   gTransformations[name_str].push_back(std::move(trans));
334 }
335 
336 // The hook we are using.
CommonClassFileLoadHookRetransformable(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jclass class_being_redefined,jobject loader,const char * name,jobject protection_domain,jint class_data_len,const unsigned char * class_dat,jint * new_class_data_len,unsigned char ** new_class_data)337 void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
338                                                     [[maybe_unused]] JNIEnv* jni_env,
339                                                     [[maybe_unused]] jclass class_being_redefined,
340                                                     [[maybe_unused]] jobject loader,
341                                                     const char* name,
342                                                     [[maybe_unused]] jobject protection_domain,
343                                                     [[maybe_unused]] jint class_data_len,
344                                                     [[maybe_unused]] const unsigned char* class_dat,
345                                                     jint* new_class_data_len,
346                                                     unsigned char** new_class_data) {
347   std::string name_str(name);
348   if (gTransformations.find(name_str) != gTransformations.end() &&
349       gTransformations[name_str].size() > 0) {
350     CommonTransformationResult& res = gTransformations[name_str][0];
351     const std::vector<unsigned char>& desired_array = IsJVM() ? res.class_bytes : res.dex_bytes;
352     unsigned char* new_data;
353     CHECK_EQ(JVMTI_ERROR_NONE, jvmti_env->Allocate(desired_array.size(), &new_data));
354     memcpy(new_data, desired_array.data(), desired_array.size());
355     *new_class_data = new_data;
356     *new_class_data_len = desired_array.size();
357     if (gPopTransformations) {
358       gTransformations[name_str].pop_front();
359     }
360   }
361 }
362 
Java_art_Redefinition_setPopRetransformations(JNIEnv *,jclass,jboolean enable)363 extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*,
364                                                                         jclass,
365                                                                         jboolean enable) {
366   gPopTransformations = enable;
367 }
368 
Java_art_Redefinition_popTransformationFor(JNIEnv * env,jclass,jstring class_name)369 extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env,
370                                                                          jclass,
371                                                                          jstring class_name) {
372   const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
373   std::string name_str(name_chrs);
374   env->ReleaseStringUTFChars(class_name, name_chrs);
375   if (gTransformations.find(name_str) != gTransformations.end() &&
376       gTransformations[name_str].size() > 0) {
377     gTransformations[name_str].pop_front();
378   } else {
379     std::stringstream err;
380     err << "No transformations found for class " << name_str;
381     std::string message = err.str();
382     env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
383   }
384 }
385 
Java_art_Redefinition_enableCommonRetransformation(JNIEnv * env,jclass,jboolean enable)386 extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env,
387                                                                                  jclass,
388                                                                                  jboolean enable) {
389   jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
390                                                        JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
391                                                        nullptr);
392   if (res != JVMTI_ERROR_NONE) {
393     JvmtiErrorToException(env, jvmti_env, res);
394   }
395 }
396 
throwRetransformationError(jvmtiEnv * jvmti,JNIEnv * env,jint num_targets,jclass * targets,jvmtiError res)397 static void throwRetransformationError(jvmtiEnv* jvmti,
398                                        JNIEnv* env,
399                                        jint num_targets,
400                                        jclass* targets,
401                                        jvmtiError res) {
402   return throwCommonRedefinitionError<false>(jvmti, env, num_targets, targets, res);
403 }
404 
DoClassRetransformation(jvmtiEnv * jvmti_env,JNIEnv * env,jobjectArray targets)405 static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArray targets) {
406   std::vector<jclass> classes;
407   jint len = env->GetArrayLength(targets);
408   classes.reserve(len);
409   for (jint i = 0; i < len; i++) {
410     classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
411   }
412   jvmtiError res = jvmti_env->RetransformClasses(len, classes.data());
413   if (res != JVMTI_ERROR_NONE) {
414     throwRetransformationError(jvmti_env, env, len, classes.data(), res);
415   }
416 }
417 
Java_art_Redefinition_doCommonClassRetransformation(JNIEnv * env,jclass,jobjectArray targets)418 extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation(
419     JNIEnv* env, jclass, jobjectArray targets) {
420   jvmtiCapabilities caps;
421   jvmtiError caps_err = jvmti_env->GetCapabilities(&caps);
422   if (caps_err != JVMTI_ERROR_NONE) {
423     env->ThrowNew(env->FindClass("java/lang/Exception"),
424                   "Unable to get current jvmtiEnv capabilities");
425     return;
426   }
427 
428   // Allocate a new environment if we don't have the can_retransform_classes capability needed to
429   // call the RetransformClasses function.
430   jvmtiEnv* real_env = nullptr;
431   if (caps.can_retransform_classes != 1) {
432     JavaVM* vm = nullptr;
433     if (env->GetJavaVM(&vm) != 0 ||
434         vm->GetEnv(reinterpret_cast<void**>(&real_env), JVMTI_VERSION_1_0) != 0) {
435       env->ThrowNew(env->FindClass("java/lang/Exception"),
436                     "Unable to create temporary jvmtiEnv for RetransformClasses call.");
437       return;
438     }
439     SetStandardCapabilities(real_env);
440   } else {
441     real_env = jvmti_env;
442   }
443   DoClassRetransformation(real_env, env, targets);
444   if (caps.can_retransform_classes != 1) {
445     real_env->DisposeEnvironment();
446   }
447 }
448 
449 // Get all capabilities except those related to retransformation.
OnLoad(JavaVM * vm,char * options,void * reserved)450 jint OnLoad(JavaVM* vm,
451             [[maybe_unused]] char* options,
452             [[maybe_unused]] void* reserved) {
453   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
454     printf("Unable to get jvmti env!\n");
455     return 1;
456   }
457   SetupCommonRetransform(RedefineType::kNormal);
458   return 0;
459 }
460 
461 }  // namespace common_retransform
462 
463 namespace common_transform {
464 
465 // Get all capabilities except those related to retransformation.
OnLoad(JavaVM * vm,char * options,void * reserved)466 jint OnLoad(JavaVM* vm,
467             [[maybe_unused]] char* options,
468             [[maybe_unused]] void* reserved) {
469   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
470     printf("Unable to get jvmti env!\n");
471     return 1;
472   }
473   SetupCommonTransform();
474   return 0;
475 }
476 
477 }  // namespace common_transform
478 
SetupCommonRedefine()479 static void SetupCommonRedefine() {
480   jvmtiCapabilities caps = GetStandardCapabilities();
481   caps.can_retransform_classes = 0;
482   caps.can_retransform_any_class = 0;
483   jvmti_env->AddCapabilities(&caps);
484 }
485 
SetupCommonRetransform(RedefineType type)486 static void SetupCommonRetransform(RedefineType type) {
487   SetStandardCapabilities(jvmti_env);
488   if (type == RedefineType::kNormal) {
489     current_callbacks.ClassFileLoadHook =
490         common_retransform::CommonClassFileLoadHookRetransformable;
491     jvmtiError res = jvmti_env->SetEventCallbacks(&current_callbacks, sizeof(current_callbacks));
492     CHECK_EQ(res, JVMTI_ERROR_NONE);
493   } else {
494     jvmtiError res = jvmti_env->SetExtensionEventCallback(
495         GetExtensionEventId(jvmti_env, "com.android.art.class.structural_dex_file_load_hook"),
496         reinterpret_cast<jvmtiExtensionEvent>(
497             common_retransform::CommonClassFileLoadHookRetransformable));
498     CHECK_EQ(res, JVMTI_ERROR_NONE);
499   }
500   common_retransform::gTransformations.clear();
501 }
502 
SetupCommonTransform()503 static void SetupCommonTransform() {
504   // Don't set the retransform caps
505   jvmtiCapabilities caps = GetStandardCapabilities();
506   caps.can_retransform_classes = 0;
507   caps.can_retransform_any_class = 0;
508   jvmti_env->AddCapabilities(&caps);
509 
510   // Use the same callback as the retransform test.
511   current_callbacks.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
512   jvmtiError res = jvmti_env->SetEventCallbacks(&current_callbacks, sizeof(current_callbacks));
513   CHECK_EQ(res, JVMTI_ERROR_NONE);
514   common_retransform::gTransformations.clear();
515 }
516 
517 }  // namespace art
518