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