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