1 /*
2  * Copyright (C) 2017 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 "jni.h"
18 
19 #include "android-base/logging.h"
20 #include "android-base/macros.h"
21 #include "jni_binder.h"
22 #include "jni_helper.h"
23 #include "jvmti_helper.h"
24 #include "jvmti.h"
25 #include "scoped_primitive_array.h"
26 #include "test_env.h"
27 
28 namespace art {
29 
Java_android_jvmti_cts_JniBindings_setTag(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject obj,jlong tag)30 extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JniBindings_setTag(
31     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jlong tag) {
32   jvmtiError ret = jvmti_env->SetTag(obj, tag);
33   JvmtiErrorToException(env, jvmti_env, ret);
34 }
35 
Java_android_jvmti_cts_JniBindings_getTag(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject obj)36 extern "C" JNIEXPORT jlong JNICALL Java_android_jvmti_cts_JniBindings_getTag(
37     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj) {
38   jlong tag = 0;
39   jvmtiError ret = jvmti_env->GetTag(obj, &tag);
40   if (JvmtiErrorToException(env, jvmti_env, ret)) {
41     return 0;
42   }
43   return tag;
44 }
45 
Java_android_jvmti_cts_JvmtiTaggingTest_getTaggedObjects(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jlongArray searchTags,jboolean returnObjects,jboolean returnTags)46 extern "C" JNIEXPORT jobjectArray JNICALL Java_android_jvmti_cts_JvmtiTaggingTest_getTaggedObjects(
47     JNIEnv* env,
48     jclass klass ATTRIBUTE_UNUSED,
49     jlongArray searchTags,
50     jboolean returnObjects,
51     jboolean returnTags) {
52   ScopedLongArrayRO scoped_array(env);
53   if (searchTags != nullptr) {
54     scoped_array.reset(searchTags);
55   }
56   const jlong* tag_ptr = scoped_array.get();
57   if (tag_ptr == nullptr) {
58     // Can never pass null.
59     tag_ptr = reinterpret_cast<const jlong*>(1);
60   }
61 
62   jint result_count = -1;
63   jobject* result_object_array = nullptr;
64   jobject** result_object_array_ptr = returnObjects == JNI_TRUE ? &result_object_array : nullptr;
65   jlong* result_tag_array = nullptr;
66   jlong** result_tag_array_ptr = returnTags == JNI_TRUE ? &result_tag_array : nullptr;
67 
68   jvmtiError ret = jvmti_env->GetObjectsWithTags(scoped_array.size(),
69                                                  tag_ptr,
70                                                  &result_count,
71                                                  result_object_array_ptr,
72                                                  result_tag_array_ptr);
73   if (JvmtiErrorToException(env, jvmti_env, ret)) {
74     return nullptr;
75   }
76 
77   CHECK_GE(result_count, 0);
78 
79   jobjectArray resultObjectArray = nullptr;
80   if (returnObjects == JNI_TRUE) {
81     auto callback = [&](jint i) {
82       return result_object_array[i];
83     };
84     resultObjectArray = CreateObjectArray(env, result_count, "java/lang/Object", callback);
85     if (resultObjectArray == nullptr) {
86       return nullptr;
87     }
88   }
89   if (result_object_array != nullptr) {
90     CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, result_object_array));
91   }
92 
93   jlongArray resultTagArray = nullptr;
94   if (returnTags == JNI_TRUE) {
95     resultTagArray = env->NewLongArray(result_count);
96     if (resultTagArray == nullptr) {
97       return nullptr;
98     }
99     env->SetLongArrayRegion(resultTagArray, 0, result_count, result_tag_array);
100   }
101   if (result_tag_array != nullptr) {
102     CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, result_tag_array));
103   }
104 
105   jobject count_integer;
106   {
107     ScopedLocalRef<jclass> integer_class(env, env->FindClass("java/lang/Integer"));
108     jmethodID methodID = env->GetMethodID(integer_class.get(), "<init>", "(I)V");
109     count_integer = env->NewObject(integer_class.get(), methodID, result_count);
110     if (count_integer == nullptr) {
111       return nullptr;
112     }
113   }
114 
115   auto callback = [&](jint i) -> jobject {
116     jobject ret = nullptr;
117     switch(i) {
118       case 0:
119         ret = resultObjectArray;
120         break;
121       case 1:
122         ret = resultTagArray;
123         break;
124       case 2:
125         ret = count_integer;
126         break;
127       default:
128         LOG(FATAL) << "Unexpected";
129     }
130     return ret;
131   };
132   return CreateObjectArray(env, 3, "java/lang/Object", callback);
133 }
134 
135 static JNINativeMethod gMethodsForMain[] = {
136   { "setTag", "(Ljava/lang/Object;J)V",
137           (void*)Java_android_jvmti_cts_JniBindings_setTag },
138 
139   { "getTag", "(Ljava/lang/Object;)J",
140           (void*)Java_android_jvmti_cts_JniBindings_getTag },
141 };
142 
register_art_Main(jvmtiEnv * jenv,JNIEnv * env)143 void register_art_Main(jvmtiEnv* jenv, JNIEnv* env) {
144   ScopedLocalRef<jclass> klass(env, GetClass(jenv, env, "art/Main", nullptr));
145   if (klass.get() == nullptr) {
146     env->ExceptionClear();
147     return;
148   }
149 
150   env->RegisterNatives(klass.get(), gMethodsForMain,
151           sizeof(gMethodsForMain) / sizeof(JNINativeMethod));
152   if (env->ExceptionCheck()) {
153     env->ExceptionClear();
154     LOG(ERROR) << "Could not register natives for Main class";
155   }
156 }
157 
158 static JNINativeMethod gMethods[] = {
159   { "getTaggedObjects", "([JZZ)[Ljava/lang/Object;",
160           (void*)Java_android_jvmti_cts_JvmtiTaggingTest_getTaggedObjects },
161 };
162 
register_android_jvmti_cts_JvmtiTaggingTest(jvmtiEnv * jenv,JNIEnv * env)163 void register_android_jvmti_cts_JvmtiTaggingTest(jvmtiEnv* jenv, JNIEnv* env) {
164   ScopedLocalRef<jclass> klass(env, GetClass(jenv, env,
165           "android/jvmti/cts/JvmtiTaggingTest", nullptr));
166   if (klass.get() == nullptr) {
167     env->ExceptionClear();
168     return;
169   }
170 
171   env->RegisterNatives(klass.get(), gMethods, sizeof(gMethods) / sizeof(JNINativeMethod));
172   if (env->ExceptionCheck()) {
173     env->ExceptionClear();
174     LOG(ERROR) << "Could not register natives for JvmtiTaggingTest class";
175   }
176 }
177 
178 }  // namespace art
179 
180