Merge master@5428150 into git_qt-dev-plus-aosp.
am: 379f31cb69

Change-Id: I49926af9fdf33ac355ea41de5dfdc6b13277383d
diff --git a/Android.bp b/Android.bp
index 50f0603..910fe4b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -193,6 +193,7 @@
         "cc/gen_test.go",
         "cc/genrule_test.go",
         "cc/library_test.go",
+        "cc/proto_test.go",
         "cc/test_data_test.go",
         "cc/util_test.go",
     ],
diff --git a/android/config.go b/android/config.go
index fff77ca..2e0750b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -200,12 +200,14 @@
 func TestConfig(buildDir string, env map[string]string) Config {
 	config := &config{
 		productVariables: productVariables{
-			DeviceName:           stringPtr("test_device"),
-			Platform_sdk_version: intPtr(26),
-			AAPTConfig:           []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
-			AAPTPreferredConfig:  stringPtr("xhdpi"),
-			AAPTCharacteristics:  stringPtr("nosdcard"),
-			AAPTPrebuiltDPI:      []string{"xhdpi", "xxhdpi"},
+			DeviceName:                  stringPtr("test_device"),
+			Platform_sdk_version:        intPtr(26),
+			DeviceSystemSdkVersions:     []string{"14", "15"},
+			Platform_systemsdk_versions: []string{"25", "26"},
+			AAPTConfig:                  []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+			AAPTPreferredConfig:         stringPtr("xhdpi"),
+			AAPTCharacteristics:         stringPtr("nosdcard"),
+			AAPTPrebuiltDPI:             []string{"xhdpi", "xxhdpi"},
 		},
 
 		buildDir:     buildDir,
diff --git a/android/module.go b/android/module.go
index abf2cae..201c27a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1425,6 +1425,10 @@
 	Srcs() Paths
 }
 
+type HostToolProvider interface {
+	HostToolPath() OptionalPath
+}
+
 // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
 // be tagged with `android:"path" to support automatic source module dependency resolution.
 //
diff --git a/android/proto.go b/android/proto.go
index 801837e..5247c68 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -14,6 +14,13 @@
 
 package android
 
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
 // TODO(ccross): protos are often used to communicate between multiple modules.  If the only
 // way to convert a proto to source is to reference it as a source file, and external modules cannot
 // reference source files in other modules, then every module that owns a proto file will need to
@@ -22,36 +29,72 @@
 // and then external modules could depend on the proto module but use their own settings to
 // generate the source.
 
-func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
-	protoFlags := []string{}
+type ProtoFlags struct {
+	Flags                 []string
+	CanonicalPathFromRoot bool
+	Dir                   ModuleGenPath
+	SubDir                ModuleGenPath
+	OutTypeFlag           string
+	OutParams             []string
+	Deps                  Paths
+}
+
+type protoDependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var ProtoPluginDepTag = protoDependencyTag{name: "plugin"}
+
+func ProtoDeps(ctx BottomUpMutatorContext, p *ProtoProperties) {
+	if String(p.Proto.Plugin) != "" && String(p.Proto.Type) != "" {
+		ctx.ModuleErrorf("only one of proto.type and proto.plugin can be specified.")
+	}
+
+	if plugin := String(p.Proto.Plugin); plugin != "" {
+		ctx.AddFarVariationDependencies([]blueprint.Variation{
+			{Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
+		}, ProtoPluginDepTag, "protoc-gen-"+plugin)
+	}
+}
+
+func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags {
+	var flags []string
+	var deps Paths
 
 	if len(p.Proto.Local_include_dirs) > 0 {
 		localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
-		protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
+		flags = append(flags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
 	}
 	if len(p.Proto.Include_dirs) > 0 {
 		rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
-		protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
+		flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
 	}
 
-	return protoFlags
-}
+	ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
+		if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
+			ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
+				ctx.OtherModuleName(dep))
+		} else {
+			plugin := String(p.Proto.Plugin)
+			deps = append(deps, hostTool.HostToolPath().Path())
+			flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
+		}
+	})
 
-func ProtoCanonicalPathFromRoot(ctx ModuleContext, p *ProtoProperties) bool {
-	if p.Proto.Canonical_path_from_root == nil {
-		return true
+	var protoOutFlag string
+	if plugin := String(p.Proto.Plugin); plugin != "" {
+		protoOutFlag = "--" + plugin + "_out"
 	}
-	return *p.Proto.Canonical_path_from_root
-}
 
-// ProtoDir returns the module's "gen/proto" directory
-func ProtoDir(ctx ModuleContext) ModuleGenPath {
-	return PathForModuleGen(ctx, "proto")
-}
-
-// ProtoSubDir returns the module's "gen/proto/path/to/module" directory
-func ProtoSubDir(ctx ModuleContext) ModuleGenPath {
-	return PathForModuleGen(ctx, "proto", ctx.ModuleDir())
+	return ProtoFlags{
+		Flags:                 flags,
+		Deps:                  deps,
+		OutTypeFlag:           protoOutFlag,
+		CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, true),
+		Dir:                   PathForModuleGen(ctx, "proto"),
+		SubDir:                PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
+	}
 }
 
 type ProtoProperties struct {
@@ -59,6 +102,9 @@
 		// Proto generator type.  C++: full or lite.  Java: micro, nano, stream, or lite.
 		Type *string `android:"arch_variant"`
 
+		// Proto plugin to use as the generator.  Must be a cc_binary_host module.
+		Plugin *string `android:"arch_variant"`
+
 		// list of directories that will be added to the protoc include paths.
 		Include_dirs []string
 
@@ -76,3 +122,28 @@
 		Canonical_path_from_root *bool
 	} `android:"arch_variant"`
 }
+
+func ProtoRule(ctx ModuleContext, rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
+	outDir WritablePath, depFile WritablePath, outputs WritablePaths) {
+
+	var protoBase string
+	if flags.CanonicalPathFromRoot {
+		protoBase = "."
+	} else {
+		rel := protoFile.Rel()
+		protoBase = strings.TrimSuffix(protoFile.String(), rel)
+	}
+
+	rule.Command().
+		Tool(ctx.Config().HostToolPath(ctx, "aprotoc")).
+		FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
+		FlagWithDepFile("--dependency_out=", depFile).
+		FlagWithArg("-I ", protoBase).
+		Flags(flags.Flags).
+		Input(protoFile).
+		Implicits(deps).
+		ImplicitOutputs(outputs)
+
+	rule.Command().
+		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).Flag(depFile.String())
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index a2a5366..2d0fac1 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -171,6 +171,20 @@
 	return outputList
 }
 
