Merge change 23740 into eclair

* changes:
  Add support for opening HPROF files in Eclipse.
This commit is contained in:
Android (Google) Code Review
2009-09-02 20:18:12 -07:00
6 changed files with 161 additions and 33 deletions

View File

@@ -230,6 +230,9 @@
<import plugin="org.eclipse.ui"/> <import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.core.runtime"/> <import plugin="org.eclipse.core.runtime"/>
<import plugin="org.eclipse.ui.console"/> <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> </requires>
<plugin <plugin

View File

@@ -8,7 +8,10 @@ Bundle-Vendor: The Android Open Source Project
Bundle-Localization: plugin Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui, Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime, 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 Eclipse-LazyStart: true
Export-Package: com.android.ddmlib, Export-Package: com.android.ddmlib,
com.android.ddmlib.log, com.android.ddmlib.log,

View File

@@ -46,6 +46,7 @@ import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@@ -55,6 +56,21 @@ import java.util.Calendar;
public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeListener, public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeListener,
IUiSelectionListener { 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 // The plug-in ID
public static final String PLUGIN_ID = "com.android.ide.eclipse.ddms"; // $NON-NLS-1$ 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 */ /** Location of the adb command line executable */
private static String sAdbLocation; private static String sAdbLocation;
private static String sToolsFolder;
private static String sHprofConverter;
/** /**
* Debug Launcher for already running apps * Debug Launcher for already running apps
*/ */
private static IDebugLauncher sRunningAppDebugLauncher; private static IDebugLauncher sRunningAppDebugLauncher;
/** Console for DDMS log message */ /** Console for DDMS log message */
private MessageConsole mDdmsConsole; 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 // read the adb location from the prefs to attempt to start it properly without
// having to wait for ADT to start // 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. // start it in a thread to return from start() asap.
new Thread() { new Thread() {
@@ -278,13 +297,32 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL
return sAdbLocation; 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 * Set the location of the adb executable and optionally starts adb
* @param adb location of adb * @param adb location of adb
* @param startAdb flag to start adb * @param startAdb flag to start adb
*/ */
public static void setAdb(String adb, boolean startAdb) { public static void setAdb(String adb, boolean startAdb) {
sAdbLocation = adb; setAdbLocation(adb);
// store the location for future ddms only start. // store the location for future ddms only start.
sPlugin.getPreferenceStore().setValue(ADB_LOCATION, sAdbLocation); 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;
}
} }

View File

@@ -17,6 +17,7 @@
package com.android.ide.eclipse.ddms.preferences; package com.android.ide.eclipse.ddms.preferences;
import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.DdmsPlugin;
import com.android.ide.eclipse.ddms.views.DeviceView.HProfHandler;
import com.android.ddmlib.DdmPreferences; import com.android.ddmlib.DdmPreferences;
import com.android.ddmuilib.DdmUiPreferences; import com.android.ddmuilib.DdmUiPreferences;
@@ -29,7 +30,7 @@ import org.eclipse.swt.graphics.FontData;
* Class used to initialize default preference values. * Class used to initialize default preference values.
*/ */
public class PreferenceInitializer extends AbstractPreferenceInitializer { public class PreferenceInitializer extends AbstractPreferenceInitializer {
public final static String ATTR_LOG_LEVEL = public final static String ATTR_LOG_LEVEL =
DdmsPlugin.PLUGIN_ID + ".logLevel"; //$NON-NLS-1$ DdmsPlugin.PLUGIN_ID + ".logLevel"; //$NON-NLS-1$
@@ -56,7 +57,10 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer {
public final static String ATTR_LOGCAT_FONT = public final static String ATTR_LOGCAT_FONT =
DdmsPlugin.PLUGIN_ID + ".logcatFont"; //$NON-NLS-1$ DdmsPlugin.PLUGIN_ID + ".logcatFont"; //$NON-NLS-1$
public final static String ATTR_HPROF_ACTION =
DdmsPlugin.PLUGIN_ID + ".hprofAction"; //$NON-NLS-1$
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@@ -84,14 +88,16 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer {
store.setDefault(ATTR_LOGCAT_FONT, store.setDefault(ATTR_LOGCAT_FONT,
new FontData("Courier", 10, SWT.NORMAL).toString()); //$NON-NLS-1$ 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() { public synchronized static void setupPreferences() {
IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
DdmPreferences.setDebugPortBase(store.getInt(ATTR_DEBUG_PORT_BASE)); DdmPreferences.setDebugPortBase(store.getInt(ATTR_DEBUG_PORT_BASE));
DdmPreferences.setSelectedDebugPort(store.getInt(ATTR_SELECTED_DEBUG_PORT)); DdmPreferences.setSelectedDebugPort(store.getInt(ATTR_SELECTED_DEBUG_PORT));
DdmPreferences.setLogLevel(store.getString(ATTR_LOG_LEVEL)); DdmPreferences.setLogLevel(store.getString(ATTR_LOG_LEVEL));

View File

@@ -17,10 +17,12 @@
package com.android.ide.eclipse.ddms.preferences; package com.android.ide.eclipse.ddms.preferences;
import com.android.ide.eclipse.ddms.DdmsPlugin; 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.ddmlib.Log.LogLevel;
import com.android.ddmuilib.PortFieldEditor; import com.android.ddmuilib.PortFieldEditor;
import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.ComboFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IntegerFieldEditor; import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.jface.preference.RadioGroupFieldEditor; import org.eclipse.jface.preference.RadioGroupFieldEditor;
@@ -63,6 +65,13 @@ public class PreferencePage extends FieldEditorPreferencePage implements
ife.setValidRange(1, 60); ife.setValidRange(1, 60);
addField(ife); 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, RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor(PreferenceInitializer.ATTR_LOG_LEVEL,
"Logging Level", 1, new String[][] { "Logging Level", 1, new String[][] {
{ "Verbose", LogLevel.VERBOSE.getStringValue() }, { "Verbose", LogLevel.VERBOSE.getStringValue() },
@@ -74,7 +83,6 @@ public class PreferencePage extends FieldEditorPreferencePage implements
}, },
getFieldEditorParent(), true); getFieldEditorParent(), true);
addField(rgfe); addField(rgfe);
} }
public void init(IWorkbench workbench) { public void init(IWorkbench workbench) {

View File

@@ -30,8 +30,12 @@ import com.android.ddmuilib.SyncProgressMonitor;
import com.android.ddmuilib.DevicePanel.IUiSelectionListener; import com.android.ddmuilib.DevicePanel.IUiSelectionListener;
import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.DdmsPlugin;
import com.android.ide.eclipse.ddms.DdmsPlugin.IDebugLauncher; 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.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.Action; import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager; 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.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display; 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.swt.widgets.Shell;
import org.eclipse.ui.IActionBars; import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages; import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.part.ViewPart;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class DeviceView extends ViewPart implements IUiSelectionListener { public class DeviceView extends ViewPart implements IUiSelectionListener {
@@ -72,11 +81,15 @@ public class DeviceView extends ViewPart implements IUiSelectionListener {
private Action mHprofAction; private Action mHprofAction;
private IDebugLauncher mDebugLauncher; 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; private final Shell mParentShell;
public HProfHandler(Shell parentShell) { HProfHandler(Shell parentShell) {
mParentShell = 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() { mParentShell.getDisplay().asyncExec(new Runnable() {
public void run() { public void run() {
final IDevice device = client.getDevice(); 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 // get the sync service to pull the HPROF file
final SyncService sync = client.getDevice().getSyncService(); final SyncService sync = client.getDevice().getSyncService();
if (sync != null) { 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 { } else {
MessageDialog.openError(mParentShell, "HPROF Error", MessageDialog.openError(mParentShell, "HPROF Error",
String.format( String.format(
@@ -134,29 +159,11 @@ public class DeviceView extends ViewPart implements IUiSelectionListener {
fileDialog.setText("Save HPROF file"); fileDialog.setText("Save HPROF file");
fileDialog.setFileName( fileDialog.setFileName(
client.getClientData().getClientDescription() + ".hprof"); client.getClientData().getClientDescription() + DOT_HPROF);
final String localFileName = fileDialog.open(); final String localFileName = fileDialog.open();
if (localFileName != null) { if (localFileName != null) {
final File localFile = new File(localFileName); pull(sync, localFileName, remoteFile);
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();
}
});
} }
} catch (Exception e) { } catch (Exception e) {
MessageDialog.openError(mParentShell, "HPROF Error", MessageDialog.openError(mParentShell, "HPROF Error",
@@ -164,6 +171,50 @@ public class DeviceView extends ViewPart implements IUiSelectionListener {
device.getSerialNumber())); 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);
}
}
} }