auto import from //depot/cupcake/@135843
diff --git a/vm/alloc/HeapDebug.c b/vm/alloc/HeapDebug.c
new file mode 100644
index 0000000..fc3655f
--- /dev/null
+++ b/vm/alloc/HeapDebug.c
@@ -0,0 +1,403 @@
+/*
+ * 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 <fcntl.h>
+#include <malloc.h>
+
+#include "Dalvik.h"
+#include "HeapInternal.h"
+#include "HeapSource.h"
+#include "Float12.h"
+
+int dvmGetHeapDebugInfo(HeapDebugInfoType info)
+{
+    switch (info) {
+    case kVirtualHeapSize:
+        return (int)dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
+    case kVirtualHeapAllocated:
+        return (int)dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
+    default:
+        return -1;
+    }
+}
+
+/* Looks up the cmdline for the process and tries to find
+ * the most descriptive five characters, then inserts the
+ * short name into the provided event value.
+ */
+#define PROC_NAME_LEN 5
+static void insertProcessName(long long *ep)
+{
+    static bool foundRealName = false;
+    static char name[PROC_NAME_LEN] = { 'X', 'X', 'X', 'X', 'X' };
+    long long event = *ep;
+
+    if (!foundRealName) {
+        int fd = open("/proc/self/cmdline", O_RDONLY);
+        if (fd > 0) {
+            char buf[128];
+            ssize_t n = read(fd, buf, sizeof(buf) - 1);
+            close(fd);
+            if (n > 0) {
+                memset(name, 0, sizeof(name));
+                if (n <= PROC_NAME_LEN) {
+                    // The whole name fits.
+                    memcpy(name, buf, n);
+                } else {
+                    /* We need to truncate.  The name will look something
+                     * like "com.android.home".  Favor the characters
+                     * immediately following the last dot.
+                     */
+                    buf[n] = '\0';
+                    char *dot = strrchr(buf, '.');
+                    if (dot == NULL) {
+                        /* Or, look for a slash, in case it's something like
+                         * "/system/bin/runtime".
+                         */
+                        dot = strrchr(buf, '/');
+                    }
+                    if (dot != NULL) {
+                        dot++;  // Skip the dot
+                        size_t dotlen = strlen(dot);
+                        if (dotlen < PROC_NAME_LEN) {
+                            /* Use all available characters.  We know that
+                             * n > PROC_NAME_LEN from the check above.
+                             */
+                            dot -= PROC_NAME_LEN - dotlen;
+                        }
+                        strncpy(name, dot, PROC_NAME_LEN);
+                    } else {
+                        // No dot; just use the leading characters.
+                        memcpy(name, buf, PROC_NAME_LEN);
+                    }
+                }
+                if (strcmp(buf, "zygote") != 0) {
+                    /* If the process is no longer called "zygote",
+                     * cache this name.
+                     */
+                    foundRealName = true;
+                }
+            }
+        }
+    }
+
+    event &= ~(0xffffffffffLL << 24);
+    event |= (long long)name[0] << 56;
+    event |= (long long)name[1] << 48;
+    event |= (long long)name[2] << 40;
+    event |= (long long)name[3] << 32;
+    event |= (long long)name[4] << 24;
+
+    *ep = event;
+}
+
+// See device/data/etc/event-log-tags
+#define EVENT_LOG_TAG_dvm_gc_info 20001
+#define EVENT_LOG_TAG_dvm_gc_madvise_info 20002
+
+void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs)
+{
+    const GcHeap *gcHeap = gDvm.gcHeap;
+    size_t perHeapActualSize[HEAP_SOURCE_MAX_HEAP_COUNT],
+           perHeapAllowedSize[HEAP_SOURCE_MAX_HEAP_COUNT],
+           perHeapNumAllocated[HEAP_SOURCE_MAX_HEAP_COUNT],
+           perHeapSizeAllocated[HEAP_SOURCE_MAX_HEAP_COUNT];
+    unsigned char eventBuf[1 + (1 + sizeof(long long)) * 4];
+    size_t actualSize, allowedSize, numAllocated, sizeAllocated;
+    size_t i;
+    size_t softLimit = dvmHeapSourceGetIdealFootprint();
+    size_t nHeaps = dvmHeapSourceGetNumHeaps();
+
+    /* Enough to quiet down gcc for unitialized variable check */
+    perHeapActualSize[0] = perHeapAllowedSize[0] = perHeapNumAllocated[0] =
+                           perHeapSizeAllocated[0] = 0;
+    actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize, 
+                                       HEAP_SOURCE_MAX_HEAP_COUNT);
+    allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT, 
+                      perHeapAllowedSize, HEAP_SOURCE_MAX_HEAP_COUNT);
+    numAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED,
+                      perHeapNumAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
+    sizeAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED,
+                      perHeapSizeAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
+
+    /* 
+     * Construct the the first 64-bit value to write to the log. 
+     * Global information:
+     *
+     * [63   ] Must be zero
+     * [62-24] ASCII process identifier
+     * [23-12] GC time in ms
+     * [11- 0] Bytes freed
+     *
+     */
+    long long event0;
+    event0 = 0LL << 63 |
+            (long long)intToFloat12(gcTimeMs) << 12 |
+            (long long)intToFloat12(sizeFreed);
+    insertProcessName(&event0);
+
+    /*
+     * Aggregated heap stats:
+     *
+     * [63-62] 10
+     * [61-60] Reserved; must be zero
+     * [59-48] Objects freed
+     * [47-36] Actual size (current footprint)
+     * [35-24] Allowed size (current hard max)
+     * [23-12] Objects allocated
+     * [11- 0] Bytes allocated
+     */
+    long long event1;
+    event1 = 2LL << 62 |
+            (long long)intToFloat12(numFreed) << 48 |
+            (long long)intToFloat12(actualSize) << 36 |
+            (long long)intToFloat12(allowedSize) << 24 |
+            (long long)intToFloat12(numAllocated) << 12 |
+            (long long)intToFloat12(sizeAllocated);
+
+    /*
+     * Report the current state of the zygote heap(s).
+     *
+     * The active heap is always heap[0].  We can be in one of three states
+     * at present:
+     *
+     *  (1) Still in the zygote.  Zygote using heap[0].
+     *  (2) In the zygote, when the first child is started.  We created a
+     *      new heap just before the first fork() call, so the original
+     *      "zygote heap" is now heap[1], and we have a small heap[0] for
+     *      anything we do from here on.
+     *  (3) In an app process.  The app gets a new heap[0], and can also
+     *      see the two zygote heaps [1] and [2] (probably unwise to
+     *      assume any specific ordering).
+     *
+     * So if nHeaps == 1, we want the stats from heap[0]; else we want
+     * the sum of the values from heap[1] to heap[nHeaps-1].
+     *
+     *
+     * Zygote heap stats (except for the soft limit, which belongs to the
+     * active heap):
+     *
+     * [63-62] 11
+     * [61-60] Reserved; must be zero
+     * [59-48] Soft Limit (for the active heap)
+     * [47-36] Actual size (current footprint)
+     * [35-24] Allowed size (current hard max)
+     * [23-12] Objects allocated
+     * [11- 0] Bytes allocated
+     */
+    long long event2;
+    size_t zActualSize, zAllowedSize, zNumAllocated, zSizeAllocated;
+    int firstHeap = (nHeaps == 1) ? 0 : 1;
+    size_t hh;
+
+    zActualSize = zAllowedSize = zNumAllocated = zSizeAllocated = 0;
+    for (hh = firstHeap; hh < nHeaps; hh++) {
+        zActualSize += perHeapActualSize[hh];
+        zAllowedSize += perHeapAllowedSize[hh];
+        zNumAllocated += perHeapNumAllocated[hh];
+        zSizeAllocated += perHeapSizeAllocated[hh];
+    }
+    event2 = 3LL << 62 |
+            (long long)intToFloat12(softLimit) << 48 |
+            (long long)intToFloat12(zActualSize) << 36 |
+            (long long)intToFloat12(zAllowedSize) << 24 |
+            (long long)intToFloat12(zNumAllocated) << 12 |
+            (long long)intToFloat12(zSizeAllocated);
+
+    /*
+     * Report the current external allocation stats and the native heap
+     * summary.
+     *
+     * [63-48] Reserved; must be zero (TODO: put new data in these slots)
+     * [47-36] dlmalloc_footprint
+     * [35-24] mallinfo: total allocated space
+     * [23-12] External byte limit
+     * [11- 0] External bytes allocated
+     */
+    long long event3;
+    size_t externalLimit, externalBytesAllocated;
+    size_t uordblks, footprint;
+
+#if 0
+    /*
+     * This adds 2-5msec to the GC cost on a DVT, or about 2-3% of the cost
+     * of a GC, so it's not horribly expensive but it's not free either.
+     */
+    extern size_t dlmalloc_footprint(void);
+    struct mallinfo mi;
+    //u8 start, end;
+
+    //start = dvmGetRelativeTimeNsec();
+    mi = mallinfo();
+    uordblks = mi.uordblks;
+    footprint = dlmalloc_footprint();
+    //end = dvmGetRelativeTimeNsec();
+    //LOGD("mallinfo+footprint took %dusec; used=%zd footprint=%zd\n",
+    //    (int)((end - start) / 1000), mi.uordblks, footprint);
+#else
+    uordblks = footprint = 0;
+#endif
+
+    externalLimit =
+            dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
+    externalBytesAllocated =
+            dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
+    event3 =
+            (long long)intToFloat12(footprint) << 36 |
+            (long long)intToFloat12(uordblks) << 24 |
+            (long long)intToFloat12(externalLimit) << 12 |
+            (long long)intToFloat12(externalBytesAllocated);
+
+    /* Build the event data.
+     * [ 0: 0] item count (4)
+     * [ 1: 1] EVENT_TYPE_LONG
+     * [ 2: 9] event0
+     * [10:10] EVENT_TYPE_LONG
+     * [11:18] event1
+     * [19:19] EVENT_TYPE_LONG
+     * [20:27] event2
+     * [28:28] EVENT_TYPE_LONG
+     * [29:36] event2
+     */
+    unsigned char *c = eventBuf;
+    *c++ = 4;
+    *c++ = EVENT_TYPE_LONG;
+    memcpy(c, &event0, sizeof(event0));
+    c += sizeof(event0);
+    *c++ = EVENT_TYPE_LONG;
+    memcpy(c, &event1, sizeof(event1));
+    c += sizeof(event1);
+    *c++ = EVENT_TYPE_LONG;
+    memcpy(c, &event2, sizeof(event2));
+    c += sizeof(event2);
+    *c++ = EVENT_TYPE_LONG;
+    memcpy(c, &event3, sizeof(event3));
+
+    (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_info, EVENT_TYPE_LIST,
+            eventBuf, sizeof(eventBuf));
+}
+
+void dvmLogMadviseStats(size_t madvisedSizes[], size_t arrayLen)
+{
+    unsigned char eventBuf[1 + (1 + sizeof(int)) * 2];
+    size_t total, zyg;
+    size_t firstHeap, i;
+    size_t nHeaps = dvmHeapSourceGetNumHeaps();
+
+    assert(arrayLen >= nHeaps);
+
+    firstHeap = nHeaps > 1 ? 1 : 0;
+    total = 0;
+    zyg = 0;
+    for (i = 0; i < nHeaps; i++) {
+        total += madvisedSizes[i];
+        if (i >= firstHeap) {
+            zyg += madvisedSizes[i];
+        }
+    }
+
+    /* Build the event data.
+     * [ 0: 0] item count (2)
+     * [ 1: 1] EVENT_TYPE_INT
+     * [ 2: 5] total madvise byte count
+     * [ 6: 6] EVENT_TYPE_INT
+     * [ 7:10] zygote heap madvise byte count
+     */
+    unsigned char *c = eventBuf;
+    *c++ = 2;
+    *c++ = EVENT_TYPE_INT;
+    memcpy(c, &total, sizeof(total));
+    c += sizeof(total);
+    *c++ = EVENT_TYPE_INT;
+    memcpy(c, &zyg, sizeof(zyg));
+    c += sizeof(zyg);
+
+    (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_madvise_info,
+            EVENT_TYPE_LIST, eventBuf, sizeof(eventBuf));
+}
+
+#if 0
+#include <errno.h>
+#include <stdio.h>
+
+typedef struct HeapDumpContext {
+    FILE *fp;
+    void *chunkStart;
+    size_t chunkLen;
+    bool chunkFree;
+} HeapDumpContext;
+
+static void
+dump_context(const HeapDumpContext *ctx)
+{
+    fprintf(ctx->fp, "0x%08x %12.12zd %s\n", (uintptr_t)ctx->chunkStart,
+            ctx->chunkLen, ctx->chunkFree ? "FREE" : "USED");
+}
+
+static void
+heap_chunk_callback(const void *chunkptr, size_t chunklen,
+                    const void *userptr, size_t userlen, void *arg)
+{
+    HeapDumpContext *ctx = (HeapDumpContext *)arg;
+    bool chunkFree = (userptr == NULL);
+
+    if (chunkFree != ctx->chunkFree ||
+            ((char *)ctx->chunkStart + ctx->chunkLen) != chunkptr)
+    {
+        /* The new chunk is of a different type or isn't
+         * contiguous with the current chunk.  Dump the
+         * old one and start a new one.
+         */
+        if (ctx->chunkStart != NULL) {
+            /* It's not the first chunk. */
+            dump_context(ctx);
+        }
+        ctx->chunkStart = (void *)chunkptr;
+        ctx->chunkLen = chunklen;
+        ctx->chunkFree = chunkFree;
+    } else {
+        /* Extend the current chunk.
+         */
+        ctx->chunkLen += chunklen;
+    }
+}
+
+/* Dumps free and used ranges, as text, to the named file.
+ */
+void dvmDumpHeapToFile(const char *fileName)
+{
+    HeapDumpContext ctx;
+    FILE *fp;
+
+    fp = fopen(fileName, "w+");
+    if (fp == NULL) {
+        LOGE("Can't open %s for writing: %s\n", fileName, strerror(errno));
+        return;
+    }
+    LOGW("Dumping heap to %s...\n", fileName);
+
+    fprintf(fp, "==== Dalvik heap dump ====\n");
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.fp = fp;
+    dvmHeapSourceWalk(heap_chunk_callback, (void *)&ctx);
+    dump_context(&ctx);
+    fprintf(fp, "==== end heap dump ====\n");
+
+    LOGW("Dumped heap to %s.\n", fileName);
+
+    fclose(fp);
+}
+#endif