+// DepFiles returns the list of paths that were passed to the RuleBuilderCommand methods that take depfile paths, such
+// as RuleBuilderCommand.DepFile or RuleBuilderCommand.FlagWithDepFile.
+func (r *RuleBuilder) DepFiles() WritablePaths {
+	var depFiles WritablePaths
+
+	for _, c := range r.commands {
+		for _, depFile := range c.depFiles {
+			depFiles = append(depFiles, depFile)
+		}
+	}
+
+	return depFiles
+}
+
 // Installs returns the list of tuples passed to Install.
 func (r *RuleBuilder) Installs() RuleBuilderInstalls {
 	return append(RuleBuilderInstalls(nil), r.installs...)
@@ -222,9 +236,17 @@
 var _ BuilderContext = ModuleContext(nil)
 var _ BuilderContext = SingletonContext(nil)
 
+func (r *RuleBuilder) depFileMergerCmd(ctx PathContext, depFiles WritablePaths) *RuleBuilderCommand {
+	return (&RuleBuilderCommand{}).
+		Tool(ctx.Config().HostToolPath(ctx, "dep_fixer")).
+		Flags(depFiles.Strings())
+}
+
 // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
 // Outputs.
 func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
+	name = ninjaNameEscape(name)
+
 	if len(r.missingDeps) > 0 {
 		ctx.Build(pctx, BuildParams{
 			Rule:        ErrorRule,
@@ -237,16 +259,45 @@
 		return
 	}
 
-	if len(r.Commands()) > 0 {
+	tools := r.Tools()
+	commands := r.Commands()
+
+	var depFile WritablePath
+	var depFormat blueprint.Deps
+	if depFiles := r.DepFiles(); len(depFiles) > 0 {
+		depFile = depFiles[0]
+		depFormat = blueprint.DepsGCC
+		if len(depFiles) > 1 {
+			// Add a command locally that merges all depfiles together into the first depfile.
+			cmd := r.depFileMergerCmd(ctx, depFiles)
+			commands = append(commands, string(cmd.buf))
+			tools = append(tools, cmd.tools...)
+		}
+	}
+
+	// Ninja doesn't like multiple outputs when depfiles are enabled, move all but the first output to
+	// ImplicitOutputs.  RuleBuilder never uses "$out", so the distinction between Outputs and ImplicitOutputs
+	// doesn't matter.
+	var output WritablePath
+	var implicitOutputs WritablePaths
+	if outputs := r.Outputs(); len(outputs) > 0 {
+		output = outputs[0]
+		implicitOutputs = outputs[1:]
+	}
+
+	if len(commands) > 0 {
 		ctx.Build(pctx, BuildParams{
 			Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
-				Command:     strings.Join(proptools.NinjaEscapeList(r.Commands()), " && "),
-				CommandDeps: r.Tools().Strings(),
+				Command:     strings.Join(proptools.NinjaEscapeList(commands), " && "),
+				CommandDeps: tools.Strings(),
 				Restat:      r.restat,
 			}),
-			Implicits:   r.Inputs(),
-			Outputs:     r.Outputs(),
-			Description: desc,
+			Implicits:       r.Inputs(),
+			Output:          output,
+			ImplicitOutputs: implicitOutputs,
+			Depfile:         depFile,
+			Deps:            depFormat,
+			Description:     desc,
 		})
 	}
 }
@@ -256,10 +307,11 @@
 // RuleBuilderCommand, so they can be used chained or unchained.  All methods that add text implicitly add a single
 // space as a separator from the previous method.
 type RuleBuilderCommand struct {
-	buf     []byte
-	inputs  Paths
-	outputs WritablePaths
-	tools   Paths
+	buf      []byte
+	inputs   Paths
+	outputs  WritablePaths
+	depFiles WritablePaths
+	tools    Paths
 }
 
 // Text adds the specified raw text to the command line.  The text should not contain input or output paths or the
@@ -284,6 +336,15 @@
 	return c.Text(flag)
 }
 
+// Flags adds the specified raw text to the command line.  The text should not contain input or output paths or the
+// rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) Flags(flags []string) *RuleBuilderCommand {
+	for _, flag := range flags {
+		c.Text(flag)
+	}
+	return c
+}
+
 // FlagWithArg adds the specified flag and argument text to the command line, with no separator between them.  The flag
 // and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
 // outputs.
@@ -360,6 +421,14 @@
 	return c
 }
 
+// DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
+// line, and causes RuleBuilder.Build file to set the depfile flag for ninja.  If multiple depfiles are added to
+// commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the depfiles together.
+func (c *RuleBuilderCommand) DepFile(path WritablePath) *RuleBuilderCommand {
+	c.depFiles = append(c.depFiles, path)
+	return c.Text(path.String())
+}
+
 // ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
 // the command line.
 func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand {
@@ -374,6 +443,15 @@
 	return c
 }
 
+// ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
+// the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja.  If multiple depfiles
+// are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
+// depfiles together.
+func (c *RuleBuilderCommand) ImplicitDepFile(path WritablePath) *RuleBuilderCommand {
+	c.depFiles = append(c.depFiles, path)
+	return c
+}
+
 // FlagWithInput adds the specified flag and input path to the command line, with no separator between them.  The path
 // will also be added to the dependencies returned by RuleBuilder.Inputs.
 func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand {
@@ -406,7 +484,35 @@
 	return c.Text(flag + path.String())
 }
 
+// FlagWithDepFile adds the specified flag and depfile path to the command line, with no separator between them.  The path
+// will also be added to the outputs returned by RuleBuilder.Outputs.
+func (c *RuleBuilderCommand) FlagWithDepFile(flag string, path WritablePath) *RuleBuilderCommand {
+	c.depFiles = append(c.depFiles, path)
+	return c.Text(flag + path.String())
+}
+
 // String returns the command line.
 func (c *RuleBuilderCommand) String() string {
 	return string(c.buf)
 }
+
+func ninjaNameEscape(s string) string {
+	b := []byte(s)
+	escaped := false
+	for i, c := range b {
+		valid := (c >= 'a' && c <= 'z') ||
+			(c >= 'A' && c <= 'Z') ||
+			(c >= '0' && c <= '9') ||
+			(c == '_') ||
+			(c == '-') ||
+			(c == '.')
+		if !valid {
+			b[i] = '_'
+			escaped = true
+		}
+	}
+	if escaped {
+		s = string(b)
+	}
+	return s
+}
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 01d23e5..7bad025 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -171,6 +171,14 @@
 	// ls -l
 }
 
+func ExampleRuleBuilderCommand_Flags() {
+	ctx := pathContext()
+	fmt.Println(NewRuleBuilder().Command().
+		Tool(PathForSource(ctx, "ls")).Flags([]string{"-l", "-a"}))
+	// Output:
+	// ls -l -a
+}
+
 func ExampleRuleBuilderCommand_FlagWithArg() {
 	ctx := pathContext()
 	fmt.Println(NewRuleBuilder().Command().
@@ -229,23 +237,27 @@
 	rule := NewRuleBuilder()
 
 	fs := map[string][]byte{
-		"input":    nil,
-		"Implicit": nil,
-		"Input":    nil,
-		"Tool":     nil,
-		"input2":   nil,
-		"tool2":    nil,
-		"input3":   nil,
+		"dep_fixer": nil,
+		"input":     nil,
+		"Implicit":  nil,
+		"Input":     nil,
+		"Tool":      nil,
+		"input2":    nil,
+		"tool2":     nil,
+		"input3":    nil,
 	}
 
 	ctx := PathContextForTesting(TestConfig("out", nil), fs)
 
 	cmd := rule.Command().
+		DepFile(PathForOutput(ctx, "DepFile")).
 		Flag("Flag").
 		FlagWithArg("FlagWithArg=", "arg").
+		FlagWithDepFile("FlagWithDepFile=", PathForOutput(ctx, "depfile")).
 		FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")).
 		FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")).
 		Implicit(PathForSource(ctx, "Implicit")).
+		ImplicitDepFile(PathForOutput(ctx, "ImplicitDepFile")).
 		ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
 		Input(PathForSource(ctx, "Input")).
 		Output(PathForOutput(ctx, "Output")).
@@ -254,6 +266,7 @@
 
 	rule.Command().
 		Text("command2").
+		DepFile(PathForOutput(ctx, "depfile2")).
 		Input(PathForSource(ctx, "input2")).
 		Output(PathForOutput(ctx, "output2")).
 		Tool(PathForSource(ctx, "tool2"))
@@ -271,25 +284,37 @@
 		Output(PathForOutput(ctx, "output3"))
 
 	wantCommands := []string{
-		"Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
-		"command2 input2 out/output2 tool2",
+		"out/DepFile Flag FlagWithArg=arg FlagWithDepFile=out/depfile FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd",
+		"command2 out/depfile2 input2 out/output2 tool2",
 		"command3 input3 out/output2 out/output3",
 	}
+
+	wantDepMergerCommand := "out/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer out/DepFile out/depfile out/ImplicitDepFile out/depfile2"
+
 	wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"})
 	wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
+	wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
 	wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
 
-	if !reflect.DeepEqual(rule.Commands(), wantCommands) {
-		t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", wantCommands, rule.Commands())
+	if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+		t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", w, g)
 	}
-	if !reflect.DeepEqual(rule.Inputs(), wantInputs) {
-		t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", wantInputs, rule.Inputs())
+
+	if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+		t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
 	}
-	if !reflect.DeepEqual(rule.Outputs(), wantOutputs) {
-		t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", wantOutputs, rule.Outputs())
+
+	if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+		t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", w, g)
 	}
-	if !reflect.DeepEqual(rule.Tools(), wantTools) {
-		t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", wantTools, rule.Tools())
+	if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+		t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", w, g)
+	}
+	if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+		t.Errorf("\nwant rule.DepFiles() = %#v\n                  got %#v", w, g)
+	}
+	if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+		t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
 	}
 }
 
