Add aidl file support to java builds

Add support for aidl files listed in srcs for java builds, and
an aidl_preprocess module type for framework and sdk aidls.

Change-Id: I3aa537f4483822e5b534c74d0b35f13a938f8947
diff --git a/Blueprints b/Blueprints
index 84c9913..2acc065 100644
--- a/Blueprints
+++ b/Blueprints
@@ -86,6 +86,7 @@
         "common/glob.go",
         "common/module.go",
         "common/paths.go",
+        "common/util.go",
     ],
 }
 
@@ -143,6 +144,7 @@
     ],
     srcs: [
         "java/builder.go",
+        "java/gen.go",
         "java/java.go",
         "java/resources.go",
     ],
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 028396a..404aed8 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -49,6 +49,7 @@
 	"LOCAL_DX_FLAGS":              "dxflags",
 	"LOCAL_JAVA_LIBRARIES":        "java_libs",
 	"LOCAL_STATIC_JAVA_LIBRARIES": "java_static_libs",
+	"LOCAL_AIDL_INCLUDES":         "aidl_includes",
 }
 
 var boolProperties = map[string]string{
diff --git a/build.ninja.in b/build.ninja.in
index 2f8fe50..420a775 100644
--- a/build.ninja.in
+++ b/build.ninja.in
@@ -53,7 +53,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:155:1
+# Defined: build/soong/Blueprints:157:1
 
 build .bootstrap/androidmk/obj/androidmk.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/androidmk/cmd/androidmk/android.go $
@@ -79,7 +79,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:168:1
+# Defined: build/soong/Blueprints:170:1
 
 build .bootstrap/androidmk-parser/pkg/android/soong/androidmk/parser.a: $
         g.bootstrap.gc $
@@ -309,7 +309,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:92:1
+# Defined: build/soong/Blueprints:93:1
 
 build .bootstrap/soong-cc/pkg/android/soong/cc.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cc/builder.go $
@@ -351,7 +351,8 @@
         ${g.bootstrap.srcDir}/build/soong/common/env.go $
         ${g.bootstrap.srcDir}/build/soong/common/glob.go $
         ${g.bootstrap.srcDir}/build/soong/common/module.go $
-        ${g.bootstrap.srcDir}/build/soong/common/paths.go | $
+        ${g.bootstrap.srcDir}/build/soong/common/paths.go $
+        ${g.bootstrap.srcDir}/build/soong/common/util.go | $
         ${g.bootstrap.gcCmd} $
         .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
         .bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
@@ -382,7 +383,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:116:1
+# Defined: build/soong/Blueprints:117:1
 
 build .bootstrap/soong-genrule/pkg/android/soong/genrule.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/genrule/genrule.go | $
@@ -419,10 +420,11 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:136:1
+# Defined: build/soong/Blueprints:137:1
 
 build .bootstrap/soong-java/pkg/android/soong/java.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/java/builder.go $
+        ${g.bootstrap.srcDir}/build/soong/java/gen.go $
         ${g.bootstrap.srcDir}/build/soong/java/java.go $
         ${g.bootstrap.srcDir}/build/soong/java/resources.go | $
         ${g.bootstrap.gcCmd} $
@@ -527,7 +529,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:129:1
+# Defined: build/soong/Blueprints:130:1
 
 build .bootstrap/soong_jar/obj/soong_jar.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_jar/soong_jar.go | $
diff --git a/cc/util.go b/cc/util.go
index 7440c25..f1134a1 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -18,45 +18,22 @@
 	"fmt"
 	"regexp"
 	"strings"
+
+	"android/soong/common"
 )
 
 // Efficiently converts a list of include directories to a single string
 // of cflags with -I prepended to each directory.
 func includeDirsToFlags(dirs []string) string {
-	return joinWithPrefix(dirs, "-I")
+	return common.JoinWithPrefix(dirs, "-I")
 }
 
 func ldDirsToFlags(dirs []string) string {
-	return joinWithPrefix(dirs, "-L")
+	return common.JoinWithPrefix(dirs, "-L")
 }
 
 func libNamesToFlags(names []string) string {
-	return joinWithPrefix(names, "-l")
-}
-
-func joinWithPrefix(strs []string, prefix string) string {
-	if len(strs) == 0 {
-		return ""
-	}
-
-	if len(strs) == 1 {
-		return prefix + strs[0]
-	}
-
-	n := len(" ") * (len(strs) - 1)
-	for _, s := range strs {
-		n += len(prefix) + len(s)
-	}
-
-	ret := make([]byte, 0, n)
-	for i, s := range strs {
-		if i != 0 {
-			ret = append(ret, ' ')
-		}
-		ret = append(ret, prefix...)
-		ret = append(ret, s...)
-	}
-	return string(ret)
+	return common.JoinWithPrefix(names, "-l")
 }
 
 func inList(s string, list []string) bool {
diff --git a/common/util.go b/common/util.go
new file mode 100644
index 0000000..190e092
--- /dev/null
+++ b/common/util.go
@@ -0,0 +1,40 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// 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 common
+
+func JoinWithPrefix(strs []string, prefix string) string {
+	if len(strs) == 0 {
+		return ""
+	}
+
+	if len(strs) == 1 {
+		return prefix + strs[0]
+	}
+
+	n := len(" ") * (len(strs) - 1)
+	for _, s := range strs {
+		n += len(prefix) + len(s)
+	}
+
+	ret := make([]byte, 0, n)
+	for i, s := range strs {
+		if i != 0 {
+			ret = append(ret, ' ')
+		}
+		ret = append(ret, prefix...)
+		ret = append(ret, s...)
+	}
+	return string(ret)
+}
diff --git a/java/builder.go b/java/builder.go
index 4eb03c2..02d65aa 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -97,6 +97,7 @@
 	dxFlags       string
 	bootClasspath string
 	classpath     string
+	aidlFlags     string
 }
 
 type jarSpec struct {
diff --git a/java/gen.go b/java/gen.go
new file mode 100644
index 0000000..0b84d44
--- /dev/null
+++ b/java/gen.go
@@ -0,0 +1,79 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+//
+// 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 java
+
+// This file generates the final rules for compiling all C/C++.  All properties related to
+// compiling should have been translated into builderFlags or another argument to the Transform*
+// functions.
+
+import (
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
+
+	"android/soong/common"
+)
+
+func init() {
+	pctx.VariableFunc("aidlCmd", func(c interface{}) (string, error) {
+		return c.(common.Config).HostBinTool("aidl")
+	})
+	pctx.VariableConfigMethod("srcDir", common.Config.SrcDir)
+}
+
+var (
+	aidl = pctx.StaticRule("aidl",
+		blueprint.RuleParams{
+			Command:     "$aidlCmd -d$depFile $aidlFlags $in $out",
+			Description: "aidl $out",
+		},
+		"depFile", "aidlFlags")
+)
+
+func genAidl(ctx common.AndroidModuleContext, aidlFile, aidlFlags string) string {
+	javaFile := strings.TrimPrefix(aidlFile, common.ModuleSrcDir(ctx))
+	javaFile = filepath.Join(common.ModuleGenDir(ctx), javaFile)
+	javaFile = pathtools.ReplaceExtension(javaFile, "java")
+	depFile := javaFile + ".d"
+
+	ctx.Build(pctx, blueprint.BuildParams{
+		Rule:      aidl,
+		Outputs:   []string{javaFile},
+		Inputs:    []string{aidlFile},
+		Implicits: []string{"$aidlCmd"},
+		Args: map[string]string{
+			"depFile":   depFile,
+			"aidlFlags": aidlFlags,
+		},
+	})
+
+	return javaFile
+}
+
+func genSources(ctx common.AndroidModuleContext, srcFiles []string,
+	flags javaBuilderFlags) []string {
+
+	for i, srcFile := range srcFiles {
+		switch filepath.Ext(srcFile) {
+		case ".aidl":
+			javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
+			srcFiles[i] = javaFile
+		}
+	}
+
+	return srcFiles
+}
diff --git a/java/java.go b/java/java.go
index 448580e..ca3a4c7 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 
 	"android/soong/common"
 )
