blob: 10ea43a1ee190444240a3787fde18b51cfe36744 [file] [log] [blame]
Alex Light3f33c0a2017-11-08 10:17:37 -08001/* Copyright (C) 2017 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
Alex Light3f33c0a2017-11-08 10:17:37 -080025 *
26 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
27 * or visit www.oracle.com if you need additional information or have any
28 * questions.
29 */
30
31#include <vector>
32
Alex Lightd55b8442019-10-15 15:46:07 -070033#include "jvmti.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080034#include "ti_extension.h"
35
36#include "art_jvmti.h"
Alex Light8c2b9292017-11-09 13:21:01 -080037#include "events.h"
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000038#include "jni_id_type.h"
39#include "runtime-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080040#include "ti_allocator.h"
Alex Lightc7588752018-02-20 11:15:54 -080041#include "ti_class.h"
Alex Light8c2b9292017-11-09 13:21:01 -080042#include "ti_ddms.h"
Alex Lightb2146942019-03-12 15:46:40 +000043#include "ti_dump.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080044#include "ti_heap.h"
Alex Lightae45cbb2018-10-18 15:49:56 -070045#include "ti_logging.h"
Alex Lightc98f83e2018-07-26 08:28:36 -070046#include "ti_monitor.h"
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +000047#include "ti_redefine.h"
Alex Light639e73b2019-05-17 21:44:36 +000048#include "ti_search.h"
Alex Lightd55b8442019-10-15 15:46:07 -070049#include "transform.h"
Alex Lightae45cbb2018-10-18 15:49:56 -070050
Alex Light8c2b9292017-11-09 13:21:01 -080051#include "thread-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080052
53namespace openjdkjvmti {
54
55struct CParamInfo {
56 const char* name;
57 jvmtiParamKind kind;
58 jvmtiParamTypes base_type;
59 jboolean null_ok;
60
61 jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
62 /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
63 /*out*/jvmtiError* err) const {
64 JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
65 char* name_ptr = param_name.get();
66 char_buffers->push_back(std::move(param_name));
Igor Murashkin5573c372017-11-16 13:34:30 -080067 return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
Alex Light3f33c0a2017-11-08 10:17:37 -080068 }
69};
70
71jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
72 jint* extension_count_ptr,
73 jvmtiExtensionFunctionInfo** extensions) {
74 if (extension_count_ptr == nullptr || extensions == nullptr) {
75 return ERR(NULL_POINTER);
76 }
77
78 std::vector<jvmtiExtensionFunctionInfo> ext_vector;
79
80 // Holders for allocated values.
81 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
82 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
83 std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
84
85 auto add_extension = [&](jvmtiExtensionFunction func,
86 const char* id,
87 const char* short_description,
88 const std::vector<CParamInfo>& params,
89 const std::vector<jvmtiError>& errors) {
90 jvmtiExtensionFunctionInfo func_info;
91 jvmtiError error;
92
93 func_info.func = func;
94
95 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
96 if (id_ptr == nullptr) {
97 return error;
98 }
99 func_info.id = id_ptr.get();
100 char_buffers.push_back(std::move(id_ptr));
101
102 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
103 if (descr == nullptr) {
104 return error;
105 }
106 func_info.short_description = descr.get();
107 char_buffers.push_back(std::move(descr));
108
109 func_info.param_count = params.size();
110 if (!params.empty()) {
111 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
112 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
113 if (params_ptr == nullptr) {
114 return error;
115 }
116 func_info.params = params_ptr.get();
117 param_buffers.push_back(std::move(params_ptr));
118
119 for (jint i = 0; i != func_info.param_count; ++i) {
120 func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
121 if (error != OK) {
122 return error;
123 }
124 }
125 } else {
126 func_info.params = nullptr;
127 }
128
129 func_info.error_count = errors.size();
130 if (!errors.empty()) {
131 JvmtiUniquePtr<jvmtiError[]> errors_ptr =
132 AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
133 if (errors_ptr == nullptr) {
134 return error;
135 }
136 func_info.errors = errors_ptr.get();
137 error_buffers.push_back(std::move(errors_ptr));
138
139 for (jint i = 0; i != func_info.error_count; ++i) {
140 func_info.errors[i] = errors[i];
141 }
142 } else {
143 func_info.errors = nullptr;
144 }
145
146 ext_vector.push_back(func_info);
147
148 return ERR(NONE);
149 };
150
151 jvmtiError error;
152
153 // Heap extensions.
154 error = add_extension(
155 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
156 "com.android.art.heap.get_object_heap_id",
157 "Retrieve the heap id of the the object tagged with the given argument. An "
158 "arbitrary object is chosen if multiple objects exist with the same tag.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800159 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800160 { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
161 { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
162 },
163 { JVMTI_ERROR_NOT_FOUND });
164 if (error != ERR(NONE)) {
165 return error;
166 }
167
168 error = add_extension(
169 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
170 "com.android.art.heap.get_heap_name",
171 "Retrieve the name of the heap with the given id.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800172 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800173 { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
174 { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
175 },
176 { JVMTI_ERROR_ILLEGAL_ARGUMENT });
177 if (error != ERR(NONE)) {
178 return error;
179 }
180
181 error = add_extension(
182 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
183 "com.android.art.heap.iterate_through_heap_ext",
184 "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
185 " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
186 " structure is reused, with the callbacks field overloaded to a signature of "
187 "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
Igor Murashkin5573c372017-11-16 13:34:30 -0800188 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800189 { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
190 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
191 { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
192 { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
193 },
Igor Murashkin5573c372017-11-16 13:34:30 -0800194 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800195 ERR(MUST_POSSESS_CAPABILITY),
196 ERR(INVALID_CLASS),
197 ERR(NULL_POINTER),
198 });
199 if (error != ERR(NONE)) {
200 return error;
201 }
202
203 error = add_extension(
204 reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
205 "com.android.art.alloc.get_global_jvmti_allocation_state",
206 "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
207 " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
208 " through the 'Deallocate' function. This number is approximate and might not correspond"
209 " exactly to the sum of the sizes of all not freed allocations.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800210 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800211 { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
212 },
213 { ERR(NULL_POINTER) });
214 if (error != ERR(NONE)) {
215 return error;
216 }
217
Alex Light8c2b9292017-11-09 13:21:01 -0800218 // DDMS extension
219 error = add_extension(
220 reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
221 "com.android.art.internal.ddm.process_chunk",
222 "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
223 " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
224 " reasons only. Agents should avoid making use of this extension when possible and instead"
225 " use the other JVMTI entrypoints explicitly.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800226 {
Alex Light8c2b9292017-11-09 13:21:01 -0800227 { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
228 { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
Alex Light6f2a6342017-12-12 09:55:05 -0800229 { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
Alex Light8c2b9292017-11-09 13:21:01 -0800230 { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
231 { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
232 { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
233 },
234 { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
235 if (error != ERR(NONE)) {
236 return error;
237 }
238
Alex Lightc7588752018-02-20 11:15:54 -0800239 // GetClassLoaderClassDescriptors extension
240 error = add_extension(
241 reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetClassLoaderClassDescriptors),
242 "com.android.art.class.get_class_loader_class_descriptors",
243 "Retrieves a list of all the classes (as class descriptors) that the given class loader is"
244 " capable of being the defining class loader for. The return format is a list of"
245 " null-terminated descriptor strings of the form \"L/java/lang/Object;\". Each descriptor"
246 " will be in the list at most once. If the class_loader is null the bootclassloader will be"
247 " used. If the class_loader is not null it must either be a java.lang.BootClassLoader, a"
248 " dalvik.system.BaseDexClassLoader or a derived type. The data_out list and all elements"
249 " must be deallocated by the caller.",
250 {
251 { "class_loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
252 { "class_descriptor_count_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
253 { "data_out", JVMTI_KIND_ALLOC_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
254 },
255 {
256 ERR(NULL_POINTER),
257 ERR(ILLEGAL_ARGUMENT),
258 ERR(OUT_OF_MEMORY),
259 ERR(NOT_IMPLEMENTED),
260 });
261 if (error != ERR(NONE)) {
262 return error;
263 }
Alex Lightc98f83e2018-07-26 08:28:36 -0700264
265 // Raw monitors no suspend
266 error = add_extension(
267 reinterpret_cast<jvmtiExtensionFunction>(MonitorUtil::RawMonitorEnterNoSuspend),
268 "com.android.art.concurrent.raw_monitor_enter_no_suspend",
269 "Normally entering a monitor will not return until both the monitor is locked and the"
270 " current thread is not suspended. This method will return once the monitor is locked"
271 " even if the thread is suspended. Note that using rawMonitorWait will wait until the"
272 " thread is not suspended again on wakeup and so should be avoided.",
273 {
274 { "raw_monitor", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false },
275 },
276 {
277 ERR(NULL_POINTER),
278 ERR(INVALID_MONITOR),
279 });
280 if (error != ERR(NONE)) {
281 return error;
282 }
Alex Lightae45cbb2018-10-18 15:49:56 -0700283
284 // GetLastError extension
285 error = add_extension(
286 reinterpret_cast<jvmtiExtensionFunction>(LogUtil::GetLastError),
287 "com.android.art.misc.get_last_error_message",
288 "In some cases the jvmti plugin will log data about errors to the android logcat. These can"
289 " be useful to tools so we make (some) of the messages available here as well. This will"
290 " fill the given 'msg' buffer with the last non-fatal message associated with this"
291 " jvmti-env. Note this is best-effort only, not all log messages will be accessible through"
292 " this API. This will return the last error-message from all threads. Care should be taken"
293 " interpreting the return value when used with a multi-threaded program. The error message"
294 " will only be cleared by a call to 'com.android.art.misc.clear_last_error_message' and will"
295 " not be cleared by intervening successful calls. If no (tracked) error message has been"
296 " sent since the last call to clear_last_error_message this API will return"
297 " JVMTI_ERROR_ABSENT_INFORMATION. Not all failures will cause an error message to be"
298 " recorded.",
299 {
300 { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
301 },
302 {
303 ERR(NULL_POINTER),
304 ERR(ABSENT_INFORMATION),
305 });
306 if (error != ERR(NONE)) {
307 return error;
308 }
309
310 // ClearLastError extension
311 error = add_extension(
312 reinterpret_cast<jvmtiExtensionFunction>(LogUtil::ClearLastError),
313 "com.android.art.misc.clear_last_error_message",
314 "Clears the error message returned by 'com.android.art.misc.get_last_error_message'.",
315 { },
316 { });
317 if (error != ERR(NONE)) {
318 return error;
319 }
320
Alex Lightb2146942019-03-12 15:46:40 +0000321 // DumpInternalState
322 error = add_extension(
323 reinterpret_cast<jvmtiExtensionFunction>(DumpUtil::DumpInternalState),
324 "com.android.art.misc.get_plugin_internal_state",
325 "Gets internal state about the plugin and serializes it to the given msg. "
326 "There is no particular format to this message beyond being human readable.",
327 {
328 { "msg", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false },
329 },
330 { ERR(NULL_POINTER) });
331 if (error != ERR(NONE)) {
332 return error;
333 }
334
Alex Light639e73b2019-05-17 21:44:36 +0000335 // AddToDexClassLoader
336 error = add_extension(
337 reinterpret_cast<jvmtiExtensionFunction>(SearchUtil::AddToDexClassLoader),
338 "com.android.art.classloader.add_to_dex_class_loader",
339 "Adds a dexfile to a given dalvik.system.BaseDexClassLoader in a manner similar to"
340 " AddToSystemClassLoader.",
341 {
342 { "classloader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
343 { "segment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false },
344 },
345 {
346 ERR(NULL_POINTER),
347 ERR(CLASS_LOADER_UNSUPPORTED),
348 ERR(ILLEGAL_ARGUMENT),
349 ERR(WRONG_PHASE),
350 });
351 if (error != ERR(NONE)) {
352 return error;
353 }
354
355 // AddToDexClassLoaderInMemory
356 error = add_extension(
357 reinterpret_cast<jvmtiExtensionFunction>(SearchUtil::AddToDexClassLoaderInMemory),
358 "com.android.art.classloader.add_to_dex_class_loader_in_memory",
359 "Adds a dexfile buffer to a given dalvik.system.BaseDexClassLoader in a manner similar to"
360 " AddToSystemClassLoader. This may only be done during the LIVE phase. The buffer is copied"
361 " and the caller is responsible for deallocating it after this call.",
362 {
363 { "classloader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
364 { "dex_bytes", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
365 { "dex_bytes_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
366 },
367 {
368 ERR(NULL_POINTER),
369 ERR(CLASS_LOADER_UNSUPPORTED),
370 ERR(ILLEGAL_ARGUMENT),
371 ERR(WRONG_PHASE),
372 });
373 if (error != ERR(NONE)) {
374 return error;
375 }
376
Alex Lightc14ec8f2019-07-18 16:08:41 -0700377 // ChangeArraySize
378 error = add_extension(
379 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::ChangeArraySize),
380 "com.android.art.heap.change_array_size",
381 "Changes the size of a java array. As far as all JNI and java code is concerned this is"
382 " atomic. Must have can_tag_objects capability. If the new length of the array is smaller"
383 " than the original length, then the array will be truncated to the new length. Otherwise,"
384 " all new slots will be filled with null, 0, or False as appropriate for the array type.",
385 {
386 { "array", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
387 { "new_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
388 },
389 {
390 ERR(NULL_POINTER),
391 ERR(MUST_POSSESS_CAPABILITY),
392 ERR(ILLEGAL_ARGUMENT),
393 ERR(OUT_OF_MEMORY),
394 });
395 if (error != ERR(NONE)) {
396 return error;
397 }
398
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +0000399 // These require index-ids and debuggable to function
400 art::Runtime* runtime = art::Runtime::Current();
401 if (runtime->GetJniIdType() == art::JniIdType::kIndices &&
402 (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) {
403 // IsStructurallyModifiableClass
404 error = add_extension(
405 reinterpret_cast<jvmtiExtensionFunction>(Redefiner::IsStructurallyModifiableClass),
406 "com.android.art.class.is_structurally_modifiable_class",
407 "Returns whether a class can potentially be 'structurally' redefined using the various"
408 " structural redefinition extensions provided.",
409 {
410 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
411 { "result", JVMTI_KIND_OUT, JVMTI_TYPE_JBOOLEAN, false },
412 },
413 {
414 ERR(INVALID_CLASS),
415 ERR(NULL_POINTER),
416 });
417 if (error != ERR(NONE)) {
418 return error;
419 }
420
Alex Lightd55b8442019-10-15 15:46:07 -0700421 // StructurallyRedefineClasses
422 error = add_extension(
423 reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClasses),
424 "com.android.art.class.structurally_redefine_classes",
425 "Entrypoint for structural class redefinition. Has the same signature as RedefineClasses."
Alex Light270db1c2019-12-03 12:20:01 +0000426 " Only supports additive changes, methods and fields may not be removed. Supertypes and"
427 " implemented interfaces may not be changed. After calling this"
428 " com.android.art.structural_dex_file_load_hook events will be triggered, followed by"
429 " re-transformable ClassFileLoadHook events. After this method completes subsequent"
430 " RetransformClasses calls will use the input to this function as the initial class"
431 " definition.",
Alex Lightd55b8442019-10-15 15:46:07 -0700432 {
Alex Light270db1c2019-12-03 12:20:01 +0000433 { "num_classes", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
434 { "class_definitions", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CVOID, false },
Alex Lightd55b8442019-10-15 15:46:07 -0700435 },
436 {
Alex Light270db1c2019-12-03 12:20:01 +0000437 ERR(CLASS_LOADER_UNSUPPORTED),
438 ERR(FAILS_VERIFICATION),
439 ERR(ILLEGAL_ARGUMENT),
440 ERR(INVALID_CLASS),
441 ERR(MUST_POSSESS_CAPABILITY),
442 ERR(MUST_POSSESS_CAPABILITY),
443 ERR(NULL_POINTER),
444 ERR(OUT_OF_MEMORY),
445 ERR(UNMODIFIABLE_CLASS),
446 ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
447 ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
448 ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
449 ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
Alex Lightd55b8442019-10-15 15:46:07 -0700450 });
451 if (error != ERR(NONE)) {
452 return error;
453 }
454
455 // StructurallyRedefineClassDirect
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +0000456 error = add_extension(
457 reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClassDirect),
458 "com.android.art.UNSAFE.class.structurally_redefine_class_direct",
459 "Temporary prototype entrypoint for redefining a single class structurally. Currently this"
460 " only supports adding new static fields to a class without any instances."
461 " ClassFileLoadHook events will NOT be triggered. This does not currently support creating"
462 " obsolete methods. This function only has rudimentary error checking. This should not be"
463 " used except for testing.",
464 {
465 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
466 { "new_def", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
467 { "new_def_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
468 },
469 {
470 ERR(CLASS_LOADER_UNSUPPORTED),
471 ERR(FAILS_VERIFICATION),
472 ERR(ILLEGAL_ARGUMENT),
473 ERR(INVALID_CLASS),
474 ERR(MUST_POSSESS_CAPABILITY),
475 ERR(MUST_POSSESS_CAPABILITY),
476 ERR(NULL_POINTER),
477 ERR(OUT_OF_MEMORY),
478 ERR(UNMODIFIABLE_CLASS),
479 ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
480 ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
481 ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
482 ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
483 });
484 if (error != ERR(NONE)) {
485 return error;
486 }
487 } else {
488 LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
489 << "class redefinition extensions.";
490 }
Alex Light8f951832020-02-24 14:31:54 -0800491 // SetVerboseFlagExt
492 error = add_extension(
493 reinterpret_cast<jvmtiExtensionFunction>(LogUtil::SetVerboseFlagExt),
494 "com.android.art.misc.set_verbose_flag_ext",
495 "Sets the verbose flags selected by the 'option' c-string. Valid options are anything that"
496 " would be accepted by the -verbose:<option> runtime flag. The verbose selections are turned"
497 " on if 'enable' is set to true and disabled otherwise. You may select multiple options at"
498 " once using commas just like with the -verbose:<option> flag. For example \"class,deopt,gc\""
499 " is equivalent to turning on all of the VLOG(class_linker), VLOG(deopt) and VLOG(gc)"
500 " messages.",
501 {
502 { "option", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
503 { "enable", JVMTI_KIND_IN, JVMTI_TYPE_JBOOLEAN, false },
504 },
505 {
506 ERR(NULL_POINTER),
507 ERR(ILLEGAL_ARGUMENT),
508 });
509 if (error != ERR(NONE)) {
510 return error;
511 }
Alex Light1a0e2922021-01-12 13:57:42 +0000512 // GetHiddenApiEnforcementPolicy
513 error = add_extension(
514 reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetHiddenApiEnforcementPolicy),
515 "com.android.art.misc.get_hidden_api_enforcement_policy",
516 "Gets the current hiddenapi enforcement policy. Policy values are defined in"
517 " `frameworks/base/core/java/android/content/pm/ApplicationInfo.java` as the"
518 " HIDDEN_API_ENFORCEMENT_ static fields. See the comments in `art/runtime/hidden_api.h` for"
519 " more information. This should be used with"
520 " `com.android.art.misc.set_hidden_api_enforcement_policy` in order to restore the"
521 " hidden-api state after temporarily toggling it.",
522 {
523 { "policy", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
524 },
525 {
526 ERR(NULL_POINTER),
527 });
528 if (error != ERR(NONE)) {
529 return error;
530 }
531 // SetHiddenApiEnforcementPolicy
532 error = add_extension(
533 reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::SetHiddenApiEnforcementPolicy),
534 "com.android.art.misc.set_hidden_api_enforcement_policy",
535 "Sets the hiddenapi enforcement policy to the given value. Policy values are defined in"
536 " `frameworks/base/core/java/android/content/pm/ApplicationInfo.java` as the"
537 " HIDDEN_API_ENFORCEMENT_ static fields. See the comments in `art/runtime/hidden_api.h` for"
538 " more information. This API should always be used sparingly and in conjunction with"
539 " `com.android.art.misc.get_hidden_api_enforcement_policy` to temporarily toggle"
540 " hidden-api on and off as changes are required.",
541 {
542 { "policy", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
543 },
544 {
545 ERR(ILLEGAL_ARGUMENT),
546 });
547 if (error != ERR(NONE)) {
548 return error;
549 }
550 // DisableHiddenApiEnforcementPolicy
551 error = add_extension(
552 reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::DisableHiddenApiEnforcementPolicy),
553 "com.android.art.misc.disable_hidden_api_enforcement_policy",
554 "Sets the hiddenapi enforcement policy to disabled. This API should always be"
555 " used sparingly and in conjunction with"
556 " `com.android.art.misc.get_hidden_api_enforcement_policy` and"
557 " `com.android.art.misc.set_hidden_api_enforcement_policy` to temporarily"
558 " toggle hidden-api on and off as changes are required.",
559 {},
560 {});
561 if (error != ERR(NONE)) {
562 return error;
563 }
Nicolas Geoffray4ac0e152019-09-18 06:14:50 +0000564
Alex Light3f33c0a2017-11-08 10:17:37 -0800565 // Copy into output buffer.
566
567 *extension_count_ptr = ext_vector.size();
568 JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
569 AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
570 if (out_data == nullptr) {
571 return error;
572 }
573 memcpy(out_data.get(),
574 ext_vector.data(),
575 ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
576 *extensions = out_data.release();
577
578 // Release all the buffer holders, we're OK now.
579 for (auto& holder : char_buffers) {
580 holder.release();
581 }
582 for (auto& holder : param_buffers) {
583 holder.release();
584 }
585 for (auto& holder : error_buffers) {
586 holder.release();
587 }
588
589 return OK;
590}
591
592
Alex Light8c2b9292017-11-09 13:21:01 -0800593jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
Alex Light3f33c0a2017-11-08 10:17:37 -0800594 jint* extension_count_ptr,
595 jvmtiExtensionEventInfo** extensions) {
Alex Light8c2b9292017-11-09 13:21:01 -0800596 std::vector<jvmtiExtensionEventInfo> ext_vector;
597
598 // Holders for allocated values.
599 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
600 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
601
602 auto add_extension = [&](ArtJvmtiEvent extension_event_index,
603 const char* id,
604 const char* short_description,
605 const std::vector<CParamInfo>& params) {
Alex Lightd55b8442019-10-15 15:46:07 -0700606 DCHECK(IsExtensionEvent(extension_event_index)) << static_cast<jint>(extension_event_index);
Alex Light8c2b9292017-11-09 13:21:01 -0800607 jvmtiExtensionEventInfo event_info;
608 jvmtiError error;
609
610 event_info.extension_event_index = static_cast<jint>(extension_event_index);
611
612 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
613 if (id_ptr == nullptr) {
614 return error;
615 }
616 event_info.id = id_ptr.get();
617 char_buffers.push_back(std::move(id_ptr));
618
619 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
620 if (descr == nullptr) {
621 return error;
622 }
623 event_info.short_description = descr.get();
624 char_buffers.push_back(std::move(descr));
625
626 event_info.param_count = params.size();
627 if (!params.empty()) {
628 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
629 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
630 if (params_ptr == nullptr) {
631 return error;
632 }
633 event_info.params = params_ptr.get();
634 param_buffers.push_back(std::move(params_ptr));
635
636 for (jint i = 0; i != event_info.param_count; ++i) {
637 event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
638 if (error != OK) {
639 return error;
640 }
641 }
642 } else {
643 event_info.params = nullptr;
644 }
645
646 ext_vector.push_back(event_info);
647
648 return ERR(NONE);
649 };
650
651 jvmtiError error;
652 error = add_extension(
653 ArtJvmtiEvent::kDdmPublishChunk,
Alex Light32846612020-07-14 10:38:06 -0700654 "com.android.art.internal.ddm.publish_chunk_safe",
Alex Light8c2b9292017-11-09 13:21:01 -0800655 "Called when there is new ddms information that the agent or other clients can use. The"
656 " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
657 " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
658 " is responsible for interpreting the information present in the 'data' buffer. This is"
659 " provided for backwards-compatibility support only. Agents should prefer to use relevant"
Alex Light32846612020-07-14 10:38:06 -0700660 " JVMTI events and functions above listening for this event. Previous publish_chunk"
661 " event was inherently unsafe since using the JNIEnv could cause deadlocks in some scenarios."
662 " The current version does not have these issues.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800663 {
Alex Light8c2b9292017-11-09 13:21:01 -0800664 { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
665 { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
666 { "data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
667 });
668 if (error != OK) {
669 return error;
670 }
Alex Light72d7e942019-07-23 13:10:20 -0700671 error = add_extension(
672 ArtJvmtiEvent::kObsoleteObjectCreated,
673 "com.android.art.heap.obsolete_object_created",
674 "Called when an obsolete object is created.\n"
675 "An object becomes obsolete when, due to some jvmti function call all references to the"
676 " object are replaced with a reference to a different object. After this call finishes there"
677 " will be no strong references to the obsolete object anywere. If the object is retrieved"
678 " using GetObjectsWithTags its type (class) may have changed and any data it contains may"
679 " have been deleted. This is primarily designed to support memory tracking agents which make"
680 " use of the ObjectFree and VMObjectAlloc events for tracking. To support this use-case if"
681 " this event is not being handled it will by default act as though the following code was"
682 " registered as a handler:\n"
683 "\n"
684 " void HandleObsoleteObjectCreated(jvmtiEnv* env, jlong* obsolete_tag, jlong* new_tag) {\n"
685 " jlong temp = *obsolete_tag;\n"
686 " *obsolete_tag = *new_tag;\n"
687 " *new_tag = temp;\n"
688 " }\n"
689 "\n"
690 "Note that this event does not support filtering based on thread. This event has the same"
691 " restrictions on JNI and JVMTI function calls as the ObjectFree event.\n"
692 "\n"
693 "Arguments:\n"
694 " obsolete_tag: Pointer to the tag the old object (now obsolete) has. Setting the pointer"
695 " will update the tag value.\n"
696 " new_tag: Pointer to the tag the new object (replacing the obsolete one) has. Setting the"
697 " pointer will update the tag value.",
698 {
699 { "obsolete_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
700 { "new_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
701 });
702 if (error != OK) {
703 return error;
704 }
Alex Lightd55b8442019-10-15 15:46:07 -0700705 art::Runtime* runtime = art::Runtime::Current();
706 if (runtime->GetJniIdType() == art::JniIdType::kIndices &&
707 (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) {
708 error = add_extension(
709 ArtJvmtiEvent::kStructuralDexFileLoadHook,
710 "com.android.art.class.structural_dex_file_load_hook",
711 "Called during class load, after a 'RetransformClasses' call, or after a 'RedefineClasses'"
712 " call in order to allow the agent to modify the class. This event is called after any"
713 " non-can_retransform_classes ClassFileLoadHookEvents and before any"
714 " can_retransform_classes ClassFileLoadHookEvents. The transformations applied are"
715 " restricted in the same way that transformations applied via the "
716 " 'com.android.art.class.structurally_redefine_classes' extension function. The arguments"
717 " to the event are identical to the ones in the ClassFileLoadHook and have the same"
718 " semantics.",
719 {
720 { "jni_env", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, false },
721 { "class_being_redefined", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true },
722 { "loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
723 { "name", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false },
724 { "protection_domain", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
725 { "dex_data_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
726 { "dex_data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
727 { "new_dex_data_len", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
728 { "new_dex_data", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, true },
729 });
730 } else {
731 LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
732 << "class redefinition extensions.";
733 }
Alex Light8c2b9292017-11-09 13:21:01 -0800734 // Copy into output buffer.
735
736 *extension_count_ptr = ext_vector.size();
737 JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
738 AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
739 if (out_data == nullptr) {
740 return error;
741 }
742 memcpy(out_data.get(),
743 ext_vector.data(),
744 ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
745 *extensions = out_data.release();
746
747 // Release all the buffer holders, we're OK now.
748 for (auto& holder : char_buffers) {
749 holder.release();
750 }
751 for (auto& holder : param_buffers) {
752 holder.release();
753 }
754
Alex Light3f33c0a2017-11-08 10:17:37 -0800755 return OK;
756}
757
Alex Light8c2b9292017-11-09 13:21:01 -0800758jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
759 jint extension_event_index,
760 jvmtiExtensionEvent callback,
761 EventHandler* event_handler) {
762 if (!IsExtensionEvent(extension_event_index)) {
763 return ERR(ILLEGAL_ARGUMENT);
764 }
765 ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
766 jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
767 // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
768 // change to the normal callbacks.
769 {
770 art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
771 if (art_env->event_callbacks.get() == nullptr) {
772 art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
773 }
774 jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
775 if (err != OK) {
776 return err;
777 }
778 }
779 return event_handler->SetEvent(art_env,
Andreas Gampe6e897762018-10-16 13:09:32 -0700780 /*thread=*/nullptr,
Alex Light8c2b9292017-11-09 13:21:01 -0800781 static_cast<ArtJvmtiEvent>(extension_event_index),
782 mode);
Alex Light3f33c0a2017-11-08 10:17:37 -0800783}
784
785} // namespace openjdkjvmti