Bug 1384312 - Support generating JNI wrappers under --with-gradle, r=nalexander
MozReview-Commit-ID: HECL60Ggeqn
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -352,16 +352,20 @@ android.applicationVariants.all { varian
// :app uses :geckoview:release and handles it's own Gecko binary inclusion,
// even though this would be most naturally done in the :geckoview project.
if (!audienceDimension.equals('official')) {
configureVariantWithGeckoBinaries(variant)
}
}
+android.applicationVariants.all { variant ->
+ configureVariantWithJNIWrappers(variant, "Fennec")
+}
+
apply plugin: 'spoon'
spoon {
// For now, let's be verbose.
debug = true
// It's not helpful to pass when we don't have a device connected.
failIfNoDeviceConnected = true
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -20,16 +20,18 @@ GARBAGE += \
GeneratedJNIWrappers.h \
FennecJNINatives.h \
FennecJNIWrappers.cpp \
FennecJNIWrappers.h \
$(NULL)
GARBAGE_DIRS += classes db jars res sync services generated
+gradle_dir := $(topobjdir)/gradle/build/mobile/android
+
# The bootclasspath is functionally identical to the classpath, but allows the
# classes given to redefine classes in core packages, such as java.lang.
# android.jar is here as it provides Android's definition of the Java Standard
# Library. The compatability lib here tweaks a few of the core classes to paint
# over changes in behaviour between versions.
JAVA_BOOTCLASSPATH := \
$(ANDROID_SDK)/android.jar \
$(NULL)
@@ -136,16 +138,17 @@ endif
# java_bundled_libs. See the note above.
# uniq purloined from http://stackoverflow.com/a/16151140.
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
java_bundled_libs := $(call uniq,$(java_bundled_libs))
java_bundled_libs := $(subst $(NULL) ,:,$(strip $(java_bundled_libs)))
+ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
GECKOVIEW_JARS = \
constants.jar \
gecko-R.jar \
gecko-mozglue.jar \
gecko-util.jar \
gecko-view.jar \
sync-thirdparty.jar \
$(NULL)
@@ -161,32 +164,41 @@ endif
ifdef MOZ_INSTALL_TRACKING
GECKOVIEW_JARS += gecko-thirdparty-adjust_sdk.jar
endif
ifdef MOZ_ANDROID_MMA
GECKOVIEW_JARS += gecko-thirdparty-leanplum_sdk.jar
endif
-geckoview_jars_classpath := $(subst $(NULL) ,:,$(strip $(GECKOVIEW_JARS)))
-
FENNEC_JARS = \
gecko-browser.jar \
gecko-thirdparty.jar \
services.jar \
$(NULL)
ifdef MOZ_ANDROID_SEARCH_ACTIVITY
FENNEC_JARS += search-activity.jar
endif
ifdef MOZ_ANDROID_MLS_STUMBLER
FENNEC_JARS += ../stumbler/stumbler.jar
endif
+else # MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
+
+GECKOVIEW_JARS := $(gradle_dir)/geckoview/intermediates/bundles/debug/classes.jar
+FENNEC_JARS := $(gradle_dir)/app/intermediates/packaged/officialPhoton/debug/classes.jar
+
+$(GECKOVIEW_JARS): .gradle.deps
+$(FENNEC_JARS): .gradle.deps
+
+endif # MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
+
+geckoview_jars_classpath := $(subst $(NULL) ,:,$(strip $(GECKOVIEW_JARS)))
# All the jars we're compiling from source. (not to be confused with
# java_bundled_libs, which holds the jars which we're including as binaries).
ALL_JARS = \
$(GECKOVIEW_JARS) \
$(FENNEC_JARS) \
$(NULL)
@@ -223,32 +235,40 @@ library_jars := \
# MOZ_ANDROID_MMA requires MOZ_INSTALL_TRACKING, so we don't need a
# separate clause for MMA (Leanplum) support.
ifdef MOZ_INSTALL_TRACKING
library_jars += $(ANDROID_SDK)/optional/org.apache.http.legacy.jar
endif # MOZ_INSTALL_TRACKING
library_jars := $(subst $(NULL) ,:,$(strip $(library_jars)))
-gradle_dir := $(topobjdir)/gradle/build/mobile/android
-
ifdef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
.gradle.deps: .aapt.deps FORCE
@$(TOUCH) $@
$(topsrcdir)/mach gradle \
- app:assembleOfficialPhotonDebug app:assembleOfficialPhotonDebugAndroidTest -x lint
+ geckoview:generateJNIWrappersForGeneratedRelease \
+ app:generateJNIWrappersForFennecOfficialPhotonDebug \
+ app:assembleOfficialPhotonDebug \
+ app:assembleOfficialPhotonDebugAndroidTest \
+ -x lint
classes.dex: .gradle.deps
$(REPORT_BUILD)
cp $(gradle_dir)/app/intermediates/transforms/dex/officialPhoton/debug/folders/1000/1f/main/classes.dex $@
+
+GeneratedJNIWrappers.cpp GeneratedJNIWrappers.h GeneratedJNINatives.h : .gradle.deps
+ $(REPORT_BUILD)
+
+FennecJNIWrappers.cpp FennecJNIWrappers.h FennecJNINatives.h: .gradle.deps
+ $(REPORT_BUILD)
+
else
classes.dex: .proguard.deps
$(REPORT_BUILD)
$(DX) --dex --output=classes.dex --force-jumbo jars-proguarded
-endif
ifdef MOZ_DISABLE_PROGUARD
PROGUARD_PASSES=0
else
ifdef MOZ_DEBUG
PROGUARD_PASSES=1
else
ifndef MOZILLA_OFFICIAL
@@ -323,16 +343,18 @@ GeneratedJNIWrappers.cpp: $(ANNOTATION_P
# This annotation processing step also generates
# FennecJNIWrappers.h and FennecJNINatives.h
FennecJNIWrappers.cpp: $(ANNOTATION_PROCESSOR_JAR_FILES) $(FENNEC_JARS)
$(JAVA) -classpath $(all_jars_classpath):$(JAVA_BOOTCLASSPATH):$(JAVA_CLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) \
org.mozilla.gecko.annotationProcessors.AnnotationProcessor \
Fennec $(FENNEC_JARS)
+endif # MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
+
include $(topsrcdir)/config/rules.mk
not_android_res_files := \
*.mkdir.done* \
*.DS_Store* \
*\#* \
*.rej \
*.orig \
@@ -531,17 +553,16 @@ gradle-omnijar:
endif
.PHONY: gradle-targets gradle-omnijar
# GeneratedJNIWrappers.cpp target also generates
# GeneratedJNIWrappers.h and GeneratedJNINatives.h
# FennecJNIWrappers.cpp target also generates
# FennecJNIWrappers.h and FennecJNINatives.h
-ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
# List of build flags used by auto-generated JNI bindings (through the
# @BuildFlag annotation in Java). For example, add a "MOZ_FOO \" line to this
# list to support @BuildFlag(MOZ_FOO).
BINDING_BUILD_FLAGS = \
$(NULL)
# Preprocess a JNI binding file using the build flags defined above.
@@ -581,21 +602,22 @@ libs:: FennecJNIWrappers.cpp
echo '*** Error: The Fennec JNI code has changed ***' && \
echo '* To update generated code in the tree, please run *' && \
echo && \
echo ' make -C $(CURDIR) update-fennec-wrappers' && \
echo && \
echo '* Repeat the build, and check in any changes. *' && \
echo '*****************************************************' && \
exit 1)
-endif
libs:: classes.dex
$(INSTALL) classes.dex $(FINAL_TARGET)
+ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
+
# Generate Java binder interfaces from AIDL files.
GECKOVIEW_AIDLS = \
org/mozilla/gecko/IGeckoEditableChild.aidl \
org/mozilla/gecko/IGeckoEditableParent.aidl \
org/mozilla/gecko/gfx/ISurfaceAllocator.aidl \
org/mozilla/gecko/media/ICodec.aidl \
org/mozilla/gecko/media/ICodecCallbacks.aidl \
org/mozilla/gecko/media/IMediaDrmBridge.aidl \
@@ -618,8 +640,10 @@ FENNEC_AIDLS = \
fennec_aidl_src_path := $(srcdir)/aidl
fennec_aidl_target_path := generated
fennec_aidl_targets := $(addprefix $(fennec_aidl_target_path)/,$(patsubst %.aidl,%.java,$(FENNEC_AIDLS:.java=)))
$(fennec_aidl_targets): $(fennec_aidl_target_path)/%.java: $(fennec_aidl_src_path)/%.aidl
@echo "Processing AIDL: $< => $@"
$(AIDL) -p$(ANDROID_SDK)/framework.aidl -I$(fennec_aidl_src_path) -I$(geckoview_aidl_src_path) -o$(fennec_aidl_target_path) $<
+
+endif # MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -162,16 +162,20 @@ android.libraryVariants.all { variant ->
task "sourcesJar${name.capitalize()}"(type: Jar) {
classifier 'sources'
description = "Generate Javadoc for build variant $name"
destinationDir = new File(destinationDir, variant.baseName)
from files(variant.javaCompile.source)
}
}
+android.libraryVariants.all { variant ->
+ configureVariantWithJNIWrappers(variant, "Generated")
+}
+
apply plugin: 'maven'
uploadArchives {
repositories.mavenDeployer {
pom.groupId = 'org.mozilla'
pom.artifactId = 'geckoview'
pom.version = VERSION_NAME
pom.project {
--- a/mobile/android/gradle/with_gecko_binaries.gradle
+++ b/mobile/android/gradle/with_gecko_binaries.gradle
@@ -120,8 +120,59 @@ ext.configureVariantWithGeckoBinaries =
generateAssetsTask.dependsOn syncLibsFromDistDir
generateAssetsTask.dependsOn syncAssetsFromDistDir
def sourceSet = productFlavor ? "${productFlavor}${buildType.capitalize()}" : buildType
android.sourceSets."${sourceSet}".assets.srcDir syncOmnijarFromDistDir.destinationDir
android.sourceSets."${sourceSet}".assets.srcDir syncAssetsFromDistDir.destinationDir
android.sourceSets."${sourceSet}".jniLibs.srcDir syncLibsFromDistDir.destinationDir
}
+
+ext.configureVariantWithJNIWrappers = { variant, module ->
+
+ def jarTask = tasks.findByName("jar${variant.name.capitalize()}Classes")
+ if (jarTask == null) {
+ jarTask = tasks.findByName("package${variant.name.capitalize()}JarArtifact")
+ }
+ if (jarTask == null) {
+ throw new GradleException("Jar task not found: \"jar${variant.name.capitalize()}Classes\"\t\"package${variant.name.capitalize()}JarArtifact\"" )
+ }
+ if (jarTask.outputs.files.size() != 1) {
+ throw new GradleException("Jar task output multiple files other than one single jar")
+ }
+
+ // At configuration time, the classpath of dependencies with internal_impl
+ // JAR files may not be correct. This manifests in
+ //
+ // 'Exception in thread "main" java.lang.NoClassDefFoundError: android/support/v4/app/ActivityCompatApi23$RequestPermissionsRequestCodeValidator'
+ //
+ // when running |mach gradle clean app:generateJNI...|. We work around this
+ // by configuring the classpath at evaluation-time, not configuration-time.
+ //
+ // The specific dependency on the `prepareDependencies` task may not be
+ // necessary, but commits like
+ // https://github.com/evant/gradle-retrolambda/commit/15108c65ee43be499a1359d9d4f88b0851d46769
+ // suggest that it is. It certainly doesn't hurt.
+ def prepareDependenciesTask = tasks.getByName("prepare${variant.name.capitalize()}Dependencies")
+
+ def wrapperTask = task("generateJNIWrappersFor${module}${variant.name.capitalize()}", type: JavaExec) {
+ classpath "${topobjdir}/build/annotationProcessors/annotationProcessors.jar"
+
+ // Configure the classpath at evaluation-time, not at
+ // configuration-time: see above comment.
+ doFirst {
+ classpath variant.javaCompile.classpath
+ // Include android.jar.
+ classpath variant.javaCompile.options.bootClasspath
+ }
+
+ main = 'org.mozilla.gecko.annotationProcessors.AnnotationProcessor'
+ args module
+ args jarTask.outputs.files.iterator().next()
+
+ workingDir "${topobjdir}/mobile/android/base"
+
+ dependsOn jarTask
+ dependsOn prepareDependenciesTask
+ }
+
+ variant.assemble.dependsOn wrapperTask
+}