aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java')
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java276
1 files changed, 276 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java
new file mode 100755
index 000000000..78fcfd448
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.actions;
+
+import com.android.SdkConstants;
+import com.android.annotations.Nullable;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.BuildToolInfo;
+import com.android.utils.GrabProcessOutput;
+import com.android.utils.GrabProcessOutput.IProcessOutput;
+import com.android.utils.GrabProcessOutput.Wait;
+import com.android.utils.SdkUtils;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * Runs dexdump on the classes.dex of a selected project.
+ */
+public class DexDumpAction implements IObjectActionDelegate {
+
+ private ISelection mSelection;
+
+ @Override
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ // pass
+ }
+
+ @Override
+ public void run(IAction action) {
+ if (mSelection instanceof IStructuredSelection) {
+ for (Iterator<?> it = ((IStructuredSelection)mSelection).iterator(); it.hasNext();) {
+ Object element = it.next();
+ IProject project = null;
+ if (element instanceof IProject) {
+ project = (IProject)element;
+ } else if (element instanceof IAdaptable) {
+ project = (IProject)((IAdaptable)element).getAdapter(IProject.class);
+ }
+ if (project != null) {
+ dexDumpProject(project);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ mSelection = selection;
+ }
+
+ /**
+ * Calls {@link #runDexDump(IProject, IProgressMonitor)} inside a job.
+ *
+ * @param project on which to run dexdump.
+ */
+ private void dexDumpProject(final IProject project) {
+ new Job("Dexdump") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ return runDexDump(project, monitor);
+ }
+ }.schedule();
+ }
+
+ /**
+ * Runs <code>dexdump</code> on the classex.dex of the project.
+ * Saves the output in a temporary file.
+ * On success, opens the file in the default text editor.
+ *
+ * @param project on which to run dexdump.
+ * @param monitor The job's monitor.
+ */
+ private IStatus runDexDump(final IProject project, IProgressMonitor monitor) {
+ File dstFile = null;
+ boolean removeDstFile = true;
+ try {
+ if (monitor != null) {
+ monitor.beginTask(String.format("Dump dex of %1$s", project.getName()), 2);
+ }
+
+ Sdk current = Sdk.getCurrent();
+ if (current == null) {
+ AdtPlugin.printErrorToConsole(project,
+ "DexDump: missing current SDK"); //$NON-NLS-1$
+ return Status.OK_STATUS;
+ }
+
+ BuildToolInfo buildToolInfo = current.getLatestBuildTool();
+ if (buildToolInfo == null) {
+ AdtPlugin.printErrorToConsole(project,
+ "SDK missing build tools. Please install build tools using SDK Manager.");
+ return Status.OK_STATUS;
+ }
+
+ File buildToolsFolder = buildToolInfo.getLocation();
+ File dexDumpFile = new File(buildToolsFolder, SdkConstants.FN_DEXDUMP);
+
+ IPath binPath = project.getFolder(SdkConstants.FD_OUTPUT).getLocation();
+ if (binPath == null) {
+ AdtPlugin.printErrorToConsole(project,
+ "DexDump: missing project /bin folder. Please compile first."); //$NON-NLS-1$
+ return Status.OK_STATUS;
+ }
+
+ File classesDexFile =
+ new File(binPath.toOSString(), SdkConstants.FN_APK_CLASSES_DEX);
+ if (!classesDexFile.exists()) {
+ AdtPlugin.printErrorToConsole(project,
+ "DexDump: missing classex.dex for project. Please compile first.");//$NON-NLS-1$
+ return Status.OK_STATUS;
+ }
+
+ try {
+ dstFile = File.createTempFile(
+ "dexdump_" + project.getName() + "_", //$NON-NLS-1$ //$NON-NLS-2$
+ ".txt"); //$NON-NLS-1$
+ } catch (Exception e) {
+ AdtPlugin.logAndPrintError(e, project.getName(),
+ "DexDump: createTempFile failed."); //$NON-NLS-1$
+ return Status.OK_STATUS;
+ }
+
+ // --- Exec command line and save result to dst file
+
+ String[] command = new String[2];
+ command[0] = dexDumpFile.getAbsolutePath();
+ command[1] = classesDexFile.getAbsolutePath();
+
+ try {
+ final Process process = Runtime.getRuntime().exec(command);
+
+ final BufferedWriter writer = new BufferedWriter(new FileWriter(dstFile));
+ try {
+ final String lineSep = SdkUtils.getLineSeparator();
+
+ int err = GrabProcessOutput.grabProcessOutput(
+ process,
+ Wait.WAIT_FOR_READERS,
+ new IProcessOutput() {
+ @Override
+ public void out(@Nullable String line) {
+ if (line != null) {
+ try {
+ writer.write(line);
+ writer.write(lineSep);
+ } catch (IOException ignore) {}
+ }
+ }
+
+ @Override
+ public void err(@Nullable String line) {
+ if (line != null) {
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE,
+ project, line);
+ }
+ }
+ });
+
+ if (err == 0) {
+ // The command worked. In this case we don't remove the
+ // temp file in the finally block.
+ removeDstFile = false;
+ } else {
+ AdtPlugin.printErrorToConsole(project,
+ "DexDump failed with code " + Integer.toString(err)); //$NON-NLS-1$
+ return Status.OK_STATUS;
+ }
+ } finally {
+ writer.close();
+ }
+ } catch (InterruptedException e) {
+ // ?
+ }
+
+ if (monitor != null) {
+ monitor.worked(1);
+ }
+
+ // --- Open the temp file in an editor
+
+ final String dstPath = dstFile.getAbsolutePath();
+ AdtPlugin.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ IFileStore fileStore =
+ EFS.getLocalFileSystem().getStore(new Path(dstPath));
+ if (!fileStore.fetchInfo().isDirectory() &&
+ fileStore.fetchInfo().exists()) {
+
+ IWorkbench wb = PlatformUI.getWorkbench();
+ IWorkbenchWindow win = wb == null ? null : wb.getActiveWorkbenchWindow();
+ final IWorkbenchPage page = win == null ? null : win.getActivePage();
+
+ if (page != null) {
+ try {
+ IDE.openEditorOnFileStore(page, fileStore);
+ } catch (PartInitException e) {
+ AdtPlugin.logAndPrintError(e, project.getName(),
+ "Opening DexDump result failed. Result is available at %1$s", //$NON-NLS-1$
+ dstPath);
+ }
+ }
+ }
+ }
+ });
+
+ if (monitor != null) {
+ monitor.worked(1);
+ }
+
+ return Status.OK_STATUS;
+
+ } catch (IOException e) {
+ AdtPlugin.logAndPrintError(e, project.getName(),
+ "DexDump failed."); //$NON-NLS-1$
+ return Status.OK_STATUS;
+
+ } finally {
+ // By default we remove the temp file on failure.
+ if (removeDstFile && dstFile != null) {
+ try {
+ dstFile.delete();
+ } catch (Exception e) {
+ AdtPlugin.logAndPrintError(e, project.getName(),
+ "DexDump: can't delete temp file %1$s.", //$NON-NLS-1$
+ dstFile.getAbsoluteFile());
+ }
+ }
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ }
+}