Wire in the DDMS heap stuff.

(It's still UNIMPLEMENTED at the bottom, though.)

Change-Id: I0f4c1c90cafb48b045685ae67300170fd696f386
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc
index d5d0917..3c728f7 100644
--- a/src/dalvik_system_VMDebug.cc
+++ b/src/dalvik_system_VMDebug.cc
@@ -38,8 +38,8 @@
   // TODO: we might need to uncomment these to make them work.
   //features.push_back("method-trace-profiling");
   //features.push_back("method-trace-profiling-streaming");
-  //features.push_back("hprof-heap-dump");
-  //features.push_back("hprof-heap-dump-streaming");
+  features.push_back("hprof-heap-dump");
+  features.push_back("hprof-heap-dump-streaming");
   return toStringArray(env, features);
 }
 
diff --git a/src/debugger.cc b/src/debugger.cc
index 2d9924d..bff410e 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -79,6 +79,13 @@
 
 static bool gDdmThreadNotification = false;
 
+// DDMS GC-related settings.
+static Dbg::HpifWhen gDdmHpifWhen = Dbg::HPIF_WHEN_NEVER;
+static Dbg::HpsgWhen gDdmHpsgWhen = Dbg::HPSG_WHEN_NEVER;
+static Dbg::HpsgWhat gDdmHpsgWhat;
+static Dbg::HpsgWhen gDdmNhsgWhen = Dbg::HPSG_WHEN_NEVER;
+static Dbg::HpsgWhat gDdmNhsgWhat;
+
 static ObjectRegistry* gRegistry = NULL;
 
 /*
@@ -223,6 +230,21 @@
   gRegistry = NULL;
 }
 
+void Dbg::GcDidFinish() {
+  if (gDdmHpifWhen != HPIF_WHEN_NEVER) {
+    LOG(DEBUG) << "Sending VM heap info to DDM";
+    DdmSendHeapInfo(gDdmHpifWhen, false);
+  }
+  if (gDdmHpsgWhen != HPSG_WHEN_NEVER) {
+    LOG(DEBUG) << "Dumping VM heap to DDM";
+    DdmSendHeapSegments(false, false);
+  }
+  if (gDdmNhsgWhen != HPSG_WHEN_NEVER) {
+    LOG(DEBUG) << "Dumping native heap to DDM";
+    DdmSendHeapSegments(false, true);
+  }
+}
+
 void Dbg::SetJdwpAllowed(bool allowed) {
   gJdwpAllowed = allowed;
 }
@@ -843,4 +865,48 @@
   }
 }
 
+int Dbg::DdmHandleHpifChunk(HpifWhen when) {
+  if (when == HPIF_WHEN_NOW) {
+    DdmSendHeapInfo(when, true);
+    return true;
+  }
+
+  if (when != HPIF_WHEN_NEVER && when != HPIF_WHEN_NEXT_GC && when != HPIF_WHEN_EVERY_GC) {
+    LOG(ERROR) << "invalid HpifWhen value: " << static_cast<int>(when);
+    return false;
+  }
+
+  gDdmHpifWhen = when;
+  return true;
+}
+
+bool Dbg::DdmHandleHpsgNhsgChunk(Dbg::HpsgWhen when, Dbg::HpsgWhat what, bool native) {
+  if (when != HPSG_WHEN_NEVER && when != HPSG_WHEN_EVERY_GC) {
+    LOG(ERROR) << "invalid HpsgWhen value: " << static_cast<int>(when);
+    return false;
+  }
+
+  if (what != HPSG_WHAT_MERGED_OBJECTS && what != HPSG_WHAT_DISTINCT_OBJECTS) {
+    LOG(ERROR) << "invalid HpsgWhat value: " << static_cast<int>(what);
+    return false;
+  }
+
+  if (native) {
+    gDdmNhsgWhen = when;
+    gDdmNhsgWhat = what;
+  } else {
+    gDdmHpsgWhen = when;
+    gDdmHpsgWhat = what;
+  }
+  return true;
+}
+
+void Dbg::DdmSendHeapInfo(HpifWhen reason, bool shouldLock) {
+  UNIMPLEMENTED(WARNING) << "reason=" << static_cast<int>(reason) << " shouldLock=" << shouldLock;
+}
+
+void Dbg::DdmSendHeapSegments(bool shouldLock, bool native) {
+  UNIMPLEMENTED(WARNING) << "shouldLock=" << shouldLock << " native=" << native;
+}
+
 }  // namespace art
diff --git a/src/debugger.h b/src/debugger.h
index 270b62a..a818a48 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -73,6 +73,9 @@
   static void StartJdwp();
   static void StopJdwp();
 
+  // Invoked by the GC in case we need to keep DDMS informed.
+  static void GcDidFinish();
+
   // Return the DebugInvokeReq for the current thread.
   static DebugInvokeReq* GetInvokeReq();
 
@@ -235,6 +238,27 @@
   static void DdmDisconnected();
   static void DdmSendChunk(int type, size_t len, const uint8_t* buf);
   static void DdmSendChunkV(int type, const struct iovec* iov, int iovcnt);
+
+  enum HpifWhen {
+    HPIF_WHEN_NEVER = 0,
+    HPIF_WHEN_NOW = 1,
+    HPIF_WHEN_NEXT_GC = 2,
+    HPIF_WHEN_EVERY_GC = 3
+  };
+  static int DdmHandleHpifChunk(HpifWhen when);
+
+  enum HpsgWhen {
+    HPSG_WHEN_NEVER = 0,
+    HPSG_WHEN_EVERY_GC = 1,
+  };
+  enum HpsgWhat {
+    HPSG_WHAT_MERGED_OBJECTS = 0,
+    HPSG_WHAT_DISTINCT_OBJECTS = 1,
+  };
+  static bool DdmHandleHpsgNhsgChunk(HpsgWhen when, HpsgWhat what, bool native);
+
+  static void DdmSendHeapInfo(HpifWhen reason, bool shouldLock);
+  static void DdmSendHeapSegments(bool shouldLock, bool native);
 };
 
 #define CHUNK_TYPE(_name) \
diff --git a/src/heap.cc b/src/heap.cc
index 9e356d1..555569a 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -5,14 +5,15 @@
 #include <limits>
 #include <vector>
 
-#include "UniquePtr.h"
+#include "debugger.h"
 #include "image.h"
 #include "mark_sweep.h"
 #include "object.h"
 #include "space.h"
 #include "stl_util.h"
-#include "timing_logger.h"
 #include "thread_list.h"
+#include "timing_logger.h"
+#include "UniquePtr.h"
 
 namespace art {
 
@@ -532,6 +533,7 @@
               << (num_bytes_allocated_/1024) << "KiB/" << (footprint/1024) << "KiB, "
               << "paused " << duration << "ms";
   }
+  Dbg::GcDidFinish();
   if (is_verbose_heap_) {
     timings.Dump();
   }
diff --git a/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 4730127..4f06e68 100644
--- a/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -154,21 +154,11 @@
 }
 
 static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
-  UNIMPLEMENTED(WARNING);
-  return 0;
-  //return dvmDdmHandleHpifChunk(when);
+  return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
 }
 
-/*
- * Enable DDM heap notifications.
- * @param when: 0=never (off), 1=during GC
- * @param what: 0=merged objects, 1=distinct objects
- * @param native: false=virtual heap, true=native heap
- */
 static jboolean DdmVmInternal_heapSegmentNotify(JNIEnv* env, jclass, jint when, jint what, jboolean native) {
-  UNIMPLEMENTED(WARNING);
-  return JNI_FALSE;
-  //return dvmDdmHandleHpsgNhsgChunk(when, what, native);
+  return Dbg::DdmHandleHpsgNhsgChunk(static_cast<Dbg::HpsgWhen>(when), static_cast<Dbg::HpsgWhat>(what), native);
 }
 
 static void DdmVmInternal_threadNotify(JNIEnv* env, jclass, jboolean enable) {