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 "901-hello-ti-agent/basics.h"
18
19 #include <thread>
20
21 #include <jni.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "android-base/macros.h"
25 #include "jvmti.h"
26
27 // Test infrastructure
28 #include "jvmti_helper.h"
29 #include "test_env.h"
30
31 namespace art {
32 namespace Test901HelloTi {
33
EnableEvent(jvmtiEnv * env,jvmtiEvent evt)34 static void EnableEvent(jvmtiEnv* env, jvmtiEvent evt) {
35 jvmtiError error = env->SetEventNotificationMode(JVMTI_ENABLE, evt, nullptr);
36 if (error != JVMTI_ERROR_NONE) {
37 printf("Failed to enable event");
38 }
39 }
40
getPhase(jvmtiEnv * jenv)41 static jvmtiPhase getPhase(jvmtiEnv* jenv) {
42 jvmtiPhase out = static_cast<jvmtiPhase>(-1);
43 jenv->GetPhase(&out);
44 return out;
45 }
46
VMStartCallback(jvmtiEnv * jenv,JNIEnv * jni_env ATTRIBUTE_UNUSED)47 static void JNICALL VMStartCallback(jvmtiEnv *jenv, JNIEnv* jni_env ATTRIBUTE_UNUSED) {
48 printf("VMStart (phase %d)\n", getPhase(jenv));
49 fsync(1);
50 }
51
VMInitCallback(jvmtiEnv * jvmti_env,JNIEnv * jni_env ATTRIBUTE_UNUSED,jthread thread ATTRIBUTE_UNUSED)52 static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
53 JNIEnv* jni_env ATTRIBUTE_UNUSED,
54 jthread thread ATTRIBUTE_UNUSED) {
55 printf("VMInit (phase %d)\n", getPhase(jvmti_env));
56 fsync(1);
57 }
58
VMDeathCallback(jvmtiEnv * jenv,JNIEnv * jni_env)59 static void JNICALL VMDeathCallback(jvmtiEnv *jenv, JNIEnv* jni_env) {
60 printf("VMDeath (phase %d)\n", getPhase(jenv));
61 fsync(1);
62 jthread cur_thr;
63 CHECK_EQ(jenv->GetCurrentThread(&cur_thr), JVMTI_ERROR_NONE);
64 CHECK(cur_thr != nullptr);
65 jni_env->DeleteLocalRef(cur_thr);
66 }
67
68
InstallVMEvents(jvmtiEnv * env)69 static void InstallVMEvents(jvmtiEnv* env) {
70 jvmtiEventCallbacks callbacks;
71 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
72 callbacks.VMStart = VMStartCallback;
73 callbacks.VMInit = VMInitCallback;
74 callbacks.VMDeath = VMDeathCallback;
75 jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
76 if (ret != JVMTI_ERROR_NONE) {
77 printf("Failed to install callbacks");
78 }
79
80 EnableEvent(env, JVMTI_EVENT_VM_START);
81 EnableEvent(env, JVMTI_EVENT_VM_INIT);
82 EnableEvent(env, JVMTI_EVENT_VM_DEATH);
83 }
84
OnLoad(JavaVM * vm,char * options ATTRIBUTE_UNUSED,void * reserved ATTRIBUTE_UNUSED)85 jint OnLoad(JavaVM* vm,
86 char* options ATTRIBUTE_UNUSED,
87 void* reserved ATTRIBUTE_UNUSED) {
88 printf("Loaded Agent for test 901-hello-ti-agent\n");
89 fsync(1);
90 jvmtiEnv* env = nullptr;
91 jvmtiEnv* env2 = nullptr;
92
93 #define CHECK_CALL_SUCCESS(c) \
94 do { \
95 if ((c) != JNI_OK) { \
96 printf("call " #c " did not succeed\n"); \
97 return -1; \
98 } \
99 } while (false)
100
101 CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_0));
102 CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env2), JVMTI_VERSION_1_0));
103 if (env == env2) {
104 printf("GetEnv returned same environment twice!\n");
105 return -1;
106 }
107 unsigned char* local_data = nullptr;
108 CHECK_CALL_SUCCESS(env->Allocate(8, &local_data));
109 strcpy(reinterpret_cast<char*>(local_data), "hello!!");
110 CHECK_CALL_SUCCESS(env->SetEnvironmentLocalStorage(local_data));
111 unsigned char* get_data = nullptr;
112 CHECK_CALL_SUCCESS(env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&get_data)));
113 if (get_data != local_data) {
114 printf("Got different data from local storage then what was set!\n");
115 return -1;
116 }
117 CHECK_CALL_SUCCESS(env2->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&get_data)));
118 if (get_data != nullptr) {
119 printf("env2 did not have nullptr local storage.\n");
120 return -1;
121 }
122 CHECK_CALL_SUCCESS(env->Deallocate(local_data));
123 jint version = 0;
124 CHECK_CALL_SUCCESS(env->GetVersionNumber(&version));
125 if ((version & JVMTI_VERSION_1) != JVMTI_VERSION_1) {
126 printf("Unexpected version number!\n");
127 return -1;
128 }
129
130 InstallVMEvents(env);
131 InstallVMEvents(env2);
132
133 CHECK_CALL_SUCCESS(env->DisposeEnvironment());
134 CHECK_CALL_SUCCESS(env2->DisposeEnvironment());
135 #undef CHECK_CALL_SUCCESS
136
137 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
138 printf("Unable to get jvmti env!\n");
139 return 1;
140 }
141 SetStandardCapabilities(jvmti_env);
142
143 jvmtiPhase current_phase;
144 jvmtiError phase_result = jvmti_env->GetPhase(¤t_phase);
145 if (phase_result != JVMTI_ERROR_NONE) {
146 printf("Could not get phase");
147 return 1;
148 }
149 if (current_phase != JVMTI_PHASE_ONLOAD) {
150 printf("Wrong phase");
151 return 1;
152 }
153
154 InstallVMEvents(jvmti_env);
155
156 return JNI_OK;
157 }
158
Java_art_Test901_setVerboseFlag(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jint iflag,jboolean val)159 extern "C" JNIEXPORT void JNICALL Java_art_Test901_setVerboseFlag(
160 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jint iflag, jboolean val) {
161 jvmtiVerboseFlag flag = static_cast<jvmtiVerboseFlag>(iflag);
162 jvmtiError result = jvmti_env->SetVerboseFlag(flag, val);
163 JvmtiErrorToException(env, jvmti_env, result);
164 }
165
Java_art_Test901_checkLivePhase(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED)166 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test901_checkLivePhase(
167 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
168 jvmtiPhase current_phase;
169 jvmtiError phase_result = jvmti_env->GetPhase(¤t_phase);
170 if (JvmtiErrorToException(env, jvmti_env, phase_result)) {
171 return JNI_FALSE;
172 }
173 return (current_phase == JVMTI_PHASE_LIVE) ? JNI_TRUE : JNI_FALSE;
174 }
175
CallJvmtiFunction(jvmtiEnv * env,jclass klass,jvmtiError * err)176 static void CallJvmtiFunction(jvmtiEnv* env, jclass klass, jvmtiError* err) {
177 jint n;
178 jmethodID* methods = nullptr;
179 *err = env->GetClassMethods(klass, &n, &methods);
180 }
181
Java_art_Test901_checkUnattached(JNIEnv * env ATTRIBUTE_UNUSED,jclass Main_klass)182 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test901_checkUnattached(
183 JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass) {
184 jvmtiError res = JVMTI_ERROR_NONE;
185 std::thread t1(CallJvmtiFunction, jvmti_env, Main_klass, &res);
186 t1.join();
187 return res == JVMTI_ERROR_UNATTACHED_THREAD;
188 }
189
Java_art_Test901_getErrorName(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jint error)190 extern "C" JNIEXPORT jstring JNICALL Java_art_Test901_getErrorName(
191 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jint error) {
192 char* name;
193 jvmtiError res = jvmti_env->GetErrorName(static_cast<jvmtiError>(error), &name);
194 if (JvmtiErrorToException(env, jvmti_env, res)) {
195 return nullptr;
196 }
197
198 jstring ret_string = env->NewStringUTF(name);
199 jvmtiError dealloc = jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
200 if (JvmtiErrorToException(env, jvmti_env, dealloc)) {
201 return nullptr;
202 }
203
204 return ret_string;
205 }
206
207 } // namespace Test901HelloTi
208 } // namespace art
209