diff options
| author | Xavier Ducrohet <xav@android.com> | 2009-09-02 17:28:50 -0700 |
|---|---|---|
| committer | Xavier Ducrohet <xav@android.com> | 2009-09-02 20:16:12 -0700 |
| commit | c4df663d9ecf81c50b1304b5102e54d2cd72bb5e (patch) | |
| tree | 0c6804b5831f184ac845d823d6b021765c80f68c | |
| parent | d7a5dd65386ef160c848a549964140d62ce29177 (diff) | |
| download | sdk-c4df663d9ecf81c50b1304b5102e54d2cd72bb5e.zip sdk-c4df663d9ecf81c50b1304b5102e54d2cd72bb5e.tar.gz sdk-c4df663d9ecf81c50b1304b5102e54d2cd72bb5e.tar.bz2 | |
Add support for opening HPROF files in Eclipse.
The action taken on successful HPROF dump can now be configured from
the plug-in preference to be either "save to disk" or "open in eclipse".
If a plug-in supporting .hprof files (such as Eclipse Memory Analyzer Tool)
is present then the file will just be opened in the tool.
"save to disk" does not convert the file, "open in eclipse" does convert
the hprof file (using hprof-conv present in the SDK)
Change-Id: Iceb347abb2af5a2979b6028c22dcbdc3bc7250ca
6 files changed, 161 insertions, 33 deletions
diff --git a/eclipse/features/com.android.ide.eclipse.ddms/feature.xml b/eclipse/features/com.android.ide.eclipse.ddms/feature.xml index c0cb12d..9b782ac 100644 --- a/eclipse/features/com.android.ide.eclipse.ddms/feature.xml +++ b/eclipse/features/com.android.ide.eclipse.ddms/feature.xml @@ -230,6 +230,9 @@ <import plugin="org.eclipse.ui"/> <import plugin="org.eclipse.core.runtime"/> <import plugin="org.eclipse.ui.console"/> + <import plugin="org.eclipse.core.resources"/> + <import plugin="org.eclipse.ui.ide"/> + <import plugin="org.eclipse.core.filesystem"/> </requires> <plugin diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF index fd818bf..3d70ec0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF @@ -8,7 +8,10 @@ Bundle-Vendor: The Android Open Source Project Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, - org.eclipse.ui.console + org.eclipse.ui.console, + org.eclipse.core.resources, + org.eclipse.ui.ide, + org.eclipse.core.filesystem Eclipse-LazyStart: true Export-Package: com.android.ddmlib, com.android.ddmlib.log, diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java index d559b0f..631b391 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java @@ -46,6 +46,7 @@ import org.eclipse.ui.console.MessageConsoleStream; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; +import java.io.File; import java.util.ArrayList; import java.util.Calendar; @@ -55,6 +56,21 @@ import java.util.Calendar; public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeListener, IUiSelectionListener { + public final static int PLATFORM_UNKNOWN = 0; + public final static int PLATFORM_LINUX = 1; + public final static int PLATFORM_WINDOWS = 2; + public final static int PLATFORM_DARWIN = 3; + + /** + * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN}, + * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}. + */ + public final static int CURRENT_PLATFORM = currentPlatform(); + + /** hprof-conv executable (with extension for the current OS) */ + public final static String FN_HPROF_CONVERTER = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ? + "hprof-conv.exe" : "hprof-conv"; //$NON-NLS-1$ //$NON-NLS-2$ + // The plug-in ID public static final String PLUGIN_ID = "com.android.ide.eclipse.ddms"; // $NON-NLS-1$ @@ -65,12 +81,15 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL /** Location of the adb command line executable */ private static String sAdbLocation; + private static String sToolsFolder; + private static String sHprofConverter; /** * Debug Launcher for already running apps */ private static IDebugLauncher sRunningAppDebugLauncher; + /** Console for DDMS log message */ private MessageConsole mDdmsConsole; @@ -217,7 +236,7 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL // read the adb location from the prefs to attempt to start it properly without // having to wait for ADT to start - sAdbLocation = eclipseStore.getString(ADB_LOCATION); + setAdbLocation(eclipseStore.getString(ADB_LOCATION)); // start it in a thread to return from start() asap. new Thread() { @@ -278,13 +297,32 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL return sAdbLocation; } + public static String getToolsFolder() { + return sToolsFolder; + } + + public static String getHprofConverter() { + return sHprofConverter; + } + + private static void setAdbLocation(String adbLocation) { + sAdbLocation = adbLocation; + + File adb = new File(sAdbLocation); + File toolsFolder = adb.getParentFile(); + sToolsFolder = toolsFolder.getAbsolutePath(); + + File hprofConverter = new File(toolsFolder, FN_HPROF_CONVERTER); + sHprofConverter = hprofConverter.getAbsolutePath(); + } + /** * Set the location of the adb executable and optionally starts adb * @param adb location of adb * @param startAdb flag to start adb */ public static void setAdb(String adb, boolean startAdb) { - sAdbLocation = adb; + setAdbLocation(adb); // store the location for future ddms only start. sPlugin.getPreferenceStore().setValue(ADB_LOCATION, sAdbLocation); @@ -562,4 +600,23 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL } + /** + * Returns current platform + * + * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN}, + * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}. + */ + public static int currentPlatform() { + String os = System.getProperty("os.name"); //$NON-NLS-1$ + if (os.startsWith("Mac OS")) { //$NON-NLS-1$ + return PLATFORM_DARWIN; + } else if (os.startsWith("Windows")) { //$NON-NLS-1$ + return PLATFORM_WINDOWS; + } else if (os.startsWith("Linux")) { //$NON-NLS-1$ + return PLATFORM_LINUX; + } + + return PLATFORM_UNKNOWN; + } + } diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java index b53d85c..4f91da0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.ddms.preferences; import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.views.DeviceView.HProfHandler; import com.android.ddmlib.DdmPreferences; import com.android.ddmuilib.DdmUiPreferences; @@ -29,7 +30,7 @@ import org.eclipse.swt.graphics.FontData; * Class used to initialize default preference values. */ public class PreferenceInitializer extends AbstractPreferenceInitializer { - + public final static String ATTR_LOG_LEVEL = DdmsPlugin.PLUGIN_ID + ".logLevel"; //$NON-NLS-1$ @@ -56,7 +57,10 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer { public final static String ATTR_LOGCAT_FONT = DdmsPlugin.PLUGIN_ID + ".logcatFont"; //$NON-NLS-1$ - + + public final static String ATTR_HPROF_ACTION = + DdmsPlugin.PLUGIN_ID + ".hprofAction"; //$NON-NLS-1$ + /* * (non-Javadoc) * @@ -84,14 +88,16 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer { store.setDefault(ATTR_LOGCAT_FONT, new FontData("Courier", 10, SWT.NORMAL).toString()); //$NON-NLS-1$ + + store.setDefault(ATTR_HPROF_ACTION, HProfHandler.ACTION_OPEN); } - + /** - * Initializes the preferences of ddmlib and ddmuilib with values from the eclipse store. + * Initializes the preferences of ddmlib and ddmuilib with values from the eclipse store. */ public synchronized static void setupPreferences() { IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); - + DdmPreferences.setDebugPortBase(store.getInt(ATTR_DEBUG_PORT_BASE)); DdmPreferences.setSelectedDebugPort(store.getInt(ATTR_SELECTED_DEBUG_PORT)); DdmPreferences.setLogLevel(store.getString(ATTR_LOG_LEVEL)); diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java index 86e87c7..87addf6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java @@ -17,10 +17,12 @@ package com.android.ide.eclipse.ddms.preferences; import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.views.DeviceView.HProfHandler; import com.android.ddmlib.Log.LogLevel; import com.android.ddmuilib.PortFieldEditor; import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.ComboFieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.IntegerFieldEditor; import org.eclipse.jface.preference.RadioGroupFieldEditor; @@ -63,6 +65,13 @@ public class PreferencePage extends FieldEditorPreferencePage implements ife.setValidRange(1, 60); addField(ife); + ComboFieldEditor cfe = new ComboFieldEditor(PreferenceInitializer.ATTR_HPROF_ACTION, + "HPROF Action:", new String[][] { + { "Save to disk", HProfHandler.ACTION_SAVE }, + { "Open in Eclipse", HProfHandler.ACTION_OPEN }, + }, getFieldEditorParent()); + addField(cfe); + RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor(PreferenceInitializer.ATTR_LOG_LEVEL, "Logging Level", 1, new String[][] { { "Verbose", LogLevel.VERBOSE.getStringValue() }, @@ -74,7 +83,6 @@ public class PreferencePage extends FieldEditorPreferencePage implements }, getFieldEditorParent(), true); addField(rgfe); - } public void init(IWorkbench workbench) { diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java index 7f9c3c8..50eee26 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java @@ -30,8 +30,12 @@ import com.android.ddmuilib.SyncProgressMonitor; import com.android.ddmuilib.DevicePanel.IUiSelectionListener; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.DdmsPlugin.IDebugLauncher; +import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; @@ -40,6 +44,7 @@ import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; @@ -47,10 +52,14 @@ import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.ViewPart; import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; public class DeviceView extends ViewPart implements IUiSelectionListener { @@ -72,11 +81,15 @@ public class DeviceView extends ViewPart implements IUiSelectionListener { private Action mHprofAction; private IDebugLauncher mDebugLauncher; - private class HProfHandler implements IHprofDumpHandler { + public class HProfHandler implements IHprofDumpHandler { + public final static String ACTION_SAVE ="hprof.save"; //$NON-NLS-1$ + public final static String ACTION_OPEN = "hprof.open"; //$NON-NLS-1$ + + public final static String DOT_HPROF = ".hprof"; //$NON-NLS-1$ private final Shell mParentShell; - public HProfHandler(Shell parentShell) { + HProfHandler(Shell parentShell) { mParentShell = parentShell; } @@ -98,7 +111,7 @@ public class DeviceView extends ViewPart implements IUiSelectionListener { }); } - public void onSuccess(final String file, final Client client) { + public void onSuccess(final String remoteFile, final Client client) { mParentShell.getDisplay().asyncExec(new Runnable() { public void run() { final IDevice device = client.getDevice(); @@ -106,7 +119,19 @@ public class DeviceView extends ViewPart implements IUiSelectionListener { // get the sync service to pull the HPROF file final SyncService sync = client.getDevice().getSyncService(); if (sync != null) { - promptAndPull(device, client, sync, file); + // 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)) { + File temp = File.createTempFile("android", DOT_HPROF); //$NON-NLS-1$ + String tempPath = temp.getAbsolutePath(); + pull(sync, tempPath, remoteFile); + + open(tempPath); + } else { + // default action is ACTION_SAVE + promptAndPull(device, client, sync, remoteFile); + } } else { MessageDialog.openError(mParentShell, "HPROF Error", String.format( @@ -134,29 +159,11 @@ public class DeviceView extends ViewPart implements IUiSelectionListener { fileDialog.setText("Save HPROF file"); fileDialog.setFileName( - client.getClientData().getClientDescription() + ".hprof"); + client.getClientData().getClientDescription() + DOT_HPROF); final String localFileName = fileDialog.open(); if (localFileName != null) { - final File localFile = new File(localFileName); - - new ProgressMonitorDialog(mParentShell).run(true, true, - new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) { - SyncResult result = sync.pullFile(remoteFile, localFileName, - new SyncProgressMonitor(monitor, String.format( - "Pulling %1$s from the device", - localFile.getName()))); - - if (result.getCode() != SyncService.RESULT_OK) { - MessageDialog.openError(mParentShell, "HPROF Error", - String.format("Failed to pull %1$s: %2$s", remoteFile, - result.getMessage())); - } - - sync.close(); - } - }); + pull(sync, localFileName, remoteFile); } } catch (Exception e) { MessageDialog.openError(mParentShell, "HPROF Error", @@ -164,6 +171,50 @@ public class DeviceView extends ViewPart implements IUiSelectionListener { device.getSerialNumber())); } } + + private void pull(final SyncService sync, + final String localFileName, final String remoteFile) + throws InvocationTargetException, InterruptedException { + new ProgressMonitorDialog(mParentShell).run(true, true, + new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) { + SyncResult result = sync.pullFile(remoteFile, localFileName, + new SyncProgressMonitor(monitor, String.format( + "Pulling %1$s from the device", + remoteFile))); + + if (result.getCode() != SyncService.RESULT_OK) { + MessageDialog.openError(mParentShell, "HPROF Error", + String.format("Failed to pull %1$s: %2$s", remoteFile, + result.getMessage())); + } + + sync.close(); + } + }); + } + + private void open(String path) throws IOException, InterruptedException, PartInitException { + // make a temp file to convert the hprof into something + // readable by normal tools + File temp = File.createTempFile("android", DOT_HPROF); + String tempPath = temp.getAbsolutePath(); + + String[] command = new String[3]; + command[0] = DdmsPlugin.getHprofConverter(); + command[1] = path; + command[2] = tempPath; + + Process p = Runtime.getRuntime().exec(command); + p.waitFor(); + + IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(tempPath)); + if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) { + IDE.openEditorOnFileStore( + getSite().getWorkbenchWindow().getActivePage(), + fileStore); + } + } } |