@@ -375,8 +400,8 @@
 			t.Errorf("want Implicits = [%q], got %q", "bar", params.Implicits.Strings())
 		}
 
-		if len(params.Outputs) != 1 || params.Outputs[0].String() != wantOutput {
-			t.Errorf("want Outputs = [%q], got %q", wantOutput, params.Outputs.Strings())
+		if params.Output.String() != wantOutput {
+			t.Errorf("want Output = %q, got %q", wantOutput, params.Output)
 		}
 
 		if !params.RuleParams.Restat {
diff --git a/android/testing.go b/android/testing.go
index 7f443a3..0ec5af5 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -196,6 +196,7 @@
 	var searchedOutputs []string
 	for _, p := range provider.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
+		outputs = append(outputs, p.ImplicitOutputs...)
 		if p.Output != nil {
 			outputs = append(outputs, p.Output)
 		}
@@ -222,6 +223,7 @@
 	var outputFullPaths []string
 	for _, p := range provider.BuildParamsForTests() {
 		outputs := append(WritablePaths(nil), p.Outputs...)
+		outputs = append(outputs, p.ImplicitOutputs...)
 		if p.Output != nil {
 			outputs = append(outputs, p.Output)
 		}
diff --git a/android/variable.go b/android/variable.go
index aa8c804..56ca666 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -43,7 +43,8 @@
 		} `android:"arch_variant"`
 
 		Malloc_not_svelte struct {
-			Cflags []string `android:"arch_variant"`
+			Cflags      []string `android:"arch_variant"`
+			Shared_libs []string `android:"arch_variant"`
 		} `android:"arch_variant"`
 
 		Safestack struct {
diff --git a/apex/apex.go b/apex/apex.go
index e07fae0..ce1ed46 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -396,9 +396,8 @@
 	outputFiles      map[apexPackaging]android.WritablePath
 	installDir       android.OutputPath
 
-	public_key_file   android.Path
-	private_key_file  android.Path
-	bundle_public_key bool
+	public_key_file  android.Path
+	private_key_file android.Path
 
 	container_certificate_file android.Path
 	container_private_key_file android.Path
@@ -746,10 +745,6 @@
 				if key, ok := child.(*apexKey); ok {
 					a.private_key_file = key.private_key_file
 					a.public_key_file = key.public_key_file
-					// If the key is not installed, bundled it with the APEX.
-					// Note: this bundled key is valid only for non-production builds
-					// (eng/userdebug).
-					a.bundle_public_key = !key.installable() && ctx.Config().Debuggable()
 					return false
 				} else {
 					ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
@@ -968,11 +963,8 @@
 		optFlags := []string{}
 
 		// Additional implicit inputs.
-		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file)
-		if a.bundle_public_key {
-			implicitInputs = append(implicitInputs, a.public_key_file)
-			optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
-		}
+		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file, a.public_key_file)
+		optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
 
 		manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
 		if overridden {
@@ -1057,7 +1049,7 @@
 
 func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
 	if a.installable() {
-		// For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along
+		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
 		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
 
@@ -1070,6 +1062,15 @@
 		})
 		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
+		// rename to apex_pubkey
+		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Cp,
+			Input:  a.public_key_file,
+			Output: copiedPubkey,
+		})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, ctx.ModuleName() + ".apex_pubkey", ".", etc, nil, nil})
+
 		if ctx.Config().FlattenApex() {
 			for _, fi := range a.filesInfo {
 				dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
@@ -1215,7 +1216,6 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
-				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
 				if a.installable() && a.mergedNoticeFile != nil {
 					fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNoticeFile.String())
 				}
@@ -1317,18 +1317,9 @@
 			Src *string
 		}
 	}
-
-	// the name of the apex_key module that contains the matching public key to be installed.
-	Key *string
 }
 
 func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if String(p.properties.Key) == "" {
-		ctx.ModuleErrorf("key is missing")
-		return
-	}
-	ctx.AddDependency(ctx.Module(), keyTag, *p.properties.Key)
-
 	// This is called before prebuilt_select and prebuilt_postdeps mutators
 	// The mutators requires that src to be set correctly for each arch so that
 	// arch variants are disabled when src is not provided for the arch.
@@ -1380,7 +1371,6 @@
 			func(w io.Writer, outputFile android.Path) {
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", p.BaseModuleName()+imageApexSuffix)
-				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(p.properties.Key))
 			},
 		},
 	}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1e8d5b4..6d101d8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -15,8 +15,6 @@
 package apex
 
 import (
-	"bufio"
-	"bytes"
 	"io/ioutil"
 	"os"
 	"strings"
@@ -299,6 +297,10 @@
 	`)
 
 	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+
+	optFlags := apexRule.Args["opt_flags"]
+	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
+
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that main rule creates an output
@@ -1197,14 +1199,6 @@
 	if actual != expected {
 		t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
 	}
-
-	apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey)
-	expected = "target/product/test_device/product/etc/security/apex"
-	actual = apex_key.installDir.RelPathString()
-	if actual != expected {
-		t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
-	}
-
 }
 
 func TestApexKeyFromOtherModule(t *testing.T) {
@@ -1252,14 +1246,6 @@
 					src: "myapex-arm.apex",
 				},
 			},
-			key: "myapex.key"
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-			product_specific: true,
 		}
 	`)
 
@@ -1269,24 +1255,4 @@
 	if prebuilt.inputApex.String() != expectedInput {
 		t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String())
 	}
-
-	// Check if the key module is added as a required module.
-	buf := &bytes.Buffer{}
-	prebuilt.AndroidMk().Extra[0](buf, nil)
-	found := false
-	scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
-	expected := "myapex.key"
-	for scanner.Scan() {
-		line := scanner.Text()
-		tok := strings.Split(line, " := ")
-		if tok[0] == "LOCAL_REQUIRED_MODULES" {
-			found = true
-			if tok[1] != "myapex.key" {
-				t.Errorf("Unexpected LOCAL_REQUIRED_MODULES '%s', expected '%s'", tok[1], expected)
-			}
-		}
-	}
-	if !found {
-		t.Errorf("Couldn't find a LOCAL_REQUIRED_MODULES entry")
-	}
 }
diff --git a/apex/key.go b/apex/key.go
index fbd29bc..a627e4b 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,8 +16,6 @@
 
 import (
 	"fmt"
-	"io"
-	"path/filepath"
 	"strings"
 
 	"android/soong/android"
@@ -39,7 +37,6 @@
 
 	public_key_file  android.Path
 	private_key_file android.Path
-	installDir       android.OutputPath
 
 	keyName string
 }
