1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "org_apache_harmony_dalvik_ddmc_DdmVmInternal.h" 18 19 #include "base/logging.h" 20 #include "base/mutex.h" 21 #include "debugger.h" 22 #include "gc/heap.h" 23 #include "jni_internal.h" 24 #include "native_util.h" 25 #include "nativehelper/jni_macros.h" 26 #include "nativehelper/ScopedLocalRef.h" 27 #include "nativehelper/ScopedPrimitiveArray.h" 28 #include "scoped_fast_native_object_access-inl.h" 29 #include "thread_list.h" 30 31 namespace art { 32 33 static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) { 34 Dbg::SetAllocTrackingEnabled(enable); 35 } 36 37 static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) { 38 ScopedFastNativeObjectAccess soa(env); 39 return Dbg::GetRecentAllocations(); 40 } 41 42 static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) { 43 return Runtime::Current()->GetHeap()->IsAllocTrackingEnabled(); 44 } 45 46 /* 47 * Get a stack trace as an array of StackTraceElement objects. Returns 48 * nullptr on failure, e.g. if the threadId couldn't be found. 49 */ 50 static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) { 51 jobjectArray trace = nullptr; 52 Thread* const self = Thread::Current(); 53 if (static_cast<uint32_t>(thin_lock_id) == self->GetThreadId()) { 54 // No need to suspend ourself to build stacktrace. 55 ScopedObjectAccess soa(env); 56 jobject internal_trace = self->CreateInternalStackTrace<false>(soa); 57 trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace); 58 } else { 59 ThreadList* thread_list = Runtime::Current()->GetThreadList(); 60 bool timed_out; 61 62 // Check for valid thread 63 if (thin_lock_id == ThreadList::kInvalidThreadId) { 64 return nullptr; 65 } 66 67 // Suspend thread to build stack trace. 68 Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, 69 SuspendReason::kInternal, 70 &timed_out); 71 if (thread != nullptr) { 72 { 73 ScopedObjectAccess soa(env); 74 jobject internal_trace = thread->CreateInternalStackTrace<false>(soa); 75 trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace); 76 } 77 // Restart suspended thread. 78 bool resumed = thread_list->Resume(thread, SuspendReason::kInternal); 79 DCHECK(resumed); 80 } else { 81 if (timed_out) { 82 LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend " 83 "within a generous timeout."; 84 } 85 } 86 } 87 return trace; 88 } 89 90 static void ThreadCountCallback(Thread*, void* context) { 91 uint16_t& count = *reinterpret_cast<uint16_t*>(context); 92 ++count; 93 } 94 95 static const int kThstBytesPerEntry = 18; 96 static const int kThstHeaderLen = 4; 97 98 static void ThreadStatsGetterCallback(Thread* t, void* context) { 99 /* 100 * Generate the contents of a THST chunk. The data encompasses all known 101 * threads. 102 * 103 * Response has: 104 * (1b) header len 105 * (1b) bytes per entry 106 * (2b) thread count 107 * Then, for each thread: 108 * (4b) thread id 109 * (1b) thread status 110 * (4b) tid 111 * (4b) utime 112 * (4b) stime 113 * (1b) is daemon? 114 * 115 * The length fields exist in anticipation of adding additional fields 116 * without wanting to break ddms or bump the full protocol version. I don't 117 * think it warrants full versioning. They might be extraneous and could 118 * be removed from a future version. 119 */ 120 char native_thread_state; 121 int utime; 122 int stime; 123 int task_cpu; 124 GetTaskStats(t->GetTid(), &native_thread_state, &utime, &stime, &task_cpu); 125 126 std::vector<uint8_t>& bytes = *reinterpret_cast<std::vector<uint8_t>*>(context); 127 JDWP::Append4BE(bytes, t->GetThreadId()); 128 JDWP::Append1BE(bytes, Dbg::ToJdwpThreadStatus(t->GetState())); 129 JDWP::Append4BE(bytes, t->GetTid()); 130 JDWP::Append4BE(bytes, utime); 131 JDWP::Append4BE(bytes, stime); 132 JDWP::Append1BE(bytes, t->IsDaemon()); 133 } 134 135 static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) { 136 std::vector<uint8_t> bytes; 137 Thread* self = static_cast<JNIEnvExt*>(env)->self; 138 { 139 MutexLock mu(self, *Locks::thread_list_lock_); 140 ThreadList* thread_list = Runtime::Current()->GetThreadList(); 141 142 uint16_t thread_count = 0; 143 thread_list->ForEach(ThreadCountCallback, &thread_count); 144 145 JDWP::Append1BE(bytes, kThstHeaderLen); 146 JDWP::Append1BE(bytes, kThstBytesPerEntry); 147 JDWP::Append2BE(bytes, thread_count); 148 149 thread_list->ForEach(ThreadStatsGetterCallback, &bytes); 150 } 151 152 jbyteArray result = env->NewByteArray(bytes.size()); 153 if (result != nullptr) { 154 env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0])); 155 } 156 return result; 157 } 158 159 static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) { 160 ScopedFastNativeObjectAccess soa(env); 161 return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when)); 162 } 163 164 static jboolean DdmVmInternal_heapSegmentNotify(JNIEnv*, jclass, jint when, jint what, jboolean native) { 165 return Dbg::DdmHandleHpsgNhsgChunk(static_cast<Dbg::HpsgWhen>(when), static_cast<Dbg::HpsgWhat>(what), native); 166 } 167 168 static void DdmVmInternal_threadNotify(JNIEnv*, jclass, jboolean enable) { 169 Dbg::DdmSetThreadNotification(enable); 170 } 171 172 static JNINativeMethod gMethods[] = { 173 NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"), 174 FAST_NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "()[B"), 175 FAST_NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "()Z"), 176 NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"), 177 NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"), 178 FAST_NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "(I)Z"), 179 NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"), 180 NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"), 181 }; 182 183 void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) { 184 REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal"); 185 } 186 187 } // namespace art 188