blob: c2acf29e1b7613c8238654a7171f5e47fbba7352 [file] [log] [blame]
/*
* Copyright (C) 2015 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.android.tools.idea.ddms.hprof;
import com.android.SdkConstants;
import com.android.tools.idea.editors.hprof.HprofCaptureType;
import com.android.tools.idea.profiling.capture.Capture;
import com.android.tools.idea.profiling.capture.CaptureTypeService;
import com.android.tools.idea.profiling.view.CapturesToolWindow;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.BaseOSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.sdk.AndroidSdkData;
import org.jetbrains.android.sdk.AndroidSdkUtils;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
public class RunHprofConvAndSaveAsAction extends DumbAwareAction {
public RunHprofConvAndSaveAsAction() {
getTemplatePresentation().setText(getActionName());
}
@Override
public void update(@NotNull AnActionEvent e) {
Presentation presentation = e.getPresentation();
presentation.setText(getActionName());
presentation.setVisible(isValidCaptureSelection(CapturesToolWindow.CAPTURE_ARRAY.getData(e.getDataContext())));
}
@NotNull
public static String getActionName() {
return AndroidBundle.message("android.profiler.hprof.actions.conv.contextmenu");
}
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (e.getProject() == null) {
return;
}
ConvertHprofDialog dialog = new ConvertHprofDialog(e.getProject());
if (!dialog.showAndGet()) {
return;
}
Capture[] captures = CapturesToolWindow.CAPTURE_ARRAY.getData(e.getDataContext());
if (isValidCaptureSelection(captures)) {
new RunHprofConvAndSaveTask(e.getProject(), captures[0].getFile(), dialog.getHprofFile()).queue();
}
}
}, ModalityState.defaultModalityState());
}
private static boolean isValidCaptureSelection(@Nullable Capture[] captures) {
return captures != null &&
captures.length == 1 &&
captures[0].getType() == CaptureTypeService.getInstance().getType(HprofCaptureType.class);
}
private static class RunHprofConvAndSaveTask extends Task.Backgroundable {
private final VirtualFile mySource;
private final File myDestination;
private Exception myException;
public RunHprofConvAndSaveTask(@Nullable Project project, @NotNull VirtualFile source, @NotNull File destination) {
super(project, AndroidBundle.message("android.profiler.hprof.actions.conv"), false);
mySource = source;
myDestination = destination;
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
convertAndSave();
}
catch (Exception e) {
myException = e;
}
}
private void convertAndSave() throws IOException, ExecutionException {
// run hprof-conv, transforming androidHprof -> destination
AndroidSdkData sdkData = AndroidSdkUtils.tryToChooseAndroidSdk();
if (sdkData == null) {
throw new ExecutionException("Unable to find path to SDK.");
}
String hprofConvPath = new File(sdkData.getLocation(), AndroidCommonUtils.platformToolPath(SdkConstants.FN_HPROF_CONV)).getPath();
ProcessBuilder pb =
new ProcessBuilder(hprofConvPath, VfsUtilCore.virtualToIoFile(mySource).getAbsolutePath(), myDestination.getAbsolutePath());
BaseOSProcessHandler handler;
handler = new BaseOSProcessHandler(pb.start(), "", null);
final StringBuilder builder = new StringBuilder();
handler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
builder.append(event.getText());
}
});
handler.startNotify();
handler.waitFor();
int exitCode = handler.getProcess().exitValue();
if (exitCode != 0) {
throw new ExecutionException(builder.toString().trim());
}
}
@Override
public void onSuccess() {
if (myException != null) {
Messages.showErrorDialog("Unexpected error while converting heap dump: " + myException.getMessage(),
AndroidBundle.message("android.profiler.hprof.actions.conv"));
}
else {
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(myDestination);
Notifications.Bus.notify(new Notification("Android", AndroidBundle.message("android.profiler.hprof.actions.conv"), AndroidBundle
.message("android.profiler.hprof.actions.conv.saved", myDestination.getAbsolutePath()), NotificationType.INFORMATION));
}
}
}
}