• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 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,
25  *
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 
33 #include "jvmti.h"
34 #include "ti_extension.h"
35 
36 #include "art_jvmti.h"
37 #include "events.h"
38 #include "jni_id_type.h"
39 #include "runtime-inl.h"
40 #include "ti_allocator.h"
41 #include "ti_class.h"
42 #include "ti_ddms.h"
43 #include "ti_dump.h"
44 #include "ti_heap.h"
45 #include "ti_logging.h"
46 #include "ti_monitor.h"
47 #include "ti_redefine.h"
48 #include "ti_search.h"
49 #include "transform.h"
50 
51 #include "thread-inl.h"
52 
53 namespace openjdkjvmti {
54 
55 struct CParamInfo {
56   const char* name;
57   jvmtiParamKind kind;
58   jvmtiParamTypes base_type;
59   jboolean null_ok;
60 
ToParamInfoopenjdkjvmti::CParamInfo61   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));
67     return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
68   }
69 };
70 
GetExtensionFunctions(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionFunctionInfo ** extensions)71 jvmtiError 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.",
159       {
160           { "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.",
172       {
173           { "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).",
188       {
189           { "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       },
194       {
195           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.",
210       {
211           { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
212       },
213       { ERR(NULL_POINTER) });
214   if (error != ERR(NONE)) {
215     return error;
216   }
217 
218   // 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.",
226       {
227         { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
228         { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
229         { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
230         { "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 
239   // 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   }
264 
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   }
283 
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 
321   // 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 
335   // 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 
377   // 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 
399   // These require index-ids and debuggable to function
400   art::Runtime* runtime = art::Runtime::Current();
401   if (runtime->GetJniIdType() == art::JniIdType::kIndices && IsFullJvmtiAvailable()) {
402     // IsStructurallyModifiableClass
403     error = add_extension(
404         reinterpret_cast<jvmtiExtensionFunction>(Redefiner::IsStructurallyModifiableClass),
405         "com.android.art.class.is_structurally_modifiable_class",
406         "Returns whether a class can potentially be 'structurally' redefined using the various"
407         " structural redefinition extensions provided.",
408         {
409           { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
410           { "result", JVMTI_KIND_OUT, JVMTI_TYPE_JBOOLEAN, false },
411         },
412         {
413           ERR(INVALID_CLASS),
414           ERR(NULL_POINTER),
415         });
416     if (error != ERR(NONE)) {
417       return error;
418     }
419 
420     // StructurallyRedefineClasses
421     error = add_extension(
422         reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClasses),
423         "com.android.art.class.structurally_redefine_classes",
424         "Entrypoint for structural class redefinition. Has the same signature as RedefineClasses."
425         " Only supports additive changes, methods and fields may not be removed. Supertypes and"
426         " implemented interfaces may not be changed. After calling this"
427         " com.android.art.structural_dex_file_load_hook events will be triggered, followed by"
428         " re-transformable ClassFileLoadHook events. After this method completes subsequent"
429         " RetransformClasses calls will use the input to this function as the initial class"
430         " definition.",
431         {
432             { "num_classes", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
433             { "class_definitions", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CVOID, false },
434         },
435         {
436             ERR(CLASS_LOADER_UNSUPPORTED),
437             ERR(FAILS_VERIFICATION),
438             ERR(ILLEGAL_ARGUMENT),
439             ERR(INVALID_CLASS),
440             ERR(MUST_POSSESS_CAPABILITY),
441             ERR(MUST_POSSESS_CAPABILITY),
442             ERR(NULL_POINTER),
443             ERR(OUT_OF_MEMORY),
444             ERR(UNMODIFIABLE_CLASS),
445             ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
446             ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
447             ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
448             ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
449         });
450     if (error != ERR(NONE)) {
451       return error;
452     }
453 
454     // StructurallyRedefineClassDirect
455     error = add_extension(
456         reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClassDirect),
457         "com.android.art.UNSAFE.class.structurally_redefine_class_direct",
458         "Temporary prototype entrypoint for redefining a single class structurally. Currently this"
459         " only supports adding new static fields to a class without any instances."
460         " ClassFileLoadHook events will NOT be triggered. This does not currently support creating"
461         " obsolete methods. This function only has rudimentary error checking. This should not be"
462         " used except for testing.",
463         {
464           { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, false },
465           { "new_def", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
466           { "new_def_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
467         },
468         {
469           ERR(CLASS_LOADER_UNSUPPORTED),
470           ERR(FAILS_VERIFICATION),
471           ERR(ILLEGAL_ARGUMENT),
472           ERR(INVALID_CLASS),
473           ERR(MUST_POSSESS_CAPABILITY),
474           ERR(MUST_POSSESS_CAPABILITY),
475           ERR(NULL_POINTER),
476           ERR(OUT_OF_MEMORY),
477           ERR(UNMODIFIABLE_CLASS),
478           ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
479           ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
480           ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
481           ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
482         });
483     if (error != ERR(NONE)) {
484       return error;
485     }
486   } else {
487     LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
488               << "class redefinition extensions.";
489   }
490   // SetVerboseFlagExt
491   error = add_extension(
492       reinterpret_cast<jvmtiExtensionFunction>(LogUtil::SetVerboseFlagExt),
493       "com.android.art.misc.set_verbose_flag_ext",
494       "Sets the verbose flags selected by the 'option' c-string. Valid options are anything that"
495       " would be accepted by the -verbose:<option> runtime flag. The verbose selections are turned"
496       " on if 'enable' is set to true and disabled otherwise. You may select multiple options at"
497       " once using commas just like with the -verbose:<option> flag. For example \"class,deopt,gc\""
498       " is equivalent to turning on all of the VLOG(class_linker), VLOG(deopt) and VLOG(gc)"
499       " messages.",
500       {
501         { "option", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
502         { "enable", JVMTI_KIND_IN, JVMTI_TYPE_JBOOLEAN, false },
503       },
504       {
505          ERR(NULL_POINTER),
506          ERR(ILLEGAL_ARGUMENT),
507       });
508   if (error != ERR(NONE)) {
509     return error;
510   }
511   // GetHiddenApiEnforcementPolicy
512   error = add_extension(
513       reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::GetHiddenApiEnforcementPolicy),
514       "com.android.art.misc.get_hidden_api_enforcement_policy",
515       "Gets the current hiddenapi enforcement policy. Policy values are defined in"
516       " `frameworks/base/core/java/android/content/pm/ApplicationInfo.java` as the"
517       " HIDDEN_API_ENFORCEMENT_ static fields. See the comments in `art/runtime/hidden_api.h` for"
518       " more information. This should be used with"
519       " `com.android.art.misc.set_hidden_api_enforcement_policy` in order to restore the"
520       " hidden-api state after temporarily toggling it.",
521       {
522         { "policy", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
523       },
524       {
525          ERR(NULL_POINTER),
526       });
527   if (error != ERR(NONE)) {
528     return error;
529   }
530   // SetHiddenApiEnforcementPolicy
531   error = add_extension(
532       reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::SetHiddenApiEnforcementPolicy),
533       "com.android.art.misc.set_hidden_api_enforcement_policy",
534       "Sets the hiddenapi enforcement policy to the given value. Policy values are defined in"
535       " `frameworks/base/core/java/android/content/pm/ApplicationInfo.java` as the"
536       " HIDDEN_API_ENFORCEMENT_ static fields. See the comments in `art/runtime/hidden_api.h` for"
537       " more information. This API should always be used sparingly and in conjunction with"
538       " `com.android.art.misc.get_hidden_api_enforcement_policy` to temporarily toggle"
539       " hidden-api on and off as changes are required.",
540       {
541         { "policy", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
542       },
543       {
544          ERR(ILLEGAL_ARGUMENT),
545       });
546   if (error != ERR(NONE)) {
547     return error;
548   }
549   // DisableHiddenApiEnforcementPolicy
550   error = add_extension(
551       reinterpret_cast<jvmtiExtensionFunction>(ClassUtil::DisableHiddenApiEnforcementPolicy),
552       "com.android.art.misc.disable_hidden_api_enforcement_policy",
553       "Sets the hiddenapi enforcement policy to disabled. This API should always be"
554       " used sparingly and in conjunction with"
555       " `com.android.art.misc.get_hidden_api_enforcement_policy` and"
556       " `com.android.art.misc.set_hidden_api_enforcement_policy` to temporarily"
557       " toggle hidden-api on and off as changes are required.",
558       {},
559       {});
560   if (error != ERR(NONE)) {
561     return error;
562   }
563 
564   // Copy into output buffer.
565 
566   *extension_count_ptr = ext_vector.size();
567   JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
568       AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
569   if (out_data == nullptr) {
570     return error;
571   }
572   memcpy(out_data.get(),
573           ext_vector.data(),
574           ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
575   *extensions = out_data.release();
576 
577   // Release all the buffer holders, we're OK now.
578   for (auto& holder : char_buffers) {
579     holder.release();
580   }
581   for (auto& holder : param_buffers) {
582     holder.release();
583   }
584   for (auto& holder : error_buffers) {
585     holder.release();
586   }
587 
588   return OK;
589 }
590 
591 
GetExtensionEvents(jvmtiEnv * env,jint * extension_count_ptr,jvmtiExtensionEventInfo ** extensions)592 jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
593                                              jint* extension_count_ptr,
594                                              jvmtiExtensionEventInfo** extensions) {
595   std::vector<jvmtiExtensionEventInfo> ext_vector;
596 
597   // Holders for allocated values.
598   std::vector<JvmtiUniquePtr<char[]>> char_buffers;
599   std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
600 
601   auto add_extension = [&](ArtJvmtiEvent extension_event_index,
602                            const char* id,
603                            const char* short_description,
604                            const std::vector<CParamInfo>& params) {
605     DCHECK(IsExtensionEvent(extension_event_index)) << static_cast<jint>(extension_event_index);
606     jvmtiExtensionEventInfo event_info;
607     jvmtiError error;
608 
609     event_info.extension_event_index = static_cast<jint>(extension_event_index);
610 
611     JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
612     if (id_ptr == nullptr) {
613       return error;
614     }
615     event_info.id = id_ptr.get();
616     char_buffers.push_back(std::move(id_ptr));
617 
618     JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
619     if (descr == nullptr) {
620       return error;
621     }
622     event_info.short_description = descr.get();
623     char_buffers.push_back(std::move(descr));
624 
625     event_info.param_count = params.size();
626     if (!params.empty()) {
627       JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
628           AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
629       if (params_ptr == nullptr) {
630         return error;
631       }
632       event_info.params = params_ptr.get();
633       param_buffers.push_back(std::move(params_ptr));
634 
635       for (jint i = 0; i != event_info.param_count; ++i) {
636         event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
637         if (error != OK) {
638           return error;
639         }
640       }
641     } else {
642       event_info.params = nullptr;
643     }
644 
645     ext_vector.push_back(event_info);
646 
647     return ERR(NONE);
648   };
649 
650   jvmtiError error;
651   error = add_extension(
652       ArtJvmtiEvent::kDdmPublishChunk,
653       "com.android.art.internal.ddm.publish_chunk_safe",
654       "Called when there is new ddms information that the agent or other clients can use. The"
655       " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
656       " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
657       " is responsible for interpreting the information present in the 'data' buffer. This is"
658       " provided for backwards-compatibility support only. Agents should prefer to use relevant"
659       " JVMTI events and functions above listening for this event. Previous publish_chunk"
660       " event was inherently unsafe since using the JNIEnv could cause deadlocks in some scenarios."
661       " The current version does not have these issues.",
662       {
663         { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
664         { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
665         { "data",  JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
666       });
667   if (error != OK) {
668     return error;
669   }
670   error = add_extension(
671       ArtJvmtiEvent::kObsoleteObjectCreated,
672       "com.android.art.heap.obsolete_object_created",
673       "Called when an obsolete object is created.\n"
674       "An object becomes obsolete when, due to some jvmti function call all references to the"
675       " object are replaced with a reference to a different object. After this call finishes there"
676       " will be no strong references to the obsolete object anywere. If the object is retrieved"
677       " using GetObjectsWithTags its type (class) may have changed and any data it contains may"
678       " have been deleted. This is primarily designed to support memory tracking agents which make"
679       " use of the ObjectFree and VMObjectAlloc events for tracking. To support this use-case if"
680       " this event is not being handled it will by default act as though the following code was"
681       " registered as a handler:\n"
682       "\n"
683       "  void HandleObsoleteObjectCreated(jvmtiEnv* env, jlong* obsolete_tag, jlong* new_tag) {\n"
684       "    jlong temp = *obsolete_tag;\n"
685       "    *obsolete_tag = *new_tag;\n"
686       "    *new_tag = temp;\n"
687       "  }\n"
688       "\n"
689       "Note that this event does not support filtering based on thread. This event has the same"
690       " restrictions on JNI and JVMTI function calls as the ObjectFree event.\n"
691       "\n"
692       "Arguments:\n"
693       "  obsolete_tag: Pointer to the tag the old object (now obsolete) has. Setting the pointer"
694       " will update the tag value.\n"
695       "  new_tag: Pointer to the tag the new object (replacing the obsolete one) has. Setting the"
696       " pointer will update the tag value.",
697       {
698         { "obsolete_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
699         { "new_tag", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JLONG, false },
700       });
701   if (error != OK) {
702     return error;
703   }
704   art::Runtime* runtime = art::Runtime::Current();
705   if (runtime->GetJniIdType() == art::JniIdType::kIndices && IsFullJvmtiAvailable()) {
706     error = add_extension(
707         ArtJvmtiEvent::kStructuralDexFileLoadHook,
708         "com.android.art.class.structural_dex_file_load_hook",
709         "Called during class load, after a 'RetransformClasses' call, or after a 'RedefineClasses'"
710         " call in order to allow the agent to modify the class. This event is called after any"
711         " non-can_retransform_classes ClassFileLoadHookEvents and before any"
712         " can_retransform_classes ClassFileLoadHookEvents. The transformations applied are"
713         " restricted in the same way that transformations applied via the "
714         " 'com.android.art.class.structurally_redefine_classes' extension function. The arguments"
715         " to the event are identical to the ones in the ClassFileLoadHook and have the same"
716         " semantics.",
717         {
718           { "jni_env", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, false },
719           { "class_being_redefined", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true },
720           { "loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
721           { "name", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false },
722           { "protection_domain", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
723           { "dex_data_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
724           { "dex_data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
725           { "new_dex_data_len", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
726           { "new_dex_data", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, true },
727         });
728   } else {
729     LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
730               << "class redefinition extensions.";
731   }
732   // Copy into output buffer.
733 
734   *extension_count_ptr = ext_vector.size();
735   JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
736       AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
737   if (out_data == nullptr) {
738     return error;
739   }
740   memcpy(out_data.get(),
741          ext_vector.data(),
742          ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
743   *extensions = out_data.release();
744 
745   // Release all the buffer holders, we're OK now.
746   for (auto& holder : char_buffers) {
747     holder.release();
748   }
749   for (auto& holder : param_buffers) {
750     holder.release();
751   }
752 
753   return OK;
754 }
755 
SetExtensionEventCallback(jvmtiEnv * env,jint extension_event_index,jvmtiExtensionEvent callback,EventHandler * event_handler)756 jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
757                                                     jint extension_event_index,
758                                                     jvmtiExtensionEvent callback,
759                                                     EventHandler* event_handler) {
760   if (!IsExtensionEvent(extension_event_index)) {
761     return ERR(ILLEGAL_ARGUMENT);
762   }
763   ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
764   jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
765   // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
766   // change to the normal callbacks.
767   {
768     art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
769     if (art_env->event_callbacks.get() == nullptr) {
770       art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
771     }
772     jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
773     if (err != OK) {
774       return err;
775     }
776   }
777   return event_handler->SetEvent(art_env,
778                                  /*thread=*/nullptr,
779                                  static_cast<ArtJvmtiEvent>(extension_event_index),
780                                  mode);
781 }
782 
783 }  // namespace openjdkjvmti
784