From b752b6ca3e8b3553e8ede1344c3b3b4aa13b825d Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Thu, 28 Jan 2010 10:44:02 -0800 Subject: [PATCH] DDMS: Add support for profiling with VM able to send the result through JDWP. Do not merge. Older VMs need to write the trace file on the SD Card which requires the appropriate permission. This new mode directly streams the trace file from the VM to DDMS. Integrated from master to be in SDK Tools r5. Bug: 2160407 Change-Id: I17d3e314d6325c1bdff041564bc939b2778b563e --- .../libs/ddmlib/src/com/android/ddmlib/Client.java | 2 +- .../ddmlib/src/com/android/ddmlib/ClientData.java | 24 ++++++++- .../src/com/android/ddmlib/HandleProfiling.java | 60 ++++++++++++++++++---- .../src/com/android/ddmuilib/InfoPanel.java | 16 +++++- .../ddmuilib/handler/MethodProfilingHandler.java | 28 +++++++++- 5 files changed, 114 insertions(+), 16 deletions(-) diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java index 52c950676..efa47d74f 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java @@ -241,7 +241,7 @@ public class Client { } public void toggleMethodProfiling() { - boolean canStream = false; //mClientData.hasFeature(ClientData.FEATURE_PROFILING_STREAMING); + boolean canStream = mClientData.hasFeature(ClientData.FEATURE_PROFILING_STREAMING); try { if (mClientData.getMethodProfilingStatus() == MethodProfilingStatus.ON) { if (canStream) { diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/ClientData.java b/ddms/libs/ddmlib/src/com/android/ddmlib/ClientData.java index 53e13528a..a064634ed 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/ClientData.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/ClientData.java @@ -18,6 +18,7 @@ package com.android.ddmlib; import com.android.ddmlib.HeapSegment.HeapSegmentElement; +import java.io.File; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -315,10 +316,29 @@ public class ClientData { void onSuccess(String remoteFilePath, Client client); /** - * Called when method tracing failed. + * Called when a method tracing was successful. + * @param remoteFilePath the device-side path of the trace file. * @param client the client that was profiled. */ - void onFailure(Client client); + void onSuccess(File localFile, Client client); + + /** + * Called when method tracing failed to start + * @param client the client that was profiled. + */ + void onStartFailure(Client client); + + /** + * Called when method tracing failed to end on the VM side + * @param client the client that was profiled. + */ + void onEndFailure(Client client); + + /** + * Called when method tracing failed to end locally. + * @param client the client that was profiled. + */ + void onEndLocalFailure(Client client, String message); } /** diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java index fcc1d26bf..7d2eb45f1 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/HandleProfiling.java @@ -19,6 +19,8 @@ package com.android.ddmlib; import com.android.ddmlib.ClientData.IMethodProfilingHandler; import com.android.ddmlib.ClientData.MethodProfilingStatus; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -154,7 +156,7 @@ final class HandleProfiling extends ChunkHandler { Log.d("ddm-prof", "Method profiling has finished"); } else { - handler.onFailure(client); + handler.onEndFailure(client); Log.w("ddm-prof", "Method profiling has failed (check device log)"); } @@ -213,12 +215,42 @@ final class HandleProfiling extends ChunkHandler { * complete .trace file. */ private void handleMPSE(Client client, ByteBuffer data) { - // TODO - byte[] stuff = new byte[Math.min(100, data.capacity())]; - data.get(stuff, 0, stuff.length); - String sample = new String(stuff); - Log.e("ddm-prof", "GOT MPSE (" + data.capacity() + " bytes): '" + - sample + "' ..."); + IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler(); + if (handler != null) { + FileOutputStream fos = null; + try { + File f = File.createTempFile(client.getClientData().getClientDescription(), + ".trace"); + fos = new FileOutputStream(f); + + byte[] stuff = new byte[data.capacity()]; + data.get(stuff, 0, stuff.length); + + fos.write(stuff); + fos.close(); + fos = null; + + Log.d("ddm-prof", "got trace file, size: " + data.capacity() + " bytes"); + + handler.onSuccess(f, client); + } catch (IOException e) { + handler.onEndLocalFailure(client, e.getMessage()); + + Log.e("ddm-prof", "fail to write trace file: " + e.getMessage()); + Log.e("ddm-prof", e); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + //ignore + } + } + } + } + + client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF); + client.update(Client.CHANGE_METHOD_PROFILING_STATUS); } /** @@ -255,7 +287,9 @@ final class HandleProfiling extends ChunkHandler { } private void handleFAIL(Client client, ByteBuffer data) { - // this can be sent if MPRS failed (like wrong permission) + // this can be sent if + // - MPRS failed (like wrong permission) + // - MPSE failed for whatever reason String filename = client.getClientData().getPendingMethodProfiling(); if (filename != null) { @@ -265,9 +299,15 @@ final class HandleProfiling extends ChunkHandler { // and notify of failure IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler(); if (handler != null) { - handler.onFailure(client); + handler.onStartFailure(client); + } + } else { + // this is MPRE + // notify of failure + IMethodProfilingHandler handler = ClientData.getMethodProfilingHandler(); + if (handler != null) { + handler.onEndFailure(client); } - } // send a query to know the current status diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java index 6cbb999ae..d6979cb2c 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java @@ -164,10 +164,22 @@ public class InfoPanel extends TablePanel { item.setText(1, isDdmAware); item = mTable.getItem(ENT_PROCESS_ID); item.setText(1, pid); + item = mTable.getItem(ENT_SUPPORTS_PROFILING); - item.setText(1, Boolean.toString(cd.hasFeature(ClientData.FEATURE_PROFILING))); + if (cd.hasFeature(ClientData.FEATURE_PROFILING_STREAMING)) { + item.setText(1, "Yes"); + } else if (cd.hasFeature(ClientData.FEATURE_PROFILING)) { + item.setText(1, "Yes (Application must be able to write on the SD Card)"); + } else { + item.setText(1, "No"); + } + item = mTable.getItem(ENT_SUPPORTS_HPROF); - item.setText(1, Boolean.toString(cd.hasFeature(ClientData.FEATURE_HPROF))); + if (cd.hasFeature(ClientData.FEATURE_HPROF)) { + item.setText(1, "Yes (Application must be able to write on the SD Card)"); + } else { + item.setText(1, "No"); + } } mCol2.pack(); diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java index f469a7dda..c029186e7 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java @@ -45,7 +45,7 @@ public class MethodProfilingHandler extends BaseFileHandler super(parentShell); } - public void onFailure(final Client client) { + public void onStartFailure(final Client client) { mParentShell.getDisplay().asyncExec(new Runnable() { public void run() { displayError( @@ -56,6 +56,28 @@ public class MethodProfilingHandler extends BaseFileHandler }); } + public void onEndFailure(final Client client) { + mParentShell.getDisplay().asyncExec(new Runnable() { + public void run() { + displayError( + "Unable to finish Method Profiling for application '%1$s'.\n" + + "Check logcat for more information.", + client.getClientData().getClientDescription()); + } + }); + } + + public void onEndLocalFailure(final Client client, final String message) { + mParentShell.getDisplay().asyncExec(new Runnable() { + public void run() { + displayError(String.format( + "Unable to write trace file locally for application\n\t%1$s\n\n%2$s", + client.getClientData().getClientDescription(), + message)); + } + }); + } + public void onSuccess(final String remoteFilePath, final Client client) { mParentShell.getDisplay().asyncExec(new Runnable() { public void run() { @@ -85,6 +107,10 @@ public class MethodProfilingHandler extends BaseFileHandler }); } + public void onSuccess(File localFile, final Client client) { + openInTraceview(localFile.getAbsolutePath()); + } + private void pullAndOpen(SyncService sync, String remoteFilePath) throws InvocationTargetException, InterruptedException, IOException { // get a temp file -- 2.11.0