1 /* 2 * Copyright (C) 2013 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 "jvmti.h" 18 19 // Test infrastructure 20 #include "jvmti_helper.h" 21 #include "nativehelper/scoped_local_ref.h" 22 #include "nativehelper/scoped_primitive_array.h" 23 #include "test_env.h" 24 25 namespace art { 26 namespace Test1940DdmExt { 27 28 typedef jvmtiError (*DdmHandleChunk)(jvmtiEnv* env, 29 jint type_in, 30 jint len_in, 31 const jbyte* data_in, 32 jint* type_out, 33 jint* len_data_out, 34 jbyte** data_out); 35 36 struct DdmsTrackingData { 37 DdmHandleChunk send_ddm_chunk; 38 jclass test_klass; 39 jmethodID publish_method; 40 }; 41 42 template <typename T> 43 static void Dealloc(T* t) { 44 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(t)); 45 } 46 47 template <typename T, typename ...Rest> 48 static void Dealloc(T* t, Rest... rs) { 49 Dealloc(t); 50 Dealloc(rs...); 51 } 52 53 extern "C" JNIEXPORT jobject JNICALL Java_art_Test1940_processChunk(JNIEnv* env, 54 jclass, 55 jobject chunk) { 56 DdmsTrackingData* data = nullptr; 57 if (JvmtiErrorToException( 58 env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 59 return nullptr; 60 } 61 CHECK(chunk != nullptr); 62 CHECK(data != nullptr); 63 CHECK(data->send_ddm_chunk != nullptr); 64 ScopedLocalRef<jclass> chunk_class(env, env->FindClass("org/apache/harmony/dalvik/ddmc/Chunk")); 65 if (env->ExceptionCheck()) { 66 return nullptr; 67 } 68 jfieldID type_field_id = env->GetFieldID(chunk_class.get(), "type", "I"); 69 jfieldID offset_field_id = env->GetFieldID(chunk_class.get(), "offset", "I"); 70 jfieldID length_field_id = env->GetFieldID(chunk_class.get(), "length", "I"); 71 jfieldID data_field_id = env->GetFieldID(chunk_class.get(), "data", "[B"); 72 jint type = env->GetIntField(chunk, type_field_id); 73 jint off = env->GetIntField(chunk, offset_field_id); 74 jint len = env->GetIntField(chunk, length_field_id); 75 ScopedLocalRef<jbyteArray> chunk_buf( 76 env, reinterpret_cast<jbyteArray>(env->GetObjectField(chunk, data_field_id))); 77 if (env->ExceptionCheck()) { 78 return nullptr; 79 } 80 ScopedByteArrayRO byte_data(env, chunk_buf.get()); 81 jint out_type; 82 jint out_size; 83 jbyte* out_data; 84 if (JvmtiErrorToException(env, jvmti_env, data->send_ddm_chunk(jvmti_env, 85 type, 86 len, 87 &byte_data[off], 88 /*out*/&out_type, 89 /*out*/&out_size, 90 /*out*/&out_data))) { 91 return nullptr; 92 } else { 93 ScopedLocalRef<jbyteArray> chunk_data(env, env->NewByteArray(out_size)); 94 env->SetByteArrayRegion(chunk_data.get(), 0, out_size, out_data); 95 Dealloc(out_data); 96 ScopedLocalRef<jobject> res(env, env->NewObject(chunk_class.get(), 97 env->GetMethodID(chunk_class.get(), 98 "<init>", 99 "(I[BII)V"), 100 out_type, 101 chunk_data.get(), 102 0, 103 out_size)); 104 return res.release(); 105 } 106 } 107 108 static void DeallocParams(jvmtiParamInfo* params, jint n_params) { 109 for (jint i = 0; i < n_params; i++) { 110 Dealloc(params[i].name); 111 } 112 } 113 114 static void JNICALL PublishCB(jvmtiEnv* jvmti, JNIEnv* jnienv, jint type, jint size, jbyte* bytes) { 115 DdmsTrackingData* data = nullptr; 116 if (JvmtiErrorToException(jnienv, jvmti, 117 jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) { 118 return; 119 } 120 ScopedLocalRef<jbyteArray> res(jnienv, jnienv->NewByteArray(size)); 121 jnienv->SetByteArrayRegion(res.get(), 0, size, bytes); 122 jnienv->CallStaticVoidMethod(data->test_klass, data->publish_method, type, res.get()); 123 } 124 125 extern "C" JNIEXPORT void JNICALL Java_art_Test1940_initializeTest(JNIEnv* env, 126 jclass, 127 jclass method_klass, 128 jobject publish_method) { 129 void* old_data = nullptr; 130 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) { 131 return; 132 } else if (old_data != nullptr) { 133 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); 134 env->ThrowNew(rt_exception.get(), "Environment already has local storage set!"); 135 return; 136 } 137 DdmsTrackingData* data = nullptr; 138 if (JvmtiErrorToException(env, 139 jvmti_env, 140 jvmti_env->Allocate(sizeof(DdmsTrackingData), 141 reinterpret_cast<unsigned char**>(&data)))) { 142 return; 143 } 144 memset(data, 0, sizeof(DdmsTrackingData)); 145 data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(method_klass)); 146 data->publish_method = env->FromReflectedMethod(publish_method); 147 if (env->ExceptionCheck()) { 148 return; 149 } 150 // Get the extensions. 151 jint n_ext = 0; 152 jvmtiExtensionFunctionInfo* infos = nullptr; 153 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetExtensionFunctions(&n_ext, &infos))) { 154 return; 155 } 156 for (jint i = 0; i < n_ext; i++) { 157 jvmtiExtensionFunctionInfo* cur_info = &infos[i]; 158 if (strcmp("com.android.art.internal.ddm.process_chunk", cur_info->id) == 0) { 159 data->send_ddm_chunk = reinterpret_cast<DdmHandleChunk>(cur_info->func); 160 } 161 // Cleanup the cur_info 162 DeallocParams(cur_info->params, cur_info->param_count); 163 Dealloc(cur_info->id, cur_info->short_description, cur_info->params, cur_info->errors); 164 } 165 // Cleanup the array. 166 Dealloc(infos); 167 if (data->send_ddm_chunk == nullptr) { 168 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); 169 env->ThrowNew(rt_exception.get(), "Unable to find memory tracking extensions."); 170 return; 171 } 172 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) { 173 return; 174 } 175 176 jint event_index = -1; 177 bool found_event = false; 178 jvmtiExtensionEventInfo* events = nullptr; 179 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetExtensionEvents(&n_ext, &events))) { 180 return; 181 } 182 for (jint i = 0; i < n_ext; i++) { 183 jvmtiExtensionEventInfo* cur_info = &events[i]; 184 if (strcmp("com.android.art.internal.ddm.publish_chunk", cur_info->id) == 0) { 185 found_event = true; 186 event_index = cur_info->extension_event_index; 187 } 188 // Cleanup the cur_info 189 DeallocParams(cur_info->params, cur_info->param_count); 190 Dealloc(cur_info->id, cur_info->short_description, cur_info->params); 191 } 192 // Cleanup the array. 193 Dealloc(events); 194 if (!found_event) { 195 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); 196 env->ThrowNew(rt_exception.get(), "Unable to find ddms extension event."); 197 return; 198 } 199 JvmtiErrorToException(env, 200 jvmti_env, 201 jvmti_env->SetExtensionEventCallback( 202 event_index, reinterpret_cast<jvmtiExtensionEvent>(PublishCB))); 203 return; 204 } 205 206 } // namespace Test1940DdmExt 207 } // namespace art 208