/* | |
* 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; | |
} | |
} |