diff --git a/mobile/android/gradle/with_gecko_binaries.gradle b/mobile/android/gradle/with_gecko_binaries.gradle index ec1f9e6b908b..27fd71877f56 100644 --- a/mobile/android/gradle/with_gecko_binaries.gradle +++ b/mobile/android/gradle/with_gecko_binaries.gradle @@ -7,11 +7,39 @@ evaluationDependsOn(':annotations') import groovy.util.FileNameFinder +import groovy.transform.Memoized import java.nio.file.Path import java.nio.file.Paths import java.security.MessageDigest +// To find the LLVM tools from the Android NDK, there are a few wrinkles. In a compiled build, +// we can use our own `ANDROID_NDK` configure option. But in an artifact build, that isn't +// defined, so we fall back to `android.ndkDirectory` -- but that's defined in +// `local.properties`, which may not define it. In that case, fall back to crawling the +// filesystem. +@Memoized +def getNDKDirectory() { + if (project.mozconfig.substs.ANDROID_NDK) { + return project.mozconfig.substs.ANDROID_NDK + } + if (project.android.ndkDirectory) { + return project.android.ndkDirectory + } + def mozbuild = System.getenv('MOZBUILD_STATE_PATH') ?: "${System.getProperty('user.home')}/.mozbuild" + def files = new FileNameFinder().getFileNames(mozbuild, "android-ndk-*/source.properties") + if (files) { + // It would be nice to sort these by version, but that's too much effort right now. + return project.file(files.first()).parentFile.toString() + } + return null +} + +ext.getNDKDirectory = { + // This is the easiest way to expose the memoized function to consumers. + getNDKDirectory() +} + // Bug 1657190: This task works around a bug in the Android-Gradle plugin. When using SNAPSHOT // builds (and possibly in other situations) the JNI library invalidation process isn't correct. If // there are two JNI libs `a.so` and `b.so` and a new snapshot updates only `a.so`, then the @@ -26,7 +54,7 @@ import java.security.MessageDigest // and use this as our own Mozilla-specific "library generation ID". We then add our own // Mozilla-specific ELF section to every library so that they will all be invalidated by the // Android-Gradle plugin of a consuming project. -class SyncLibsAndUpdateGeneration extends DefaultTask { +class SyncLibsAndUpdateGenerationID extends DefaultTask { @InputDirectory File source @@ -36,34 +64,12 @@ class SyncLibsAndUpdateGeneration extends DefaultTask { @OutputDirectory File destinationDir - // To find the LLVM tools from the Android NDK, there are a few wrinkles. In a compiled build, - // we can use our own `ANDROID_NDK` configure option. But in an artifact build, that isn't - // defined, so we fall back to `android.ndkDirectory` -- but that's defined in - // `local.properties`, which may not define it. In that case, fall back to crawling the - // filesystem. - @Input - String ndkDirectory = { - if (project.mozconfig.substs.ANDROID_NDK) { - return project.mozconfig.substs.ANDROID_NDK - } - if (project.android.ndkDirectory) { - return project.android.ndkDirectory - } - def mozbuild = System.getenv('MOZBUILD_STATE_PATH') ?: "${System.getProperty('user.home')}/.mozbuild" - project.logger.lifecycle("mozbuild: ${mozbuild}") - def files = new FileNameFinder().getFileNames(mozbuild, "android-ndk-*/source.properties") - if (files) { - // It would be nice to sort these by version, but that's too much effort right now. - return project.file(files.first()).parentFile.toString() - } - throw new GradleException("Could not determine Android NDK directory. Set `ndk.dir` in `${project.topsrcdir}/local.properties`") - }() - // The `**` in the pattern depends on the host architecture. We could compute them or bake them // in, but this is easy enough. `FileNameFinder` won't return a directory, so we find a file // and return its parent directory. @Input - File llvmBin = project.file(new FileNameFinder().getFileNames(ndkDirectory, "toolchains/llvm/prebuilt/**/bin/llvm-*").first()).parentFile + File llvmBin = project.file(new FileNameFinder().getFileNames(project.ext.getNDKDirectory(), "toolchains/llvm/prebuilt/**/bin/llvm-*") + .first()).parentFile // Sibling to `.note.gnu.build-id`. @Input @@ -178,12 +184,25 @@ ext.configureVariantWithGeckoBinaries = { variant -> } // For !MOZILLA_OFFICIAL builds, work around an Android-Gradle plugin bug that causes startup - // crashes with local substitution. See class comment above. - def syncLibsFromDistDir = { if (!mozconfig.substs.MOZILLA_OFFICIAL) { + // crashes with local substitution. But -- we want to allow artifact builds that don't have the + // NDK installed. See class comment above. + def shouldUpdateGenerationID = { + if (mozconfig.substs.MOZILLA_OFFICIAL) { + return false + } else if (ext.getNDKDirectory() == null) { + logger.warn("Could not determine Android NDK directory.") + logger.warn("Set `ndk.dir` in `${project.topsrcdir}/local.properties` to avoid startup crashes when using `substitute-local-geckoview.gradle`.") + logger.warn("See https://bugzilla.mozilla.org/show_bug.cgi?id=1657190.") + return false + } + return true + }() + + def syncLibsFromDistDir = { if (shouldUpdateGenerationID) { def jarTask = tasks["bundleLibRuntime${variant.name.capitalize()}"] def bundleJar = jarTask.outputs.files.find({ it.name == 'classes.jar' }) - task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: SyncLibsAndUpdateGeneration) { + task("syncLibsAndUpdateGenerationIDFromDistDirFor${variant.name.capitalize()}", type: SyncLibsAndUpdateGenerationID) { source file("${distDir}/lib") destinationDir file("${project.buildDir}/moz.build/src/${variant.name}/jniLibs") // Include the hash of classes.jar as well, so that JVM-only changes don't leave every