Add support for java annotation processors

Add annotation_processor and annotation_processor_classes properties.

Test: m -j checkbuild
Change-Id: I41a6cd42f0c048070a99cb18af150030170498f7
diff --git a/java/java.go b/java/java.go
index b76c2a4..b4ed207 100644
--- a/java/java.go
+++ b/java/java.go
@@ -99,6 +99,12 @@
 
 	// If set to false, don't allow this module to be installed.  Defaults to true.
 	Installable *bool
+
+	// List of modules to use as annotation processors
+	Annotation_processors []string
+
+	// List of classes to pass to javac to use as annotation processors
+	Annotation_processor_classes []string
 }
 
 type CompilerDeviceProperties struct {
@@ -162,11 +168,12 @@
 }
 
 var (
-	staticLibTag     = dependencyTag{name: "staticlib"}
-	libTag           = dependencyTag{name: "javalib"}
-	bootClasspathTag = dependencyTag{name: "bootclasspath"}
-	frameworkResTag  = dependencyTag{name: "framework-res"}
-	sdkDependencyTag = dependencyTag{name: "sdk"}
+	staticLibTag           = dependencyTag{name: "staticlib"}
+	libTag                 = dependencyTag{name: "javalib"}
+	bootClasspathTag       = dependencyTag{name: "bootclasspath"}
+	frameworkResTag        = dependencyTag{name: "framework-res"}
+	sdkDependencyTag       = dependencyTag{name: "sdk"}
+	annotationProcessorTag = dependencyTag{name: "annotation processor"}
 )
 
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
@@ -195,6 +202,7 @@
 	}
 	ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
 	ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
+	ctx.AddDependency(ctx.Module(), annotationProcessorTag, j.properties.Annotation_processors...)
 
 	android.ExtractSourcesDeps(ctx, j.properties.Srcs)
 }
@@ -221,9 +229,18 @@
 	return flags
 }
 
-func (j *Module) collectDeps(ctx android.ModuleContext) (classpath, bootClasspath, staticJars,
-	aidlIncludeDirs, srcFileLists android.Paths, aidlPreprocess android.OptionalPath) {
+type deps struct {
+	classpath            android.Paths
+	bootClasspath        android.Paths
+	staticJars           android.Paths
+	aidlIncludeDirs      android.Paths
+	srcFileLists         android.Paths
+	annotationProcessors android.Paths
+	aidlPreprocess       android.OptionalPath
+}
 
+func (j *Module) collectDeps(ctx android.ModuleContext) deps {
+	var deps deps
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -240,50 +257,60 @@
 
 		switch tag {
 		case bootClasspathTag:
-			bootClasspath = append(bootClasspath, dep.ClasspathFiles()...)
+			deps.bootClasspath = append(deps.bootClasspath, dep.ClasspathFiles()...)
 		case libTag:
-			classpath = append(classpath, dep.ClasspathFiles()...)
+			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
 		case staticLibTag:
-			classpath = append(classpath, dep.ClasspathFiles()...)
-			staticJars = append(staticJars, dep.ClasspathFiles()...)
+			deps.classpath = append(deps.classpath, dep.ClasspathFiles()...)
+			deps.staticJars = append(deps.staticJars, dep.ClasspathFiles()...)
+		case annotationProcessorTag:
+			deps.annotationProcessors = append(deps.annotationProcessors, dep.ClasspathFiles()...)
 		case frameworkResTag:
 			if ctx.ModuleName() == "framework" {
 				// framework.jar has a one-off dependency on the R.java and Manifest.java files
 				// generated by framework-res.apk
-				srcFileLists = append(srcFileLists, module.(*AndroidApp).aaptJavaFileList)
+				deps.srcFileLists = append(deps.srcFileLists, module.(*AndroidApp).aaptJavaFileList)
 			}
 		case sdkDependencyTag:
 			sdkDep := module.(sdkDependency)
-			bootClasspath = append(bootClasspath, sdkDep.ClasspathFiles()...)
+			deps.bootClasspath = append(deps.bootClasspath, sdkDep.ClasspathFiles()...)
 			if sdkDep.AidlPreprocessed().Valid() {
-				if aidlPreprocess.Valid() {
+				if deps.aidlPreprocess.Valid() {
 					ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
-						aidlPreprocess, sdkDep.AidlPreprocessed())
+						deps.aidlPreprocess, sdkDep.AidlPreprocessed())
 				} else {
-					aidlPreprocess = sdkDep.AidlPreprocessed()
+					deps.aidlPreprocess = sdkDep.AidlPreprocessed()
 				}
 			}
 		default:
 			panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 		}
 
-		aidlIncludeDirs = append(aidlIncludeDirs, dep.AidlIncludeDirs()...)
+		deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 	})
 
