1 /* 2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdatomic.h> 27 28 #include "vmDebug.h" 29 30 #include "JDWP.h" 31 #include "debugLoop.h" 32 #include "transport.h" 33 #include "util.h" 34 35 static _Atomic(jlong) lastDebuggerActivity = ATOMIC_VAR_INIT(0LL); 36 static _Atomic(jboolean) hasSeenDebuggerActivity = ATOMIC_VAR_INIT(JNI_FALSE); 37 38 // Reset the tracking variables. 39 void vmDebug_onDisconnect() 40 { 41 atomic_store(&lastDebuggerActivity, 0LL); 42 atomic_store(&hasSeenDebuggerActivity, JNI_FALSE); 43 } 44 45 // Mark us as having seen actual debugger activity (so isDebuggerConnected can return true) and that 46 // we are currently doing something as the debugger. 47 void vmDebug_notifyDebuggerActivityStart() 48 { 49 atomic_store(&lastDebuggerActivity, 0LL); 50 atomic_store(&hasSeenDebuggerActivity, JNI_TRUE); 51 } 52 53 // Update the timestamp for the last debugger activity. 54 void vmDebug_notifyDebuggerActivityEnd() 55 { 56 atomic_store(&lastDebuggerActivity, milliTime()); 57 } 58 59 // For backwards compatibility we are only considered 'connected' as far as VMDebug is concerned if 60 // we have gotten at least one non-ddms JDWP packet. 61 static jboolean 62 isDebuggerConnected() 63 { 64 return transport_is_open() && atomic_load(&hasSeenDebuggerActivity); 65 } 66 67 static jboolean JNICALL 68 VMDebug_isDebuggerConnected(JNIEnv* env, jclass klass) 69 { 70 return isDebuggerConnected(); 71 } 72 73 static jboolean JNICALL 74 VMDebug_isDebuggingEnabled(JNIEnv* env, jclass klass) 75 { 76 // We are running the debugger so debugging is definitely enabled. 77 return JNI_TRUE; 78 } 79 80 static jlong JNICALL 81 VMDebug_lastDebuggerActivity(JNIEnv* env, jclass klass) 82 { 83 if (!isDebuggerConnected()) { 84 LOG_ERROR(("VMDebug.lastDebuggerActivity called without active debugger")); 85 return -1; 86 } 87 jlong last_time = atomic_load(&lastDebuggerActivity); 88 if (last_time == 0) { 89 LOG_MISC(("debugger is performing an action")); 90 return 0; 91 } 92 93 jlong cur_time = milliTime(); 94 95 if (cur_time < last_time) { 96 LOG_ERROR(("Time seemed to go backwards: last was %lld, current is %lld", 97 last_time, cur_time)); 98 return 0; 99 } 100 jlong res = cur_time - last_time; 101 LOG_MISC(("Debugger interval is %lld", res)); 102 return res; 103 } 104 105 void 106 vmDebug_initalize(JNIEnv* env) 107 { 108 WITH_LOCAL_REFS(env, 1) { 109 jclass vmdebug_class = JNI_FUNC_PTR(env,FindClass)(env, "dalvik/system/VMDebug"); 110 if (vmdebug_class == NULL) { 111 // The VMDebug class isn't available. We don't need to do anything. 112 LOG_MISC(("dalvik.system.VMDebug does not seem to be available on this runtime.")); 113 // Get rid of the ClassNotFoundException. 114 JNI_FUNC_PTR(env,ExceptionClear)(env); 115 goto finish; 116 } 117 118 JNINativeMethod methods[3]; 119 120 // Take over the implementation of these three functions. 121 methods[0].name = "lastDebuggerActivity"; 122 methods[0].signature = "()J"; 123 methods[0].fnPtr = (void*)VMDebug_lastDebuggerActivity; 124 125 methods[1].name = "isDebuggingEnabled"; 126 methods[1].signature = "()Z"; 127 methods[1].fnPtr = (void*)VMDebug_isDebuggingEnabled; 128 129 methods[2].name = "isDebuggerConnected"; 130 methods[2].signature = "()Z"; 131 methods[2].fnPtr = (void*)VMDebug_isDebuggerConnected; 132 133 jint res = JNI_FUNC_PTR(env,RegisterNatives)(env, 134 vmdebug_class, 135 methods, 136 sizeof(methods) / sizeof(JNINativeMethod)); 137 if (res != JNI_OK) { 138 EXIT_ERROR(JVMTI_ERROR_INTERNAL, 139 "RegisterNatives returned failure for VMDebug class"); 140 } 141 142 finish: ; 143 } END_WITH_LOCAL_REFS(env); 144 } 145 146