From 07970839eb39a1a18013c8bd15052b761736208e Mon Sep 17 00:00:00 2001 From: Andy McFadden <> Date: Tue, 24 Mar 2009 18:15:57 -0700 Subject: [PATCH] Automated import from //branches/donutburger/...@140700,140700 --- core/java/android/ddm/DdmHandleHeap.java | 44 +++++- core/java/android/ddm/DdmHandleHello.java | 51 ++++++- core/java/android/ddm/DdmHandleProfiling.java | 137 ++++++++++++++++++ core/java/android/ddm/DdmRegister.java | 1 + core/java/android/os/Debug.java | 8 + 5 files changed, 236 insertions(+), 5 deletions(-) create mode 100644 core/java/android/ddm/DdmHandleProfiling.java diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java index 54457c215cc27..95fa0a265d152 100644 --- a/core/java/android/ddm/DdmHandleHeap.java +++ b/core/java/android/ddm/DdmHandleHeap.java @@ -20,17 +20,20 @@ import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; import org.apache.harmony.dalvik.ddmc.DdmVmInternal; +import android.os.Debug; import android.util.Config; import android.util.Log; +import java.io.IOException; import java.nio.ByteBuffer; /** - * Handle thread-related traffic. + * Handle native and virtual heap requests. */ public class DdmHandleHeap extends ChunkHandler { public static final int CHUNK_HPIF = type("HPIF"); public static final int CHUNK_HPSG = type("HPSG"); + public static final int CHUNK_HPDU = type("HPDU"); public static final int CHUNK_NHSG = type("NHSG"); public static final int CHUNK_HPGC = type("HPGC"); public static final int CHUNK_REAE = type("REAE"); @@ -49,6 +52,7 @@ public class DdmHandleHeap extends ChunkHandler { public static void register() { DdmServer.registerHandler(CHUNK_HPIF, mInstance); DdmServer.registerHandler(CHUNK_HPSG, mInstance); + DdmServer.registerHandler(CHUNK_HPDU, mInstance); DdmServer.registerHandler(CHUNK_NHSG, mInstance); DdmServer.registerHandler(CHUNK_HPGC, mInstance); DdmServer.registerHandler(CHUNK_REAE, mInstance); @@ -80,6 +84,8 @@ public class DdmHandleHeap extends ChunkHandler { return handleHPIF(request); } else if (type == CHUNK_HPSG) { return handleHPSGNHSG(request, false); + } else if (type == CHUNK_HPDU) { + return handleHPDU(request); } else if (type == CHUNK_NHSG) { return handleHPSGNHSG(request, true); } else if (type == CHUNK_HPGC) { @@ -97,7 +103,7 @@ public class DdmHandleHeap extends ChunkHandler { } /* - * Handle a "HeaP InFo request". + * Handle a "HeaP InFo" request. */ private Chunk handleHPIF(Chunk request) { ByteBuffer in = wrapChunk(request); @@ -136,6 +142,40 @@ public class DdmHandleHeap extends ChunkHandler { } } + /* + * Handle a "HeaP DUmp" request. + * + * This currently just returns a result code. We could pull up + * the entire contents of the file and return them, but hprof dump + * files can be a few megabytes. + */ + private Chunk handleHPDU(Chunk request) { + ByteBuffer in = wrapChunk(request); + byte result; + + /* get the filename for the output file */ + int len = in.getInt(); + String fileName = getString(in, len); + if (Config.LOGD) + Log.d("ddm-heap", "Heap dump: file='" + fileName + "'"); + + try { + Debug.dumpHprofData(fileName); + result = 0; + } catch (UnsupportedOperationException uoe) { + Log.w("ddm-heap", "hprof dumps not supported in this VM"); + result = -1; + } catch (IOException ioe) { + result = -1; + } catch (RuntimeException ioe) { + result = -1; + } + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { result }; + return new Chunk(CHUNK_HPDU, reply, 0, reply.length); + } + /* * Handle a "HeaP Garbage Collection" request. */ diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index e4d630e4880a6..c5d591f633a91 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -26,12 +26,13 @@ import android.os.Debug; import java.nio.ByteBuffer; /** - * Handle a HELO chunk. + * Handle "hello" messages and feature discovery. */ public class DdmHandleHello extends ChunkHandler { public static final int CHUNK_HELO = type("HELO"); public static final int CHUNK_WAIT = type("WAIT"); + public static final int CHUNK_FEAT = type("FEAT"); private static DdmHandleHello mInstance = new DdmHandleHello(); @@ -44,6 +45,7 @@ public class DdmHandleHello extends ChunkHandler { */ public static void register() { DdmServer.registerHandler(CHUNK_HELO, mInstance); + DdmServer.registerHandler(CHUNK_FEAT, mInstance); } /** @@ -73,12 +75,27 @@ public class DdmHandleHello extends ChunkHandler { } /** - * Handle a chunk of data. We're only registered for "HELO". + * Handle a chunk of data. */ public Chunk handleChunk(Chunk request) { if (Config.LOGV) - Log.v("ddm-hello", "Handling " + name(request.type) + " chunk"); + Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); + int type = request.type; + if (type == CHUNK_HELO) { + return handleHELO(request); + } else if (type == CHUNK_FEAT) { + return handleFEAT(request); + } else { + throw new RuntimeException("Unknown packet " + + ChunkHandler.name(type)); + } + } + + /* + * Handle introductory packet. + */ + private Chunk handleHELO(Chunk request) { if (false) return createFailChunk(123, "This is a test"); @@ -125,6 +142,34 @@ public class DdmHandleHello extends ChunkHandler { return reply; } + /* + * Handle request for list of supported features. + */ + private Chunk handleFEAT(Chunk request) { + // TODO: query the VM to ensure that support for these features + // is actually compiled in + final String[] features = { + "hprof-heap-dump", "method-trace-profiling" + }; + + if (Config.LOGD) + Log.d("ddm-heap", "Got feature list request"); + + int size = 4 + 4 * features.length; + for (int i = features.length-1; i >= 0; i--) + size += features[i].length() * 2; + + ByteBuffer out = ByteBuffer.allocate(size); + out.order(ChunkHandler.CHUNK_ORDER); + out.putInt(features.length); + for (int i = features.length-1; i >= 0; i--) { + out.putInt(features[i].length()); + putString(out, features[i]); + } + + return new Chunk(CHUNK_FEAT, out); + } + /** * Send up a WAIT chunk. The only currently defined value for "reason" * is zero, which means "waiting for a debugger". diff --git a/core/java/android/ddm/DdmHandleProfiling.java b/core/java/android/ddm/DdmHandleProfiling.java new file mode 100644 index 0000000000000..beed50507fa28 --- /dev/null +++ b/core/java/android/ddm/DdmHandleProfiling.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2009 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. + */ + +package android.ddm; + +import org.apache.harmony.dalvik.ddmc.Chunk; +import org.apache.harmony.dalvik.ddmc.ChunkHandler; +import org.apache.harmony.dalvik.ddmc.DdmServer; +import android.os.Debug; +import android.util.Config; +import android.util.Log; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Handle profiling requests. + */ +public class DdmHandleProfiling extends ChunkHandler { + + public static final int CHUNK_MPRS = type("MPRS"); + public static final int CHUNK_MPRE = type("MPRE"); + public static final int CHUNK_MPRQ = type("MPRQ"); + + private static DdmHandleProfiling mInstance = new DdmHandleProfiling(); + + + /* singleton, do not instantiate */ + private DdmHandleProfiling() {} + + /** + * Register for the messages we're interested in. + */ + public static void register() { + DdmServer.registerHandler(CHUNK_MPRS, mInstance); + DdmServer.registerHandler(CHUNK_MPRE, mInstance); + DdmServer.registerHandler(CHUNK_MPRQ, mInstance); + } + + /** + * Called when the DDM server connects. The handler is allowed to + * send messages to the server. + */ + public void connected() {} + + /** + * Called when the DDM server disconnects. Can be used to disable + * periodic transmissions or clean up saved state. + */ + public void disconnected() {} + + /** + * Handle a chunk of data. + */ + public Chunk handleChunk(Chunk request) { + if (Config.LOGV) + Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); + int type = request.type; + + if (type == CHUNK_MPRS) { + return handleMPRS(request); + } else if (type == CHUNK_MPRE) { + return handleMPRE(request); + } else if (type == CHUNK_MPRQ) { + return handleMPRQ(request); + } else { + throw new RuntimeException("Unknown packet " + + ChunkHandler.name(type)); + } + } + + /* + * Handle a "Method PRofiling Start" request. + */ + private Chunk handleMPRS(Chunk request) { + ByteBuffer in = wrapChunk(request); + + int bufferSize = in.getInt(); + int flags = in.getInt(); + int len = in.getInt(); + String fileName = getString(in, len); + if (Config.LOGV) + Log.v("ddm-heap", "Method profiling start: filename='" + fileName + + "', size=" + bufferSize + ", flags=" + flags); + + try { + Debug.startMethodTracing(fileName, bufferSize, flags); + return null; // empty response + } catch (RuntimeException re) { + return createFailChunk(1, re.getMessage()); + } + } + + /* + * Handle a "Method PRofiling End" request. + */ + private Chunk handleMPRE(Chunk request) { + byte result; + + try { + Debug.stopMethodTracing(); + result = 0; + } catch (RuntimeException re) { + Log.w("ddm-heap", "Method profiling end failed: " + + re.getMessage()); + result = 1; + } + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { result }; + return new Chunk(CHUNK_MPRE, reply, 0, reply.length); + } + + /* + * Handle a "Method PRofiling Query" request. + */ + private Chunk handleMPRQ(Chunk request) { + int result = Debug.isMethodTracingActive() ? 1 : 0; + + /* create a non-empty reply so the handler fires on completion */ + byte[] reply = { (byte) result }; + return new Chunk(CHUNK_MPRQ, reply, 0, reply.length); + } +} + diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java index b7f1ab8dbb353..debf189bb1d09 100644 --- a/core/java/android/ddm/DdmRegister.java +++ b/core/java/android/ddm/DdmRegister.java @@ -50,6 +50,7 @@ public class DdmRegister { DdmHandleThread.register(); DdmHandleHeap.register(); DdmHandleNativeHeap.register(); + DdmHandleProfiling.register(); DdmHandleExit.register(); DdmServer.registrationComplete(); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 950bb09d03c4c..5ea5aaedccaf6 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -363,6 +363,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo VMDebug.startMethodTracing(pathName, bufferSize, flags); } + /** + * Determine whether method tracing is currently active. + * @hide + */ + public static boolean isMethodTracingActive() { + return VMDebug.isMethodTracingActive(); + } + /** * Stop method tracing. */