From d3cc5cac69f3e2229a353554f6f50d969610ce3d Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 12 Nov 2013 09:36:20 -0800 Subject: NDK Integration first pass. Change-Id: Ib34a975c5bbbc559fc20f3b582566e7e3d69044b --- .../java/com/android/builder/AndroidBuilder.java | 20 ++++++-- .../java/com/android/builder/DefaultSdkParser.java | 10 +++- .../com/android/builder/PlatformSdkParser.java | 6 +++ .../main/java/com/android/builder/SdkParser.java | 7 +++ .../com/android/builder/VariantConfiguration.java | 2 +- .../builder/internal/packaging/Packager.java | 11 +++-- .../android/builder/testing/ConnectedDevice.java | 17 ++++++- .../android/builder/testing/SimpleTestRunner.java | 54 +++++++++++++++++----- .../java/com/android/builder/testing/TestData.java | 4 ++ 9 files changed, 108 insertions(+), 23 deletions(-) (limited to 'builder') diff --git a/builder/src/main/java/com/android/builder/AndroidBuilder.java b/builder/src/main/java/com/android/builder/AndroidBuilder.java index 9a6fa79..83e345d 100644 --- a/builder/src/main/java/com/android/builder/AndroidBuilder.java +++ b/builder/src/main/java/com/android/builder/AndroidBuilder.java @@ -65,6 +65,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -166,6 +167,7 @@ public class AndroidBuilder { /** * Helper method to get the boot classpath to be used during compilation. */ + @NonNull public static List getBootClasspath(@NonNull SdkParser sdkParser) { List classpath = Lists.newArrayList(); @@ -195,12 +197,18 @@ public class AndroidBuilder { * Returns an {@link AaptRunner} able to run aapt commands. * @return an AaptRunner object */ + @NonNull public AaptRunner getAaptRunner() { return new AaptRunner( mBuildTools.getPath(BuildToolInfo.PathId.AAPT), mCmdLineRunner); } + @NonNull + public CommandLineRunner getCommandLineRunner() { + return mCmdLineRunner; + } + /** * Generate the BuildConfig class for the project. * @param packageName the package in which to generate the class @@ -1074,7 +1082,8 @@ public class AndroidBuilder { * @param classesDexLocation the location of the classes.dex file * @param packagedJars the jars that are packaged (libraries + jar dependencies) * @param javaResourcesLocation the processed Java resource folder - * @param jniLibsLocation the location of the compiled JNI libraries + * @param jniLibsFolders the folders containing jni shared libraries + * @param abiFilters optional ABI filter * @param jniDebugBuild whether the app should include jni debug data * @param signingConfig the signing configuration * @param outApkLocation location of the APK. @@ -1091,7 +1100,8 @@ public class AndroidBuilder { @NonNull String classesDexLocation, @NonNull List packagedJars, @Nullable String javaResourcesLocation, - @Nullable String jniLibsLocation, + @Nullable Collection jniLibsFolders, + @Nullable Set abiFilters, boolean jniDebugBuild, @Nullable SigningConfig signingConfig, @NonNull String outApkLocation) throws DuplicateFileException, FileNotFoundException, @@ -1128,8 +1138,10 @@ public class AndroidBuilder { } // also add resources from library projects and jars - if (jniLibsLocation != null) { - packager.addNativeLibraries(jniLibsLocation); + if (jniLibsFolders != null) { + for (File jniFolder : jniLibsFolders) { + packager.addNativeLibraries(jniFolder, abiFilters); + } } packager.sealApk(); diff --git a/builder/src/main/java/com/android/builder/DefaultSdkParser.java b/builder/src/main/java/com/android/builder/DefaultSdkParser.java index 3f52971..6244fb9 100644 --- a/builder/src/main/java/com/android/builder/DefaultSdkParser.java +++ b/builder/src/main/java/com/android/builder/DefaultSdkParser.java @@ -50,6 +50,7 @@ import static com.android.SdkConstants.FN_SOURCE_PROP; public class DefaultSdkParser implements SdkParser { private final String mSdkLocation; + private final File mNdkLocation; private SdkManager mManager; private IAndroidTarget mTarget; @@ -60,12 +61,13 @@ public class DefaultSdkParser implements SdkParser { private File mAdb; private File mZipAlign; - public DefaultSdkParser(@NonNull String sdkLocation) { + public DefaultSdkParser(@NonNull String sdkLocation, @Nullable File ndkLocation) { if (!sdkLocation.endsWith(File.separator)) { mSdkLocation = sdkLocation + File.separator; } else { mSdkLocation = sdkLocation; } + mNdkLocation = ndkLocation; } @Override @@ -211,4 +213,10 @@ public class DefaultSdkParser implements SdkParser { return mTools; } + + @Nullable + @Override + public File getNdkLocation() { + return mNdkLocation; + } } diff --git a/builder/src/main/java/com/android/builder/PlatformSdkParser.java b/builder/src/main/java/com/android/builder/PlatformSdkParser.java index 3325ea0..d0e1828 100644 --- a/builder/src/main/java/com/android/builder/PlatformSdkParser.java +++ b/builder/src/main/java/com/android/builder/PlatformSdkParser.java @@ -165,4 +165,10 @@ public class PlatformSdkParser implements SdkParser { } return mHostTools; } + + @Nullable + @Override + public File getNdkLocation() { + return null; + } } diff --git a/builder/src/main/java/com/android/builder/SdkParser.java b/builder/src/main/java/com/android/builder/SdkParser.java index 7c4e0c2..c247694 100644 --- a/builder/src/main/java/com/android/builder/SdkParser.java +++ b/builder/src/main/java/com/android/builder/SdkParser.java @@ -94,6 +94,13 @@ public interface SdkParser { @NonNull File getAdb(); + /** + * Returns the location of artifact repositories built-in the SDK. + * @return a non null list of repository folders. + */ @NonNull List getRepositories(); + + @Nullable + File getNdkLocation(); } \ No newline at end of file diff --git a/builder/src/main/java/com/android/builder/VariantConfiguration.java b/builder/src/main/java/com/android/builder/VariantConfiguration.java index 10994db..a5978d4 100644 --- a/builder/src/main/java/com/android/builder/VariantConfiguration.java +++ b/builder/src/main/java/com/android/builder/VariantConfiguration.java @@ -948,7 +948,7 @@ public class VariantConfiguration implements TestData { @Nullable @Override public Set getSupportedAbis() { - // no ndk support yet, so return null + // TODO no ndk support yet, so return null return null; } } diff --git a/builder/src/main/java/com/android/builder/internal/packaging/Packager.java b/builder/src/main/java/com/android/builder/internal/packaging/Packager.java index 445d607..f60323e 100644 --- a/builder/src/main/java/com/android/builder/internal/packaging/Packager.java +++ b/builder/src/main/java/com/android/builder/internal/packaging/Packager.java @@ -39,6 +39,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.regex.Pattern; @@ -402,7 +403,7 @@ public final class Packager implements IArchiveBuilder { * * This may or may not copy gdbserver into the apk based on whether the debug mode is set. * - * @param jniLibLocation the root folder containing the abi folders which contain the .so + * @param nativeFolder the root folder containing the abi folders which contain the .so * * @throws PackagerException if an error occurred * @throws SealedPackageException if the APK is already sealed. @@ -411,14 +412,12 @@ public final class Packager implements IArchiveBuilder { * * @see #setJniDebugMode(boolean) */ - public void addNativeLibraries(String jniLibLocation) + public void addNativeLibraries(@NonNull File nativeFolder, @Nullable Set abiFilters) throws PackagerException, SealedPackageException, DuplicateFileException { if (mIsSealed) { throw new SealedPackageException("APK is already sealed"); } - File nativeFolder = new File(jniLibLocation); - if (!nativeFolder.isDirectory()) { // not a directory? check if it's a file or doesn't exist if (nativeFolder.exists()) { @@ -434,6 +433,10 @@ public final class Packager implements IArchiveBuilder { if (abiList != null) { for (File abi : abiList) { + if (abiFilters != null && !abiFilters.contains(abi.getName())) { + continue; + } + if (abi.isDirectory()) { // ignore files File[] libs = abi.listFiles(); diff --git a/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java b/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java index 8a1aa64..7e6ae77 100644 --- a/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java +++ b/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java @@ -25,9 +25,11 @@ import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import com.android.utils.ILogger; +import com.google.common.collect.Lists; import java.io.File; import java.io.IOException; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -115,8 +117,19 @@ public class ConnectedDevice extends DeviceConnector { @NonNull @Override - public String getAbi() { - return null; //To change body of implemented methods use File | Settings | File Templates. + public List getAbis() { + List abis = Lists.newArrayListWithExpectedSize(2); + String abi = iDevice.getProperty(IDevice.PROP_DEVICE_CPU_ABI); + if (abi != null) { + abis.add(abi); + } + + abi = iDevice.getProperty(IDevice.PROP_DEVICE_CPU_ABI2); + if (abi != null) { + abis.add(abi); + } + + return abis; } @Override diff --git a/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java b/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java index 85114d4..237d871 100644 --- a/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java +++ b/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java @@ -26,6 +26,7 @@ import com.android.utils.ILogger; import java.io.File; import java.util.List; +import java.util.Set; /** * Basic {@link TestRunner} running tests on all devices. @@ -47,21 +48,11 @@ public class SimpleTestRunner implements TestRunner { WaitableExecutor executor = new WaitableExecutor(maxThreads); - int minSdkVersion = testData.getMinSdkVersion(); for (DeviceConnector device : deviceList) { - int deviceApiLevel = device.getApiLevel(); - if (minSdkVersion <= deviceApiLevel) { + if (filterOutDevice(device, testData, logger, projectName, variantName)) { executor.execute(new SimpleTestCallable(device, projectName, variantName, testApk, testedApk, testData, resultsDir, timeout, logger)); - } else { - if (deviceApiLevel == 0) { - logger.info("Skipping device '%s' for '%s:%s': Unknown API Level", - device.getName(), projectName, variantName); - } else { - logger.info("Skipping device '%s' for '%s:%s'", - device.getName(), projectName, variantName); - } } } @@ -82,4 +73,45 @@ public class SimpleTestRunner implements TestRunner { return success; } + + private boolean filterOutDevice(@NonNull DeviceConnector device, @NonNull TestData testData, + @NonNull ILogger logger, + @NonNull String projectName, @NonNull String variantName) { + int deviceApiLevel = device.getApiLevel(); + if (deviceApiLevel == 0) { + logger.info("Skipping device '%s' for '%s:%s': Unknown API Level", + device.getName(), projectName, variantName); + return false; + } + + if (testData.getMinSdkVersion() > deviceApiLevel) { + logger.info("Skipping device '%s' for '%s:%s'", + device.getName(), projectName, variantName); + + return false; + } + + Set appAbis = testData.getSupportedAbis(); + if (appAbis != null) { + List deviceAbis = device.getAbis(); + if (deviceAbis == null || deviceAbis.isEmpty()) { + logger.info("Skipping device '%s' for '%s:%s': Unknown ABI", + device.getName(), projectName, variantName); + return false; + } + + boolean compatibleAbi = false; + for (String deviceAbi : deviceAbis) { + if (appAbis.contains(deviceAbi)) { + compatibleAbi = true; + } + } + + if (!compatibleAbi) { + return false; + } + } + + return true; + } } diff --git a/builder/src/main/java/com/android/builder/testing/TestData.java b/builder/src/main/java/com/android/builder/testing/TestData.java index 0bc7b61..a736026 100644 --- a/builder/src/main/java/com/android/builder/testing/TestData.java +++ b/builder/src/main/java/com/android/builder/testing/TestData.java @@ -52,6 +52,10 @@ public interface TestData { int getMinSdkVersion(); + /** + * List of supported ABIs. Null means all. + * @return a list of abi or null for all + */ @Nullable Set getSupportedAbis(); } -- cgit v1.2.3