Add nanopb-c support

Test: cd hardware/ril; mma
Change-Id: Id1481940d15a2a3f6eb29af54ee30080ff2286cb
diff --git a/android/config.go b/android/config.go
index 367b42c..50c1413 100644
--- a/android/config.go
+++ b/android/config.go
@@ -351,6 +351,10 @@
 
 var _ bootstrap.ConfigBlueprintToolLocation = (*config)(nil)
 
+func (c *config) HostToolPath(ctx PathContext, tool string) Path {
+	return PathForOutput(ctx, "host", c.PrebuiltOS(), "bin", tool)
+}
+
 // HostSystemTool looks for non-hermetic tools from the system we're running on.
 // Generally shouldn't be used, but useful to find the XCode SDK, etc.
 func (c *config) HostSystemTool(name string) string {
diff --git a/cc/builder.go b/cc/builder.go
index 6d5b595..bf35f84 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -231,8 +231,6 @@
 	ldFlags         string
 	libFlags        string
 	yaccFlags       string
-	protoFlags      string
-	protoOutParams  string
 	tidyFlags       string
 	sAbiFlags       string
 	yasmFlags       string
@@ -242,7 +240,6 @@
 	tidy            bool
 	coverage        bool
 	sAbiDump        bool
-	protoRoot       bool
 
 	systemIncludeFlags string
 
@@ -252,6 +249,14 @@
 	stripKeepMiniDebugInfo bool
 	stripAddGnuDebuglink   bool
 	stripUseLlvmStrip      bool
+
+	protoDeps        android.Paths
+	protoFlags       string
+	protoOutTypeFlag string
+	protoOutParams   string
+	protoC           bool
+	protoOptionsFile bool
+	protoRoot        bool
 }
 
 type Objects struct {
diff --git a/cc/cc.go b/cc/cc.go
index 4a432f4..ed65aa6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -130,8 +130,6 @@
 	CppFlags        []string // Flags that apply to C++ source files
 	ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
 	YaccFlags       []string // Flags that apply to Yacc source files
-	protoFlags      []string // Flags that apply to proto source files
-	protoOutParams  []string // Flags that modify the output of proto generated files
 	aidlFlags       []string // Flags that apply to aidl source files
 	rsFlags         []string // Flags that apply to renderscript source files
 	LdFlags         []string // Flags that apply to linker command lines
@@ -148,7 +146,6 @@
 	Tidy      bool
 	Coverage  bool
 	SAbiDump  bool
-	ProtoRoot bool
 
 	RequiredInstructionSet string
 	DynamicLinker          string
@@ -157,6 +154,14 @@
 	LdFlagsDeps android.Paths // Files depended on by linker flags
 
 	GroupStaticLibs bool
+
+	protoDeps        android.Paths
+	protoFlags       []string // Flags that apply to proto source files
+	protoOutTypeFlag string   // The output type, --cpp_out for example
+	protoOutParams   []string // Flags that modify the output of proto generated files
+	protoC           bool     // Whether to use C instead of C++
+	protoOptionsFile bool     // Whether to look for a .options file next to the .proto
+	ProtoRoot        bool
 }
 
 type ObjectLinkerProperties struct {
diff --git a/cc/gen.go b/cc/gen.go
index 29a2bb2..4852794 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -182,8 +182,7 @@
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile)
 		case ".proto":
-			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags,
-				buildFlags.protoOutParams, buildFlags.protoRoot)
+			ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
 			srcFiles[i] = ccFile
 			deps = append(deps, headerFile)
 		case ".aidl":
diff --git a/cc/proto.go b/cc/proto.go
index 6e6f95e..61fd607 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -31,41 +31,56 @@
 var (
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
-			Command: "$protocCmd --cpp_out=$protoOutParams:$outDir --dependency_out=$out.d -I $protoBase $protoFlags $in && " +
+			Command: "$protocCmd $protoOut=$protoOutParams:$outDir --dependency_out=$out.d -I $protoBase $protoFlags $in && " +
 				`$depFixCmd $out.d`,
 			CommandDeps: []string{"$protocCmd", "$depFixCmd"},
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-		}, "protoFlags", "protoOutParams", "protoBase", "outDir")
+		}, "protoFlags", "protoOut", "protoOutParams", "protoBase", "outDir")
 )
 
 // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
 // the paths to the generated files.
