blob: 5ba29946d1c66764d29c93e90a6ba140837d3a74 [file] [log] [blame]
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -07001/*
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
Elliott Hughes07ed66b2012-12-12 18:34:25 -080017#include "base/logging.h"
Elliott Hughes76b61672012-12-12 17:47:30 -080018#include "base/mutex.h"
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070019#include "debugger.h"
Elliott Hugheseac76672012-05-24 21:56:51 -070020#include "jni_internal.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070021#include "scoped_thread_state_change.h"
22#include "ScopedLocalRef.h"
Elliott Hugheseac76672012-05-24 21:56:51 -070023#include "ScopedPrimitiveArray.h"
Elliott Hughesbfe487b2011-10-26 15:48:55 -070024#include "stack.h"
25#include "thread_list.h"
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070026
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070027namespace art {
28
Elliott Hughes1bac54f2012-03-16 12:48:31 -070029static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) {
Elliott Hughes545a0642011-11-08 19:10:03 -080030 Dbg::SetAllocTrackingEnabled(enable);
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070031}
32
Ian Rogers00f7d0e2012-07-19 15:28:27 -070033static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) {
34 ScopedObjectAccess soa(env);
Elliott Hughes545a0642011-11-08 19:10:03 -080035 return Dbg::GetRecentAllocations();
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070036}
37
Elliott Hughes1bac54f2012-03-16 12:48:31 -070038static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
Elliott Hughes545a0642011-11-08 19:10:03 -080039 return Dbg::IsAllocTrackingEnabled();
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -070040}
41
42/*
43 * Get a stack trace as an array of StackTraceElement objects. Returns
44 * NULL on failure, e.g. if the threadId couldn't be found.
45 */
Elliott Hughesbfe487b2011-10-26 15:48:55 -070046static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
Elliott Hughesf327e072013-01-09 16:01:26 -080047 ScopedLocalRef<jobject> peer(env, NULL);
48 {
49 Thread* t = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(thin_lock_id);
50 if (t == NULL) {
51 return NULL;
52 }
53 ScopedObjectAccess soa(env);
54 peer.reset(soa.AddLocalReference<jobject>(t->GetPeer()));
55 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -070056 if (peer.get() == NULL) {
Elliott Hughesbfe487b2011-10-26 15:48:55 -070057 return NULL;
58 }
Elliott Hughesf327e072013-01-09 16:01:26 -080059
Ian Rogers00f7d0e2012-07-19 15:28:27 -070060 // Suspend thread to build stack trace.
Elliott Hughesf327e072013-01-09 16:01:26 -080061 bool timed_out;
62 Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timed_out);
Ian Rogers00f7d0e2012-07-19 15:28:27 -070063 if (thread != NULL) {
64 jobject trace;
65 {
66 ScopedObjectAccess soa(env);
67 trace = thread->CreateInternalStackTrace(soa);
68 }
69 // Restart suspended thread.
70 Runtime::Current()->GetThreadList()->Resume(thread, true);
71 return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
72 } else {
Elliott Hughesf327e072013-01-09 16:01:26 -080073 if (timed_out) {
Ian Rogers15bf2d32012-08-28 17:33:04 -070074 LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
75 "within a generous timeout.";
76 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -070077 return NULL;
78 }
Elliott Hughesbfe487b2011-10-26 15:48:55 -070079}
80
81static void ThreadCountCallback(Thread*, void* context) {
82 uint16_t& count = *reinterpret_cast<uint16_t*>(context);
83 ++count;
84}
85
86static const int kThstBytesPerEntry = 18;
87static const int kThstHeaderLen = 4;
88
89static void ThreadStatsGetterCallback(Thread* t, void* context) {
Elliott Hughesbfe487b2011-10-26 15:48:55 -070090 /*
91 * Generate the contents of a THST chunk. The data encompasses all known
92 * threads.
93 *
94 * Response has:
95 * (1b) header len
96 * (1b) bytes per entry
97 * (2b) thread count
98 * Then, for each thread:
Elliott Hughes21f32d72011-11-09 17:44:13 -080099 * (4b) thread id
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700100 * (1b) thread status
101 * (4b) tid
102 * (4b) utime
103 * (4b) stime
104 * (1b) is daemon?
105 *
106 * The length fields exist in anticipation of adding additional fields
107 * without wanting to break ddms or bump the full protocol version. I don't
108 * think it warrants full versioning. They might be extraneous and could
109 * be removed from a future version.
110 */
Elliott Hughesba0b9c52012-09-20 11:25:12 -0700111 char native_thread_state;
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700112 int utime, stime, task_cpu;
Elliott Hughesba0b9c52012-09-20 11:25:12 -0700113 GetTaskStats(t->GetTid(), native_thread_state, utime, stime, task_cpu);
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700114
Elliott Hughes21f32d72011-11-09 17:44:13 -0800115 std::vector<uint8_t>& bytes = *reinterpret_cast<std::vector<uint8_t>*>(context);
116 JDWP::Append4BE(bytes, t->GetThinLockId());
Ian Rogers50b35e22012-10-04 10:09:15 -0700117 JDWP::Append1BE(bytes, t->GetState());
Elliott Hughes21f32d72011-11-09 17:44:13 -0800118 JDWP::Append4BE(bytes, t->GetTid());
119 JDWP::Append4BE(bytes, utime);
120 JDWP::Append4BE(bytes, stime);
121 JDWP::Append1BE(bytes, t->IsDaemon());
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700122}
123
124static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700125 std::vector<uint8_t> bytes;
Ian Rogers50b35e22012-10-04 10:09:15 -0700126 Thread* self = static_cast<JNIEnvExt*>(env)->self;
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700127 {
Ian Rogers50b35e22012-10-04 10:09:15 -0700128 MutexLock mu(self, *Locks::thread_list_lock_);
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700129 ThreadList* thread_list = Runtime::Current()->GetThreadList();
130
Elliott Hughes21f32d72011-11-09 17:44:13 -0800131 uint16_t thread_count = 0;
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700132 thread_list->ForEach(ThreadCountCallback, &thread_count);
133
Elliott Hughes21f32d72011-11-09 17:44:13 -0800134 JDWP::Append1BE(bytes, kThstHeaderLen);
135 JDWP::Append1BE(bytes, kThstBytesPerEntry);
136 JDWP::Append2BE(bytes, thread_count);
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700137
Elliott Hughes21f32d72011-11-09 17:44:13 -0800138 thread_list->ForEach(ThreadStatsGetterCallback, &bytes);
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700139 }
140
141 jbyteArray result = env->NewByteArray(bytes.size());
Elliott Hughes545a0642011-11-08 19:10:03 -0800142 if (result != NULL) {
143 env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0]));
144 }
Elliott Hughesbfe487b2011-10-26 15:48:55 -0700145 return result;
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700146}
147
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700148static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
149 ScopedObjectAccess soa(env);
Elliott Hughes767a1472011-10-26 18:49:02 -0700150 return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700151}
152
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700153static jboolean DdmVmInternal_heapSegmentNotify(JNIEnv*, jclass, jint when, jint what, jboolean native) {
Elliott Hughes767a1472011-10-26 18:49:02 -0700154 return Dbg::DdmHandleHpsgNhsgChunk(static_cast<Dbg::HpsgWhen>(when), static_cast<Dbg::HpsgWhat>(what), native);
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700155}
156
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700157static void DdmVmInternal_threadNotify(JNIEnv*, jclass, jboolean enable) {
Elliott Hughes47fce012011-10-25 18:37:19 -0700158 Dbg::DdmSetThreadNotification(enable);
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700159}
160
161static JNINativeMethod gMethods[] = {
162 NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"),
163 NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "()[B"),
164 NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "()Z"),
165 NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
166 NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
167 NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "(I)Z"),
168 NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"),
169 NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"),
170};
171
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700172void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) {
Elliott Hugheseac76672012-05-24 21:56:51 -0700173 REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal");
Elliott Hughesf6a1e1e2011-10-25 16:28:04 -0700174}
175
176} // namespace art