Home | History | Annotate | Download | only in openjdkjvmti
      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  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     26  *
     27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     28  * or visit www.oracle.com if you need additional information or have any
     29  * questions.
     30  */
     31 
     32 #include "ti_threadgroup.h"
     33 
     34 #include "art_field-inl.h"
     35 #include "art_jvmti.h"
     36 #include "base/logging.h"
     37 #include "base/macros.h"
     38 #include "base/mutex.h"
     39 #include "handle_scope-inl.h"
     40 #include "jni_internal.h"
     41 #include "mirror/class.h"
     42 #include "mirror/object-inl.h"
     43 #include "mirror/string.h"
     44 #include "obj_ptr.h"
     45 #include "object_lock.h"
     46 #include "runtime.h"
     47 #include "scoped_thread_state_change-inl.h"
     48 #include "thread-current-inl.h"
     49 #include "thread_list.h"
     50 #include "well_known_classes.h"
     51 
     52 namespace openjdkjvmti {
     53 
     54 
     55 jvmtiError ThreadGroupUtil::GetTopThreadGroups(jvmtiEnv* env,
     56                                                jint* group_count_ptr,
     57                                                jthreadGroup** groups_ptr) {
     58   // We only have a single top group. So we can take the current thread and move upwards.
     59   if (group_count_ptr == nullptr || groups_ptr == nullptr) {
     60     return ERR(NULL_POINTER);
     61   }
     62 
     63   art::Runtime* runtime = art::Runtime::Current();
     64   if (runtime == nullptr) {
     65     // Must be starting the runtime, or dying.
     66     return ERR(WRONG_PHASE);
     67   }
     68 
     69   jobject sys_thread_group = runtime->GetSystemThreadGroup();
     70   if (sys_thread_group == nullptr) {
     71     // Seems we're still starting up.
     72     return ERR(WRONG_PHASE);
     73   }
     74 
     75   unsigned char* data;
     76   jvmtiError result = env->Allocate(sizeof(jthreadGroup), &data);
     77   if (result != ERR(NONE)) {
     78     return result;
     79   }
     80 
     81   jthreadGroup* groups = reinterpret_cast<jthreadGroup*>(data);
     82   *groups =
     83       reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv())->NewLocalRef(sys_thread_group);
     84   *groups_ptr = groups;
     85   *group_count_ptr = 1;
     86 
     87   return ERR(NONE);
     88 }
     89 
     90 jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env,
     91                                                jthreadGroup group,
     92                                                jvmtiThreadGroupInfo* info_ptr) {
     93   if (group == nullptr) {
     94     return ERR(INVALID_THREAD_GROUP);
     95   }
     96 
     97   art::ScopedObjectAccess soa(art::Thread::Current());
     98   if (soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup) == JNI_FALSE) {
     99     return ERR(INVALID_THREAD_GROUP);
    100   }
    101 
    102   art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(group);
    103 
    104   // Do the name first. It's the only thing that can fail.
    105   {
    106     art::ArtField* name_field =
    107         art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_name);
    108     CHECK(name_field != nullptr);
    109     art::ObjPtr<art::mirror::String> name_obj =
    110         art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj));
    111     std::string tmp_str;
    112     const char* tmp_cstr;
    113     if (name_obj == nullptr) {
    114       tmp_cstr = "";
    115     } else {
    116       tmp_str = name_obj->ToModifiedUtf8();
    117       tmp_cstr = tmp_str.c_str();
    118     }
    119     jvmtiError result;
    120     JvmtiUniquePtr<char[]> copy = CopyString(env, tmp_cstr, &result);
    121     if (copy == nullptr) {
    122       return result;
    123     }
    124     info_ptr->name = copy.release();
    125   }
    126 
    127   // Parent.
    128   {
    129     art::ArtField* parent_field =
    130         art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_parent);
    131     CHECK(parent_field != nullptr);
    132     art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj);
    133     info_ptr->parent = parent_group == nullptr
    134                            ? nullptr
    135                            : soa.AddLocalReference<jthreadGroup>(parent_group);
    136   }
    137 
    138   // Max priority.
    139   {
    140     art::ArtField* prio_field = obj->GetClass()->FindDeclaredInstanceField("maxPriority", "I");
    141     CHECK(prio_field != nullptr);
    142     info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj));
    143   }
    144 
    145   // Daemon.
    146   {
    147     art::ArtField* daemon_field = obj->GetClass()->FindDeclaredInstanceField("daemon", "Z");
    148     CHECK(daemon_field != nullptr);
    149     info_ptr->is_daemon = daemon_field->GetBoolean(obj) == 0 ? JNI_FALSE : JNI_TRUE;
    150   }
    151 
    152   return ERR(NONE);
    153 }
    154 
    155 
    156 static bool IsInDesiredThreadGroup(art::Handle<art::mirror::Object> desired_thread_group,
    157                                    art::ObjPtr<art::mirror::Object> peer)
    158     REQUIRES_SHARED(art::Locks::mutator_lock_) {
    159   CHECK(desired_thread_group != nullptr);
    160 
    161   art::ArtField* thread_group_field =
    162       art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
    163   DCHECK(thread_group_field != nullptr);
    164   art::ObjPtr<art::mirror::Object> group = thread_group_field->GetObject(peer);
    165   return (group == desired_thread_group.Get());
    166 }
    167 
    168 static void GetThreads(art::Handle<art::mirror::Object> thread_group,
    169                        std::vector<art::ObjPtr<art::mirror::Object>>* thread_peers)
    170     REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!art::Locks::thread_list_lock_) {
    171   CHECK(thread_group != nullptr);
    172 
    173   art::MutexLock mu(art::Thread::Current(), *art::Locks::thread_list_lock_);
    174   for (art::Thread* t : art::Runtime::Current()->GetThreadList()->GetList()) {
    175     if (t->IsStillStarting()) {
    176       continue;
    177     }
    178     art::ObjPtr<art::mirror::Object> peer = t->GetPeerFromOtherThread();
    179     if (peer == nullptr) {
    180       continue;
    181     }
    182     if (IsInDesiredThreadGroup(thread_group, peer)) {
    183       thread_peers->push_back(peer);
    184     }
    185   }
    186 }
    187 
    188 static void GetChildThreadGroups(art::Handle<art::mirror::Object> thread_group,
    189                                  std::vector<art::ObjPtr<art::mirror::Object>>* thread_groups)
    190     REQUIRES_SHARED(art::Locks::mutator_lock_) {
    191   CHECK(thread_group != nullptr);
    192 
    193   // Get the ThreadGroup[] "groups" out of this thread group...
    194   art::ArtField* groups_field =
    195       art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_groups);
    196   art::ObjPtr<art::mirror::Object> groups_array = groups_field->GetObject(thread_group.Get());
    197 
    198   if (groups_array == nullptr) {
    199     return;
    200   }
    201   CHECK(groups_array->IsObjectArray());
    202 
    203   art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> groups_array_as_array =
    204       groups_array->AsObjectArray<art::mirror::Object>();
    205 
    206   // Copy all non-null elements.
    207   for (int32_t i = 0; i < groups_array_as_array->GetLength(); ++i) {
    208     art::ObjPtr<art::mirror::Object> entry = groups_array_as_array->Get(i);
    209     if (entry != nullptr) {
    210       thread_groups->push_back(entry);
    211     }
    212   }
    213 }
    214 
    215 jvmtiError ThreadGroupUtil::GetThreadGroupChildren(jvmtiEnv* env,
    216                                                    jthreadGroup group,
    217                                                    jint* thread_count_ptr,
    218                                                    jthread** threads_ptr,
    219                                                    jint* group_count_ptr,
    220                                                    jthreadGroup** groups_ptr) {
    221   if (group == nullptr) {
    222     return ERR(INVALID_THREAD_GROUP);
    223   }
    224 
    225   art::ScopedObjectAccess soa(art::Thread::Current());
    226 
    227   if (!soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup)) {
    228     return ERR(INVALID_THREAD_GROUP);
    229   }
    230 
    231   art::StackHandleScope<1> hs(soa.Self());
    232   art::Handle<art::mirror::Object> thread_group = hs.NewHandle(
    233       soa.Decode<art::mirror::Object>(group));
    234 
    235   art::ObjectLock<art::mirror::Object> thread_group_lock(soa.Self(), thread_group);
    236 
    237   std::vector<art::ObjPtr<art::mirror::Object>> thread_peers;
    238   GetThreads(thread_group, &thread_peers);
    239 
    240   std::vector<art::ObjPtr<art::mirror::Object>> thread_groups;
    241   GetChildThreadGroups(thread_group, &thread_groups);
    242 
    243   JvmtiUniquePtr<jthread[]> peers_uptr;
    244   if (!thread_peers.empty()) {
    245     jvmtiError res;
    246     peers_uptr = AllocJvmtiUniquePtr<jthread[]>(env, thread_peers.size(), &res);
    247     if (peers_uptr == nullptr) {
    248       return res;
    249     }
    250   }
    251 
    252   JvmtiUniquePtr<jthreadGroup[]> group_uptr;
    253   if (!thread_groups.empty()) {
    254     jvmtiError res;
    255     group_uptr = AllocJvmtiUniquePtr<jthreadGroup[]>(env, thread_groups.size(), &res);
    256     if (group_uptr == nullptr) {
    257       return res;
    258     }
    259   }
    260 
    261   // Can't fail anymore from here on.
    262 
    263   // Copy data into out buffers.
    264   for (size_t i = 0; i != thread_peers.size(); ++i) {
    265     peers_uptr[i] = soa.AddLocalReference<jthread>(thread_peers[i]);
    266   }
    267   for (size_t i = 0; i != thread_groups.size(); ++i) {
    268     group_uptr[i] = soa.AddLocalReference<jthreadGroup>(thread_groups[i]);
    269   }
    270 
    271   *thread_count_ptr = static_cast<jint>(thread_peers.size());
    272   *threads_ptr = peers_uptr.release();
    273   *group_count_ptr = static_cast<jint>(thread_groups.size());
    274   *groups_ptr = group_uptr.release();
    275 
    276   return ERR(NONE);
    277 }
    278 
    279 }  // namespace openjdkjvmti
    280