@@ -85,6 +86,13 @@
 
 		// jarjar_rules: if not blank, run jarjar using the specified rules file
 		Jarjar_rules string
+
+		// aidl_includes: directories to pass to aidl tool
+		Aidl_includes []string
+
+		// aidl_export_include_dirs: directories that should be added as include directories
+		// for any aidl sources of modules that depend on this module
+		Export_aidl_include_dirs []string
 	}
 
 	// output file suitable for inserting into the classpath of another compile
@@ -96,6 +104,8 @@
 	// jarSpecs suitable for inserting resources from a static library into another jar
 	resourceJarSpecs []jarSpec
 
+	exportAidlIncludeDirs []string
+
 	// installed file for binary dependency
 	installFile string
 }
@@ -108,6 +118,8 @@
 	ClasspathFile() string
 	ClassJarSpecs() []jarSpec
 	ResourceJarSpecs() []jarSpec
+	AidlIncludeDirs() []string
+	AidlPreprocessed() string
 }
 
 func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported,
@@ -126,6 +138,7 @@
 			return "core-libart"
 		} else if j.properties.Sdk_version == "current" {
 			// TODO: !TARGET_BUILD_APPS
+			// TODO: export preprocessed framework.aidl from android_stubs_current
 			return "android_stubs_current"
 		} else if j.properties.Sdk_version == "system_current" {
 			return "android_system_stubs_current"
@@ -156,8 +169,29 @@
 	return deps
 }
 
