Add support for dalvik.system.VMDebug functions am: b4095656e5
am: fa36837dd2
Change-Id: Ieab3b31bbe46fd68751cd72d9508268a2463303d
diff --git a/src/share/back/debugInit.c b/src/share/back/debugInit.c
index 474c197..043e639 100644
--- a/src/share/back/debugInit.c
+++ b/src/share/back/debugInit.c
@@ -39,6 +39,9 @@
#include "invoker.h"
#include "sys.h"
+// ANDROID-CHANGED: Allow us to initialize VMDebug apis.
+#include "vmDebug.h"
+
/* How the options get to OnLoad: */
#define XDEBUG "-Xdebug"
#define XRUN "-Xrunjdwp"
@@ -776,6 +779,9 @@
classTrack_initialize(env);
debugLoop_initialize();
+ // ANDROID-CHANGED: Take over relevant VMDebug APIs.
+ vmDebug_initalize(env);
+
initMonitor = debugMonitorCreate("JDWP Initialization Monitor");
diff --git a/src/share/back/debugLoop.c b/src/share/back/debugLoop.c
index 55d4894..765f836 100644
--- a/src/share/back/debugLoop.c
+++ b/src/share/back/debugLoop.c
@@ -23,6 +23,9 @@
* questions.
*/
+// ANDROID-CHANGED: Include stdatomic so we can safely update and read the lastDebuggerActivity.
+#include <stdatomic.h>
+
#include "util.h"
#include "transport.h"
#include "debugLoop.h"
@@ -48,6 +51,17 @@
static jrawMonitorID vmDeathLock;
static jboolean transportError;
+// ANDROID-CHANGED: The time the last debugger activity occurred or '0' if a debugger command is
+// currently in progress or the debugger has not started.
+static _Atomic(jlong) lastDebuggerActivity = ATOMIC_VAR_INIT(0LL);
+
+// ANDROID-CHANGED: Accessor for lastDebuggerActivity.
+jlong
+debugLoop_lastDebuggerActivity(void)
+{
+ return atomic_load(&lastDebuggerActivity);
+}
+
static jboolean
lastCommand(jdwpCmdPacket *cmd)
{
@@ -64,6 +78,8 @@
debugLoop_initialize(void)
{
vmDeathLock = debugMonitorCreate("JDWP VM_DEATH Lock");
+ // Android Changed: Set lastDebuggerActivity to 0 since we have not done anything yet.
+ atomic_store(&lastDebuggerActivity, 0LL);
}
void
@@ -133,6 +149,13 @@
*/
debugMonitorEnter(vmDeathLock);
+ // ANDROID-CHANGED: Set lastDebuggerActivity to zero to notify that we are doing
+ // debugger activity. We only do this if the cmdSet is not DDMS for historical reasons.
+ jboolean is_ddms = (cmd->cmdSet == JDWP_COMMAND_SET(DDM));
+ if (!is_ddms) {
+ atomic_store(&lastDebuggerActivity, 0LL);
+ }
+
/* Initialize the input and output streams */
inStream_init(&in, p);
outStream_initReply(&out, inStream_id(&in));
@@ -159,6 +182,13 @@
replyToSender = func(&in, &out);
}
+ // ANDROID-CHANGED: Set lastDebuggerActivity to the current milli-time to notify VMDebug
+ // that we did something. We only do this if the cmdSet is not DDMS for historical
+ // reasons.
+ if (!is_ddms) {
+ atomic_store(&lastDebuggerActivity, milliTime());
+ }
+
/* Reply to the sender */
if (replyToSender) {
if (inStream_error(&in)) {
diff --git a/src/share/back/debugLoop.h b/src/share/back/debugLoop.h
index 47695b7..7e3db4a 100644
--- a/src/share/back/debugLoop.h
+++ b/src/share/back/debugLoop.h
@@ -30,4 +30,9 @@
void debugLoop_run(void);
void debugLoop_sync(void);
+// ANDROID-CHANGED: getter for last debugger activity time. Value is the CLOCK_MONOTONIC
+// millisecond time the last debugger action completed or 0 if a debugger action is ongoing.
+// A debugger action is any JDWP command packet (except for those in JDWP_COMMAND_SET(DDM)).
+jlong debugLoop_lastDebuggerActivity(void);
+
#endif
diff --git a/src/share/back/util.c b/src/share/back/util.c
index f99f0b4..eece730 100644
--- a/src/share/back/util.c
+++ b/src/share/back/util.c
@@ -24,6 +24,8 @@
*/
#include <ctype.h>
+// ANDROID-CHANGED: Include time.h so we can use clock_gettime to implement milliTime.
+#include <time.h>
#include "util.h"
#include "transport.h"
@@ -41,6 +43,17 @@
static jboolean isArrayClass(jclass clazz);
static char * getPropertyUTF8(JNIEnv *env, char *propertyName);
+// ANDROID-CHANGED: Implement a helper to get the current time in milliseconds according to
+// CLOCK_MONOTONIC.
+jlong
+milliTime(void)
+{
+ struct timespec now;
+ memset(&now, 0, sizeof(now));
+ (void)clock_gettime(CLOCK_MONOTONIC, &now);
+ return ((jlong)now.tv_sec) * 1000LL + ((jlong)now.tv_nsec) / 1000000LL;
+}
+
/* Save an object reference for use later (create a NewGlobalRef) */
void
saveGlobalRef(JNIEnv *env, jobject obj, jobject *pobj)
diff --git a/src/share/back/util.h b/src/share/back/util.h
index 3b67bfa..68174fd 100644
--- a/src/share/back/util.h
+++ b/src/share/back/util.h
@@ -329,6 +329,9 @@
jvmtiError classInstanceCounts(jint classCount, jclass *classes, jlong *counts);
jvmtiError objectReferrers(jobject obj, ObjectBatch *referrers, int maxObjects);
+// ANDROID-CHANGED: Helper function to get current time in milliseconds on CLOCK_MONOTONIC
+jlong milliTime(void);
+
/*
* Command handling helpers shared among multiple command sets
*/
diff --git a/src/share/back/vmDebug.c b/src/share/back/vmDebug.c
new file mode 100644
index 0000000..7509620
--- /dev/null
+++ b/src/share/back/vmDebug.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "vmDebug.h"
+
+#include "JDWP.h"
+#include "debugLoop.h"
+#include "transport.h"
+#include "util.h"
+
+static jboolean JNICALL
+VMDebug_isDebuggerConnected(JNIEnv* env, jclass klass)
+{
+ return transport_is_open();
+}
+
+static jboolean JNICALL
+VMDebug_isDebuggingEnabled(JNIEnv* env, jclass klass)
+{
+ // We are running the debugger so debugging is definitely enabled.
+ return JNI_TRUE;
+}
+
+static jlong JNICALL
+VMDebug_lastDebuggerActivity(JNIEnv* env, jclass klass)
+{
+ if (!transport_is_open()) {
+ LOG_ERROR(("VMDebug.lastDebuggerActivity called without active debugger"));
+ return -1;
+ }
+ jlong last_time = debugLoop_lastDebuggerActivity();
+ if (last_time == 0) {
+ LOG_MISC(("debugger is performing an action"));
+ return 0;
+ }
+
+ jlong cur_time = milliTime();
+
+ if (cur_time < last_time) {
+ LOG_ERROR(("Time seemed to go backwards: last was %lld, current is %lld",
+ last_time, cur_time));
+ return 0;
+ }
+ jlong res = cur_time - last_time;
+ LOG_MISC(("Debugger interval is %lld", res));
+ return res;
+}
+
+void
+vmDebug_initalize(JNIEnv* env)
+{
+ WITH_LOCAL_REFS(env, 1) {
+ jclass vmdebug_class = JNI_FUNC_PTR(env,FindClass)(env, "dalvik/system/VMDebug");
+ if (vmdebug_class == NULL) {
+ // The VMDebug class isn't available. We don't need to do anything.
+ LOG_MISC(("dalvik.system.VMDebug does not seem to be available on this runtime."));
+ // Get rid of the ClassNotFoundException.
+ JNI_FUNC_PTR(env,ExceptionClear)(env);
+ goto finish;
+ }
+
+ JNINativeMethod methods[3];
+
+ // Take over the implementation of these three functions.
+ methods[0].name = "lastDebuggerActivity";
+ methods[0].signature = "()J";
+ methods[0].fnPtr = (void*)VMDebug_lastDebuggerActivity;
+
+ methods[1].name = "isDebuggingEnabled";
+ methods[1].signature = "()Z";
+ methods[1].fnPtr = (void*)VMDebug_isDebuggingEnabled;
+
+ methods[2].name = "isDebuggerConnected";
+ methods[2].signature = "()Z";
+ methods[2].fnPtr = (void*)VMDebug_isDebuggerConnected;
+
+ jint res = JNI_FUNC_PTR(env,RegisterNatives)(env,
+ vmdebug_class,
+ methods,
+ sizeof(methods) / sizeof(JNINativeMethod));
+ if (res != JNI_OK) {
+ EXIT_ERROR(JVMTI_ERROR_INTERNAL,
+ "RegisterNatives returned failure for VMDebug class");
+ }
+
+ finish: ;
+ } END_WITH_LOCAL_REFS(env);
+}
+
diff --git a/src/share/back/vmDebug.h b/src/share/back/vmDebug.h
new file mode 100644
index 0000000..f14bed2
--- /dev/null
+++ b/src/share/back/vmDebug.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+
+#ifndef JDWP_VMDEBUG_H
+#define JDWP_VMDEBUG_H
+
+void vmDebug_initalize(JNIEnv* env);
+
+#endif
+