mCurrentActivator.selectAll();
}
}
-
}
/**
super(parentShell);
}
- public void onFailure(final Client client) {
+ public void onEndFailure(final Client client, final String message) {
mDisplay.asyncExec(new Runnable() {
public void run() {
try {
- displayError("Unable to create HPROF file for application '%1$s'.\n" +
+ displayErrorFromUiThread(
+ "Unable to create HPROF file for application '%1$s'\n\n%2$s" +
"Check logcat for more information.",
- client.getClientData().getClientDescription());
+ client.getClientData().getClientDescription(),
+ message != null ? message + "\n\n" : "");
} finally {
// this will make sure the dump hprof button is re-enabled for the
// current selection. as the client is finished dumping an hprof file
client.getClientData().getClientDescription() + ".hprof",
remoteFilePath, "Save HPROF file");
if (result != null && result.getCode() != SyncService.RESULT_OK) {
- displayError(
+ displayErrorFromUiThread(
"Unable to download HPROF file from device '%1$s'.\n\n%2$s",
device.getSerialNumber(), result.getMessage());
}
} else {
- displayError("Unable to download HPROF file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
device.getSerialNumber());
}
} catch (Exception e) {
- displayError("Unable to download HPROF file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
device.getSerialNumber());
} finally {
});
}
- private void displayError(String format, Object... args) {
- MessageDialog.openError(mParentShell, "HPROF Error",
- String.format(format, args));
+ public void onSuccess(final byte[] data, final Client client) {
+ mDisplay.asyncExec(new Runnable() {
+ public void run() {
+ promptAndSave(client.getClientData().getClientDescription() + ".hprof", data,
+ "Save HPROF file");
+ }
+ });
+ }
+
+ @Override
+ protected String getDialogTitle() {
+ return "HPROF Error";
}
}
* Makes the VM dump an HPROF file
*/
public void dumpHprof() {
- boolean canStream = false; //mClientData.hasFeature(ClientData.FEATURE_HPROF_STREAMING);
+ boolean canStream = mClientData.hasFeature(ClientData.FEATURE_HPROF_STREAMING);
try {
if (canStream) {
HandleHeap.sendHPDS(this);
} else {
- String file = "/sdcard/" + mClientData.getClientDescription().replaceAll("\\:.*", "") +
- ".hprof";
+ String file = "/sdcard/" + mClientData.getClientDescription().replaceAll(
+ "\\:.*", "") + ".hprof";
HandleHeap.sendHPDU(this, file);
}
} catch (IOException e) {
import com.android.ddmlib.HeapSegment.HeapSegmentElement;
-import java.io.File;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
void onSuccess(String remoteFilePath, Client client);
/**
- * Called when the HPROF dump failed.
- * @param client the client for which the HPROF file was.
+ * Called when a HPROF dump was successful.
+ * @param data the data containing the HPROF file, streamed from the VM
+ * @param client the client that was profiled.
+ */
+ void onSuccess(byte[] data, Client client);
+
+ /**
+ * Called when a hprof dump failed to end on the VM side
+ * @param client the client that was profiled.
+ * @param message an optional (<code>null<code> ok) error message to be displayed.
*/
- void onFailure(Client client);
+ void onEndFailure(Client client, String message);
}
/**
/**
* Called when a method tracing was successful.
- * @param remoteFilePath the device-side path of the trace file.
+ * @param data the data containing the trace file, streamed from the VM
* @param client the client that was profiled.
*/
- void onSuccess(File localFile, Client client);
+ void onSuccess(byte[] data, Client client);
/**
* Called when method tracing failed to start
* @param message an optional (<code>null<code> ok) error message to be displayed.
*/
void onEndFailure(Client client, String message);
-
- /**
- * Called when method tracing failed to end locally.
- * @param client the client that was profiled.
- * @param message the mandatory message to display.
- */
- void onEndLocalFailure(Client client, String message);
}
/**
finishChunkPacket(packet, CHUNK_HPDS, buf.position());
Log.d("ddm-heap", "Sending " + name(CHUNK_HPDS));
client.sendAndConsume(packet, mInst);
- client.getClientData().setPendingHprofDump("[streaming]");
}
/*
Log.d("ddm-heap", "Heap dump request has finished");
} else {
- handler.onFailure(client);
+ handler.onEndFailure(client, null);
Log.w("ddm-heap", "Heap dump request failed (check device log)");
}
}
* hprof dump.
*/
private void handleHPDS(Client client, ByteBuffer data) {
- Log.w("ddm-prof", "got hprof file, size: " + data.capacity() + " bytes");
+ IHprofDumpHandler handler = ClientData.getHprofDumpHandler();
+ if (handler != null) {
+ byte[] stuff = new byte[data.capacity()];
+ data.get(stuff, 0, stuff.length);
+
+ Log.d("ddm-hprof", "got hprof file, size: " + data.capacity() + " bytes");
+
+ handler.onSuccess(stuff, client);
+ }
}
/**
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;
private void handleMPSE(Client client, ByteBuffer data) {
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
- }
- }
- }
+ byte[] stuff = new byte[data.capacity()];
+ data.get(stuff, 0, stuff.length);
+
+ Log.d("ddm-prof", "got trace file, size: " + stuff.length + " bytes");
+
+ handler.onSuccess(stuff, client);
}
client.getClientData().setMethodProfilingStatus(MethodProfilingStatus.OFF);
}
item = mTable.getItem(ENT_SUPPORTS_HPROF);
- if (cd.hasFeature(ClientData.FEATURE_HPROF)) {
+ if (cd.hasFeature(ClientData.FEATURE_HPROF_STREAMING)) {
+ item.setText(1, "Yes");
+ } else 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");
import com.android.ddmuilib.SyncProgressMonitor;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* @see IHprofDumpHandler
* @see IMethodProfilingHandler
*/
-public class BaseFileHandler {
+public abstract class BaseFileHandler {
protected final Shell mParentShell;
mParentShell = parentShell;
}
+ protected abstract String getDialogTitle();
+
/**
* Prompts the user for a save location and pulls the remote files into this location.
* <p/>This <strong>must</strong> be called from the UI Thread.
}
/**
- * Pulls a file off of a device
+ * Prompts the user for a save location and copies a temp file into it.
+ * <p/>This <strong>must</strong> be called from the UI Thread.
+ * @param localFileName The default local name
+ * @param tempFilePath The name of the temp file to copy.
+ * @param title The title of the File Save dialog.
+ * @return true if success, false on error or cancel.
+ */
+ protected boolean promptAndSave(String localFileName, byte[] data, String title) {
+ FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE);
+
+ fileDialog.setText(title);
+ fileDialog.setFileName(localFileName);
+
+ String localFilePath = fileDialog.open();
+ if (localFilePath != null) {
+ try {
+ saveFile(data, new File(localFilePath));
+ return true;
+ } catch (IOException e) {
+ String errorMsg = e.getMessage();
+ displayErrorInUiThread(
+ "Failed to save file '%1$s'%2$s",
+ localFilePath,
+ errorMsg != null ? ":\n" + errorMsg : ".");
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Pulls a file off of a device. This displays a {@link ProgressMonitorDialog} and therefore
+ * must be run from the UI Thread.
* @param sync the {@link SyncService} to use to pull the file.
* @param localFilePath the path of the local file to create
* @param remoteFilePath the path of the remote file to pull
return res[0];
}
+
+ /**
+ * Display an error message.
+ * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the
+ * UI Thread. This is safe to be called from a non-UI Thread.
+ * @param format the string to display
+ * @param args the string arguments
+ */
+ protected void displayErrorInUiThread(final String format, final Object... args) {
+ mParentShell.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openError(mParentShell, getDialogTitle(),
+ String.format(format, args));
+ }
+ });
+ }
+
+ /**
+ * Display an error message.
+ * This must be called from the UI Thread.
+ * @param format the string to display
+ * @param args the string arguments
+ */
+ protected void displayErrorFromUiThread(final String format, final Object... args) {
+ MessageDialog.openError(mParentShell, getDialogTitle(),
+ String.format(format, args));
+ }
+
+ /**
+ * Saves a given data into a temp file and returns its corresponding {@link File} object.
+ * @param data the data to save
+ * @return the File into which the data was written or null if it failed.
+ * @throws IOException
+ */
+ protected File saveTempFile(byte[] data) throws IOException {
+ File f = File.createTempFile("ddms", null);
+ saveFile(data, f);
+ return f;
+ }
+
+ /**
+ * Saves some data into a given File.
+ * @param data the data to save
+ * @param output the file into the data is saved.
+ * @throws IOException
+ */
+ protected void saveFile(byte[] data, File output) throws IOException {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(output);
+ fos.write(data);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
}
import com.android.ddmuilib.DdmUiPreferences;
import com.android.ddmuilib.console.DdmConsole;
-import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import java.io.BufferedReader;
super(parentShell);
}
- public void onStartFailure(final Client client, final String message) {
- mParentShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- displayError(
- "Unable to create Method Profiling file for application '%1$s'\n\n%2$s" +
- "Check logcat for more information.",
- client.getClientData().getClientDescription(),
- message != null ? message + "\n\n" : "");
- }
- });
+ @Override
+ protected String getDialogTitle() {
+ return "Method Profiling Error";
}
- public void onEndFailure(final Client client, final String message) {
- mParentShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- displayError(
- "Unable to finish Method Profiling for application '%1$s'\n\n%2$s" +
- "Check logcat for more information.",
- client.getClientData().getClientDescription(),
- message != null ? message + "\n\n" : "");
- }
- });
+ public void onStartFailure(final Client client, final String message) {
+ displayErrorInUiThread(
+ "Unable to create Method Profiling file for application '%1$s'\n\n%2$s" +
+ "Check logcat for more information.",
+ client.getClientData().getClientDescription(),
+ message != null ? message + "\n\n" : "");
}
- public void onEndLocalFailure(final Client client, final String message) {
- mParentShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- displayError(
- "Unable to write trace file locally for application '%1$s'\n\n%2$s",
- client.getClientData().getClientDescription(),
- message);
- }
- });
+ public void onEndFailure(final Client client, final String message) {
+ displayErrorInUiThread(
+ "Unable to finish Method Profiling for application '%1$s'\n\n%2$s" +
+ "Check logcat for more information.",
+ client.getClientData().getClientDescription(),
+ message != null ? message + "\n\n" : "");
}
public void onSuccess(final String remoteFilePath, final Client client) {
mParentShell.getDisplay().asyncExec(new Runnable() {
public void run() {
if (remoteFilePath == null) {
- displayError(
+ displayErrorFromUiThread(
"Unable to download trace file: unknown file name.\n" +
"This can happen if you disconnected the device while recording the trace.");
return;
if (sync != null) {
pullAndOpen(sync, remoteFilePath);
} else {
- displayError("Unable to download trace file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download trace file from device '%1$s'.",
device.getSerialNumber());
}
} catch (Exception e) {
- displayError("Unable to download trace file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download trace file from device '%1$s'.",
device.getSerialNumber());
}
}
});
}
- public void onSuccess(File localFile, final Client client) {
- openInTraceview(localFile.getAbsolutePath());
+ public void onSuccess(byte[] data, final Client client) {
+ try {
+ File tempFile = saveTempFile(data);
+ openInTraceview(tempFile.getAbsolutePath());
+ } catch (IOException e) {
+ String errorMsg = e.getMessage();
+ displayErrorInUiThread(
+ "Failed to save trace data into temp file%1$s",
+ errorMsg != null ? ":\n" + errorMsg : ".");
+ }
}
+ /**
+ * pulls and open a file. This is run from the UI thread.
+ */
private void pullAndOpen(SyncService sync, String remoteFilePath)
throws InvocationTargetException, InterruptedException, IOException {
// get a temp file
// open the temp file in traceview
openInTraceview(tempPath);
} else {
- displayError("Unable to download trace file:\n\n%1$s",
+ displayErrorFromUiThread("Unable to download trace file:\n\n%1$s",
result.getMessage());
}
} else {
// this really shouldn't happen.
- displayError("Unable to download trace file.");
+ displayErrorFromUiThread("Unable to download trace file.");
}
}
Log.e("traceview", e);
}
}
-
- private void displayError(String format, Object... args) {
- MessageDialog.openError(mParentShell, "Method Profiling Error",
- String.format(format, args));
- }
}
super(parentShell);
}
- public void onFailure(final Client client) {
+ @Override
+ protected String getDialogTitle() {
+ return "HPROF Error";
+ }
+
+
+ public void onEndFailure(final Client client, final String message) {
mParentShell.getDisplay().asyncExec(new Runnable() {
public void run() {
try {
- displayError("Unable to create HPROF file for application '%1$s'.\n" +
+ displayErrorFromUiThread(
+ "Unable to create HPROF file for application '%1$s'.\n\n%2$s" +
"Check logcat for more information.",
- client.getClientData().getClientDescription());
+ client.getClientData().getClientDescription(),
+ message != null ? message + "\n\n" : "");
} finally {
// this will make sure the dump hprof button is re-enabled for the
// current selection. as the client is finished dumping an hprof file
}
if (result != null && result.getCode() != SyncService.RESULT_OK) {
- displayError(
+ displayErrorFromUiThread(
"Unable to download HPROF file from device '%1$s'.\n\n%2$s",
device.getSerialNumber(), result.getMessage());
}
} else {
- displayError("Unable to download HPROF file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
device.getSerialNumber());
}
} catch (Exception e) {
- displayError("Unable to download HPROF file from device '%1$s'.",
+ displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.",
device.getSerialNumber());
} finally {
});
}
+ public void onSuccess(final byte[] data, final Client client) {
+ mParentShell.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ // get from the preference what action to take
+ IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
+ String value = store.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
+
+ if (ACTION_OPEN.equals(value)) {
+ try {
+ File tempFile = saveTempFile(data);
+ open(tempFile.getAbsolutePath());
+ } catch (Exception e) {
+ String errorMsg = e.getMessage();
+ displayErrorFromUiThread(
+ "Failed to save hprof data into temp file%1$s",
+ errorMsg != null ? ":\n" + errorMsg : ".");
+ }
+ } else {
+ // default action is ACTION_SAVE
+ promptAndSave(client.getClientData().getClientDescription() + DOT_HPROF,
+ data, "Save HPROF file");
+ }
+ }
+ });
+ }
+
private void open(String path) throws IOException, InterruptedException, PartInitException {
// make a temp file to convert the hprof into something
// readable by normal tools
fileStore);
}
}
-
- private void displayError(String format, Object... args) {
- MessageDialog.openError(mParentShell, "HPROF Error",
- String.format(format, args));
- }
}