aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins
diff options
context:
space:
mode:
authorRaphael Moll <ralf@android.com>2010-08-28 14:36:54 -0700
committerAndroid Code Review <code-review@android.com>2010-08-28 14:36:54 -0700
commit34ac12032875a3e3d0b17d19540cb65d0fbbe507 (patch)
treeff17c534d8207b5bf3ebebecaa2c167f17196d3b /eclipse/plugins
parent91821236d71ec9f46828ff85b6936227f5e4a9d2 (diff)
parentb3307cb06c8e4f7ab5d91955be0401cedee9811c (diff)
downloadsdk-34ac12032875a3e3d0b17d19540cb65d0fbbe507.zip
sdk-34ac12032875a3e3d0b17d19540cb65d0fbbe507.tar.gz
sdk-34ac12032875a3e3d0b17d19540cb65d0fbbe507.tar.bz2
Merge "ADT: new action to run dexdump on project."
Diffstat (limited to 'eclipse/plugins')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml6
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java335
2 files changed, 341 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index 62f4e5b..9eb522a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -288,6 +288,12 @@
id="com.android.ide.eclipse.adt.project.RenamePackageAction"
label="Rename Application Package"
menubarPath="com.android.ide.eclipse.adt.AndroidTools/group3"/>
+ <action
+ class="com.android.ide.eclipse.adt.internal.actions.DexDumpAction"
+ enablesFor="1"
+ id="com.android.ide.eclipse.adt.DexDumpAction"
+ label="Display dex bytecode"
+ menubarPath="com.android.ide.eclipse.adt.AndroidTools/group3"/>
</objectContribution>
<objectContribution
id="com.android.ide.eclipse.adt.contribution3"
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 0000000..8a527d6
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java
@@ -0,0 +1,335 @@
+/*
+ * 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.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.SdkConstants;
+
+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.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+
+/**
+ * Runs dexdump on the classes.dex of a selected project.
+ */
+public class DexDumpAction implements IObjectActionDelegate {
+
+ private ISelection mSelection;
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ // pass
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ 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;
+ }
+
+ String sdkOsPath = current.getSdkLocation();
+ File dexDumpFile = new File(new File(sdkOsPath, SdkConstants.FD_PLATFORM_TOOLS),
+ 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 {
+ int err = grabProcessOutput(project, command, dstFile);
+ 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;
+ }
+ } 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() {
+ 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();
+ }
+ }
+ }
+
+
+ /**
+ * Get the stdout+stderr output of a process and return when the process is done.
+ * @param command The command line for the process to run.
+ * @param dstFile The file where to write the stdout.
+ * @return the process return code.
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ private final int grabProcessOutput(
+ final IProject project,
+ String[] command,
+ final File dstFile)
+ throws InterruptedException, IOException {
+
+ final BufferedWriter writer = new BufferedWriter(new FileWriter(dstFile));
+
+ String sep = System.getProperty("line.separator"); //$NON-NLS-1$
+ if (sep == null || sep.length() < 1) {
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
+ sep = "\r\n"; //$NON-NLS-1$
+ } else {
+ sep = "\n"; //$NON-NLS-1$
+ }
+ }
+ final String lineSep = sep;
+
+ final Process process = Runtime.getRuntime().exec(command);
+
+ try {
+ // read the lines as they come. if null is returned, it's
+ // because the process finished
+ Thread t1 = new Thread("") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ // create a buffer to read the stderr output
+ InputStreamReader is = new InputStreamReader(process.getInputStream());
+ BufferedReader outReader = new BufferedReader(is);
+
+ try {
+ while (true) {
+ String line = outReader.readLine();
+ if (line != null) {
+ writer.write(line);
+ writer.write(lineSep);
+ } else {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ // do nothing.
+ }
+ }
+ };
+
+ Thread t2 = new Thread("") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ InputStreamReader is = new InputStreamReader(process.getErrorStream());
+ BufferedReader errReader = new BufferedReader(is);
+
+ try {
+ while (true) {
+ String line = errReader.readLine();
+ if (line != null) {
+ AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE,
+ project, line);
+ } else {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ // do nothing.
+ }
+ }
+
+ };
+
+ t1.start();
+ t2.start();
+
+ // it looks like on windows process#waitFor() can return
+ // before the thread have filled the arrays, so we wait for both threads and the
+ // process itself.
+ try {
+ t1.join();
+ } catch (InterruptedException e) {
+ }
+ try {
+ t2.join();
+ } catch (InterruptedException e) {
+ }
+
+ // get the return code from the process
+ return process.waitFor();
+ } finally {
+ try {
+ writer.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+}