-	return
+	return deps
 }
 
 func (j *Module) compile(ctx android.ModuleContext) {
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Export_aidl_include_dirs)
 
-	classpath, bootClasspath, staticJars, aidlIncludeDirs, srcFileLists,
-		aidlPreprocess := j.collectDeps(ctx)
+	deps := j.collectDeps(ctx)
 
 	var flags javaBuilderFlags
 
 	javacFlags := j.properties.Javacflags
 
+	if len(deps.annotationProcessors) > 0 {
+		javacFlags = append(javacFlags,
+			"-processorpath "+strings.Join(deps.annotationProcessors.Strings(), ":"))
+	}
+
+	for _, c := range j.properties.Annotation_processor_classes {
+		javacFlags = append(javacFlags, "-processor "+c)
+	}
+
 	if j.properties.Java_version != nil {
 		flags.javaVersion = *j.properties.Java_version
 	} else {
@@ -295,25 +322,25 @@
 		flags.javacFlags = "$javacFlags"
 	}
 
-	aidlFlags := j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs)
+	aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
 	if len(aidlFlags) > 0 {
 		ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
 		flags.aidlFlags = "$aidlFlags"
 	}
 
-	var deps android.Paths
+	var extraDeps android.Paths
 
-	if len(bootClasspath) > 0 {
-		flags.bootClasspath = "-bootclasspath " + strings.Join(bootClasspath.Strings(), ":")
-		deps = append(deps, bootClasspath...)
+	if len(deps.bootClasspath) > 0 {
+		flags.bootClasspath = "-bootclasspath " + strings.Join(deps.bootClasspath.Strings(), ":")
+		extraDeps = append(extraDeps, deps.bootClasspath...)
 	} else if ctx.Device() {
 		// Explicitly clear the bootclasspath for device builds
 		flags.bootClasspath = `-bootclasspath ""`
 	}
 
-	if len(classpath) > 0 {
-		flags.classpath = "-classpath " + strings.Join(classpath.Strings(), ":")
-		deps = append(deps, classpath...)
+	if len(deps.classpath) > 0 {
+		flags.classpath = "-classpath " + strings.Join(deps.classpath.Strings(), ":")
+		extraDeps = append(extraDeps, deps.classpath...)
 	}
 
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
@@ -326,7 +353,7 @@
 		}
 	})
 
-	srcFileLists = append(srcFileLists, j.ExtraSrcLists...)
+	deps.srcFileLists = append(deps.srcFileLists, j.ExtraSrcLists...)
 
 	var extraJarDeps android.Paths
 
@@ -334,7 +361,7 @@
 
 	if len(srcFiles) > 0 {
 		// Compile java sources into .class files
-		classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, deps)
+		classes := TransformJavaToClasses(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
 		if ctx.Failed() {
 			return
 		}
@@ -346,7 +373,7 @@
 			// the jar command so the two compiles can run in parallel.
 			// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
 			//    enable error-prone without affecting the output class files.
-			errorprone := RunErrorProne(ctx, srcFiles, srcFileLists, flags, deps)
+			errorprone := RunErrorProne(ctx, srcFiles, deps.srcFileLists, flags, extraDeps)
 			extraJarDeps = append(extraJarDeps, errorprone)
 		}
 
@@ -366,7 +393,7 @@
 		jars = append(jars, resourceJar)
 	}
 
-	jars = append(jars, staticJars...)
+	jars = append(jars, deps.staticJars...)
 
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes-combined.jar.  If there is only one input jar this step will be skipped.