org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc 5.55 KB
Newer Older
Elliott Hughes's avatar
Elliott Hughes committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2008 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.
 */

17
#include "base/logging.h"
18
#include "base/mutex.h"
Elliott Hughes's avatar
Elliott Hughes committed
19
#include "debugger.h"
20
#include "jni_internal.h"
21
#include "scoped_fast_native_object_access.h"
Ian Rogers's avatar
Ian Rogers committed
22
#include "ScopedLocalRef.h"
23
#include "ScopedPrimitiveArray.h"
24 25
#include "stack.h"
#include "thread_list.h"
Elliott Hughes's avatar
Elliott Hughes committed
26 27 28

namespace art {

29
static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) {
30
  Dbg::SetAllocTrackingEnabled(enable);
Elliott Hughes's avatar
Elliott Hughes committed
31 32
}

Ian Rogers's avatar
Ian Rogers committed
33
static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) {
34
  ScopedFastNativeObjectAccess soa(env);
35
  return Dbg::GetRecentAllocations();
Elliott Hughes's avatar
Elliott Hughes committed
36 37
}

38
static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
39
  return Dbg::IsAllocTrackingEnabled();
Elliott Hughes's avatar
Elliott Hughes committed
40 41 42 43 44 45
}

/*
 * Get a stack trace as an array of StackTraceElement objects.  Returns
 * NULL on failure, e.g. if the threadId couldn't be found.
 */
46
static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
Ian Rogers's avatar
Ian Rogers committed
47
  // Suspend thread to build stack trace.
48
  ThreadList* thread_list = Runtime::Current()->GetThreadList();
49
  jobjectArray trace = nullptr;
50
  bool timed_out;
51
  Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
Ian Rogers's avatar
Ian Rogers committed
52 53 54
  if (thread != NULL) {
    {
      ScopedObjectAccess soa(env);
55 56
      jobject internal_trace = thread->CreateInternalStackTrace(soa);
      trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
Ian Rogers's avatar
Ian Rogers committed
57 58
    }
    // Restart suspended thread.
59
    thread_list->Resume(thread, false);
Ian Rogers's avatar
Ian Rogers committed
60
  } else {
61
    if (timed_out) {
Ian Rogers's avatar
Ian Rogers committed
62 63 64
      LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
          "within a generous timeout.";
    }
65
  }
66
  return trace;
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
}

static void ThreadCountCallback(Thread*, void* context) {
  uint16_t& count = *reinterpret_cast<uint16_t*>(context);
  ++count;
}

static const int kThstBytesPerEntry = 18;
static const int kThstHeaderLen = 4;

static void ThreadStatsGetterCallback(Thread* t, void* context) {
  /*
   * Generate the contents of a THST chunk.  The data encompasses all known
   * threads.
   *
   * Response has:
   *  (1b) header len
   *  (1b) bytes per entry
   *  (2b) thread count
   * Then, for each thread:
87
   *  (4b) thread id
88 89 90 91 92 93 94 95 96 97 98
   *  (1b) thread status
   *  (4b) tid
   *  (4b) utime
   *  (4b) stime
   *  (1b) is daemon?
   *
   * The length fields exist in anticipation of adding additional fields
   * without wanting to break ddms or bump the full protocol version.  I don't
   * think it warrants full versioning.  They might be extraneous and could
   * be removed from a future version.
   */
99
  char native_thread_state;
100 101 102 103
  int utime;
  int stime;
  int task_cpu;
  GetTaskStats(t->GetTid(), &native_thread_state, &utime, &stime, &task_cpu);
104

105
  std::vector<uint8_t>& bytes = *reinterpret_cast<std::vector<uint8_t>*>(context);
106
  JDWP::Append4BE(bytes, t->GetThreadId());
107
  JDWP::Append1BE(bytes, Dbg::ToJdwpThreadStatus(t->GetState()));
108 109 110 111
  JDWP::Append4BE(bytes, t->GetTid());
  JDWP::Append4BE(bytes, utime);
  JDWP::Append4BE(bytes, stime);
  JDWP::Append1BE(bytes, t->IsDaemon());
Elliott Hughes's avatar
Elliott Hughes committed
112 113 114
}

static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
115
  std::vector<uint8_t> bytes;
116
  Thread* self = static_cast<JNIEnvExt*>(env)->self;
117
  {
118
    MutexLock mu(self, *Locks::thread_list_lock_);
119 120
    ThreadList* thread_list = Runtime::Current()->GetThreadList();

121
    uint16_t thread_count = 0;
122 123
    thread_list->ForEach(ThreadCountCallback, &thread_count);

124 125 126
    JDWP::Append1BE(bytes, kThstHeaderLen);
    JDWP::Append1BE(bytes, kThstBytesPerEntry);
    JDWP::Append2BE(bytes, thread_count);
127

128
    thread_list->ForEach(ThreadStatsGetterCallback, &bytes);
129 130 131
  }

  jbyteArray result = env->NewByteArray(bytes.size());
132 133 134
  if (result != NULL) {
    env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0]));
  }
135
  return result;
Elliott Hughes's avatar
Elliott Hughes committed
136 137
}

Ian Rogers's avatar
Ian Rogers committed
138
static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
139
  ScopedFastNativeObjectAccess soa(env);
Elliott Hughes's avatar
Elliott Hughes committed
140
  return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
Elliott Hughes's avatar
Elliott Hughes committed
141 142
}

143
static jboolean DdmVmInternal_heapSegmentNotify(JNIEnv*, jclass, jint when, jint what, jboolean native) {
Elliott Hughes's avatar
Elliott Hughes committed
144
  return Dbg::DdmHandleHpsgNhsgChunk(static_cast<Dbg::HpsgWhen>(when), static_cast<Dbg::HpsgWhat>(what), native);
Elliott Hughes's avatar
Elliott Hughes committed
145 146
}

147
static void DdmVmInternal_threadNotify(JNIEnv*, jclass, jboolean enable) {
Elliott Hughes's avatar
Elliott Hughes committed
148
  Dbg::DdmSetThreadNotification(enable);
Elliott Hughes's avatar
Elliott Hughes committed
149 150 151 152
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"),
153 154
  NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "!()[B"),
  NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "!()Z"),
Elliott Hughes's avatar
Elliott Hughes committed
155 156
  NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
  NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
157
  NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "!(I)Z"),
Elliott Hughes's avatar
Elliott Hughes committed
158 159 160 161 162
  NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"),
  NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"),
};

void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) {
163
  REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal");
Elliott Hughes's avatar
Elliott Hughes committed
164 165 166
}

}  // namespace art