Merge "Add DDM.Chunk extension command support."
am: e8a216345d

Change-Id: Ica0637765eaeb5c0360bf73b85d74beca9534987
diff --git a/make/data/jdwp/jdwp.spec b/make/data/jdwp/jdwp.spec
index aadede2..6c742b4 100644
--- a/make/data/jdwp/jdwp.spec
+++ b/make/data/jdwp/jdwp.spec
@@ -3027,6 +3027,28 @@
         )
     )
 )
+(CommandSet DDM=-57
+    "The extension commands for ddms. Note that this is equivalent to the uint8_t value '199'."
+    (Command Chunk = 1
+        "Returns the output of processing a DDMS chunk with any registered handlers. Note: When an error occurs or no data is returned no error code will be set and the reply will be empty.  This is for backwards compatibility."
+        (Out
+            (int ddms_type "The ddms type of the data that follows")
+            (Repeat ddms_data_length
+                (byte ddms_data "DDMS data to be processed by the handler registered for the given input_type.")
+            )
+        )
+        (Reply
+            (int ddms_type "The ddms type of the data that follows")
+            (Repeat ddms_data_length
+                (byte ddms_data "DDMS data returned from the handler")
+            )
+        )
+        (ErrorSet
+            (Error NOT_IMPLEMENTED "DDMS is not supported or set up.")
+            (Error VM_DEAD)
+        )
+    )
+)
 (ConstantSet Error
     (Constant NONE                   =0   "No error has occurred.")
     (Constant INVALID_THREAD         =10  "Passed thread is null, is not a valid thread or has exited.")
diff --git a/src/share/back/DDMImpl.c b/src/share/back/DDMImpl.c
new file mode 100644
index 0000000..80fe669
--- /dev/null
+++ b/src/share/back/DDMImpl.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1999, 2005, 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 "util.h"
+#include "DDMImpl.h"
+#include "inStream.h"
+#include "outStream.h"
+
+static jboolean
+chunk(PacketInputStream *in, PacketOutputStream *out)
+{
+    int i;
+    jint type_in;
+    jint type_out;
+    jint len_in;
+    jint len_out;
+    jbyte* data_in;
+    jbyte* data_out;
+    jvmtiError error;
+
+    type_in = inStream_readInt(in);
+    len_in = inStream_readInt(in);
+    data_in = inStream_readBytes(in, len_in, (jbyte*)jvmtiAllocate(len_in));
+
+    if (inStream_error(in)) {
+        return JNI_TRUE;
+    }
+
+    if (gdata->ddm_process_chunk == NULL) {
+        jvmtiDeallocate(data_in);
+        outStream_setError(out, JDWP_ERROR(NOT_IMPLEMENTED));
+        return JNI_TRUE;
+    }
+
+    LOG_JVMTI(("com.android.art.internal.ddm.process_chunk()"));
+    error = gdata->ddm_process_chunk(gdata->jvmti,
+                                     type_in,
+                                     len_in,
+                                     data_in,
+                                     &type_out,
+                                     &len_out,
+                                     &data_out);
+
+    jvmtiDeallocate(data_in);
+
+    if (error != JVMTI_ERROR_NONE) {
+        // For backwards-compatibility we do not actually return any error or any data at all
+        // here.
+        LOG_MISC(("Suppressing error from com.android.art.internal.ddm.process_chunk for backwards "
+                  "compatibility. Error was %s (%d)", jvmtiErrorText(error), error));
+        return JNI_TRUE;
+    }
+
+    outStream_writeInt(out, type_out);
+    outStream_writeByteArray(out, len_out, data_out);
+    jvmtiDeallocate(data_out);
+
+    return JNI_TRUE;
+}
+
+void *DDM_Cmds[] = { (void *)1
+    ,(void *)chunk
+};
diff --git a/src/share/back/DDMImpl.h b/src/share/back/DDMImpl.h
new file mode 100644
index 0000000..4d92ef4
--- /dev/null
+++ b/src/share/back/DDMImpl.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1999, 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.
+ */
+extern void *DDM_Cmds[];
+
diff --git a/src/share/back/debugDispatch.c b/src/share/back/debugDispatch.c
index e9e8c0e..f97fed7 100644
--- a/src/share/back/debugDispatch.c
+++ b/src/share/back/debugDispatch.c
@@ -42,6 +42,7 @@
 #include "ArrayReferenceImpl.h"
 #include "EventRequestImpl.h"
 #include "StackFrameImpl.h"
+#include "DDMImpl.h"
 
 static void **l1Array;
 
@@ -94,12 +95,15 @@
 {
     void **l2Array;
 
-    if (cmdSet > JDWP_HIGHEST_COMMAND_SET) {
+    // ANDROID-CHANGED: DDMS has cmdSet -57 (199u). Check for this one specifically.
+    if (cmdSet == JDWP_COMMAND_SET(DDM)) {
+        l2Array = (void **)DDM_Cmds;
+    } else if (cmdSet > JDWP_HIGHEST_COMMAND_SET || cmdSet < 0) {
         return NULL;
+    } else {
+        l2Array = (void **)l1Array[cmdSet];
     }
 
-    l2Array = (void **)l1Array[cmdSet];
-
     /*
      * If there is no such CommandSet or the Command
      * is greater than the nummber of commands (the first
diff --git a/src/share/back/debugInit.c b/src/share/back/debugInit.c
index 955e9eb..474c197 100644
--- a/src/share/back/debugInit.c
+++ b/src/share/back/debugInit.c
@@ -194,6 +194,44 @@
            minor_runtime >= minor_compiletime;
 }
 
+// ANDROID-CHANGED: Function to get and set the com.android.art.internal.ddm.process_chunk extension
+// function. This returns JNI_ERR if something went wrong with searching. If the extension is not
+// found we return JNI_OK and don't bother updating the gdata pointer.
+static jint find_ddm_process_chunk()
+{
+    jvmtiError error;
+    jvmtiExtensionFunctionInfo* extension_info;
+    jint num_extensions;
+    jboolean found;
+    int i;
+    int j;
+
+    found = JNI_FALSE;
+    error = JVMTI_FUNC_PTR(gdata->jvmti,GetExtensionFunctions)
+            (gdata->jvmti, &num_extensions, &extension_info);
+    if (error != JVMTI_ERROR_NONE) {
+        ERROR_MESSAGE(("JDWP Unable to get jvmti extension functions: %s(%d)",
+                       jvmtiErrorText(error), error));
+        return JNI_ERR;
+    }
+    // We iterate through every extension function even once we found the one we want in order to
+    // clean them all up as we go.
+    for (i = 0; i < num_extensions; i++) {
+        if (strcmp("com.android.art.internal.ddm.process_chunk", extension_info[i].id) == 0) {
+            gdata->ddm_process_chunk = (DdmProcessChunk) extension_info[i].func;
+        }
+        jvmtiDeallocate(extension_info[i].id);
+        jvmtiDeallocate(extension_info[i].short_description);
+        for (j = 0; j < extension_info[i].param_count; j++) {
+            jvmtiDeallocate(extension_info[i].params[j].name);
+        }
+        jvmtiDeallocate(extension_info[i].params);
+        jvmtiDeallocate(extension_info[i].errors);
+    }
+    jvmtiDeallocate(extension_info);
+    return JNI_OK;
+}
+
 /* OnLoad startup:
  *   Returning JNI_ERR will cause the java_g VM to core dump, be careful.
  */
@@ -400,6 +438,13 @@
         return JNI_ERR;
     }
 
+    // ANDROID-CHANGED: Find com.android.art.internal.ddm.process_chunk function if it exists.
+    if (find_ddm_process_chunk() != JNI_OK) {
+        ERROR_MESSAGE(("Fatal error while attempting to find the "
+                       "com.android.art.internal.ddm.process_chunk extension function"));
+        return JNI_ERR;
+    }
+
     LOG_MISC(("OnLoad: DONE"));
     return JNI_OK;
 }
diff --git a/src/share/back/util.h b/src/share/back/util.h
index 0f9aa1c..3b67bfa 100644
--- a/src/share/back/util.h
+++ b/src/share/back/util.h
@@ -74,6 +74,15 @@
 
 typedef jint FrameNumber;
 
+// ANDROID-CHANGED: support for DDMS extension apis.
+typedef jvmtiError (*DdmProcessChunk)(jvmtiEnv* jvmti,
+                                      jint type_in,
+                                      jint length_in,
+                                      const jbyte* data_in,
+                                      jint* type_out,
+                                      jint* length_out,
+                                      jbyte** data_out);
+
 typedef struct {
     jvmtiEnv *jvmti;
     JavaVM   *jvm;
@@ -136,6 +145,9 @@
      /* Indication that the agent has been loaded */
      jboolean isLoaded;
 
+     /* ANDROID-CHANGED: com.android.art.internal.ddm.process_chunk extension function */
+     DdmProcessChunk ddm_process_chunk;
+
 } BackendGlobalData;
 
 extern BackendGlobalData * gdata;