@@ -64,7 +61,7 @@
 }
 
 func (m *apexKey) installable() bool {
-	return m.properties.Installable == nil || proptools.Bool(m.properties.Installable)
+	return false
 }
 
 func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -99,25 +96,6 @@
 		return
 	}
 	m.keyName = pubKeyName
-
-	m.installDir = android.PathForModuleInstall(ctx, "etc/security/apex")
-	if m.installable() {
-		ctx.InstallFile(m.installDir, m.keyName, m.public_key_file)
-	}
-}
-
-func (m *apexKey) AndroidMk() android.AndroidMkData {
-	return android.AndroidMkData{
-		Class:      "ETC",
-		OutputFile: android.OptionalPathForPath(m.public_key_file),
-		Extra: []android.AndroidMkExtraFunc{
-			func(w io.Writer, outputFile android.Path) {
-				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", m.installDir.RelPathString()))
-				fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.keyName)
-				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !m.installable())
-			},
-		},
-	}
 }
 
 ////////////////////////////////////////////////////////////////////////
diff --git a/cc/binary.go b/cc/binary.go
index 51e68fc..35c3d85 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -384,7 +384,7 @@
 
 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
 		deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
-		builderFlags, outputFile, nil)
+		builderFlags, outputFile)
 
 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
diff --git a/cc/builder.go b/cc/builder.go
index 6dd7c05..c64243f 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -26,7 +26,6 @@
 	"strings"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
 	"android/soong/cc/config"
@@ -260,13 +259,9 @@
 	stripAddGnuDebuglink   bool
 	stripUseGnuStrip       bool
 
-	protoDeps        android.Paths
-	protoFlags       string
-	protoOutTypeFlag string
-	protoOutParams   string
+	proto            android.ProtoFlags
 	protoC           bool
 	protoOptionsFile bool
-	protoRoot        bool
 }
 
 type Objects struct {
@@ -600,7 +595,7 @@
 // and shared libraries, to a shared library (.so) or dynamic executable
 func TransformObjToDynamicBinary(ctx android.ModuleContext,
 	objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps android.Paths,
-	crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath, implicitOutputs android.WritablePaths) {
+	crtBegin, crtEnd android.OptionalPath, groupLate bool, flags builderFlags, outputFile android.WritablePath) {
 
 	ldCmd := "${config.ClangBin}/clang++"
 
@@ -637,11 +632,7 @@
 	}
 
 	for _, lib := range sharedLibs {
-		libFile := lib.String()
-		if ctx.Windows() {
-			libFile = pathtools.ReplaceExtension(libFile, "a")
-		}
-		libFlagsList = append(libFlagsList, libFile)
+		libFlagsList = append(libFlagsList, lib.String())
 	}
 
 	deps = append(deps, staticLibs...)
@@ -652,12 +643,11 @@
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:            ld,
-		Description:     "link " + outputFile.Base(),
-		Output:          outputFile,
-		ImplicitOutputs: implicitOutputs,
-		Inputs:          objFiles,
-		Implicits:       deps,
+		Rule:        ld,
+		Description: "link " + outputFile.Base(),
+		Output:      outputFile,
+		Inputs:      objFiles,
+		Implicits:   deps,
 		Args: map[string]string{
 			"ldCmd":    ldCmd,
 			"crtBegin": crtBegin.String(),
diff --git a/cc/cc.go b/cc/cc.go
index f5a1567..0668fd9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -162,13 +162,9 @@
 
 	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
+	proto            android.ProtoFlags
+	protoC           bool // Whether to use C instead of C++
+	protoOptionsFile bool // Whether to look for a .options file next to the .proto
 }
 
 type ObjectLinkerProperties struct {
@@ -1597,6 +1593,10 @@
 			return
 		}
 
+		if depTag == android.ProtoPluginDepTag {
+			return
+		}
+
 		if dep.Target().Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
 			return
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 8c0bcfe..05d74b9 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -54,6 +54,7 @@
 func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
+	ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
 	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
diff --git a/cc/compiler.go b/cc/compiler.go
index fe46a3c..f9af4d8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -221,6 +221,7 @@
 	deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...)
 	deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers...)
 
+	android.ProtoDeps(ctx, &compiler.Proto)
 	if compiler.hasSrcExt(".proto") {
 		deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
 	}
diff --git a/cc/library.go b/cc/library.go
index cab75ac..cf20747 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -357,10 +357,9 @@
 				)
 			}
 		} else {
-			f = append(f, "-shared")
-			if !ctx.Windows() {
-				f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
-			}
+			f = append(f,
+				"-shared",
+				"-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix())
 		}
 
 		flags.LdFlags = append(f, flags.LdFlags...)
@@ -684,14 +683,6 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := outputFile
 
-	var implicitOutputs android.WritablePaths
-	if ctx.Windows() {
-		importLibraryPath := android.PathForModuleOut(ctx, pathtools.ReplaceExtension(fileName, "a"))
-
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
-		implicitOutputs = append(implicitOutputs, importLibraryPath)
-	}
-
 	builderFlags := flagsToBuilderFlags(flags)
 
 	// Optimize out relinking against shared libraries whose interface hasn't changed by
@@ -743,7 +734,7 @@
 
 	TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 		deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
-		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs)
+		linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
 
 	objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -848,10 +839,10 @@
 	if Bool(library.Properties.Proto.Export_proto_headers) {
 		if library.baseCompiler.hasSrcExt(".proto") {
 			includes := []string{}
-			if flags.ProtoRoot {
-				includes = append(includes, "-I"+android.ProtoSubDir(ctx).String())
+			if flags.proto.CanonicalPathFromRoot {
+				includes = append(includes, "-I"+flags.proto.SubDir.String())
 			}
-			includes = append(includes, "-I"+android.ProtoDir(ctx).String())
+			includes = append(includes, "-I"+flags.proto.Dir.String())
 			library.reexportFlags(includes)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, includes...)
 			library.reexportDeps(library.baseCompiler.pathDeps) // TODO: restrict to proto deps
diff --git a/cc/linker.go b/cc/linker.go
index 179a998..b279c06 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -255,6 +255,17 @@
 			}
 		}
 
+		if inList("libc_scudo", deps.SharedLibs) {
+			// libc_scudo is an alternate implementation of all
+			// allocation functions (malloc, free), that uses
+			// the scudo allocator instead of the default native
+			// allocator. If this library is in the list, make
+			// sure it's first so it properly overrides the
+			// allocation functions of all other shared libraries.
+			_, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
+			deps.SharedLibs = append([]string{"libc_scudo"}, deps.SharedLibs...)
+		}
+
 		// If libc and libdl are both in system_shared_libs make sure libdl comes after libc
 		// to avoid loading libdl before libc.
 		if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) &&
@@ -290,6 +301,10 @@
 	if ctx.Darwin() {
 		return false
 	}
+	// http://b/110800681 - lld cannot link Android's Windows modules yet.
+	if ctx.Windows() {
+		return false
+	}
 	if linker.Properties.Use_clang_lld != nil {
 		return Bool(linker.Properties.Use_clang_lld)
 	}
@@ -343,7 +358,7 @@
 			// darwin defaults to treating undefined symbols as errors
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-undefined,dynamic_lookup")
 		}
-	} else if !ctx.Darwin() && !ctx.Windows() {
+	} else if !ctx.Darwin() {
 		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
 	}
 
@@ -380,7 +395,7 @@
 
 	flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
 