-func genProto(ctx android.ModuleContext, protoFile android.Path,
-	protoFlags, protoOutParams string, root bool) (ccFile, headerFile android.WritablePath) {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (ccFile, headerFile android.WritablePath) {
+
+	srcSuffix := ".cc"
+	if flags.protoC {
+		srcSuffix = ".c"
+	}
 
 	var protoBase string
-	if root {
+	if flags.protoRoot {
 		protoBase = "."
-		ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
+		ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb"+srcSuffix)
 		headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
 	} else {
 		rel := protoFile.Rel()
 		protoBase = strings.TrimSuffix(protoFile.String(), rel)
-		ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.cc"))
+		ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb"+srcSuffix))
 		headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h"))
 	}
 
+	protoDeps := flags.protoDeps
+	if flags.protoOptionsFile {
+		optionsFile := pathtools.ReplaceExtension(protoFile.String(), "options")
+		optionsPath := android.ExistentPathForSource(ctx, optionsFile)
+		if optionsPath.Valid() {
+			protoDeps = append(android.Paths{optionsPath.Path()}, protoDeps...)
+		}
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:           proto,
 		Description:    "protoc " + protoFile.Rel(),
 		Output:         ccFile,
 		ImplicitOutput: headerFile,
 		Input:          protoFile,
+		Implicits:      protoDeps,
 		Args: map[string]string{
 			"outDir":         android.ProtoDir(ctx).String(),
-			"protoFlags":     protoFlags,
-			"protoOutParams": protoOutParams,
+			"protoFlags":     flags.protoFlags,
+			"protoOut":       flags.protoOutTypeFlag,
+			"protoOutParams": flags.protoOutParams,
 			"protoBase":      protoBase,
 		},
 	})
@@ -91,6 +106,12 @@
 		} else {
 			lib = "libprotobuf-cpp-lite"
 		}
+	case "nanopb-c":
+		lib = "libprotobuf-c-nano"
+		static = true
+	case "nanopb-c-enable_malloc":
+		lib = "libprotobuf-c-nano-enable_malloc"
+		static = true
 	default:
 		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
 			String(p.Proto.Type))
@@ -118,8 +139,33 @@
 
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
-	if String(p.Proto.Type) == "lite" {
+	var plugin string
+
+	switch String(p.Proto.Type) {
+	case "nanopb-c", "nanopb-c-enable_malloc":
+		flags.protoC = true
+		flags.protoOptionsFile = true
+		flags.protoOutTypeFlag = "--nanopb_out"
+		plugin = "protoc-gen-nanopb"
+	case "full":
+		flags.protoOutTypeFlag = "--cpp_out"
+	case "lite":
+		flags.protoOutTypeFlag = "--cpp_out"
 		flags.protoOutParams = append(flags.protoOutParams, "lite")
+	case "":
+		// TODO(b/119714316): this should be equivalent to "lite" in
+		// order to match protoDeps, but some modules are depending on
+		// this behavior
+		flags.protoOutTypeFlag = "--cpp_out"
+	default:
+		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+			String(p.Proto.Type))
+	}
+
+	if plugin != "" {
+		path := ctx.Config().HostToolPath(ctx, plugin)
+		flags.protoDeps = append(flags.protoDeps, path)
+		flags.protoFlags = append(flags.protoFlags, "--plugin="+path.String())
 	}
 
 	return flags
diff --git a/cc/util.go b/cc/util.go
index c900423..925dd74 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -68,8 +68,6 @@
 		conlyFlags:      strings.Join(in.ConlyFlags, " "),
 		cppFlags:        strings.Join(in.CppFlags, " "),
 		yaccFlags:       strings.Join(in.YaccFlags, " "),
-		protoFlags:      strings.Join(in.protoFlags, " "),
-		protoOutParams:  strings.Join(in.protoOutParams, ","),
 		aidlFlags:       strings.Join(in.aidlFlags, " "),
 		rsFlags:         strings.Join(in.rsFlags, " "),
 		ldFlags:         strings.Join(in.LdFlags, " "),
@@ -81,11 +79,18 @@
 		coverage:        in.Coverage,
 		tidy:            in.Tidy,
 		sAbiDump:        in.SAbiDump,
-		protoRoot:       in.ProtoRoot,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
 		groupStaticLibs: in.GroupStaticLibs,
+
+		protoDeps:        in.protoDeps,
+		protoFlags:       strings.Join(in.protoFlags, " "),
+		protoOutTypeFlag: in.protoOutTypeFlag,
+		protoOutParams:   strings.Join(in.protoOutParams, ","),
+		protoC:           in.protoC,
+		protoOptionsFile: in.protoOptionsFile,
+		protoRoot:        in.ProtoRoot,
 	}
 }