+func (j *javaBase) aidlFlags(ctx common.AndroidModuleContext, aidlPreprocess string,
+	aidlIncludeDirs []string) string {
+
+	localAidlIncludes := pathtools.PrefixPaths(j.properties.Aidl_includes, common.ModuleSrcDir(ctx))
+
+	var flags []string
+	if aidlPreprocess != "" {
+		flags = append(flags, "-p"+aidlPreprocess)
+	} else {
+		flags = append(flags, common.JoinWithPrefix(aidlIncludeDirs, "-I"))
+	}
+
+	flags = append(flags, common.JoinWithPrefix(j.exportAidlIncludeDirs, "-I"))
+	flags = append(flags, common.JoinWithPrefix(localAidlIncludes, "-I"))
+	flags = append(flags, "-I"+common.ModuleSrcDir(ctx))
+	flags = append(flags, "-I"+filepath.Join(common.ModuleSrcDir(ctx), "src"))
+
+	return strings.Join(flags, " ")
+}
+
 func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath []string,
-	bootClasspath string, classJarSpecs, resourceJarSpecs []jarSpec) {
+	bootClasspath string, classJarSpecs, resourceJarSpecs []jarSpec, aidlPreprocess string,
+	aidlIncludeDirs []string) {
 
 	ctx.VisitDirectDeps(func(module blueprint.Module) {
 		otherName := ctx.OtherModuleName(module)
@@ -173,12 +207,21 @@
 			} else {
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
+			aidlIncludeDirs = append(aidlIncludeDirs, j.AidlIncludeDirs()...)
+			if j.AidlPreprocessed() != "" {
+				if aidlPreprocess != "" {
+					ctx.ModuleErrorf("multiple dependencies with preprocessed aidls:\n %q\n %q",
+						aidlPreprocess, j.AidlPreprocessed())
+				} else {
+					aidlPreprocess = j.AidlPreprocessed()
+				}
+			}
 		} else {
 			ctx.ModuleErrorf("unknown dependency module type for %q", otherName)
 		}
 	})
 
-	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs
+	return classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess, aidlIncludeDirs
 }
 
 func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
@@ -186,16 +229,20 @@
 }
 
 func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
+
+	j.exportAidlIncludeDirs = pathtools.PrefixPaths(j.properties.Export_aidl_include_dirs,
+		common.ModuleSrcDir(ctx))
+
+	classpath, bootClasspath, classJarSpecs, resourceJarSpecs, aidlPreprocess,
+		aidlIncludeDirs := j.collectDeps(ctx)
+
 	flags := javaBuilderFlags{
 		javacFlags: strings.Join(j.properties.Javacflags, " "),
+		aidlFlags:  j.aidlFlags(ctx, aidlPreprocess, aidlIncludeDirs),
 	}
 
 	var javacDeps []string
 
-	srcFiles := common.ExpandSources(ctx, j.properties.Srcs)
-
-	classpath, bootClasspath, classJarSpecs, resourceJarSpecs := j.collectDeps(ctx)
-
 	if bootClasspath != "" {
 		flags.bootClasspath = "-bootclasspath " + bootClasspath
 		javacDeps = append(javacDeps, bootClasspath)
@@ -206,6 +253,10 @@
 		javacDeps = append(javacDeps, classpath...)
 	}
 
+	srcFiles := common.ExpandSources(ctx, j.properties.Srcs)
+
+	srcFiles = genSources(ctx, srcFiles, flags)
+
 	// Compile java sources into .class files
 	classes := TransformJavaToClasses(ctx, srcFiles, flags, javacDeps)
 	if ctx.Failed() {
@@ -296,6 +347,14 @@
 	return j.resourceJarSpecs
 }
 
+func (j *javaBase) AidlIncludeDirs() []string {
+	return j.exportAidlIncludeDirs
+}
+
+func (j *javaBase) AidlPreprocessed() string {
+	return ""
+}
+
 //
 // Java libraries (.jar file)
 //
@@ -362,9 +421,11 @@
 	common.AndroidModuleBase
 
 	properties struct {
-		Srcs []string
+		Srcs              []string
+		Aidl_preprocessed string
 	}
 
+	aidlPreprocessed                string
 	classpathFile                   string
 	classJarSpecs, resourceJarSpecs []jarSpec
 }
@@ -381,7 +442,9 @@
 	j.classpathFile = prebuilt
 	j.classJarSpecs = []jarSpec{classJarSpec}
 	j.resourceJarSpecs = []jarSpec{resourceJarSpec}
-
+	if j.properties.Aidl_preprocessed != "" {
+		j.aidlPreprocessed = filepath.Join(common.ModuleSrcDir(ctx), j.properties.Aidl_preprocessed)
+	}
 	ctx.InstallFileName("framework", ctx.ModuleName()+".jar", j.classpathFile)
 }
 
@@ -399,6 +462,14 @@
 	return j.resourceJarSpecs
 }
 
+func (j *JavaPrebuilt) AidlIncludeDirs() []string {
+	return nil
+}
+
+func (j *JavaPrebuilt) AidlPreprocessed() string {
+	return j.aidlPreprocessed
+}
+
 func JavaPrebuiltFactory() (blueprint.Module, []interface{}) {
 	module := &JavaPrebuilt{}
 
diff --git a/root.bp b/root.bp
index 18e734f..fbd0be2 100644
--- a/root.bp
+++ b/root.bp
@@ -10,4 +10,5 @@
     "prebuilts/ndk",
     "prebuilts/sdk",
     "system/core/*",
+    "frameworks/base/tools/aidl",
 ]