1 /*
2  * Copyright (C) 2019 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 <stdio.h>
18 
19 #include <vector>
20 
21 #include "android-base/logging.h"
22 #include "android-base/macros.h"
23 #include "jni.h"
24 #include "jvmti.h"
25 
26 // Test infrastructure
27 #include "jvmti_helper.h"
28 #include "scoped_local_ref.h"
29 #include "test_env.h"
30 
31 namespace art {
32 namespace Test2005PauseAllRedefineMultithreaded {
33 
34 static constexpr jlong kRedefinedObjectTag = 0xDEADBEEF;
35 
36 extern "C" JNIEXPORT void JNICALL
Java_art_Test2005_UpdateFieldValuesAndResumeThreads(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobjectArray threads_arr,jclass redefined_class,jobjectArray new_fields,jstring default_val)37 Java_art_Test2005_UpdateFieldValuesAndResumeThreads(JNIEnv* env,
38                                                     jclass klass ATTRIBUTE_UNUSED,
39                                                     jobjectArray threads_arr,
40                                                     jclass redefined_class,
41                                                     jobjectArray new_fields,
42                                                     jstring default_val) {
43   std::vector<jthread> threads;
44   for (jint i = 0; i < env->GetArrayLength(threads_arr); i++) {
45     threads.push_back(env->GetObjectArrayElement(threads_arr, i));
46   }
47   std::vector<jfieldID> fields;
48   for (jint i = 0; i < env->GetArrayLength(new_fields); i++) {
49     fields.push_back(env->FromReflectedField(env->GetObjectArrayElement(new_fields, i)));
50   }
51   // Tag every instance of the redefined class with kRedefinedObjectTag
52   CHECK_EQ(jvmti_env->IterateOverInstancesOfClass(
53                redefined_class,
54                JVMTI_HEAP_OBJECT_EITHER,
55                [](jlong class_tag ATTRIBUTE_UNUSED,
56                   jlong size ATTRIBUTE_UNUSED,
57                   jlong* tag_ptr,
58                   void* user_data ATTRIBUTE_UNUSED) -> jvmtiIterationControl {
59                  *tag_ptr = kRedefinedObjectTag;
60                  return JVMTI_ITERATION_CONTINUE;
61                },
62                nullptr),
63            JVMTI_ERROR_NONE);
64   jobject* objs;
65   jint cnt;
66   // Get the objects.
67   CHECK_EQ(jvmti_env->GetObjectsWithTags(1, &kRedefinedObjectTag, &cnt, &objs, nullptr),
68            JVMTI_ERROR_NONE);
69   // Set every field that's null
70   for (jint i = 0; i < cnt; i++) {
71     jobject obj = objs[i];
72     for (jfieldID field : fields) {
73       if (ScopedLocalRef<jobject>(env, env->GetObjectField(obj, field)).get() == nullptr) {
74         env->SetObjectField(obj, field, default_val);
75       }
76     }
77   }
78   LOG(INFO) << "Setting " << cnt << " objects with default values";
79   if (!threads.empty()) {
80     std::vector<jvmtiError> errs(threads.size(), JVMTI_ERROR_NONE);
81     CHECK_EQ(jvmti_env->ResumeThreadList(threads.size(), threads.data(), errs.data()),
82              JVMTI_ERROR_NONE);
83   }
84   jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(objs));
85 }
86 
87 }  // namespace Test2005PauseAllRedefineMultithreaded
88 }  // namespace art
89