-	if ctx.Host() && !ctx.Windows() {
+	if ctx.Host() {
 		rpath_prefix := `\$$ORIGIN/`
 		if ctx.Darwin() {
 			rpath_prefix = "@loader_path/"
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 966ec36..5ffeb32 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -29,16 +29,20 @@
 	prebuilt() *android.Prebuilt
 }
 
+type prebuiltLinkerProperties struct {
+
+	// a prebuilt library or binary. Can reference a genrule module that generates an executable file.
+	Srcs []string `android:"path,arch_variant"`
+
+	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
+	// symbols, etc), default true.
+	Check_elf_files *bool
+}
+
 type prebuiltLinker struct {
 	android.Prebuilt
 
-	properties struct {
-		Srcs []string `android:"path,arch_variant"`
-
-		// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
-		// symbols, etc), default true.
-		Check_elf_files *bool
-	}
+	properties prebuiltLinkerProperties
 }
 
 func (p *prebuiltLinker) prebuilt() *android.Prebuilt {
@@ -112,6 +116,8 @@
 	return false
 }
 
+// cc_prebuilt_library_shared installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
 func prebuiltSharedLibraryFactory() android.Module {
 	module, _ := NewPrebuiltSharedLibrary(android.HostAndDeviceSupported)
 	return module.Init()
@@ -137,6 +143,8 @@
 	return module, library
 }
 
+// cc_prebuilt_library_static installs a precompiled static library that are
+// listed in the srcs property in the device's directory.
 func prebuiltStaticLibraryFactory() android.Module {
 	module, _ := NewPrebuiltStaticLibrary(android.HostAndDeviceSupported)
 	return module.Init()
@@ -197,6 +205,8 @@
 	return nil
 }
 
+// cc_prebuilt_binary installs a precompiled executable in srcs property in the
+// device's directory.
 func prebuiltBinaryFactory() android.Module {
 	module, _ := NewPrebuiltBinary(android.HostAndDeviceSupported)
 	return module.Init()
diff --git a/cc/proto.go b/cc/proto.go
index ce8a30e..f818edc 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -15,126 +15,99 @@
 package cc
 
 import (
-	"strings"
-
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
 )
 
-func init() {
-	pctx.HostBinToolVariable("protocCmd", "aprotoc")
-	pctx.HostBinToolVariable("depFixCmd", "dep_fixer")
-}
-
-var (
-	proto = pctx.AndroidStaticRule("protoc",
-		blueprint.RuleParams{
-			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", "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, flags builderFlags) (ccFile, headerFile android.WritablePath) {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (cc, header android.WritablePath) {
+	var ccFile, headerFile android.ModuleGenPath
 
 	srcSuffix := ".cc"
 	if flags.protoC {
 		srcSuffix = ".c"
 	}
 
-	var protoBase string
-	if flags.protoRoot {
-		protoBase = "."
+	if flags.proto.CanonicalPathFromRoot {
 		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"+srcSuffix))
 		headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h"))
 	}
 
-	protoDeps := flags.protoDeps
+	protoDeps := flags.proto.Deps
 	if flags.protoOptionsFile {
 		optionsFile := pathtools.ReplaceExtension(protoFile.String(), "options")
-		optionsPath := android.ExistentPathForSource(ctx, optionsFile)
-		if optionsPath.Valid() {
-			protoDeps = append(android.Paths{optionsPath.Path()}, protoDeps...)
-		}
+		optionsPath := android.PathForSource(ctx, optionsFile)
+		protoDeps = append(android.Paths{optionsPath}, 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":     flags.protoFlags,
-			"protoOut":       flags.protoOutTypeFlag,
-			"protoOutParams": flags.protoOutParams,
-			"protoBase":      protoBase,
-		},
-	})
+	outDir := flags.proto.Dir
+	depFile := ccFile.ReplaceExtension(ctx, "d")
+	outputs := android.WritablePaths{ccFile, headerFile}
+
+	rule := android.NewRuleBuilder()
+
+	android.ProtoRule(ctx, rule, protoFile, flags.proto, protoDeps, outDir, depFile, outputs)
+
+	rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
 
 	return ccFile, headerFile
 }
 
-func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
+func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bool) Deps {
 	var lib string
 
-	switch String(p.Proto.Type) {
-	case "full":
-		if ctx.useSdk() {
-			lib = "libprotobuf-cpp-full-ndk"
+	if String(p.Proto.Plugin) == "" {
+		switch String(p.Proto.Type) {
+		case "full":
+			if ctx.useSdk() {
+				lib = "libprotobuf-cpp-full-ndk"
+				static = true
+			} else {
+				lib = "libprotobuf-cpp-full"
+			}
+		case "lite", "":
+			if ctx.useSdk() {
+				lib = "libprotobuf-cpp-lite-ndk"
+				static = true
+			} else {
+				lib = "libprotobuf-cpp-lite"
+			}
+		case "nanopb-c":
+			lib = "libprotobuf-c-nano"
 			static = true
-		} else {
-			lib = "libprotobuf-cpp-full"
-		}
-	case "lite", "":
-		if ctx.useSdk() {
-			lib = "libprotobuf-cpp-lite-ndk"
+		case "nanopb-c-enable_malloc":
+			lib = "libprotobuf-c-nano-enable_malloc"
 			static = true
-		} else {
-			lib = "libprotobuf-cpp-lite"
+		case "nanopb-c-16bit":
+			lib = "libprotobuf-c-nano-16bit"
+			static = true
+		case "nanopb-c-enable_malloc-16bit":
+			lib = "libprotobuf-c-nano-enable_malloc-16bit"
+			static = true
+		case "nanopb-c-32bit":
+			lib = "libprotobuf-c-nano-32bit"
+			static = true
+		case "nanopb-c-enable_malloc-32bit":
+			lib = "libprotobuf-c-nano-enable_malloc-32bit"
+			static = true
+		default:
+			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+				String(p.Proto.Type))
 		}
-	case "nanopb-c":
-		lib = "libprotobuf-c-nano"
-		static = true
-	case "nanopb-c-enable_malloc":
-		lib = "libprotobuf-c-nano-enable_malloc"
-		static = true
-	case "nanopb-c-16bit":
-		lib = "libprotobuf-c-nano-16bit"
-		static = true
-	case "nanopb-c-enable_malloc-16bit":
-		lib = "libprotobuf-c-nano-enable_malloc-16bit"
-		static = true
-	case "nanopb-c-32bit":
-		lib = "libprotobuf-c-nano-32bit"
-		static = true
-	case "nanopb-c-enable_malloc-32bit":
-		lib = "libprotobuf-c-nano-enable_malloc-32bit"
-		static = true
-	default:
-		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
-			String(p.Proto.Type))
-	}
 
-	if static {
-		deps.StaticLibs = append(deps.StaticLibs, lib)
-		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
-	} else {
-		deps.SharedLibs = append(deps.SharedLibs, lib)
-		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
+		if static {
+			deps.StaticLibs = append(deps.StaticLibs, lib)
+			deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib)
+		} else {
+			deps.SharedLibs = append(deps.SharedLibs, lib)
+			deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib)
+		}
 	}
 
 	return deps
@@ -143,41 +116,41 @@
 func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
 	flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
 
-	flags.ProtoRoot = android.ProtoCanonicalPathFromRoot(ctx, p)
-	if flags.ProtoRoot {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.ProtoSubDir(ctx).String())
+	flags.proto = android.GetProtoFlags(ctx, p)
+	if flags.proto.CanonicalPathFromRoot {
+		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.SubDir.String())
 	}
-	flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.ProtoDir(ctx).String())
+	flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.Dir.String())
 
-	flags.protoFlags = android.ProtoFlags(ctx, p)
+	if String(p.Proto.Plugin) == "" {
+		var plugin string
 
-	var plugin string
+		switch String(p.Proto.Type) {
+		case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit":
+			flags.protoC = true
+			flags.protoOptionsFile = true
+			flags.proto.OutTypeFlag = "--nanopb_out"
+			plugin = "protoc-gen-nanopb"
+		case "full":
+			flags.proto.OutTypeFlag = "--cpp_out"
+		case "lite":
+			flags.proto.OutTypeFlag = "--cpp_out"
+			flags.proto.OutParams = append(flags.proto.OutParams, "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.proto.OutTypeFlag = "--cpp_out"
+		default:
+			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+				String(p.Proto.Type))
+		}
 
-	switch String(p.Proto.Type) {
-	case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit":
-		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())
+		if plugin != "" {
+			path := ctx.Config().HostToolPath(ctx, plugin)
+			flags.proto.Deps = append(flags.proto.Deps, path)
+			flags.proto.Flags = append(flags.proto.Flags, "--plugin="+path.String())
+		}
 	}
 
 	return flags
diff --git a/cc/proto_test.go b/cc/proto_test.go
new file mode 100644
index 0000000..a7fcef9
--- /dev/null
+++ b/cc/proto_test.go
@@ -0,0 +1,75 @@
+// Copyright 2016 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 cc
+
+import (
+	"runtime"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestProto(t *testing.T) {
+	t.Run("simple", func(t *testing.T) {
+		ctx := testCc(t, `
+		cc_library_shared {
+			name: "libfoo",
+			srcs: ["a.proto"],
+		}`)
+
+		proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Output("proto/a.pb.cc")
+
+		if cmd := proto.RuleParams.Command; !strings.Contains(cmd, "--cpp_out=") {
+			t.Errorf("expected '--cpp_out' in %q", cmd)
+		}
+	})
+
+	t.Run("plugin", func(t *testing.T) {
+		if runtime.GOOS != "linux" {
+			t.Skip("TODO(b/129763458): cc_binary_host tests fail on mac when trying to exec xcrun")
+		}
+		ctx := testCc(t, `
+		cc_binary_host {
+			name: "protoc-gen-foobar",
+			stl: "none",
+		}
+
+		cc_library_shared {
+			name: "libfoo",
+			srcs: ["a.proto"],
+			proto: {
+				plugin: "foobar",
+			},
+		}`)
+
+		buildOS := android.BuildOs.String()
+
+		proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Output("proto/a.pb.cc")
+		foobar := ctx.ModuleForTests("protoc-gen-foobar", buildOS+"_x86_64")
+
+		cmd := proto.RuleParams.Command
+		if w := "--foobar_out="; !strings.Contains(cmd, w) {
+			t.Errorf("expected %q in %q", w, cmd)
+		}
+
+		foobarPath := foobar.Module().(android.HostToolProvider).HostToolPath().String()
+
+		if w := "--plugin=protoc-gen-foobar=" + foobarPath; !strings.Contains(cmd, w) {
+			t.Errorf("expected %q in %q", w, cmd)
+		}
+	})
+
+}
diff --git a/cc/util.go b/cc/util.go
index 782bf61..5dcbaef 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -84,13 +84,9 @@
 
 		groupStaticLibs: in.GroupStaticLibs,
 
-		protoDeps:        in.protoDeps,
-		protoFlags:       strings.Join(in.protoFlags, " "),
-		protoOutTypeFlag: in.protoOutTypeFlag,
-		protoOutParams:   strings.Join(in.protoOutParams, ","),
+		proto:            in.proto,
 		protoC:           in.protoC,
 		protoOptionsFile: in.protoOptionsFile,
-		protoRoot:        in.ProtoRoot,
 	}
 }
 
