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,jobjectArray threads_arr,jclass redefined_class,jobjectArray new_fields,jstring default_val)37 Java_art_Test2005_UpdateFieldValuesAndResumeThreads(JNIEnv* env,
38                                                     [[maybe_unused]] jclass klass,
39                                                     jobjectArray threads_arr,
40                                                     jclass redefined_class,
41                                                     jobjectArray new_fields,
42                                                     jstring default_val) {
43   std::vector<jthread> threads;
44   threads.reserve(env->GetArrayLength(threads_arr));
45   for (jint i = 0; i < env->GetArrayLength(threads_arr); i++) {
46     threads.push_back(env->GetObjectArrayElement(threads_arr, i));
47   }
48   std::vector<jfieldID> fields;
49   fields.reserve(env->GetArrayLength(new_fields));
50   for (jint i = 0; i < env->GetArrayLength(new_fields); i++) {
51     fields.push_back(env->FromReflectedField(env->GetObjectArrayElement(new_fields, i)));
52   }
53   // Tag every instance of the redefined class with kRedefinedObjectTag
54   CHECK_EQ(jvmti_env->IterateOverInstancesOfClass(
55                redefined_class,
56                JVMTI_HEAP_OBJECT_EITHER,
57                []([[maybe_unused]] jlong class_tag,
58                   [[maybe_unused]] jlong size,
59                   jlong* tag_ptr,
60                   [[maybe_unused]] void* user_data) -> jvmtiIterationControl {
61                  *tag_ptr = kRedefinedObjectTag;
62                  return JVMTI_ITERATION_CONTINUE;
63                },
64                nullptr),
65            JVMTI_ERROR_NONE);
66   jobject* objs;
67   jint cnt;
68   // Get the objects.
69   CHECK_EQ(jvmti_env->GetObjectsWithTags(1, &kRedefinedObjectTag, &cnt, &objs, nullptr),
70            JVMTI_ERROR_NONE);
71   // Set every field that's null
72   for (jint i = 0; i < cnt; i++) {
73     jobject obj = objs[i];
74     for (jfieldID field : fields) {
75       if (ScopedLocalRef<jobject>(env, env->GetObjectField(obj, field)).get() == nullptr) {
76         env->SetObjectField(obj, field, default_val);
77       }
78     }
79   }
80   LOG(INFO) << "Setting " << cnt << " objects with default values";
81   if (!threads.empty()) {
82     std::vector<jvmtiError> errs(threads.size(), JVMTI_ERROR_NONE);
83     CHECK_EQ(jvmti_env->ResumeThreadList(threads.size(), threads.data(), errs.data()),
84              JVMTI_ERROR_NONE);
85   }
86   jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(objs));
87 }
88 
89 extern "C" JNIEXPORT jobject JNICALL
Java_Main_fastNativeSleepAndReturnInteger42(JNIEnv * env,jclass klass)90 Java_Main_fastNativeSleepAndReturnInteger42(JNIEnv* env, [[maybe_unused]] jclass klass) {
91   jclass integer_class = env->FindClass("java/lang/Integer");
92   CHECK(integer_class != nullptr);
93   jmethodID integer_value_of =
94       env->GetStaticMethodID(integer_class, "valueOf", "(I)Ljava/lang/Integer;");
95   CHECK(integer_value_of != nullptr);
96   jobject value = env->CallStaticObjectMethod(integer_class, integer_value_of, 42);
97   CHECK(value != nullptr);
98   // Sleep for 500ms, blocking thread suspension (this method is @FastNative).
99   // Except for some odd thread timing, this should ensure that the suspend
100   // request from the redefinition thread is seen by the suspend check in the
101   // JNI stub when we exit this function and then processed with the JNI stub
102   // still on the stack. The instrumentation previously erroneously
103   // intercepted returning to the JNI stub and the "instrumentation exit"
104   // handler treated the return value `jobject` as `mirror::Object*`.
105   usleep(500000);
106   return value;
107 }
108 
109 }  // namespace Test2005PauseAllRedefineMultithreaded
110 }  // namespace art
111