/*
 * 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.
 */

#include "org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"

#include <android-base/logging.h>

#include "base/file_utils.h"
#include "base/mutex.h"
#include "base/endian_utils.h"
#include "debugger.h"
#include "gc/heap.h"
#include "jni/jni_internal.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_local_ref.h"
#include "nativehelper/scoped_primitive_array.h"
#include "scoped_fast_native_object_access-inl.h"
#include "thread_list.h"

namespace art {

static void DdmVmInternal_setRecentAllocationsTrackingEnabled(JNIEnv*, jclass, jboolean enable) {
  Dbg::SetAllocTrackingEnabled(enable);
}

static void DdmVmInternal_setThreadNotifyEnabled(JNIEnv*, jclass, jboolean enable) {
  Dbg::DdmSetThreadNotification(enable);
}

static Thread* GetSelf(JNIEnv* env) {
  return static_cast<JNIEnvExt*>(env)->GetSelf();
}

/*
 * Get a stack trace as an array of StackTraceElement objects.  Returns
 * nullptr on failure, e.g. if the threadId couldn't be found.
 */
static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
  jobjectArray trace = nullptr;
  Thread* const self = GetSelf(env);
  if (static_cast<uint32_t>(thin_lock_id) == self->GetThreadId()) {
    // No need to suspend ourself to build stacktrace.
    ScopedObjectAccess soa(env);
    jobject internal_trace = self->CreateInternalStackTrace(soa);
    trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
  } else {
    ThreadList* thread_list = Runtime::Current()->GetThreadList();
    bool timed_out;

    // Check for valid thread
    if (thin_lock_id == ThreadList::kInvalidThreadId) {
      return nullptr;
    }

    // Suspend thread to build stack trace.
    Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id,
                                                          SuspendReason::kInternal,
                                                          &timed_out);
    if (thread != nullptr) {
      {
        ScopedObjectAccess soa(env);
        jobject internal_trace = thread->CreateInternalStackTrace(soa);
        trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
      }
      // Restart suspended thread.
      bool resumed = thread_list->Resume(thread, SuspendReason::kInternal);
      DCHECK(resumed);
    } else {
      if (timed_out) {
        LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
            "within a generous timeout.";
      }
    }
  }
  return trace;
}

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 constexpr uint8_t ToJdwpThreadStatus(ThreadState state) {
  /*
  * ThreadStatus constants.
  */
  enum JdwpThreadStatus : uint8_t {
    TS_ZOMBIE   = 0,
    TS_RUNNING  = 1,  // RUNNING
    TS_SLEEPING = 2,  // (in Thread.sleep())
    TS_MONITOR  = 3,  // WAITING (monitor wait)
    TS_WAIT     = 4,  // (in Object.wait())
  };
  switch (state) {
    case ThreadState::kBlocked:
      return TS_MONITOR;
    case ThreadState::kNative:
    case ThreadState::kRunnable:
    case ThreadState::kSuspended:
      return TS_RUNNING;
    case ThreadState::kObsoleteRunnable:
      break;  // Obsolete value.
    case ThreadState::kSleeping:
      return TS_SLEEPING;
    case ThreadState::kStarting:
    case ThreadState::kTerminated:
      return TS_ZOMBIE;
    case ThreadState::kTimedWaiting:
    case ThreadState::kWaitingForTaskProcessor:
    case ThreadState::kWaitingForLockInflation:
    case ThreadState::kWaitingForCheckPointsToRun:
    case ThreadState::kWaitingForDebuggerSend:
    case ThreadState::kWaitingForDebuggerSuspension:
    case ThreadState::kWaitingForDebuggerToAttach:
    case ThreadState::kWaitingForDeoptimization:
    case ThreadState::kWaitingForGcToComplete:
    case ThreadState::kWaitingForGetObjectsAllocated:
    case ThreadState::kWaitingForJniOnLoad:
    case ThreadState::kWaitingForMethodTracingStart:
    case ThreadState::kWaitingForSignalCatcherOutput:
    case ThreadState::kWaitingForVisitObjects:
    case ThreadState::kWaitingInMainDebuggerLoop:
    case ThreadState::kWaitingInMainSignalCatcherLoop:
    case ThreadState::kWaitingPerformingGc:
    case ThreadState::kWaitingWeakGcRootRead:
    case ThreadState::kWaitingForGcThreadFlip:
    case ThreadState::kNativeForAbort:
    case ThreadState::kWaiting:
      return TS_WAIT;
      // Don't add a 'default' here so the compiler can spot incompatible enum changes.
  }
  LOG(FATAL) << "Unknown thread state: " << state;
  UNREACHABLE();
}

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:
   *  (4b) thread id
   *  (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.
   */
  char native_thread_state;
  int utime;
  int stime;
  int task_cpu;
  GetTaskStats(t->GetTid(), &native_thread_state, &utime, &stime, &task_cpu);

  std::vector<uint8_t>& bytes = *reinterpret_cast<std::vector<uint8_t>*>(context);
  Append4BE(bytes, t->GetThreadId());
  Append1BE(bytes, ToJdwpThreadStatus(t->GetState()));
  Append4BE(bytes, t->GetTid());
  Append4BE(bytes, utime);
  Append4BE(bytes, stime);
  Append1BE(bytes, t->IsDaemon());
}

static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
  std::vector<uint8_t> bytes;
  Thread* self = GetSelf(env);
  {
    MutexLock mu(self, *Locks::thread_list_lock_);
    ThreadList* thread_list = Runtime::Current()->GetThreadList();

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

    Append1BE(bytes, kThstHeaderLen);
    Append1BE(bytes, kThstBytesPerEntry);
    Append2BE(bytes, thread_count);

    thread_list->ForEach(ThreadStatsGetterCallback, &bytes);
  }

  jbyteArray result = env->NewByteArray(bytes.size());
  if (result != nullptr) {
    env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0]));
  }
  return result;
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(DdmVmInternal, setRecentAllocationsTrackingEnabled, "(Z)V"),
  NATIVE_METHOD(DdmVmInternal, setThreadNotifyEnabled, "(Z)V"),
  NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
  NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
};

void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal");
}

}  // namespace art
