aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java1225
1 files changed, 0 insertions, 1225 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
deleted file mode 100644
index 78d9d94e4..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
+++ /dev/null
@@ -1,1225 +0,0 @@
-/*
- * 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.build;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AndroidPrintStream;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
-import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.prefs.AndroidLocation.AndroidLocationException;
-import com.android.sdklib.BuildToolInfo;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
-import com.android.sdklib.build.ApkBuilder;
-import com.android.sdklib.build.ApkBuilder.JarStatus;
-import com.android.sdklib.build.ApkBuilder.SigningInfo;
-import com.android.sdklib.build.ApkCreationException;
-import com.android.sdklib.build.DuplicateFileException;
-import com.android.sdklib.build.RenderScriptProcessor;
-import com.android.sdklib.build.SealedApkException;
-import com.android.sdklib.internal.build.DebugKeyProvider;
-import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
-import com.android.utils.GrabProcessOutput;
-import com.android.utils.GrabProcessOutput.IProcessOutput;
-import com.android.utils.GrabProcessOutput.Wait;
-import com.google.common.base.Charsets;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.HashFunction;
-import com.google.common.hash.Hashing;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jdt.core.IClasspathContainer;
-import org.eclipse.jdt.core.IClasspathEntry;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jface.preference.IPreferenceStore;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * Helper with methods for the last 3 steps of the generation of an APK.
- *
- * {@link #packageResources(IFile, IProject[], String, int, String, String)} packages the
- * application resources using aapt into a zip file that is ready to be integrated into the apk.
- *
- * {@link #executeDx(IJavaProject, String, String, IJavaProject[])} will convert the Java byte
- * code into the Dalvik bytecode.
- *
- * {@link #finalPackage(String, String, String, boolean, IJavaProject, IProject[], IJavaProject[], String, boolean)}
- * will make the apk from all the previous components.
- *
- * This class only executes the 3 above actions. It does not handle the errors, and simply sends
- * them back as custom exceptions.
- *
- * Warnings are handled by the {@link ResourceMarker} interface.
- *
- * Console output (verbose and non verbose) is handled through the {@link AndroidPrintStream} passed
- * to the constructor.
- *
- */
-public class BuildHelper {
-
- private static final String CONSOLE_PREFIX_DX = "Dx"; //$NON-NLS-1$
- private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$
-
- private static final String COMMAND_CRUNCH = "crunch"; //$NON-NLS-1$
- private static final String COMMAND_PACKAGE = "package"; //$NON-NLS-1$
-
- @NonNull
- private final ProjectState mProjectState;
- @NonNull
- private final IProject mProject;
- @NonNull
- private final BuildToolInfo mBuildToolInfo;
- @NonNull
- private final AndroidPrintStream mOutStream;
- @NonNull
- private final AndroidPrintStream mErrStream;
- private final boolean mForceJumbo;
- private final boolean mDisableDexMerger;
- private final boolean mVerbose;
- private final boolean mDebugMode;
-
- private final Set<String> mCompiledCodePaths = new HashSet<String>();
-
- public static final boolean BENCHMARK_FLAG = false;
- public static long sStartOverallTime = 0;
- public static long sStartJavaCTime = 0;
-
- private final static int MILLION = 1000000;
- private String mProguardFile;
-
- /**
- * An object able to put a marker on a resource.
- */
- public interface ResourceMarker {
- void setWarning(IResource resource, String message);
- }
-
- /**
- * Creates a new post-compiler helper
- * @param project
- * @param outStream
- * @param errStream
- * @param debugMode whether this is a debug build
- * @param verbose
- * @throws CoreException
- */
- public BuildHelper(@NonNull ProjectState projectState,
- @NonNull BuildToolInfo buildToolInfo,
- @NonNull AndroidPrintStream outStream,
- @NonNull AndroidPrintStream errStream,
- boolean forceJumbo, boolean disableDexMerger, boolean debugMode,
- boolean verbose, ResourceMarker resMarker) throws CoreException {
- mProjectState = projectState;
- mProject = projectState.getProject();
- mBuildToolInfo = buildToolInfo;
- mOutStream = outStream;
- mErrStream = errStream;
- mDebugMode = debugMode;
- mVerbose = verbose;
- mForceJumbo = forceJumbo;
- mDisableDexMerger = disableDexMerger;
-
- gatherPaths(resMarker);
- }
-
- public void updateCrunchCache() throws AaptExecException, AaptResultException {
- // Benchmarking start
- long startCrunchTime = 0;
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- startCrunchTime = System.nanoTime();
- }
-
- // Get the resources folder to crunch from
- IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES);
- List<String> resPaths = new ArrayList<String>();
- resPaths.add(resFolder.getLocation().toOSString());
-
- // Get the output folder where the cache is stored.
- IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(mProject);
- IFolder cacheFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE);
- String cachePath = cacheFolder.getLocation().toOSString();
-
- /* For crunching, we don't need the osManifestPath, osAssetsPath, or the configFilter
- * parameters for executeAapt
- */
- executeAapt(COMMAND_CRUNCH, "", resPaths, "", cachePath, "", 0);
-
- // Benchmarking end
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$
- + ((System.nanoTime() - startCrunchTime)/MILLION) + "ms"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- }
- }
-
- /**
- * Packages the resources of the projet into a .ap_ file.
- * @param manifestFile the manifest of the project.
- * @param libProjects the list of library projects that this project depends on.
- * @param resFilter an optional resource filter to be used with the -c option of aapt. If null
- * no filters are used.
- * @param versionCode an optional versionCode to be inserted in the manifest during packaging.
- * If the value is <=0, no values are inserted.
- * @param outputFolder where to write the resource ap_ file.
- * @param outputFilename the name of the resource ap_ file.
- * @throws AaptExecException
- * @throws AaptResultException
- */
- public void packageResources(IFile manifestFile, List<IProject> libProjects, String resFilter,
- int versionCode, String outputFolder, String outputFilename)
- throws AaptExecException, AaptResultException {
-
- // Benchmarking start
- long startPackageTime = 0;
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- startPackageTime = System.nanoTime();
- }
-
- // need to figure out some path before we can execute aapt;
- IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(mProject);
-
- // get the cache folder
- IFolder cacheFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE);
-
- // get the BC folder
- IFolder bcFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_BC);
-
- // get the resource folder
- IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES);
-
- // and the assets folder
- IFolder assetsFolder = mProject.getFolder(AdtConstants.WS_ASSETS);
-
- // we need to make sure this one exists.
- if (assetsFolder.exists() == false) {
- assetsFolder = null;
- }
-
- // list of res folder (main project + maybe libraries)
- ArrayList<String> osResPaths = new ArrayList<String>();
-
- IPath resLocation = resFolder.getLocation();
- IPath manifestLocation = manifestFile.getLocation();
-
- if (resLocation != null && manifestLocation != null) {
-
- // png cache folder first.
- addFolderToList(osResPaths, cacheFolder);
- addFolderToList(osResPaths, bcFolder);
-
- // regular res folder next.
- osResPaths.add(resLocation.toOSString());
-
- // then libraries
- if (libProjects != null) {
- for (IProject lib : libProjects) {
- // png cache folder first
- IFolder libBinFolder = BaseProjectHelper.getAndroidOutputFolder(lib);
-
- IFolder libCacheFolder = libBinFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE);
- addFolderToList(osResPaths, libCacheFolder);
-
- IFolder libBcFolder = libBinFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_BC);
- addFolderToList(osResPaths, libBcFolder);
-
- // regular res folder next.
- IFolder libResFolder = lib.getFolder(AdtConstants.WS_RESOURCES);
- addFolderToList(osResPaths, libResFolder);
- }
- }
-
- String osManifestPath = manifestLocation.toOSString();
-
- String osAssetsPath = null;
- if (assetsFolder != null) {
- osAssetsPath = assetsFolder.getLocation().toOSString();
- }
-
- // build the default resource package
- executeAapt(COMMAND_PACKAGE, osManifestPath, osResPaths, osAssetsPath,
- outputFolder + File.separator + outputFilename, resFilter,
- versionCode);
- }
-
- // Benchmarking end
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$
- + ((System.nanoTime() - startPackageTime)/MILLION) + "ms"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- }
- }
-
- /**
- * Adds os path of a folder to a list only if the folder actually exists.
- * @param pathList
- * @param folder
- */
- private void addFolderToList(List<String> pathList, IFolder folder) {
- // use a File instead of the IFolder API to ignore workspace refresh issue.
- File testFile = new File(folder.getLocation().toOSString());
- if (testFile.isDirectory()) {
- pathList.add(testFile.getAbsolutePath());
- }
- }
-
- /**
- * Makes a final package signed with the debug key.
- *
- * Packages the dex files, the temporary resource file into the final package file.
- *
- * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter
- * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)}
- *
- * @param intermediateApk The path to the temporary resource file.
- * @param dex The path to the dex file.
- * @param output The path to the final package file to create.
- * @param libProjects an optional list of library projects (can be null)
- * @return true if success, false otherwise.
- * @throws ApkCreationException
- * @throws AndroidLocationException
- * @throws KeytoolException
- * @throws NativeLibInJarException
- * @throws CoreException
- * @throws DuplicateFileException
- */
- public void finalDebugPackage(String intermediateApk, String dex, String output,
- List<IProject> libProjects, ResourceMarker resMarker)
- throws ApkCreationException, KeytoolException, AndroidLocationException,
- NativeLibInJarException, DuplicateFileException, CoreException {
-
- AdtPlugin adt = AdtPlugin.getDefault();
- if (adt == null) {
- return;
- }
-
- // get the debug keystore to use.
- IPreferenceStore store = adt.getPreferenceStore();
- String keystoreOsPath = store.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE);
- if (keystoreOsPath == null || new File(keystoreOsPath).isFile() == false) {
- keystoreOsPath = DebugKeyProvider.getDefaultKeyStoreOsPath();
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- Messages.ApkBuilder_Using_Default_Key);
- } else {
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
- String.format(Messages.ApkBuilder_Using_s_To_Sign, keystoreOsPath));
- }
-
- // from the keystore, get the signing info
- SigningInfo info = ApkBuilder.getDebugKey(keystoreOsPath, mVerbose ? mOutStream : null);
-
- finalPackage(intermediateApk, dex, output, libProjects,
- info != null ? info.key : null, info != null ? info.certificate : null, resMarker);
- }
-
- /**
- * Makes the final package.
- *
- * Packages the dex files, the temporary resource file into the final package file.
- *
- * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter
- * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)}
- *
- * @param intermediateApk The path to the temporary resource file.
- * @param dex The path to the dex file.
- * @param output The path to the final package file to create.
- * @param debugSign whether the apk must be signed with the debug key.
- * @param libProjects an optional list of library projects (can be null)
- * @param abiFilter an optional filter. If not null, then only the matching ABI is included in
- * the final archive
- * @return true if success, false otherwise.
- * @throws NativeLibInJarException
- * @throws ApkCreationException
- * @throws CoreException
- * @throws DuplicateFileException
- */
- public void finalPackage(String intermediateApk, String dex, String output,
- List<IProject> libProjects,
- PrivateKey key, X509Certificate certificate, ResourceMarker resMarker)
- throws NativeLibInJarException, ApkCreationException, DuplicateFileException,
- CoreException {
-
- try {
- ApkBuilder apkBuilder = new ApkBuilder(output, intermediateApk, dex,
- key, certificate,
- mVerbose ? mOutStream: null);
- apkBuilder.setDebugMode(mDebugMode);
-
- // either use the full compiled code paths or just the proguard file
- // if present
- Collection<String> pathsCollection = mCompiledCodePaths;
- if (mProguardFile != null) {
- pathsCollection = Collections.singletonList(mProguardFile);
- mProguardFile = null;
- }
-
- // Now we write the standard resources from all the output paths.
- for (String path : pathsCollection) {
- File file = new File(path);
- if (file.isFile()) {
- JarStatus jarStatus = apkBuilder.addResourcesFromJar(file);
-
- // check if we found native libraries in the external library. This
- // constitutes an error or warning depending on if they are in lib/
- if (jarStatus.getNativeLibs().size() > 0) {
- String libName = file.getName();
-
- String msg = String.format(
- "Native libraries detected in '%1$s'. See console for more information.",
- libName);
-
- ArrayList<String> consoleMsgs = new ArrayList<String>();
-
- consoleMsgs.add(String.format(
- "The library '%1$s' contains native libraries that will not run on the device.",
- libName));
-
- if (jarStatus.hasNativeLibsConflicts()) {
- consoleMsgs.add("Additionally some of those libraries will interfer with the installation of the application because of their location in lib/");
- consoleMsgs.add("lib/ is reserved for NDK libraries.");
- }
-
- consoleMsgs.add("The following libraries were found:");
-
- for (String lib : jarStatus.getNativeLibs()) {
- consoleMsgs.add(" - " + lib);
- }
-
- String[] consoleStrings = consoleMsgs.toArray(new String[consoleMsgs.size()]);
-
- // if there's a conflict or if the prefs force error on any native code in jar
- // files, throw an exception
- if (jarStatus.hasNativeLibsConflicts() ||
- AdtPrefs.getPrefs().getBuildForceErrorOnNativeLibInJar()) {
- throw new NativeLibInJarException(jarStatus, msg, libName, consoleStrings);
- } else {
- // otherwise, put a warning, and output to the console also.
- if (resMarker != null) {
- resMarker.setWarning(mProject, msg);
- }
-
- for (String string : consoleStrings) {
- mOutStream.println(string);
- }
- }
- }
- } else if (file.isDirectory()) {
- // this is technically not a source folder (class folder instead) but since we
- // only care about Java resources (ie non class/java files) this will do the
- // same
- apkBuilder.addSourceFolder(file);
- }
- }
-
- // now write the native libraries.
- // First look if the lib folder is there.
- IResource libFolder = mProject.findMember(SdkConstants.FD_NATIVE_LIBS);
- if (libFolder != null && libFolder.exists() &&
- libFolder.getType() == IResource.FOLDER) {
- // get a File for the folder.
- apkBuilder.addNativeLibraries(libFolder.getLocation().toFile());
- }
-
- // next the native libraries for the renderscript support mode.
- if (mProjectState.getRenderScriptSupportMode()) {
- IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(mProject);
- IResource rsLibFolder = androidOutputFolder.getFolder(
- AdtConstants.WS_BIN_RELATIVE_RS_LIBS);
- File rsLibFolderFile = rsLibFolder.getLocation().toFile();
- if (rsLibFolderFile.isDirectory()) {
- apkBuilder.addNativeLibraries(rsLibFolderFile);
- }
-
- File rsLibs = RenderScriptProcessor.getSupportNativeLibFolder(
- mBuildToolInfo.getLocation().getAbsolutePath());
- if (rsLibs.isDirectory()) {
- apkBuilder.addNativeLibraries(rsLibs);
- }
- }
-
- // write the native libraries for the library projects.
- if (libProjects != null) {
- for (IProject lib : libProjects) {
- libFolder = lib.findMember(SdkConstants.FD_NATIVE_LIBS);
- if (libFolder != null && libFolder.exists() &&
- libFolder.getType() == IResource.FOLDER) {
- apkBuilder.addNativeLibraries(libFolder.getLocation().toFile());
- }
- }
- }
-
- // seal the APK.
- apkBuilder.sealApk();
- } catch (SealedApkException e) {
- // this won't happen as we control when the apk is sealed.
- }
- }
-
- public void setProguardOutput(String proguardFile) {
- mProguardFile = proguardFile;
- }
-
- public Collection<String> getCompiledCodePaths() {
- return mCompiledCodePaths;
- }
-
- public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles,
- File obfuscatedJar, File logOutput)
- throws ProguardResultException, ProguardExecException, IOException {
- IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
-
- // prepare the command line for proguard
- List<String> command = new ArrayList<String>();
- command.add(AdtPlugin.getOsAbsoluteProguard());
-
- for (File configFile : proguardConfigs) {
- command.add("-include"); //$NON-NLS-1$
- command.add(quotePath(configFile.getAbsolutePath()));
- }
-
- command.add("-injars"); //$NON-NLS-1$
- StringBuilder sb = new StringBuilder(quotePath(inputJar.getAbsolutePath()));
- for (String jarFile : jarFiles) {
- sb.append(File.pathSeparatorChar);
- sb.append(quotePath(jarFile));
- }
- command.add(quoteWinArg(sb.toString()));
-
- command.add("-outjars"); //$NON-NLS-1$
- command.add(quotePath(obfuscatedJar.getAbsolutePath()));
-
- command.add("-libraryjars"); //$NON-NLS-1$
- sb = new StringBuilder(quotePath(target.getPath(IAndroidTarget.ANDROID_JAR)));
- IOptionalLibrary[] libraries = target.getOptionalLibraries();
- if (libraries != null) {
- for (IOptionalLibrary lib : libraries) {
- sb.append(File.pathSeparatorChar);
- sb.append(quotePath(lib.getJarPath()));
- }
- }
- command.add(quoteWinArg(sb.toString()));
-
- if (logOutput != null) {
- if (logOutput.isDirectory() == false) {
- logOutput.mkdirs();
- }
-
- command.add("-dump"); //$NON-NLS-1$
- command.add(new File(logOutput, "dump.txt").getAbsolutePath()); //$NON-NLS-1$
-
- command.add("-printseeds"); //$NON-NLS-1$
- command.add(new File(logOutput, "seeds.txt").getAbsolutePath()); //$NON-NLS-1$
-
- command.add("-printusage"); //$NON-NLS-1$
- command.add(new File(logOutput, "usage.txt").getAbsolutePath()); //$NON-NLS-1$
-
- command.add("-printmapping"); //$NON-NLS-1$
- command.add(new File(logOutput, "mapping.txt").getAbsolutePath()); //$NON-NLS-1$
- }
-
- String commandArray[] = null;
-
- if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) {
- commandArray = createWindowsProguardConfig(command);
- }
-
- if (commandArray == null) {
- // For Mac & Linux, use a regular command string array.
- commandArray = command.toArray(new String[command.size()]);
- }
-
- // Define PROGUARD_HOME to point to $SDK/tools/proguard if it's not yet defined.
- // The Mac/Linux proguard.sh can infer it correctly but not the proguard.bat one.
- String[] envp = null;
- Map<String, String> envMap = new TreeMap<String, String>(System.getenv());
- if (!envMap.containsKey("PROGUARD_HOME")) { //$NON-NLS-1$
- envMap.put("PROGUARD_HOME", Sdk.getCurrent().getSdkOsLocation() + //$NON-NLS-1$
- SdkConstants.FD_TOOLS + File.separator +
- SdkConstants.FD_PROGUARD);
- envp = new String[envMap.size()];
- int i = 0;
- for (Map.Entry<String, String> entry : envMap.entrySet()) {
- envp[i++] = String.format("%1$s=%2$s", //$NON-NLS-1$
- entry.getKey(),
- entry.getValue());
- }
- }
-
- if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
- sb = new StringBuilder();
- for (String c : commandArray) {
- sb.append(c).append(' ');
- }
- AdtPlugin.printToConsole(mProject, sb.toString());
- }
-
- // launch
- int execError = 1;
- try {
- // launch the command line process
- Process process = Runtime.getRuntime().exec(commandArray, envp);
-
- // list to store each line of stderr
- ArrayList<String> results = new ArrayList<String>();
-
- // get the output and return code from the process
- execError = grabProcessOutput(mProject, process, results);
-
- if (mVerbose) {
- for (String resultString : results) {
- mOutStream.println(resultString);
- }
- }
-
- if (execError != 0) {
- throw new ProguardResultException(execError,
- results.toArray(new String[results.size()]));
- }
-
- } catch (IOException e) {
- String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]);
- throw new ProguardExecException(msg, e);
- } catch (InterruptedException e) {
- String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]);
- throw new ProguardExecException(msg, e);
- }
- }
-
- /**
- * For tools R8 up to R11, the proguard.bat launcher on Windows only accepts
- * arguments %1..%9. Since we generally have about 15 arguments, we were working
- * around this by generating a temporary config file for proguard and then using
- * that.
- * Starting with tools R12, the proguard.bat launcher has been fixed to take
- * all arguments using %* so we no longer need this hack.
- *
- * @param command
- * @return
- * @throws IOException
- */
- private String[] createWindowsProguardConfig(List<String> command) throws IOException {
-
- // Arg 0 is the proguard.bat path and arg 1 is the user config file
- String launcher = AdtPlugin.readFile(new File(command.get(0)));
- if (launcher.contains("%*")) { //$NON-NLS-1$
- // This is the launcher from Tools R12. Don't work around it.
- return null;
- }
-
- // On Windows, proguard.bat can only pass %1...%9 to the java -jar proguard.jar
- // call, but we have at least 15 arguments here so some get dropped silently
- // and quoting is a big issue. So instead we'll work around that by writing
- // all the arguments to a temporary config file.
-
- String[] commandArray = new String[3];
-
- commandArray[0] = command.get(0);
- commandArray[1] = command.get(1);
-
- // Write all the other arguments to a config file
- File argsFile = File.createTempFile(TEMP_PREFIX, ".pro"); //$NON-NLS-1$
- // TODO FIXME this may leave a lot of temp files around on a long session.
- // Should have a better way to clean up e.g. before each build.
- argsFile.deleteOnExit();
-
- FileWriter fw = new FileWriter(argsFile);
-
- for (int i = 2; i < command.size(); i++) {
- String s = command.get(i);
- fw.write(s);
- fw.write(s.startsWith("-") ? ' ' : '\n'); //$NON-NLS-1$
- }
-
- fw.close();
-
- commandArray[2] = "@" + argsFile.getAbsolutePath(); //$NON-NLS-1$
- return commandArray;
- }
-
- /**
- * Quotes a single path for proguard to deal with spaces.
- *
- * @param path The path to quote.
- * @return The original path if it doesn't contain a space.
- * Or the original path surrounded by single quotes if it contains spaces.
- */
- private String quotePath(String path) {
- if (path.indexOf(' ') != -1) {
- path = '\'' + path + '\'';
- }
- return path;
- }
-
- /**
- * Quotes a compound proguard argument to deal with spaces.
- * <p/>
- * Proguard takes multi-path arguments such as "path1;path2" for some options.
- * When the {@link #quotePath} methods adds quotes for such a path if it contains spaces,
- * the proguard shell wrapper will absorb the quotes, so we need to quote around the
- * quotes.
- *
- * @param path The path to quote.
- * @return The original path if it doesn't contain a single quote.
- * Or on Windows the original path surrounded by double quotes if it contains a quote.
- */
- private String quoteWinArg(String path) {
- if (path.indexOf('\'') != -1 &&
- SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) {
- path = '"' + path + '"';
- }
- return path;
- }
-
-
- /**
- * Execute the Dx tool for dalvik code conversion.
- * @param javaProject The java project
- * @param inputPaths the input paths for DX
- * @param osOutFilePath the path of the dex file to create.
- *
- * @throws CoreException
- * @throws DexException
- */
- public void executeDx(IJavaProject javaProject, Collection<String> inputPaths,
- String osOutFilePath)
- throws CoreException, DexException {
-
- // get the dex wrapper
- Sdk sdk = Sdk.getCurrent();
- DexWrapper wrapper = sdk.getDexWrapper(mBuildToolInfo);
-
- if (wrapper == null) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
- }
-
- try {
- // set a temporary prefix on the print streams.
- mOutStream.setPrefix(CONSOLE_PREFIX_DX);
- mErrStream.setPrefix(CONSOLE_PREFIX_DX);
-
- IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(javaProject.getProject());
- File binFile = binFolder.getLocation().toFile();
- File dexedLibs = new File(binFile, "dexedLibs");
- if (dexedLibs.exists() == false) {
- dexedLibs.mkdir();
- }
-
- // replace the libs by their dexed versions (dexing them if needed.)
- List<String> finalInputPaths = new ArrayList<String>(inputPaths.size());
- if (mDisableDexMerger || inputPaths.size() == 1) {
- // only one input, no need to put a pre-dexed version, even if this path is
- // just a jar file (case for proguard'ed builds)
- finalInputPaths.addAll(inputPaths);
- } else {
-
- for (String input : inputPaths) {
- File inputFile = new File(input);
- if (inputFile.isDirectory()) {
- finalInputPaths.add(input);
- } else if (inputFile.isFile()) {
- String fileName = getDexFileName(inputFile);
-
- File dexedLib = new File(dexedLibs, fileName);
- String dexedLibPath = dexedLib.getAbsolutePath();
-
- if (dexedLib.isFile() == false ||
- dexedLib.lastModified() < inputFile.lastModified()) {
-
- if (mVerbose) {
- mOutStream.println(
- String.format("Pre-Dexing %1$s -> %2$s", input, fileName));
- }
-
- if (dexedLib.isFile()) {
- dexedLib.delete();
- }
-
- int res = wrapper.run(dexedLibPath, Collections.singleton(input),
- mForceJumbo, mVerbose, mOutStream, mErrStream);
-
- if (res != 0) {
- // output error message and mark the project.
- String message = String.format(Messages.Dalvik_Error_d, res);
- throw new DexException(message);
- }
- } else {
- if (mVerbose) {
- mOutStream.println(
- String.format("Using Pre-Dexed %1$s <- %2$s",
- fileName, input));
- }
- }
-
- finalInputPaths.add(dexedLibPath);
- }
- }
- }
-
- if (mVerbose) {
- for (String input : finalInputPaths) {
- mOutStream.println("Input: " + input);
- }
- }
-
- int res = wrapper.run(osOutFilePath,
- finalInputPaths,
- mForceJumbo,
- mVerbose,
- mOutStream, mErrStream);
-
- mOutStream.setPrefix(null);
- mErrStream.setPrefix(null);
-
- if (res != 0) {
- // output error message and marker the project.
- String message = String.format(Messages.Dalvik_Error_d, res);
- throw new DexException(message);
- }
- } catch (DexException e) {
- throw e;
- } catch (Throwable t) {
- String message = t.getMessage();
- if (message == null) {
- message = t.getClass().getCanonicalName();
- }
- message = String.format(Messages.Dalvik_Error_s, message);
-
- throw new DexException(message, t);
- }
- }
-
- private String getDexFileName(File inputFile) {
- // get the filename
- String name = inputFile.getName();
- // remove the extension
- int pos = name.lastIndexOf('.');
- if (pos != -1) {
- name = name.substring(0, pos);
- }
-
- // add a hash of the original file path
- HashFunction hashFunction = Hashing.md5();
- HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charsets.UTF_8);
-
- return name + "-" + hashCode.toString() + ".jar";
- }
-
- /**
- * Executes aapt. If any error happen, files or the project will be marked.
- * @param command The command for aapt to execute. Currently supported: package and crunch
- * @param osManifestPath The path to the manifest file
- * @param osResPath The path to the res folder
- * @param osAssetsPath The path to the assets folder. This can be null.
- * @param osOutFilePath The path to the temporary resource file to create,
- * or in the case of crunching the path to the cache to create/update.
- * @param configFilter The configuration filter for the resources to include
- * (used with -c option, for example "port,en,fr" to include portrait, English and French
- * resources.)
- * @param versionCode optional version code to insert in the manifest during packaging. If <=0
- * then no value is inserted
- * @throws AaptExecException
- * @throws AaptResultException
- */
- private void executeAapt(String aaptCommand, String osManifestPath,
- List<String> osResPaths, String osAssetsPath, String osOutFilePath,
- String configFilter, int versionCode) throws AaptExecException, AaptResultException {
- IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
-
- String aapt = mBuildToolInfo.getPath(BuildToolInfo.PathId.AAPT);
-
- // Create the command line.
- ArrayList<String> commandArray = new ArrayList<String>();
- commandArray.add(aapt);
- commandArray.add(aaptCommand);
- if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
- commandArray.add("-v"); //$NON-NLS-1$
- }
-
- // Common to all commands
- for (String path : osResPaths) {
- commandArray.add("-S"); //$NON-NLS-1$
- commandArray.add(path);
- }
-
- if (aaptCommand.equals(COMMAND_PACKAGE)) {
- commandArray.add("-f"); //$NON-NLS-1$
- commandArray.add("--no-crunch"); //$NON-NLS-1$
-
- // if more than one res, this means there's a library (or more) and we need
- // to activate the auto-add-overlay
- if (osResPaths.size() > 1) {
- commandArray.add("--auto-add-overlay"); //$NON-NLS-1$
- }
-
- if (mDebugMode) {
- commandArray.add("--debug-mode"); //$NON-NLS-1$
- }
-
- if (versionCode > 0) {
- commandArray.add("--version-code"); //$NON-NLS-1$
- commandArray.add(Integer.toString(versionCode));
- }
-
- if (configFilter != null) {
- commandArray.add("-c"); //$NON-NLS-1$
- commandArray.add(configFilter);
- }
-
- // never compress apks.
- commandArray.add("-0");
- commandArray.add("apk");
-
- commandArray.add("-M"); //$NON-NLS-1$
- commandArray.add(osManifestPath);
-
- if (osAssetsPath != null) {
- commandArray.add("-A"); //$NON-NLS-1$
- commandArray.add(osAssetsPath);
- }
-
- commandArray.add("-I"); //$NON-NLS-1$
- commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR));
-
- commandArray.add("-F"); //$NON-NLS-1$
- commandArray.add(osOutFilePath);
- } else if (aaptCommand.equals(COMMAND_CRUNCH)) {
- commandArray.add("-C"); //$NON-NLS-1$
- commandArray.add(osOutFilePath);
- }
-
- String command[] = commandArray.toArray(
- new String[commandArray.size()]);
-
- if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
- StringBuilder sb = new StringBuilder();
- for (String c : command) {
- sb.append(c);
- sb.append(' ');
- }
- AdtPlugin.printToConsole(mProject, sb.toString());
- }
-
- // Benchmarking start
- long startAaptTime = 0;
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Starting " + aaptCommand //$NON-NLS-1$
- + " call to Aapt"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- startAaptTime = System.nanoTime();
- }
-
- // launch
- try {
- // launch the command line process
- Process process = Runtime.getRuntime().exec(command);
-
- // list to store each line of stderr
- ArrayList<String> stdErr = new ArrayList<String>();
-
- // get the output and return code from the process
- int returnCode = grabProcessOutput(mProject, process, stdErr);
-
- if (mVerbose) {
- for (String stdErrString : stdErr) {
- mOutStream.println(stdErrString);
- }
- }
- if (returnCode != 0) {
- throw new AaptResultException(returnCode,
- stdErr.toArray(new String[stdErr.size()]));
- }
- } catch (IOException e) {
- String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]);
- throw new AaptExecException(msg, e);
- } catch (InterruptedException e) {
- String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]);
- throw new AaptExecException(msg, e);
- }
-
- // Benchmarking end
- if (BENCHMARK_FLAG) {
- String msg = "BENCHMARK ADT: Ending " + aaptCommand //$NON-NLS-1$
- + " call to Aapt.\nBENCHMARK ADT: Time Elapsed: " //$NON-NLS-1$
- + ((System.nanoTime() - startAaptTime)/MILLION) + "ms"; //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
- }
- }
-
- /**
- * Computes all the project output and dependencies that must go into building the apk.
- *
- * @param resMarker
- * @throws CoreException
- */
- private void gatherPaths(ResourceMarker resMarker)
- throws CoreException {
- IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
-
- // get a java project for the project.
- IJavaProject javaProject = JavaCore.create(mProject);
-
-
- // get the output of the main project
- IPath path = javaProject.getOutputLocation();
- IResource outputResource = wsRoot.findMember(path);
- if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
- mCompiledCodePaths.add(outputResource.getLocation().toOSString());
- }
-
- // we could use IJavaProject.getResolvedClasspath directly, but we actually
- // want to see the containers themselves.
- IClasspathEntry[] classpaths = javaProject.readRawClasspath();
- if (classpaths != null) {
- for (IClasspathEntry e : classpaths) {
- // ignore non exported entries, unless they're in the DEPEDENCIES container,
- // in which case we always want it (there may be some older projects that
- // have it as non exported).
- if (e.isExported() ||
- (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER &&
- e.getPath().toString().equals(AdtConstants.CONTAINER_DEPENDENCIES))) {
- handleCPE(e, javaProject, wsRoot, resMarker);
- }
- }
- }
- }
-
- private void handleCPE(IClasspathEntry entry, IJavaProject javaProject,
- IWorkspaceRoot wsRoot, ResourceMarker resMarker) {
-
- // if this is a classpath variable reference, we resolve it.
- if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
- entry = JavaCore.getResolvedClasspathEntry(entry);
- }
-
- if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
- IProject refProject = wsRoot.getProject(entry.getPath().lastSegment());
- try {
- // ignore if it's an Android project, or if it's not a Java Project
- if (refProject.hasNature(JavaCore.NATURE_ID) &&
- refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- IJavaProject refJavaProject = JavaCore.create(refProject);
-
- // get the output folder
- IPath path = refJavaProject.getOutputLocation();
- IResource outputResource = wsRoot.findMember(path);
- if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
- mCompiledCodePaths.add(outputResource.getLocation().toOSString());
- }
- }
- } catch (CoreException exception) {
- // can't query the project nature? ignore
- }
-
- } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
- handleClasspathLibrary(entry, wsRoot, resMarker);
- } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
- // get the container
- try {
- IClasspathContainer container = JavaCore.getClasspathContainer(
- entry.getPath(), javaProject);
- // ignore the system and default_system types as they represent
- // libraries that are part of the runtime.
- if (container != null && container.getKind() == IClasspathContainer.K_APPLICATION) {
- IClasspathEntry[] entries = container.getClasspathEntries();
- for (IClasspathEntry cpe : entries) {
- handleCPE(cpe, javaProject, wsRoot, resMarker);
- }
- }
- } catch (JavaModelException jme) {
- // can't resolve the container? ignore it.
- AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath());
- }
- }
- }
-
- private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot,
- ResourceMarker resMarker) {
- // get the IPath
- IPath path = e.getPath();
-
- IResource resource = wsRoot.findMember(path);
-
- if (resource != null && resource.getType() == IResource.PROJECT) {
- // if it's a project we should just ignore it because it's going to be added
- // later when we add all the referenced projects.
-
- } else if (SdkConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
- // case of a jar file (which could be relative to the workspace or a full path)
- if (resource != null && resource.exists() &&
- resource.getType() == IResource.FILE) {
- mCompiledCodePaths.add(resource.getLocation().toOSString());
- } else {
- // if the jar path doesn't match a workspace resource,
- // then we get an OSString and check if this links to a valid file.
- String osFullPath = path.toOSString();
-
- File f = new File(osFullPath);
- if (f.isFile()) {
- mCompiledCodePaths.add(osFullPath);
- } else {
- String message = String.format( Messages.Couldnt_Locate_s_Error,
- path);
- // always output to the console
- mOutStream.println(message);
-
- // put a marker
- if (resMarker != null) {
- resMarker.setWarning(mProject, message);
- }
- }
- }
- } else {
- // this can be the case for a class folder.
- if (resource != null && resource.exists() &&
- resource.getType() == IResource.FOLDER) {
- mCompiledCodePaths.add(resource.getLocation().toOSString());
- } else {
- // if the path doesn't match a workspace resource,
- // then we get an OSString and check if this links to a valid folder.
- String osFullPath = path.toOSString();
-
- File f = new File(osFullPath);
- if (f.isDirectory()) {
- mCompiledCodePaths.add(osFullPath);
- }
- }
- }
- }
-
- /**
- * Checks a {@link IFile} to make sure it should be packaged as standard resources.
- * @param file the IFile representing the file.
- * @return true if the file should be packaged as standard java resources.
- */
- public static boolean checkFileForPackaging(IFile file) {
- String name = file.getName();
-
- String ext = file.getFileExtension();
- return ApkBuilder.checkFileForPackaging(name, ext);
- }
-
- /**
- * Checks whether an {@link IFolder} and its content is valid for packaging into the .apk as
- * standard Java resource.
- * @param folder the {@link IFolder} to check.
- */
- public static boolean checkFolderForPackaging(IFolder folder) {
- String name = folder.getName();
- return ApkBuilder.checkFolderForPackaging(name);
- }
-
- /**
- * Returns a list of {@link IJavaProject} matching the provided {@link IProject} objects.
- * @param projects the IProject objects.
- * @return a new list object containing the IJavaProject object for the given IProject objects.
- * @throws CoreException
- */
- public static List<IJavaProject> getJavaProjects(List<IProject> projects) throws CoreException {
- ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
-
- for (IProject p : projects) {
- if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
-
- list.add(JavaCore.create(p));
- }
- }
-
- return list;
- }
-
- /**
- * Get the stderr output of a process and return when the process is done.
- * @param process The process to get the output from
- * @param stderr The array to store the stderr output
- * @return the process return code.
- * @throws InterruptedException
- */
- public final static int grabProcessOutput(
- final IProject project,
- final Process process,
- final ArrayList<String> stderr)
- throws InterruptedException {
-
- return GrabProcessOutput.grabProcessOutput(
- process,
- Wait.WAIT_FOR_READERS, // we really want to make sure we get all the output!
- new IProcessOutput() {
-
- @SuppressWarnings("unused")
- @Override
- public void out(@Nullable String line) {
- if (line != null) {
- // If benchmarking always print the lines that
- // correspond to benchmarking info returned by ADT
- if (BENCHMARK_FLAG && line.startsWith("BENCHMARK:")) { //$NON-NLS-1$
- AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS,
- project, line);
- } else {
- AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE,
- project, line);
- }
- }
- }
-
- @Override
- public void err(@Nullable String line) {
- if (line != null) {
- stderr.add(line);
- if (BuildVerbosity.VERBOSE == AdtPrefs.getPrefs().getBuildVerbosity()) {
- AdtPlugin.printErrorToConsole(project, line);
- }
- }
- }
- });
- }
-}