diff options
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 3 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/heap.cc | 48 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/heap.h | 2 | ||||
| -rwxr-xr-x | test/907-get-loaded-classes/build | 17 | ||||
| -rw-r--r-- | test/907-get-loaded-classes/expected.txt | 0 | ||||
| -rw-r--r-- | test/907-get-loaded-classes/get_loaded_classes.cc | 81 | ||||
| -rw-r--r-- | test/907-get-loaded-classes/get_loaded_classes.h | 30 | ||||
| -rw-r--r-- | test/907-get-loaded-classes/info.txt | 1 | ||||
| -rwxr-xr-x | test/907-get-loaded-classes/run | 43 | ||||
| -rw-r--r-- | test/907-get-loaded-classes/src/Main.java | 61 | ||||
| -rw-r--r-- | test/Android.bp | 1 |
11 files changed, 286 insertions, 1 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 05da585b3a..ac8d5e12d1 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -476,7 +476,8 @@ class JvmtiFunctions { } static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) { - return ERR(NOT_IMPLEMENTED); + HeapUtil heap_util(&gObjectTagTable); + return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr); } static jvmtiError GetClassLoaderClasses(jvmtiEnv* env, diff --git a/runtime/openjdkjvmti/heap.cc b/runtime/openjdkjvmti/heap.cc index 95d9a1d315..859941c81f 100644 --- a/runtime/openjdkjvmti/heap.cc +++ b/runtime/openjdkjvmti/heap.cc @@ -19,7 +19,10 @@ #include "art_jvmti.h" #include "base/macros.h" #include "base/mutex.h" +#include "class_linker.h" #include "gc/heap.h" +#include "java_vm_ext.h" +#include "jni_env_ext.h" #include "mirror/class.h" #include "object_callbacks.h" #include "object_tagging.h" @@ -163,4 +166,49 @@ jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env ATTRIBUTE_UNUSED, return ERR(NONE); } +jvmtiError HeapUtil::GetLoadedClasses(jvmtiEnv* env, + jint* class_count_ptr, + jclass** classes_ptr) { + if (class_count_ptr == nullptr || classes_ptr == nullptr) { + return ERR(NULL_POINTER); + } + + class ReportClassVisitor : public art::ClassVisitor { + public: + explicit ReportClassVisitor(art::Thread* self) : self_(self) {} + + bool operator()(art::mirror::Class* klass) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { + art::JNIEnvExt* jni_env = self_->GetJniEnv(); + classes_.push_back(reinterpret_cast<jclass>(jni_env->vm->AddGlobalRef(self_, klass))); + return true; + } + + art::Thread* self_; + std::vector<jclass> classes_; + }; + + art::Thread* self = art::Thread::Current(); + ReportClassVisitor rcv(self); + { + art::ScopedObjectAccess soa(self); + art::Runtime::Current()->GetClassLinker()->VisitClasses(&rcv); + } + + size_t size = rcv.classes_.size(); + jclass* classes = nullptr; + jvmtiError alloc_ret = env->Allocate(static_cast<jlong>(size * sizeof(jclass)), + reinterpret_cast<unsigned char**>(&classes)); + if (alloc_ret != ERR(NONE)) { + return alloc_ret; + } + + for (size_t i = 0; i < size; ++i) { + classes[i] = rcv.classes_[i]; + } + *classes_ptr = classes; + *class_count_ptr = static_cast<jint>(size); + + return ERR(NONE); +} + } // namespace openjdkjvmti diff --git a/runtime/openjdkjvmti/heap.h b/runtime/openjdkjvmti/heap.h index fb9a2164ae..b6becb97bb 100644 --- a/runtime/openjdkjvmti/heap.h +++ b/runtime/openjdkjvmti/heap.h @@ -28,6 +28,8 @@ class HeapUtil { explicit HeapUtil(ObjectTagTable* tags) : tags_(tags) { } + jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr); + jvmtiError IterateThroughHeap(jvmtiEnv* env, jint heap_filter, jclass klass, diff --git a/test/907-get-loaded-classes/build b/test/907-get-loaded-classes/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/907-get-loaded-classes/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +./default-build "$@" --experimental agents diff --git a/test/907-get-loaded-classes/expected.txt b/test/907-get-loaded-classes/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/907-get-loaded-classes/expected.txt diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc new file mode 100644 index 0000000000..e752bcbbeb --- /dev/null +++ b/test/907-get-loaded-classes/get_loaded_classes.cc @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "get_loaded_classes.h" + +#include <iostream> +#include <pthread.h> +#include <stdio.h> +#include <vector> + +#include "base/macros.h" +#include "jni.h" +#include "openjdkjvmti/jvmti.h" +#include "ScopedLocalRef.h" +#include "ScopedUtfChars.h" + +#include "ti-agent/common_load.h" + +namespace art { +namespace Test907GetLoadedClasses { + +static jstring GetClassName(JNIEnv* jni_env, jclass cls) { + ScopedLocalRef<jclass> class_class(jni_env, jni_env->GetObjectClass(cls)); + jmethodID mid = jni_env->GetMethodID(class_class.get(), "getName", "()Ljava/lang/String;"); + return reinterpret_cast<jstring>(jni_env->CallObjectMethod(cls, mid)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getLoadedClasses( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + jint count = -1; + jclass* classes = nullptr; + jvmtiError result = jvmti_env->GetLoadedClasses(&count, &classes); + if (result != JVMTI_ERROR_NONE) { + char* err; + jvmti_env->GetErrorName(result, &err); + printf("Failure running GetLoadedClasses: %s\n", err); + return nullptr; + } + + ScopedLocalRef<jclass> obj_class(env, env->FindClass("java/lang/String")); + if (obj_class.get() == nullptr) { + return nullptr; + } + + jobjectArray ret = env->NewObjectArray(count, obj_class.get(), nullptr); + if (ret == nullptr) { + return ret; + } + + for (size_t i = 0; i < static_cast<size_t>(count); ++i) { + jstring class_name = GetClassName(env, classes[i]); + env->SetObjectArrayElement(ret, static_cast<jint>(i), class_name); + env->DeleteLocalRef(class_name); + } + + // Need to: + // 1) Free the local references. + // 2) Deallocate. + for (size_t i = 0; i < static_cast<size_t>(count); ++i) { + env->DeleteGlobalRef(classes[i]); + } + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)); + + return ret; +} + +} // namespace Test907GetLoadedClasses +} // namespace art diff --git a/test/907-get-loaded-classes/get_loaded_classes.h b/test/907-get-loaded-classes/get_loaded_classes.h new file mode 100644 index 0000000000..4d27f898cc --- /dev/null +++ b/test/907-get-loaded-classes/get_loaded_classes.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_ +#define ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_ + +#include <jni.h> + +namespace art { +namespace Test907GetLoadedClasses { + +jint OnLoad(JavaVM* vm, char* options, void* reserved); + +} // namespace Test907GetLoadedClasses +} // namespace art + +#endif // ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_ diff --git a/test/907-get-loaded-classes/info.txt b/test/907-get-loaded-classes/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/907-get-loaded-classes/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/907-get-loaded-classes/run b/test/907-get-loaded-classes/run new file mode 100755 index 0000000000..3e135a378d --- /dev/null +++ b/test/907-get-loaded-classes/run @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +plugin=libopenjdkjvmtid.so +agent=libtiagentd.so +lib=tiagentd +if [[ "$@" == *"-O"* ]]; then + agent=libtiagent.so + plugin=libopenjdkjvmti.so + lib=tiagent +fi + +if [[ "$@" == *"--jvm"* ]]; then + arg="jvm" +else + arg="art" +fi + +if [[ "$@" != *"--debuggable"* ]]; then + other_args=" -Xcompiler-option --debuggable " +else + other_args="" +fi + +./default-run "$@" --experimental agents \ + --experimental runtime-plugins \ + --runtime-option -agentpath:${agent}=906-iterate-heap,${arg} \ + --android-runtime-option -Xplugin:${plugin} \ + ${other_args} \ + --args ${lib} diff --git a/test/907-get-loaded-classes/src/Main.java b/test/907-get-loaded-classes/src/Main.java new file mode 100644 index 0000000000..468d037a52 --- /dev/null +++ b/test/907-get-loaded-classes/src/Main.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +public class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[1]); + + doTest(); + } + + public static void doTest() throws Exception { + // Ensure some classes are loaded. + A a = new A(); + B b = new B(); + A[] aArray = new A[5]; + + String[] classes = getLoadedClasses(); + HashSet<String> classesSet = new HashSet<>(Arrays.asList(classes)); + + String[] shouldBeLoaded = new String[] { + "java.lang.Object", "java.lang.Class", "java.lang.String", "Main$A", "Main$B", "[LMain$A;" + }; + + boolean error = false; + for (String s : shouldBeLoaded) { + if (!classesSet.contains(s)) { + System.out.println("Did not find " + s); + error = true; + } + } + + if (error) { + System.out.println(Arrays.toString(classes)); + } + } + + static class A { + } + + static class B { + } + + private static native String[] getLoadedClasses(); +} diff --git a/test/Android.bp b/test/Android.bp index 45673f55ff..8496ffdc91 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -249,6 +249,7 @@ art_cc_defaults { "904-object-allocation/tracking.cc", "905-object-free/tracking_free.cc", "906-iterate-heap/iterate_heap.cc", + "907-get-loaded-classes/get_loaded_classes.cc", ], shared_libs: [ "libbase", |