blob: e74662e76ed3dc84646a6434f7926c2b0ae7505b [file] [log] [blame]
/*
* Copyright (C) 2012 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 com.motorola.studio.android.adt;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
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.preference.IPreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData.IHprofDumpHandler;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.SyncService;
import com.android.ddmuilib.SyncProgressMonitor;
import com.android.ddmuilib.handler.BaseFileHandler;
import com.android.ide.eclipse.ddms.DdmsPlugin;
import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer;
import com.motorola.studio.android.AndroidPlugin;
import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorola.studio.android.i18n.AndroidNLS;
/**
*
* Class to handle post HPROF dumping things. Based on the existing HprofHandler from ADT.
*/
public class MotodevHProfDumpHandler extends BaseFileHandler implements IHprofDumpHandler
{
public final static String SAVE_ACTION = "hprof.save"; //$NON-NLS-1$
public final static String OPEN_ACTION = "hprof.open"; //$NON-NLS-1$
public final static String HPROF_FILE_EXTENSION = ".hprof"; //$NON-NLS-1$
private final static String FORMATTED_ERROR_STRING = " '%1$s'.\n\n%2$s"; //$NON-NLS-1$
private final static String FORMATTED_ERROR_STRING_2 = " '%1$s'."; //$NON-NLS-1$
private final static String DATE_FORMAT = "yyyy-MM-dd HH-mm-ss"; //$NON-NLS-1$
private String selectedApp;
private final IProgressMonitor progressMonitor;
/**
* @return the selectedApp
*/
public String getSelectedApp()
{
return selectedApp;
}
/**
* @param selectedApp the selectedApp to set
*/
public void setSelectedApp(String selectedApp)
{
this.selectedApp = selectedApp;
}
public MotodevHProfDumpHandler(Shell parentShell, IProgressMonitor monitor)
{
super(parentShell);
this.progressMonitor = monitor;
}
@Override
protected String getDialogTitle()
{
return AndroidNLS.UI_Hprof_Handler_Dialog_Error_Title;
}
public void onEndFailure(final Client client, final String message)
{
mParentShell.getDisplay().asyncExec(new Runnable()
{
public void run()
{
displayErrorFromUiThread(AndroidNLS.UI_Hprof_Handler_Dialog_Unable_to_create_Hprof
+ FORMATTED_ERROR_STRING
+ AndroidNLS.UI_Hprof_Handler_Dialog_Error_Check_Log_Cat, client
.getClientData().getClientDescription(), message != null
? message + "\n\n" : ""); //$NON-NLS-1$ //$NON-NLS-2$
}
});
synchronized (DDMSFacade.class)
{
DDMSFacade.class.notify();
}
}
public void onSuccess(final String remoteFilePath, final Client client)
{
mParentShell.getDisplay().asyncExec(new Runnable()
{
public void run()
{
extractRemoteHprof(remoteFilePath, client);
}
});
synchronized (DDMSFacade.class)
{
DDMSFacade.class.notify();
}
}
private void extractRemoteHprof(final String remoteFilePath, final Client client)
{
progressMonitor.beginTask(AndroidNLS.DumpHprofFile_GeneratingMemoryAnalysisOutput, 100);
final IDevice targetDevice = client.getDevice();
try
{
// get the sync service to pull the HPROF file
final SyncService syncService = client.getDevice().getSyncService();
if (syncService != null)
{
// get from the preference what action to take
IPreferenceStore preferenceStore = DdmsPlugin.getDefault().getPreferenceStore();
String actionValue =
preferenceStore.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (SAVE_ACTION.equals(actionValue))
{
warnAboutSaveHprofPreference();
}
actionValue = preferenceStore.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (OPEN_ACTION.equals(actionValue))
{
progressMonitor.setTaskName(AndroidNLS.DumpHprofFile_CreatingTempFile);
File hprofTempFile = File.createTempFile(selectedApp, HPROF_FILE_EXTENSION);
progressMonitor.worked(25);
String tempHprofFilePath = hprofTempFile.getAbsolutePath();
progressMonitor
.setTaskName(AndroidNLS.DumpHprofFile_GettingFileFromRemoteDevice);
progressMonitor.worked(50);
syncService.pullFile(remoteFilePath, tempHprofFilePath,
new SyncProgressMonitor(progressMonitor, "")); //$NON-NLS-1$
openHprofFileInEditor(tempHprofFilePath);
}
else
{
progressMonitor.setTaskName(AndroidNLS.DumpHprofFile_SavingFile);
try
{
promptAndPull(syncService, client.getClientData().getClientDescription()
+ HPROF_FILE_EXTENSION, remoteFilePath,
AndroidNLS.MotodevHProfDumpHandler_saveHProfFile);
}
catch (Exception e)
{
displayErrorFromUiThread(
AndroidNLS.UI_Hprof_Handler_Dialog_Unable_to_download_Hprof
+ FORMATTED_ERROR_STRING, targetDevice.getSerialNumber(),
e.getLocalizedMessage());
}
progressMonitor.worked(100);
}
}
else
{
displayErrorFromUiThread(
AndroidNLS.UI_Hprof_Handler_Dialog_Unable_to_download_Hprof
+ FORMATTED_ERROR_STRING_2, targetDevice.getSerialNumber());
}
}
catch (Exception e)
{
displayErrorFromUiThread(AndroidNLS.UI_Hprof_Handler_Dialog_Unable_to_download_Hprof
+ FORMATTED_ERROR_STRING_2, targetDevice.getSerialNumber());
}
finally
{
progressMonitor.done();
}
}
public void onSuccess(final byte[] data, final Client client)
{
mParentShell.getDisplay().asyncExec(new Runnable()
{
public void run()
{
extractLocalHprof(data, client, progressMonitor);
}
});
synchronized (DDMSFacade.class)
{
DDMSFacade.class.notify();
}
}
private void extractLocalHprof(final byte[] data, final Client client, IProgressMonitor monitor)
{
monitor.beginTask(AndroidNLS.DumpHprofFile_GeneratingMemoryAnalysisOutput, 100);
IPreferenceStore preferenceStore = DdmsPlugin.getDefault().getPreferenceStore();
String value = preferenceStore.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (SAVE_ACTION.equals(value))
{
warnAboutSaveHprofPreference();
}
value = preferenceStore.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (OPEN_ACTION.equals(value))
{
try
{
monitor.setTaskName(AndroidNLS.DumpHprofFile_SavingTempFile);
File tempHprofFile = saveTempFile(data, HPROF_FILE_EXTENSION);
monitor.worked(50);
monitor.setTaskName(AndroidNLS.DumpHprofFile_OpeningMemoryAnalysisFile);
openHprofFileInEditor(tempHprofFile.getAbsolutePath());
monitor.worked(50);
}
catch (Exception e)
{
String errorMsg = e.getMessage();
displayErrorFromUiThread(
AndroidNLS.UI_Hprof_Handler_Dialog_Unable_to_Save_Hprof_Data
+ FORMATTED_ERROR_STRING_2, errorMsg != null ? ":\n" + errorMsg //$NON-NLS-1$
: "."); //$NON-NLS-1$
}
}
else
{
monitor.setTaskName(AndroidNLS.DumpHprofFile_SavingFile);
promptAndSave(client.getClientData().getClientDescription() + HPROF_FILE_EXTENSION,
data, AndroidNLS.UI_Hprof_Handler_Save_Prompt);
monitor.worked(100);
}
monitor.done();
}
private void warnAboutSaveHprofPreference()
{
Display.getCurrent().syncExec(new Runnable()
{
public void run()
{
boolean openPrefPage =
DialogWithToggleUtils.showQuestion(
AndroidPlugin.WARN_ABOUT_HPROF_PREFERENCE,
AndroidNLS.MotodevHProfDumpHandler_warnAboutHprofSavePrefTitle,
AndroidNLS.MotodevHProfDumpHandler_warnAboutHprofSavePrefMsg);
if (openPrefPage)
{
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
EclipseUtils.openPreference(ww.getShell(),
"com.android.ide.eclipse.ddms.preferences.PreferencePage"); //$NON-NLS-1$
}
}
});
}
/**
* Opens the HProf file into MAT editor
* @param path
* @throws IOException
* @throws InterruptedException
* @throws PartInitException
*/
private void openHprofFileInEditor(String path) throws IOException, InterruptedException,
PartInitException
{
// make a file to convert the hprof into something
// readable by normal tools
String hprofPath = getHProfLocalFileName(path);
String[] commands = new String[3];
commands[0] = DdmsPlugin.getHprofConverter();
commands[1] = path;
commands[2] = hprofPath;
Process p = Runtime.getRuntime().exec(commands);
p.waitFor();
IFileStore fileSystemStore = EFS.getLocalFileSystem().getStore(new Path(hprofPath));
if (!fileSystemStore.fetchInfo().isDirectory() && fileSystemStore.fetchInfo().exists())
{
IWorkbenchPage workbenchPage =
AndroidPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow()
.getActivePage();
IEditorPart editorPart = IDE.openEditorOnFileStore(workbenchPage, fileSystemStore);
// Store information about the opened file and the selected app
AndroidPlugin.getDefault().getPreferenceStore()
.setValue(editorPart.getEditorInput().getName(), selectedApp);
}
}
/**
* Gets local (desktop) file name based on selected app and the current date
* @param path
* @return
*/
private String getHProfLocalFileName(String path)
{
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
File ddmsPath = new File(path);
File hprofFileHandler =
new File(ddmsPath.getParent(), selectedApp + " " + dateFormat.format(date) //$NON-NLS-1$
+ HPROF_FILE_EXTENSION);
String hprofPath = hprofFileHandler.getAbsolutePath();
return hprofPath;
}
}