diff options
author | Bob Badour <bbadour@google.com> | 2020-05-06 14:30:13 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-05-06 14:30:13 +0000 |
commit | d3c69fa48e25645a343d97ac392300583e38b30a (patch) | |
tree | fd845444b59dfc72656b7781596e0b1a0662c4c7 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java | |
parent | 0300bcd44ebe99ec7118dab453986fefd9a0555e (diff) | |
parent | fc7cda06f54946e3a03ea008c1ba086d90aeef84 (diff) | |
download | sdk-d3c69fa48e25645a343d97ac392300583e38b30a.tar.gz |
Merge "Revert "Remove unused project."" am: fc7cda06f5
Change-Id: I1dbd864aa8ee9e2a44b6acc173c12740abf9447f
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java new file mode 100644 index 000000000..3f882842b --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2008 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.build; + +import com.android.SdkConstants; +import com.android.ide.eclipse.adt.AdtPlugin; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import java.io.File; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collection; + +/** + * Wrapper to access dx.jar through reflection. + * <p/>Since there is no proper api to call the method in the dex library, this wrapper is going + * to access it through reflection. + */ +public final class DexWrapper { + + private final static String DEX_MAIN = "com.android.dx.command.dexer.Main"; //$NON-NLS-1$ + private final static String DEX_CONSOLE = "com.android.dx.command.DxConsole"; //$NON-NLS-1$ + private final static String DEX_ARGS = "com.android.dx.command.dexer.Main$Arguments"; //$NON-NLS-1$ + + private final static String MAIN_RUN = "run"; //$NON-NLS-1$ + + private Method mRunMethod; + + private Constructor<?> mArgConstructor; + private Field mArgOutName; + private Field mArgVerbose; + private Field mArgJarOutput; + private Field mArgFileNames; + private Field mArgForceJumbo; + + private Field mConsoleOut; + private Field mConsoleErr; + + /** + * Loads the dex library from a file path. + * + * The loaded library can be used via + * {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}. + * + * @param osFilepath the location of the dx.jar file. + * @return an IStatus indicating the result of the load. + */ + public synchronized IStatus loadDex(String osFilepath) { + try { + File f = new File(osFilepath); + if (f.isFile() == false) { + return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( + Messages.DexWrapper_s_does_not_exists, osFilepath)); + } + URL url = f.toURI().toURL(); + + @SuppressWarnings("resource") + URLClassLoader loader = new URLClassLoader(new URL[] { url }, + DexWrapper.class.getClassLoader()); + + // get the classes. + Class<?> mainClass = loader.loadClass(DEX_MAIN); + Class<?> consoleClass = loader.loadClass(DEX_CONSOLE); + Class<?> argClass = loader.loadClass(DEX_ARGS); + + try { + // now get the fields/methods we need + mRunMethod = mainClass.getMethod(MAIN_RUN, argClass); + + mArgConstructor = argClass.getConstructor(); + mArgOutName = argClass.getField("outName"); //$NON-NLS-1$ + mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$ + mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$ + mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$ + mArgForceJumbo = argClass.getField("forceJumbo"); //$NON-NLS-1$ + + mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$ + mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$ + + } catch (SecurityException e) { + return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e); + } catch (NoSuchMethodException e) { + return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e); + } catch (NoSuchFieldException e) { + return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e); + } + + return Status.OK_STATUS; + } catch (MalformedURLException e) { + // really this should not happen. + return createErrorStatus( + String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); + } catch (ClassNotFoundException e) { + return createErrorStatus( + String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); + } + } + + /** + * Removes any reference to the dex library. + * <p/> + * {@link #loadDex(String)} must be called on the wrapper + * before {@link #run(String, String[], boolean, PrintStream, PrintStream)} can + * be used again. + */ + public synchronized void unload() { + mRunMethod = null; + mArgConstructor = null; + mArgOutName = null; + mArgJarOutput = null; + mArgFileNames = null; + mArgVerbose = null; + mConsoleOut = null; + mConsoleErr = null; + System.gc(); + } + + /** + * Runs the dex command. + * The wrapper must have been initialized via {@link #loadDex(String)} first. + * + * @param osOutFilePath the OS path to the outputfile (classes.dex + * @param osFilenames list of input source files (.class and .jar files) + * @param forceJumbo force jumbo mode. + * @param verbose verbose mode. + * @param outStream the stdout console + * @param errStream the stderr console + * @return the integer return code of com.android.dx.command.dexer.Main.run() + * @throws CoreException + */ + public synchronized int run(String osOutFilePath, Collection<String> osFilenames, + boolean forceJumbo, boolean verbose, + PrintStream outStream, PrintStream errStream) throws CoreException { + + assert mRunMethod != null; + assert mArgConstructor != null; + assert mArgOutName != null; + assert mArgJarOutput != null; + assert mArgFileNames != null; + assert mArgForceJumbo != null; + assert mArgVerbose != null; + assert mConsoleOut != null; + assert mConsoleErr != null; + + if (mRunMethod == null) { + throw new CoreException(createErrorStatus( + String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, + "wrapper was not properly loaded first"), + null /*exception*/)); + } + + try { + // set the stream + mConsoleErr.set(null /* obj: static field */, errStream); + mConsoleOut.set(null /* obj: static field */, outStream); + + // create the Arguments object. + Object args = mArgConstructor.newInstance(); + mArgOutName.set(args, osOutFilePath); + mArgFileNames.set(args, osFilenames.toArray(new String[osFilenames.size()])); + mArgJarOutput.set(args, osOutFilePath.endsWith(SdkConstants.DOT_JAR)); + mArgForceJumbo.set(args, forceJumbo); + mArgVerbose.set(args, verbose); + + // call the run method + Object res = mRunMethod.invoke(null /* obj: static method */, args); + + if (res instanceof Integer) { + return ((Integer)res).intValue(); + } + + return -1; + } catch (Exception e) { + Throwable t = e; + while (t.getCause() != null) { + t = t.getCause(); + } + + String msg = t.getMessage(); + if (msg == null) { + msg = String.format("%s. Check the Eclipse log for stack trace.", + t.getClass().getName()); + } + + throw new CoreException(createErrorStatus( + String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, msg), t)); + } + } + + private static IStatus createErrorStatus(String message, Throwable e) { + AdtPlugin.log(e, message); + AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message); + + return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e); + } +} |