diff --git a/cmd/dep_fixer/main.go b/cmd/dep_fixer/main.go
index 0647fb2..f94cf2f 100644
--- a/cmd/dep_fixer/main.go
+++ b/cmd/dep_fixer/main.go
@@ -29,30 +29,42 @@
 
 func main() {
 	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, "Usage: %s <depfile.d>", os.Args[0])
+		fmt.Fprintf(os.Stderr, "Usage: %s [-o <output>] <depfile.d> [<depfile.d>...]", os.Args[0])
 		flag.PrintDefaults()
 	}
 	output := flag.String("o", "", "Optional output file (defaults to rewriting source if necessary)")
 	flag.Parse()
 
-	if flag.NArg() != 1 {
-		log.Fatal("Expected a single file as an argument")
+	if flag.NArg() < 1 {
+		log.Fatal("Expected at least one input file as an argument")
 	}
 
-	old, err := ioutil.ReadFile(flag.Arg(0))
-	if err != nil {
-		log.Fatalf("Error opening %q: %v", flag.Arg(0), err)
+	var mergedDeps *Deps
+	var firstInput []byte
+
+	for i, arg := range flag.Args() {
+		input, err := ioutil.ReadFile(arg)
+		if err != nil {
+			log.Fatalf("Error opening %q: %v", arg, err)
+		}
+
+		deps, err := Parse(arg, bytes.NewBuffer(append([]byte(nil), input...)))
+		if err != nil {
+			log.Fatalf("Failed to parse: %v", err)
+		}
+
+		if i == 0 {
+			mergedDeps = deps
+			firstInput = input
+		} else {
+			mergedDeps.Inputs = append(mergedDeps.Inputs, deps.Inputs...)
+		}
 	}
 
-	deps, err := Parse(flag.Arg(0), bytes.NewBuffer(append([]byte(nil), old...)))
-	if err != nil {
-		log.Fatalf("Failed to parse: %v", err)
-	}
-
-	new := deps.Print()
+	new := mergedDeps.Print()
 
 	if *output == "" || *output == flag.Arg(0) {
-		if !bytes.Equal(old, new) {
+		if !bytes.Equal(firstInput, new) {
 			err := ioutil.WriteFile(flag.Arg(0), new, 0666)
 			if err != nil {
 				log.Fatalf("Failed to write: %v", err)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 32acd8c..e259b1d 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -49,8 +49,10 @@
 	GeneratedDeps() android.Paths
 }
 
+// Alias for android.HostToolProvider
+// Deprecated: use android.HostToolProvider instead.
 type HostToolProvider interface {
-	HostToolPath() android.OptionalPath
+	android.HostToolProvider
 }
 
 type hostToolDependencyTag struct {
@@ -193,7 +195,7 @@
 				tool := ctx.OtherModuleName(module)
 				var path android.OptionalPath
 
-				if t, ok := module.(HostToolProvider); ok {
+				if t, ok := module.(android.HostToolProvider); ok {
 					if !t.(android.Module).Enabled() {
 						if ctx.Config().AllowMissingDependencies() {
 							ctx.AddMissingDependencies([]string{tool})
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 19b22f7..5cb51b8 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -527,4 +527,4 @@
 	return android.OptionalPathForPath(t.outputFile)
 }
 
-var _ HostToolProvider = (*testTool)(nil)
+var _ android.HostToolProvider = (*testTool)(nil)
diff --git a/java/builder.go b/java/builder.go
index d8b303e..44767a5 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -153,10 +153,7 @@
 	kotlincFlags     string
 	kotlincClasspath classpath
 
-	protoFlags       []string
-	protoOutTypeFlag string // The flag itself: --java_out
-	protoOutParams   string // Parameters to that flag: --java_out=$protoOutParams:$outDir
-	protoRoot        bool
+	proto android.ProtoFlags
 }
 
 func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 141f7ba..cbb52f1 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -103,7 +103,7 @@
 		expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
 	}
 
-	outputs := bootArt.Outputs.Strings()
+	outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings()
 	sort.Strings(outputs)
 	sort.Strings(expectedOutputs)
 
diff --git a/java/gen.go b/java/gen.go
index 8362556..500d887 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -118,7 +118,7 @@
 			javaFile := genLogtags(ctx, srcFile)
 			outSrcFiles = append(outSrcFiles, javaFile)
 		case ".proto":
-			srcJarFile := genProto(ctx, srcFile, flags)
+			srcJarFile := genProto(ctx, srcFile, flags.proto)
 			outSrcFiles = append(outSrcFiles, srcJarFile)
 		case ".sysprop":
 			srcJarFile := genSysprop(ctx, srcFile)
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 86531eb..9627dc6 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -159,9 +159,9 @@
 	for moduleList, pathList := range moduleListToPathList {
 		for i := range pathList {
 			if pathList[i] == nil {
+				pathList[i] = android.PathForOutput(ctx, "missing")
 				if ctx.Config().AllowMissingDependencies() {
 					missingDeps = append(missingDeps, (*moduleList)[i])
-					pathList[i] = android.PathForOutput(ctx, "missing")
 				} else {
 					ctx.Errorf("failed to find dex jar path for module %q",
 						(*moduleList)[i])
@@ -236,6 +236,8 @@
 			android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")).
 		FlagWithInput("--blacklist ",
 			android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")).
+		FlagWithInput("--greylist-packages ",
+			android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")).
 		FlagWithOutput("--output ", tempPath)
 
 	commitChangeForRestat(rule, tempPath, outputPath)
diff --git a/java/java.go b/java/java.go
index beee1a5..0417dee 100644
--- a/java/java.go
+++ b/java/java.go
@@ -481,6 +481,7 @@
 		{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
 	}, pluginTag, j.properties.Plugins...)
 
+	android.ProtoDeps(ctx, &j.protoProperties)
 	if j.hasSrcExt(".proto") {
 		protoDeps(ctx, &j.protoProperties)
 	}
@@ -768,12 +769,6 @@
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
-			case android.DefaultsDepTag, android.SourceDepTag:
-				// Nothing to do
-			case publicApiFileTag, systemApiFileTag, testApiFileTag:
-				// Nothing to do
-			default:
-				ctx.ModuleErrorf("dependency on genrule %q may only be in srcs, libs, or static_libs", otherName)
 			}
 		default:
 			switch tag {
diff --git a/java/java_test.go b/java/java_test.go
index ec4c100..4158621 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -138,6 +138,9 @@
 		"prebuilts/sdk/17/public/android.jar":         nil,
 		"prebuilts/sdk/17/public/framework.aidl":      nil,
 		"prebuilts/sdk/17/system/android.jar":         nil,
+		"prebuilts/sdk/25/public/android.jar":         nil,
+		"prebuilts/sdk/25/public/framework.aidl":      nil,
+		"prebuilts/sdk/25/system/android.jar":         nil,
 		"prebuilts/sdk/current/core/android.jar":      nil,
 		"prebuilts/sdk/current/public/android.jar":    nil,
 		"prebuilts/sdk/current/public/framework.aidl": nil,
diff --git a/java/proto.go b/java/proto.go
index 8028039..37de1d2 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -15,108 +15,83 @@
 package java
 
 import (
-	"strings"
-
-	"github.com/google/blueprint"
-
 	"android/soong/android"
 )
 
-func init() {
-	pctx.HostBinToolVariable("protocCmd", "aprotoc")
-	pctx.HostBinToolVariable("depFixCmd", "dep_fixer")
-}
-
-var (
-	proto = pctx.AndroidStaticRule("protoc",
-		blueprint.RuleParams{
-			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$protocCmd $protoOut=$protoOutParams:$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
-				`$depFixCmd $out.d && ` +
-				`${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
-			CommandDeps: []string{
-				"$protocCmd",
-				"$depFixCmd",
-				"${config.SoongZipCmd}",
-			},
-			Depfile: "${out}.d",
-			Deps:    blueprint.DepsGCC,
-		}, "protoBase", "protoFlags", "protoOut", "protoOutParams")
-)
-
-func genProto(ctx android.ModuleContext, protoFile android.Path, flags javaBuilderFlags) android.Path {
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
 	srcJarFile := android.GenPathWithExt(ctx, "proto", protoFile, "srcjar")
 
-	var protoBase string
-	if flags.protoRoot {
-		protoBase = "."
-	} else {
-		protoBase = strings.TrimSuffix(protoFile.String(), protoFile.Rel())
-	}
+	outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
+	depFile := srcJarFile.ReplaceExtension(ctx, "srcjar.d")
 
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        proto,
-		Description: "protoc " + protoFile.Rel(),
-		Output:      srcJarFile,
-		Input:       protoFile,
-		Args: map[string]string{
-			"protoBase":      protoBase,
-			"protoOut":       flags.protoOutTypeFlag,
-			"protoOutParams": flags.protoOutParams,
-			"protoFlags":     strings.Join(flags.protoFlags, " "),
-		},
-	})
+	rule := android.NewRuleBuilder()
+
+	rule.Command().Text("rm -rf").Flag(outDir.String())
+	rule.Command().Text("mkdir -p").Flag(outDir.String())
+
+	android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
+
+	// Proto generated java files have an unknown package name in the path, so package the entire output directory
+	// into a srcjar.
+	rule.Command().
+		Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+		Flag("-jar").
+		FlagWithOutput("-o ", srcJarFile).
+		FlagWithArg("-C ", outDir.String()).
+		FlagWithArg("-D ", outDir.String())
+
+	rule.Command().Text("rm -rf").Flag(outDir.String())
+
+	rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
 
 	return srcJarFile
 }
 
 func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) {
-	switch String(p.Proto.Type) {
-	case "micro":
-		ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-micro")
-	case "nano":
-		ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-nano")
-	case "lite", "":
-		ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
-	case "full":
-		if ctx.Host() {
-			ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full")
-		} else {
-			ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
+	if String(p.Proto.Plugin) == "" {
+		switch String(p.Proto.Type) {
+		case "micro":
+			ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-micro")
+		case "nano":
+			ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-nano")
+		case "lite", "":
+			ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
+		case "full":
+			if ctx.Host() {
+				ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full")
+			} else {
+				ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
+			}
+		default:
+			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+				String(p.Proto.Type))
 		}
-	default:
-		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
-			String(p.Proto.Type))
 	}
 }
 
 func protoFlags(ctx android.ModuleContext, j *CompilerProperties, p *android.ProtoProperties,
 	flags javaBuilderFlags) javaBuilderFlags {
 
-	switch String(p.Proto.Type) {
-	case "micro":
-		flags.protoOutTypeFlag = "--javamicro_out"
-	case "nano":
-		flags.protoOutTypeFlag = "--javanano_out"
-	case "lite":
-		flags.protoOutTypeFlag = "--java_out"
-		flags.protoOutParams = "lite"
-	case "full", "":
-		flags.protoOutTypeFlag = "--java_out"
-	default:
-		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
-			String(p.Proto.Type))
-	}
+	flags.proto = android.GetProtoFlags(ctx, p)
 
-	if len(j.Proto.Output_params) > 0 {
-		if flags.protoOutParams != "" {
-			flags.protoOutParams += ","
+	if String(p.Proto.Plugin) == "" {
+		switch String(p.Proto.Type) {
+		case "micro":
+			flags.proto.OutTypeFlag = "--javamicro_out"
+		case "nano":
+			flags.proto.OutTypeFlag = "--javanano_out"
+		case "lite":
+			flags.proto.OutTypeFlag = "--java_out"
+			flags.proto.OutParams = append(flags.proto.OutParams, "lite")
+		case "full", "":
+			flags.proto.OutTypeFlag = "--java_out"
+		default:
+			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
+				String(p.Proto.Type))
 		}
-		flags.protoOutParams += strings.Join(j.Proto.Output_params, ",")
 	}
 
-	flags.protoFlags = android.ProtoFlags(ctx, p)
-	flags.protoRoot = android.ProtoCanonicalPathFromRoot(ctx, p)
+	flags.proto.OutParams = append(flags.proto.OutParams, j.Proto.Output_params...)
 
 	return flags
 }
diff --git a/java/sdk.go b/java/sdk.go
index 0959be7..48e7746 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -84,7 +84,7 @@
 		v = strconv.Itoa(latestSdkVersion)
 	}
 
-	i, err := sdkVersionToNumber(ctx, v)
+	numericSdkVersion, err := sdkVersionToNumber(ctx, v)
 	if err != nil {
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 		return sdkDep{}
@@ -151,15 +151,14 @@
 
 	// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
 	// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
-	if strings.HasPrefix(v, "system_") && i != android.FutureApiLevel {
+	if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel {
 		allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
 		if ctx.DeviceSpecific() || ctx.SocSpecific() {
 			if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
 				allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
 			}
 		}
-		version := strings.TrimPrefix(v, "system_")
-		if len(allowed_versions) > 0 && !android.InList(version, allowed_versions) {
+		if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) {
 			ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
 				v, allowed_versions)
 		}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index a11ea2f..8ac10ba 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -50,11 +50,11 @@
 	},
 	{
 
-		name:          "sdk v14",
-		properties:    `sdk_version: "14",`,
+		name:          "sdk v25",
+		properties:    `sdk_version: "25",`,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 	{
 
@@ -72,11 +72,11 @@
 	},
 	{
 
-		name:          "system_14",
-		properties:    `sdk_version: "system_14",`,
+		name:          "system_25",
+		properties:    `sdk_version: "system_25",`,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/14/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 	{
 
@@ -140,12 +140,12 @@
 	},
 	{
 
-		name:          "unbundled sdk v14",
+		name:          "unbundled sdk v25",
 		unbundled:     true,
-		properties:    `sdk_version: "14",`,
+		properties:    `sdk_version: "25",`,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 	{
 
@@ -162,7 +162,7 @@
 		pdk:           true,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/17/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 	{
 		name:          "pdk current",
@@ -170,15 +170,15 @@
 		properties:    `sdk_version: "current",`,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/17/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 	{
-		name:          "pdk 14",
+		name:          "pdk 25",
 		pdk:           true,
-		properties:    `sdk_version: "14",`,
+		properties:    `sdk_version: "25",`,
 		bootclasspath: []string{`""`},
 		system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-		classpath:     []string{"prebuilts/sdk/14/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+		classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 	},
 }
 
@@ -285,6 +285,44 @@
 					t.Errorf("bootclasspath expected %q != got %q", expected, got)
 				}
 			})
+
+			// Test again with PLATFORM_VERSION_CODENAME=REL
+			t.Run("REL", func(t *testing.T) {
+				config := testConfig(nil)
+				config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
+				config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
+
+				if testcase.unbundled {
+					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+				}
+				if testcase.pdk {
+					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+				}
+				ctx := testContext(config, bp, nil)
+				run(t, ctx, config)
+
+				javac := ctx.ModuleForTests("foo", variant).Rule("javac")
+
+				got := javac.Args["bootClasspath"]
+				if got != bc {
+					t.Errorf("bootclasspath expected %q != got %q", bc, got)
+				}
+
+				got = javac.Args["classpath"]
+				if got != c {
+					t.Errorf("classpath expected %q != got %q", c, got)
+				}
+
+				var deps []string
+				if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
+					deps = append(deps, bootclasspath...)
+				}
+				deps = append(deps, classpath...)
+
+				if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
+					t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
+				}
+			})
 		})
 	}
 
diff --git a/java/testing.go b/java/testing.go
index 713eca1..db06ae1 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -28,7 +28,6 @@
 		env["ANDROID_JAVA8_HOME"] = "jdk8"
 	}
 	config := android.TestArchConfig(buildDir, env)
-	config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
 
 	return config
 }
diff --git a/phony/phony.go b/phony/phony.go
index e8a6550..ed6a2fe 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -34,7 +34,7 @@
 func PhonyFactory() android.Module {
 	module := &phony{}
 
-	android.InitAndroidModule(module)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	return module
 }
 
@@ -51,6 +51,9 @@
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+			if p.Host() {
+				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+			}
 			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(p.requiredModuleNames, " "))
 			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 		},
diff --git a/python/proto.go b/python/proto.go
index 2370cd2..b3ffaa6 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -16,58 +16,35 @@
 
 import (
 	"android/soong/android"
-	"strings"
-
-	"github.com/google/blueprint"
 )
 
-func init() {
-	pctx.HostBinToolVariable("protocCmd", "aprotoc")
-}
+func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags, pkgPath string) android.Path {
+	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
 
-var (
-	proto = pctx.AndroidStaticRule("protoc",
-		blueprint.RuleParams{
-			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$protocCmd --python_out=$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
-				`$parCmd -o $out $pkgPathArgs -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
-			CommandDeps: []string{
-				"$protocCmd",
-				"$parCmd",
-			},
-			Depfile: "${out}.d",
-			Deps:    blueprint.DepsGCC,
-		}, "protoBase", "protoFlags", "pkgPathArgs")
-)
+	outDir := srcsZipFile.ReplaceExtension(ctx, "tmp")
+	depFile := srcsZipFile.ReplaceExtension(ctx, "srcszip.d")
 
-func genProto(ctx android.ModuleContext, p *android.ProtoProperties,
-	protoFile android.Path, protoFlags []string, pkgPath string) android.Path {
-	srcJarFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
+	rule := android.NewRuleBuilder()
 
-	protoRoot := android.ProtoCanonicalPathFromRoot(ctx, p)
+	rule.Command().Text("rm -rf").Flag(outDir.String())
+	rule.Command().Text("mkdir -p").Flag(outDir.String())
 
-	var protoBase string
-	if protoRoot {
-		protoBase = "."
-	} else {
-		protoBase = strings.TrimSuffix(protoFile.String(), protoFile.Rel())
-	}
+	android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
 
-	var pkgPathArgs string
+	// Proto generated python files have an unknown package name in the path, so package the entire output directory
+	// into a srcszip.
+	zipCmd := rule.Command().
+		Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+		FlagWithOutput("-o ", srcsZipFile).
+		FlagWithArg("-C ", outDir.String()).
+		FlagWithArg("-D ", outDir.String())
 	if pkgPath != "" {
-		pkgPathArgs = "-P " + pkgPath
+		zipCmd.FlagWithArg("-P ", pkgPath)
 	}
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        proto,
-		Description: "protoc " + protoFile.Rel(),
-		Output:      srcJarFile,
-		Input:       protoFile,
-		Args: map[string]string{
-			"protoBase":   protoBase,
-			"protoFlags":  strings.Join(protoFlags, " "),
-			"pkgPathArgs": pkgPathArgs,
-		},
-	})
 
-	return srcJarFile
+	rule.Command().Text("rm -rf").Flag(outDir.String())
+
+	rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
+
+	return srcsZipFile
 }
diff --git a/python/python.go b/python/python.go
index 6eb9b6e..ad08909 100644
--- a/python/python.go
+++ b/python/python.go
@@ -288,6 +288,8 @@
 }
 
 func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
+	android.ProtoDeps(ctx, &p.protoProperties)
+
 	if p.hasSrcExt(ctx, protoExt) && p.Name() != "libprotobuf-python" {
 		ctx.AddVariationDependencies(nil, pythonLibTag, "libprotobuf-python")
 	}
@@ -516,9 +518,11 @@
 	}
 	var zips android.Paths
 	if len(protoSrcs) > 0 {
+		protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
+		protoFlags.OutTypeFlag = "--python_out"
+
 		for _, srcFile := range protoSrcs {
-			zip := genProto(ctx, &p.protoProperties, srcFile,
-				android.ProtoFlags(ctx, &p.protoProperties), pkgPath)
+			zip := genProto(ctx, srcFile, protoFlags, pkgPath)
 			zips = append(zips, zip)
 		}
 	}