Merge "Blacklist more libraries from no-vendor-variant VNDK"
diff --git a/Android.bp b/Android.bp
index 7465341..a4e6e7d 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..84dd66f 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,
@@ -499,6 +501,22 @@
 	return String(c.productVariables.Platform_sdk_codename)
 }
 
+func (c *config) PlatformSecurityPatch() string {
+	return String(c.productVariables.Platform_security_patch)
+}
+
+func (c *config) PlatformPreviewSdkVersion() string {
+	return String(c.productVariables.Platform_preview_sdk_version)
+}
+
+func (c *config) PlatformMinSupportedTargetSdkVersion() string {
+	return String(c.productVariables.Platform_min_supported_target_sdk_version)
+}
+
+func (c *config) PlatformBaseOS() string {
+	return String(c.productVariables.Platform_base_os)
+}
+
 func (c *config) MinSupportedSdkVersion() int {
 	return 16
 }
diff --git a/android/defs.go b/android/defs.go
index cd8b4e3..4890c66 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -20,7 +20,7 @@
 )
 
 var (
-	pctx = NewPackageContext("android/soong/common")
+	pctx = NewPackageContext("android/soong/android")
 
 	cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
 		Config.CpPreserveSymlinksFlags)
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/namespace.go b/android/namespace.go
index dca2b8c..50bdcba 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -355,15 +355,19 @@
 
 var _ blueprint.Namespace = (*Namespace)(nil)
 
+type namespaceProperties struct {
+	// a list of namespaces that contain modules that will be referenced
+	// by modules in this namespace.
+	Imports []string `android:"path"`
+}
+
 type NamespaceModule struct {
 	ModuleBase
 
 	namespace *Namespace
 	resolver  *NameResolver
 
-	properties struct {
-		Imports []string
-	}
+	properties namespaceProperties
 }
 
 func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -376,6 +380,16 @@
 	return *n.nameProperties.Name
 }
 
+// soong_namespace provides a scope to modules in an Android.bp file to prevent
+// module name conflicts with other defined modules in different Android.bp
+// files. Once soong_namespace has been defined in an Android.bp file, the
+// namespacing is applied to all modules that follow the soong_namespace in
+// the current Android.bp file, as well as modules defined in Android.bp files
+// in subdirectories. An Android.bp file in a subdirectory can define its own
+// soong_namespace which is applied to all its modules and as well as modules
+// defined in subdirectories Android.bp files. Modules in a soong_namespace are
+// visible to Make by listing the namespace path in PRODUCT_SOONG_NAMESPACES
+// make variable in a makefile.
 func NamespaceFactory() Module {
 	module := &NamespaceModule{}
 
diff --git a/android/override_module.go b/android/override_module.go
index 02db359..119bca1 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -134,10 +134,15 @@
 
 // Overrides a base module with the given OverrideModule.
 func (b *OverridableModuleBase) override(ctx BaseModuleContext, o OverrideModule) {
+	// Adds the base module to the overrides property, if exists, of the overriding module. See the
+	// comment on OverridableModuleBase.overridesProperty for details.
+	if b.overridesProperty != nil {
+		*b.overridesProperty = append(*b.overridesProperty, b.Name())
+	}
 	for _, p := range b.overridableProperties {
 		for _, op := range o.getOverridingProperties() {
 			if proptools.TypeEqual(p, op) {
-				err := proptools.PrependProperties(p, op, nil)
+				err := proptools.AppendProperties(p, op, nil)
 				if err != nil {
 					if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
 						ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
@@ -148,13 +153,6 @@
 			}
 		}
 	}
-	// Adds the base module to the overrides property, if exists, of the overriding module. See the
-	// comment on OverridableModuleBase.overridesProperty for details.
-	if b.overridesProperty != nil {
-		*b.overridesProperty = append(*b.overridesProperty, b.Name())
-	}
-	// The base module name property has to be updated separately for Name() to work as intended.
-	b.module.base().nameProperties.Name = proptools.StringPtr(o.Name())
 }
 
 // Mutators for override/overridable modules. All the fun happens in these functions. It is critical
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 5bd0e2d..df25a89 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -18,6 +18,7 @@
 	"fmt"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 // This file implements common functionality for handling modules that may exist as prebuilts,
@@ -42,6 +43,7 @@
 	properties PrebuiltProperties
 	module     Module
 	srcs       *[]string
+	src        *string
 }
 
 func (p *Prebuilt) Name(name string) string {
@@ -49,19 +51,27 @@
 }
 
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
-	if len(*p.srcs) == 0 {
-		ctx.PropertyErrorf("srcs", "missing prebuilt source file")
-		return nil
-	}
+	if p.srcs != nil {
+		if len(*p.srcs) == 0 {
+			ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+			return nil
+		}
 
-	if len(*p.srcs) > 1 {
-		ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
-		return nil
-	}
+		if len(*p.srcs) > 1 {
+			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+			return nil
+		}
 
-	// Return the singleton source after expanding any filegroup in the
-	// sources.
-	return PathForModuleSrc(ctx, (*p.srcs)[0])
+		// Return the singleton source after expanding any filegroup in the
+		// sources.
+		return PathForModuleSrc(ctx, (*p.srcs)[0])
+	} else {
+		if proptools.String(p.src) == "" {
+			ctx.PropertyErrorf("src", "missing prebuilt source file")
+			return nil
+		}
+		return PathForModuleSrc(ctx, *p.src)
+	}
 }
 
 func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
@@ -70,13 +80,19 @@
 	p.srcs = srcs
 }
 
+func InitSingleSourcePrebuiltModule(module PrebuiltInterface, src *string) {
+	p := module.Prebuilt()
+	module.AddProperties(&p.properties)
+	p.src = src
+}
+
 type PrebuiltInterface interface {
 	Module
 	Prebuilt() *Prebuilt
 }
 
 func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
+	ctx.BottomUp("prebuilts", PrebuiltMutator).Parallel()
 }
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
@@ -84,9 +100,9 @@
 	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
 }
 
-// prebuiltMutator ensures that there is always a module with an undecorated name, and marks
+// PrebuiltMutator ensures that there is always a module with an undecorated name, and marks
 // prebuilt modules that have both a prebuilt and a source module.
-func prebuiltMutator(ctx BottomUpMutatorContext) {
+func PrebuiltMutator(ctx BottomUpMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
 		name := m.base().BaseModuleName()
@@ -104,7 +120,7 @@
 func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
-		if p.srcs == nil {
+		if p.srcs == nil && p.src == nil {
 			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
 		}
 		if !p.properties.SourceExists {
@@ -143,7 +159,11 @@
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
-	if len(*p.srcs) == 0 {
+	if p.srcs != nil && len(*p.srcs) == 0 {
+		return false
+	}
+
+	if p.src != nil && *p.src == "" {
 		return false
 	}
 
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..21af31f 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 {
@@ -136,14 +137,18 @@
 	BuildNumberFromFile *string `json:",omitempty"`
 	DateFromFile        *string `json:",omitempty"`
 
-	Platform_version_name             *string  `json:",omitempty"`
-	Platform_sdk_version              *int     `json:",omitempty"`
-	Platform_sdk_codename             *string  `json:",omitempty"`
-	Platform_sdk_final                *bool    `json:",omitempty"`
-	Platform_version_active_codenames []string `json:",omitempty"`
-	Platform_version_future_codenames []string `json:",omitempty"`
-	Platform_vndk_version             *string  `json:",omitempty"`
-	Platform_systemsdk_versions       []string `json:",omitempty"`
+	Platform_version_name                     *string  `json:",omitempty"`
+	Platform_sdk_version                      *int     `json:",omitempty"`
+	Platform_sdk_codename                     *string  `json:",omitempty"`
+	Platform_sdk_final                        *bool    `json:",omitempty"`
+	Platform_version_active_codenames         []string `json:",omitempty"`
+	Platform_version_future_codenames         []string `json:",omitempty"`
+	Platform_vndk_version                     *string  `json:",omitempty"`
+	Platform_systemsdk_versions               []string `json:",omitempty"`
+	Platform_security_patch                   *string  `json:",omitempty"`
+	Platform_preview_sdk_version              *string  `json:",omitempty"`
+	Platform_min_supported_target_sdk_version *string  `json:",omitempty"`
+	Platform_base_os                          *string  `json:",omitempty"`
 
 	DeviceName              *string  `json:",omitempty"`
 	DeviceArch              *string  `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index c1f52a6..3327a56 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -119,7 +119,7 @@
 )
 
 func init() {
-	pctx.Import("android/soong/common")
+	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/java")
 	pctx.HostBinToolVariable("apexer", "apexer")
 	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
@@ -149,6 +149,7 @@
 	android.RegisterModuleType("apex", apexBundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
+	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
@@ -395,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
@@ -745,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)
@@ -967,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 {
@@ -1056,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"))
 
@@ -1069,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)
@@ -1214,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())
 				}
@@ -1283,3 +1284,103 @@
 	android.InitDefaultsModule(module)
 	return module
 }
+
+//
+// Prebuilt APEX
+//
+type Prebuilt struct {
+	android.ModuleBase
+	prebuilt android.Prebuilt
+
+	properties PrebuiltProperties
+
+	inputApex  android.Path
+	installDir android.OutputPath
+}
+
+type PrebuiltProperties struct {
+	// the path to the prebuilt .apex file to import.
+	Source string `blueprint:"mutated"`
+
+	Src  *string
+	Arch struct {
+		Arm struct {
+			Src *string
+		}
+		Arm64 struct {
+			Src *string
+		}
+		X86 struct {
+			Src *string
+		}
+		X86_64 struct {
+			Src *string
+		}
+	}
+}
+
+func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// 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.
+	if len(ctx.MultiTargets()) != 1 {
+		ctx.ModuleErrorf("compile_multilib shouldn't be \"both\" for prebuilt_apex")
+		return
+	}
+	var src string
+	switch ctx.MultiTargets()[0].Arch.ArchType {
+	case android.Arm:
+		src = String(p.properties.Arch.Arm.Src)
+	case android.Arm64:
+		src = String(p.properties.Arch.Arm64.Src)
+	case android.X86:
+		src = String(p.properties.Arch.X86.Src)
+	case android.X86_64:
+		src = String(p.properties.Arch.X86_64.Src)
+	default:
+		ctx.ModuleErrorf("prebuilt_apex does not support %q", ctx.MultiTargets()[0].Arch.String())
+		return
+	}
+	if src == "" {
+		src = String(p.properties.Src)
+	}
+	p.properties.Source = src
+}
+
+func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// TODO(jungjw): Check the key validity.
+	p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
+	p.installDir = android.PathForModuleInstall(ctx, "apex")
+	ctx.InstallFile(p.installDir, ctx.ModuleName()+imageApexSuffix, p.inputApex)
+}
+
+func (p *Prebuilt) Prebuilt() *android.Prebuilt {
+	return &p.prebuilt
+}
+
+func (p *Prebuilt) Name() string {
+	return p.prebuilt.Name(p.ModuleBase.Name())
+}
+
+func (p *Prebuilt) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(p.inputApex),
+		Include:    "$(BUILD_PREBUILT)",
+		Extra: []android.AndroidMkExtraFunc{
+			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)
+			},
+		},
+	}
+}
+
+// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
+func PrebuiltFactory() android.Module {
+	module := &Prebuilt{}
+	module.AddProperties(&module.properties)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties.Source)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8a2e55a..6d101d8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -36,11 +36,14 @@
 	ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
 	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
 	ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
+	ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
 		ctx.BottomUp("apex", apexMutator)
+		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
+		ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
 	})
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
@@ -54,6 +57,9 @@
 	ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
 	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
+	})
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", cc.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
@@ -163,6 +169,8 @@
 		"custom_notice":                        nil,
 		"testkey2.avbpubkey":                   nil,
 		"testkey2.pem":                         nil,
+		"myapex-arm64.apex":                    nil,
+		"myapex-arm.apex":                      nil,
 	})
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -289,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
@@ -1187,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) {
@@ -1229,3 +1233,26 @@
 		t.Errorf("wrong private key path. expected %q. actual %q", expected_privkey, actual_privkey)
 	}
 }
+
+func TestPrebuilt(t *testing.T) {
+	ctx := testApex(t, `
+		prebuilt_apex {
+			name: "myapex",
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+		}
+	`)
+
+	prebuilt := ctx.ModuleForTests("myapex", "android_common").Module().(*Prebuilt)
+
+	expectedInput := "myapex-arm64.apex"
+	if prebuilt.inputApex.String() != expectedInput {
+		t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String())
+	}
+}
diff --git a/apex/key.go b/apex/key.go
index 848e8ce..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) {
@@ -93,31 +90,12 @@
 	pubKeyName := m.public_key_file.Base()[0 : len(m.public_key_file.Base())-len(m.public_key_file.Ext())]
 	privKeyName := m.private_key_file.Base()[0 : len(m.private_key_file.Base())-len(m.private_key_file.Ext())]
 
-	if pubKeyName != privKeyName {
+	if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName {
 		ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname",
 			m.public_key_file.String(), pubKeyName, m.private_key_file, privKeyName)
 		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 7f7c600..35c3d85 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -57,13 +57,13 @@
 	android.RegisterModuleType("cc_binary_host", binaryHostFactory)
 }
 
-// Module factory for binaries
+// cc_binary produces a binary that is runnable on a device.
 func BinaryFactory() android.Module {
 	module, _ := NewBinary(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
-// Module factory for host binaries
+// cc_binary_host produces a binary that is runnable on a host.
 func binaryHostFactory() android.Module {
 	module, _ := NewBinary(android.HostSupported)
 	return module.Init()
@@ -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...)
@@ -417,6 +417,10 @@
 	return binary.symlinks
 }
 
+func (binary *binaryDecorator) nativeCoverage() bool {
+	return true
+}
+
 // /system/bin/linker -> /apex/com.android.runtime/bin/linker
 func (binary *binaryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, file android.Path) {
 	dir := binary.baseInstaller.installDir(ctx)
diff --git a/cc/builder.go b/cc/builder.go
index dab887c..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"
@@ -70,6 +69,8 @@
 			CommandDeps:    []string{"$ldCmd"},
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
+			// clang -Wl,--out-implib doesn't update its output file if it hasn't changed.
+			Restat: true,
 		},
 		"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags")
 
@@ -258,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 {
@@ -598,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++"
 
@@ -635,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...)
@@ -650,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 c80d00c..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 {
@@ -267,6 +263,7 @@
 	isStubs() bool
 	bootstrap() bool
 	mustUseVendorVariant() bool
+	nativeCoverage() bool
 }
 
 type ModuleContext interface {
@@ -312,6 +309,8 @@
 	link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
 	appendLdflags([]string)
 	unstrippedOutputFilePath() android.Path
+
+	nativeCoverage() bool
 }
 
 type installer interface {
@@ -604,6 +603,10 @@
 	return Bool(c.Properties.Bootstrap)
 }
 
+func (c *Module) nativeCoverage() bool {
+	return c.linker != nil && c.linker.nativeCoverage()
+}
+
 func isBionic(name string) bool {
 	switch name {
 	case "libc", "libm", "libdl", "linker":
@@ -794,6 +797,10 @@
 	return ctx.mod.bootstrap()
 }
 
+func (ctx *moduleContextImpl) nativeCoverage() bool {
+	return ctx.mod.nativeCoverage()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -1586,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
@@ -1966,6 +1977,11 @@
 func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
+// cc_defaults provides a set of properties that can be inherited by other cc
+// modules. A module can use the properties from a cc_defaults using
+// `defaults: ["<:default_module_name>"]`. Properties of both modules are
+// merged (when possible) by prepending the default module's values to the
+// depending module's values.
 func defaultsFactory() android.Module {
 	return DefaultsFactory()
 }
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 0ab1f01..f9af4d8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -221,12 +221,14 @@
 	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))
 	}
 
 	if compiler.hasSrcExt(".sysprop") {
-		deps.SharedLibs = append(deps.SharedLibs, "libbase")
+		deps.HeaderLibs = append(deps.HeaderLibs, "libbase_headers")
+		deps.SharedLibs = append(deps.SharedLibs, "liblog")
 	}
 
 	if Bool(compiler.Properties.Openmp) {
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 81439f3..347bfab 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -132,13 +132,13 @@
 
 		// Warnings from clang-8.0
 		"-Wno-defaulted-function-deleted",
-	}, " "))
 
-	pctx.StaticVariable("ClangExtraCppflags", strings.Join([]string{
 		// Disable -Winconsistent-missing-override until we can clean up the existing
 		// codebase for it.
 		"-Wno-inconsistent-missing-override",
+	}, " "))
 
+	pctx.StaticVariable("ClangExtraCppflags", strings.Join([]string{
 		// Enable clang's thread-safety annotations in libcxx.
 		// Turn off -Wthread-safety-negative, to avoid breaking projects that use -Weverything.
 		"-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
diff --git a/cc/config/global.go b/cc/config/global.go
index e3fab0c..372ffc4 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -120,8 +120,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r353983"
-	ClangDefaultShortVersion = "9.0.1"
+	ClangDefaultVersion      = "clang-r353983b"
+	ClangDefaultShortVersion = "9.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/coverage.go b/cc/coverage.go
index ad2f1e4..9dc7f06 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -23,6 +23,9 @@
 type CoverageProperties struct {
 	Native_coverage *bool
 
+	NeedCoverageVariant bool `blueprint:"mutated"`
+	NeedCoverageBuild   bool `blueprint:"mutated"`
+
 	CoverageEnabled   bool `blueprint:"mutated"`
 	IsCoverageVariant bool `blueprint:"mutated"`
 }
@@ -38,9 +41,24 @@
 	return []interface{}{&cov.Properties}
 }
 
-func (cov *coverage) begin(ctx BaseModuleContext) {}
-
 func (cov *coverage) deps(ctx BaseModuleContext, deps Deps) Deps {
+	if cov.Properties.NeedCoverageBuild {
+		// Link libprofile-extras/libprofile-extras_ndk when coverage
+		// variant is required.  This is a no-op unless coverage is
+		// actually enabled during linking, when
+		// '-uinit_profile_extras' is added (in flags()) to force the
+		// setup code in libprofile-extras be linked into the
+		// binary/library.
+		//
+		// We cannot narrow it further to only the 'cov' variant since
+		// the mutator hasn't run (and we don't have the 'cov' variant
+		// yet).
+		if !ctx.useSdk() {
+			deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras")
+		} else {
+			deps.LateStaticLibs = append(deps.LateStaticLibs, "libprofile-extras_ndk")
+		}
+	}
 	return deps
 }
 
@@ -95,46 +113,54 @@
 
 	if cov.linkCoverage {
 		flags.LdFlags = append(flags.LdFlags, "--coverage")
+
+		// Force linking of constructor/setup code in libprofile-extras
+		flags.LdFlags = append(flags.LdFlags, "-uinit_profile_extras")
 	}
 
 	return flags
 }
 
-func coverageMutator(mctx android.BottomUpMutatorContext) {
+func (cov *coverage) begin(ctx BaseModuleContext) {
 	// Coverage is disabled globally
-	if !mctx.DeviceConfig().NativeCoverageEnabled() {
+	if !ctx.DeviceConfig().NativeCoverageEnabled() {
 		return
 	}
 
-	if c, ok := mctx.Module().(*Module); ok {
-		var needCoverageVariant bool
-		var needCoverageBuild bool
+	var needCoverageVariant bool
+	var needCoverageBuild bool
 
-		if mctx.Host() {
-			// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
-			// Just turn off for now.
-		} else if c.IsStubs() {
-			// Do not enable coverage for platform stub libraries
-		} else if c.isNDKStubLibrary() {
-			// Do not enable coverage for NDK stub libraries
-		} else if c.coverage != nil {
-			// Check if Native_coverage is set to false.  This property defaults to true.
-			needCoverageVariant = BoolDefault(c.coverage.Properties.Native_coverage, true)
+	if ctx.Host() {
+		// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
+		// Just turn off for now.
+	} else if !ctx.nativeCoverage() {
+		// Native coverage is not supported for this module type.
+	} else {
+		// Check if Native_coverage is set to false.  This property defaults to true.
+		needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true)
 
-			if sdk_version := String(c.Properties.Sdk_version); sdk_version != "current" {
-				// Native coverage is not supported for SDK versions < 23
-				if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
-					needCoverageVariant = false
-				}
-			}
-
-			if needCoverageVariant {
-				// Coverage variant is actually built with coverage if enabled for its module path
-				needCoverageBuild = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+		if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" {
+			// Native coverage is not supported for SDK versions < 23
+			if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
+				needCoverageVariant = false
 			}
 		}
 
 		if needCoverageVariant {
+			// Coverage variant is actually built with coverage if enabled for its module path
+			needCoverageBuild = ctx.DeviceConfig().CoverageEnabledForPath(ctx.ModuleDir())
+		}
+	}
+
+	cov.Properties.NeedCoverageBuild = needCoverageBuild
+	cov.Properties.NeedCoverageVariant = needCoverageVariant
+}
+
+func coverageMutator(mctx android.BottomUpMutatorContext) {
+	if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
+		needCoverageVariant := c.coverage.Properties.NeedCoverageVariant
+		needCoverageBuild := c.coverage.Properties.NeedCoverageBuild
+		if needCoverageVariant {
 			m := mctx.CreateVariations("", "cov")
 
 			// Setup the non-coverage version and set HideFromMake and
diff --git a/cc/library.go b/cc/library.go
index e5bb347..cf20747 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -153,42 +153,48 @@
 	android.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
 }
 
-// Module factory for combined static + shared libraries, device by default but with possible host
-// support
+// cc_library creates both static and/or shared libraries for a device and/or
+// host. By default, a cc_library has a single variant that targets the device.
+// Specifying `host_supported: true` also creates a library that targets the
+// host.
 func LibraryFactory() android.Module {
 	module, _ := NewLibrary(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
-// Module factory for static libraries
+// cc_library_static creates a static library for a device and/or host binary.
 func LibraryStaticFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
 	return module.Init()
 }
 
-// Module factory for shared libraries
+// cc_library_shared creates a shared library for a device and/or host.
 func LibrarySharedFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyShared()
 	return module.Init()
 }
 
-// Module factory for host static libraries
+// cc_library_host_static creates a static library that is linkable to a host
+// binary.
 func LibraryHostStaticFactory() android.Module {
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyStatic()
 	return module.Init()
 }
 
-// Module factory for host shared libraries
+// cc_library_host_shared creates a shared library that is usable on a host.
 func LibraryHostSharedFactory() android.Module {
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyShared()
 	return module.Init()
 }
 
-// Module factory for header-only libraries
+// cc_library_headers contains a set of c/c++ headers which are imported by
+// other soong cc modules using the header_libs property. For best practices,
+// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
+// Make.
 func LibraryHeaderFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.HeaderOnly()
@@ -351,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...)
@@ -678,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
@@ -737,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...)
@@ -755,6 +752,13 @@
 	return library.unstrippedOutputFile
 }
 
+func (library *libraryDecorator) nativeCoverage() bool {
+	if library.header() || library.buildStubs() {
+		return false
+	}
+	return true
+}
+
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
 	isLlndk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
 
@@ -835,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/llndk_library.go b/cc/llndk_library.go
index cdd2c48..5a36b7f 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -161,6 +161,10 @@
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
+func (stub *llndkStubDecorator) nativeCoverage() bool {
+	return false
+}
+
 func NewLLndkStubLibrary() *Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
diff --git a/cc/lto.go b/cc/lto.go
index 0d7a246..1084869 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -91,22 +91,22 @@
 		flags.CFlags = append(flags.CFlags, ltoFlag)
 		flags.LdFlags = append(flags.LdFlags, ltoFlag)
 
-		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && !lto.useClangLld(ctx) {
+		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) {
 			// Set appropriate ThinLTO cache policy
-			cacheDirFormat := "-Wl,-plugin-opt,cache-dir="
+			cacheDirFormat := "-Wl,--thinlto-cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
 			flags.LdFlags = append(flags.LdFlags, cacheDirFormat+cacheDir)
 
 			// Limit the size of the ThinLTO cache to the lesser of 10% of available
 			// disk space and 10GB.
-			cachePolicyFormat := "-Wl,-plugin-opt,cache-policy="
+			cachePolicyFormat := "-Wl,--thinlto-cache-policy="
 			policy := "cache_size=10%:cache_size_bytes=10g"
 			flags.LdFlags = append(flags.LdFlags, cachePolicyFormat+policy)
 		}
 
 		// If the module does not have a profile, be conservative and do not inline
 		// or unroll loops during LTO, in order to prevent significant size bloat.
-		if !ctx.isPgoCompile() && !lto.useClangLld(ctx) {
+		if !ctx.isPgoCompile() {
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
 		}
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 3ae4452..7199467 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -338,6 +338,10 @@
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
+func (stub *stubDecorator) nativeCoverage() bool {
+	return false
+}
+
 func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
 	arch := ctx.Target().Arch.ArchType.Name
 	apiLevel := stub.properties.ApiLevel
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 9265bff..e39bae5 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -63,7 +63,7 @@
 	android.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	android.RegisterSingletonType("ndk", NdkSingleton)
 
-	pctx.Import("android/soong/common")
+	pctx.Import("android/soong/android")
 }
 
 func getNdkInstallBase(ctx android.PathContext) android.OutputPath {
diff --git a/cc/object.go b/cc/object.go
index b9c5742..50ecc38 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -33,6 +33,9 @@
 	Properties ObjectLinkerProperties
 }
 
+// cc_object runs the compiler without running the linker. It is rarely
+// necessary, but sometimes used to generate .s files from .c files to use as
+// input to a cc_genrule module.
 func ObjectFactory() android.Module {
 	module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
 	module.linker = &objectLinker{
@@ -111,3 +114,7 @@
 func (object *objectLinker) unstrippedOutputFilePath() android.Path {
 	return nil
 }
+
+func (object *objectLinker) nativeCoverage() bool {
+	return true
+}
diff --git a/cc/pgo.go b/cc/pgo.go
index 9363916..7334ea2 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -27,8 +27,11 @@
 
 var (
 	// Add flags to ignore warnings that profiles are old or missing for
-	// some functions
-	profileUseOtherFlags = []string{"-Wno-backend-plugin"}
+	// some functions, and turn on the experimental new pass manager.
+	profileUseOtherFlags = []string{
+		"-Wno-backend-plugin",
+		"-fexperimental-new-pass-manager",
+	}
 
 	globalPgoProfileProjects = []string{
 		"toolchain/pgo-profiles",
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 4c893d4..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 {
@@ -108,6 +112,12 @@
 	return p.libraryDecorator.shared()
 }
 
+func (p *prebuiltLibraryLinker) nativeCoverage() bool {
+	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()
@@ -133,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()
@@ -193,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/test.go b/cc/test.go
index 045cc4f..dae2a37 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -74,31 +74,41 @@
 	android.RegisterModuleType("cc_benchmark_host", BenchmarkHostFactory)
 }
 
-// Module factory for tests
+// cc_test generates a test config file and an executable binary file to test
+// specific functionality on a device. The executable binary gets an implicit
+// static_libs dependency on libgtests unless the gtest flag is set to false.
 func TestFactory() android.Module {
 	module := NewTest(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
-// Module factory for test libraries
+// cc_test_library creates an archive of files (i.e. .o files) which is later
+// referenced by another module (such as cc_test, cc_defaults or cc_test_library)
+// for archiving or linking.
 func TestLibraryFactory() android.Module {
 	module := NewTestLibrary(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
-// Module factory for benchmarks
+// cc_benchmark compiles an executable binary that performs benchmark testing
+// of a specific component in a device. Additional files such as test suites
+// and test configuration are installed on the side of the compiled executed
+// binary.
 func BenchmarkFactory() android.Module {
 	module := NewBenchmark(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
-// Module factory for host tests
+// cc_test_host compiles a test host binary.
 func TestHostFactory() android.Module {
 	module := NewTest(android.HostSupported)
 	return module.Init()
 }
 
-// Module factory for host benchmarks
+// cc_benchmark_host compiles an executable binary that performs benchmark
+// testing of a specific component in the host. Additional files such as
+// test suites and test configuration are installed on the side of the
+// compiled executed binary.
 func BenchmarkHostFactory() android.Module {
 	module := NewBenchmark(android.HostSupported)
 	return module.Init()
diff --git a/cc/testing.go b/cc/testing.go
index b3b2756..2f41de1 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -70,16 +70,6 @@
 		}
 
 		cc_library {
-			name: "libbase",
-			no_libgcc: true,
-			nocrt: true,
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			}
-		}
-		cc_library {
 			name: "libc",
 			no_libgcc: true,
 			nocrt: true,
diff --git a/cc/tidy.go b/cc/tidy.go
index 0b78d6f..5455392 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -31,6 +31,9 @@
 
 	// Extra checks to enable or disable in clang-tidy
 	Tidy_checks []string
+
+	// Checks that should be treated as errors.
+	Tidy_checks_as_errors []string
 }
 
 type tidyFeature struct {
@@ -116,5 +119,9 @@
 	}
 	flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
 
+	if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
+		tidyChecksAsErrors := "-warnings-as-errors=" + strings.Join(esc(tidy.Properties.Tidy_checks_as_errors), ",")
+		flags.TidyFlags = append(flags.TidyFlags, tidyChecksAsErrors)
+	}
 	return flags
 }
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 5811b01..ae08b1c 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -77,3 +77,7 @@
 
 	return android.PathForSource(ctx, *library.Properties.Src)
 }
+
+func (library *toolchainLibraryDecorator) nativeCoverage() bool {
+	return false
+}
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/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp
new file mode 100644
index 0000000..5397f4b
--- /dev/null
+++ b/cmd/diff_target_files/Android.bp
@@ -0,0 +1,16 @@
+blueprint_go_binary {
+    name: "diff_target_files",
+    srcs: [
+        "compare.go",
+        "diff_target_files.go",
+        "glob.go",
+        "target_files.go",
+        "whitelist.go",
+        "zip_artifact.go",
+    ],
+    testSrcs: [
+        "compare_test.go",
+        "glob_test.go",
+        "whitelist_test.go",
+    ],
+}
diff --git a/cmd/diff_target_files/compare.go b/cmd/diff_target_files/compare.go
new file mode 100644
index 0000000..00cd9ca
--- /dev/null
+++ b/cmd/diff_target_files/compare.go
@@ -0,0 +1,133 @@
+// Copyright 2019 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 main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// compareTargetFiles takes two ZipArtifacts and compares the files they contain by examining
+// the path, size, and CRC of each file.
+func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, whitelists []whitelist, filters []string) (zipDiff, error) {
+	priZipFiles, err := priZip.Files()
+	if err != nil {
+		return zipDiff{}, fmt.Errorf("error fetching target file lists from primary zip %v", err)
+	}
+
+	refZipFiles, err := refZip.Files()
+	if err != nil {
+		return zipDiff{}, fmt.Errorf("error fetching target file lists from reference zip %v", err)
+	}
+
+	priZipFiles, err = filterTargetZipFiles(priZipFiles, artifact, filters)
+	if err != nil {
+		return zipDiff{}, err
+	}
+
+	refZipFiles, err = filterTargetZipFiles(refZipFiles, artifact, filters)
+	if err != nil {
+		return zipDiff{}, err
+	}
+
+	// Compare the file lists from both builds
+	diff := diffTargetFilesLists(refZipFiles, priZipFiles)
+
+	return applyWhitelists(diff, whitelists)
+}
+
+// zipDiff contains the list of files that differ between two zip files.
+type zipDiff struct {
+	modified         [][2]*ZipArtifactFile
+	onlyInA, onlyInB []*ZipArtifactFile
+}
+
+// String pretty-prints the list of files that differ between two zip files.
+func (d *zipDiff) String() string {
+	buf := &bytes.Buffer{}
+
+	must := func(n int, err error) {
+		if err != nil {
+			panic(err)
+		}
+	}
+
+	var sizeChange int64
+
+	if len(d.modified) > 0 {
+		must(fmt.Fprintln(buf, "files modified:"))
+		for _, f := range d.modified {
+			must(fmt.Fprintf(buf, "   %v (%v bytes -> %v bytes)\n", f[0].Name, f[0].UncompressedSize64, f[1].UncompressedSize64))
+			sizeChange += int64(f[1].UncompressedSize64) - int64(f[0].UncompressedSize64)
+		}
+	}
+
+	if len(d.onlyInA) > 0 {
+		must(fmt.Fprintln(buf, "files removed:"))
+		for _, f := range d.onlyInA {
+			must(fmt.Fprintf(buf, " - %v (%v bytes)\n", f.Name, f.UncompressedSize64))
+			sizeChange -= int64(f.UncompressedSize64)
+		}
+	}
+
+	if len(d.onlyInB) > 0 {
+		must(fmt.Fprintln(buf, "files added:"))
+		for _, f := range d.onlyInB {
+			must(fmt.Fprintf(buf, " + %v (%v bytes)\n", f.Name, f.UncompressedSize64))
+			sizeChange += int64(f.UncompressedSize64)
+		}
+	}
+
+	if len(d.modified) > 0 || len(d.onlyInA) > 0 || len(d.onlyInB) > 0 {
+		must(fmt.Fprintf(buf, "total size change: %v bytes\n", sizeChange))
+	}
+
+	return buf.String()
+}
+
+func diffTargetFilesLists(a, b []*ZipArtifactFile) zipDiff {
+	i := 0
+	j := 0
+
+	diff := zipDiff{}
+
+	for i < len(a) && j < len(b) {
+		if a[i].Name == b[j].Name {
+			if a[i].UncompressedSize64 != b[j].UncompressedSize64 || a[i].CRC32 != b[j].CRC32 {
+				diff.modified = append(diff.modified, [2]*ZipArtifactFile{a[i], b[j]})
+			}
+			i++
+			j++
+		} else if a[i].Name < b[j].Name {
+			// a[i] is not present in b
+			diff.onlyInA = append(diff.onlyInA, a[i])
+			i++
+		} else {
+			// b[j] is not present in a
+			diff.onlyInB = append(diff.onlyInB, b[j])
+			j++
+		}
+	}
+	for i < len(a) {
+		diff.onlyInA = append(diff.onlyInA, a[i])
+		i++
+	}
+	for j < len(b) {
+		diff.onlyInB = append(diff.onlyInB, b[j])
+		j++
+	}
+
+	return diff
+}
diff --git a/cmd/diff_target_files/compare_test.go b/cmd/diff_target_files/compare_test.go
new file mode 100644
index 0000000..9d3f8a5
--- /dev/null
+++ b/cmd/diff_target_files/compare_test.go
@@ -0,0 +1,131 @@
+// Copyright 2019 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 main
+
+import (
+	"archive/zip"
+	"reflect"
+	"testing"
+)
+
+func TestDiffTargetFilesLists(t *testing.T) {
+	zipArtifactFile := func(name string, crc32 uint32, size uint64) *ZipArtifactFile {
+		return &ZipArtifactFile{
+			File: &zip.File{
+				FileHeader: zip.FileHeader{
+					Name:               name,
+					CRC32:              crc32,
+					UncompressedSize64: size,
+				},
+			},
+		}
+	}
+	x0 := zipArtifactFile("x", 0, 0)
+	x1 := zipArtifactFile("x", 1, 0)
+	x2 := zipArtifactFile("x", 0, 2)
+	y0 := zipArtifactFile("y", 0, 0)
+	//y1 := zipArtifactFile("y", 1, 0)
+	//y2 := zipArtifactFile("y", 1, 2)
+	z0 := zipArtifactFile("z", 0, 0)
+	z1 := zipArtifactFile("z", 1, 0)
+	//z2 := zipArtifactFile("z", 1, 2)
+
+	testCases := []struct {
+		name string
+		a, b []*ZipArtifactFile
+		diff zipDiff
+	}{
+		{
+			name: "same",
+			a:    []*ZipArtifactFile{x0, y0, z0},
+			b:    []*ZipArtifactFile{x0, y0, z0},
+			diff: zipDiff{nil, nil, nil},
+		},
+		{
+			name: "first only in a",
+			a:    []*ZipArtifactFile{x0, y0, z0},
+			b:    []*ZipArtifactFile{y0, z0},
+			diff: zipDiff{nil, []*ZipArtifactFile{x0}, nil},
+		},
+		{
+			name: "middle only in a",
+			a:    []*ZipArtifactFile{x0, y0, z0},
+			b:    []*ZipArtifactFile{x0, z0},
+			diff: zipDiff{nil, []*ZipArtifactFile{y0}, nil},
+		},
+		{
+			name: "last only in a",
+			a:    []*ZipArtifactFile{x0, y0, z0},
+			b:    []*ZipArtifactFile{x0, y0},
+			diff: zipDiff{nil, []*ZipArtifactFile{z0}, nil},
+		},
+
+		{
+			name: "first only in b",
+			a:    []*ZipArtifactFile{y0, z0},
+			b:    []*ZipArtifactFile{x0, y0, z0},
+			diff: zipDiff{nil, nil, []*ZipArtifactFile{x0}},
+		},
+		{
+			name: "middle only in b",
+			a:    []*ZipArtifactFile{x0, z0},
+			b:    []*ZipArtifactFile{x0, y0, z0},
+			diff: zipDiff{nil, nil, []*ZipArtifactFile{y0}},
+		},
+		{
+			name: "last only in b",
+			a:    []*ZipArtifactFile{x0, y0},
+			b:    []*ZipArtifactFile{x0, y0, z0},
+			diff: zipDiff{nil, nil, []*ZipArtifactFile{z0}},
+		},
+
+		{
+			name: "diff",
+			a:    []*ZipArtifactFile{x0},
+			b:    []*ZipArtifactFile{x1},
+			diff: zipDiff{[][2]*ZipArtifactFile{{x0, x1}}, nil, nil},
+		},
+		{
+			name: "diff plus unique last",
+			a:    []*ZipArtifactFile{x0, y0},
+			b:    []*ZipArtifactFile{x1, z0},
+			diff: zipDiff{[][2]*ZipArtifactFile{{x0, x1}}, []*ZipArtifactFile{y0}, []*ZipArtifactFile{z0}},
+		},
+		{
+			name: "diff plus unique first",
+			a:    []*ZipArtifactFile{x0, z0},
+			b:    []*ZipArtifactFile{y0, z1},
+			diff: zipDiff{[][2]*ZipArtifactFile{{z0, z1}}, []*ZipArtifactFile{x0}, []*ZipArtifactFile{y0}},
+		},
+		{
+			name: "diff size",
+			a:    []*ZipArtifactFile{x0},
+			b:    []*ZipArtifactFile{x2},
+			diff: zipDiff{[][2]*ZipArtifactFile{{x0, x2}}, nil, nil},
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			diff := diffTargetFilesLists(test.a, test.b)
+
+			if !reflect.DeepEqual(diff, test.diff) {
+
+				t.Errorf("diffTargetFilesLists = %v, %v, %v", diff.modified, diff.onlyInA, diff.onlyInB)
+				t.Errorf("                  want %v, %v, %v", test.diff.modified, test.diff.onlyInA, test.diff.onlyInB)
+			}
+		})
+	}
+}
diff --git a/cmd/diff_target_files/diff_target_files.go b/cmd/diff_target_files/diff_target_files.go
new file mode 100644
index 0000000..75bc8ee
--- /dev/null
+++ b/cmd/diff_target_files/diff_target_files.go
@@ -0,0 +1,82 @@
+// Copyright 2019 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 main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+)
+
+var (
+	whitelists     = newMultiString("whitelist", "whitelist patterns in the form <pattern>[:<regex of line to ignore>]")
+	whitelistFiles = newMultiString("whitelist_file", "files containing whitelist definitions")
+
+	filters = newMultiString("filter", "filter patterns to apply to files in target-files.zip before comparing")
+)
+
+func newMultiString(name, usage string) *multiString {
+	var f multiString
+	flag.Var(&f, name, usage)
+	return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string     { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+	flag.Parse()
+
+	if flag.NArg() != 2 {
+		fmt.Fprintf(os.Stderr, "Error, exactly two arguments are required\n")
+		os.Exit(1)
+	}
+
+	whitelists, err := parseWhitelists(*whitelists, *whitelistFiles)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error parsing whitelists: %v\n", err)
+		os.Exit(1)
+	}
+
+	priZip, err := NewLocalZipArtifact(flag.Arg(0))
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error opening zip file %v: %v\n", flag.Arg(0), err)
+		os.Exit(1)
+	}
+	defer priZip.Close()
+
+	refZip, err := NewLocalZipArtifact(flag.Arg(1))
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error opening zip file %v: %v\n", flag.Arg(1), err)
+		os.Exit(1)
+	}
+	defer refZip.Close()
+
+	diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, whitelists, *filters)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error comparing zip files: %v\n", err)
+		os.Exit(1)
+	}
+
+	fmt.Print(diff.String())
+
+	if len(diff.modified) > 0 || len(diff.onlyInA) > 0 || len(diff.onlyInB) > 0 {
+		fmt.Fprintln(os.Stderr, "differences found")
+		os.Exit(1)
+	}
+}
diff --git a/cmd/diff_target_files/glob.go b/cmd/diff_target_files/glob.go
new file mode 100644
index 0000000..ed91af7
--- /dev/null
+++ b/cmd/diff_target_files/glob.go
@@ -0,0 +1,81 @@
+// Copyright 2019 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 main
+
+import (
+	"errors"
+	"path/filepath"
+	"strings"
+)
+
+// Match returns true if name matches pattern using the same rules as filepath.Match, but supporting
+// recursive globs (**).
+func Match(pattern, name string) (bool, error) {
+	if filepath.Base(pattern) == "**" {
+		return false, errors.New("pattern has '**' as last path element")
+	}
+
+	patternDir := pattern[len(pattern)-1] == '/'
+	nameDir := name[len(name)-1] == '/'
+
+	if patternDir != nameDir {
+		return false, nil
+	}
+
+	if nameDir {
+		name = name[:len(name)-1]
+		pattern = pattern[:len(pattern)-1]
+	}
+
+	for {
+		var patternFile, nameFile string
+		pattern, patternFile = filepath.Dir(pattern), filepath.Base(pattern)
+
+		if patternFile == "**" {
+			if strings.Contains(pattern, "**") {
+				return false, errors.New("pattern contains multiple '**'")
+			}
+			// Test if the any prefix of name matches the part of the pattern before **
+			for {
+				if name == "." || name == "/" {
+					return name == pattern, nil
+				}
+				if match, err := filepath.Match(pattern, name); err != nil {
+					return false, err
+				} else if match {
+					return true, nil
+				}
+				name = filepath.Dir(name)
+			}
+		} else if strings.Contains(patternFile, "**") {
+			return false, errors.New("pattern contains other characters between '**' and path separator")
+		}
+
+		name, nameFile = filepath.Dir(name), filepath.Base(name)
+
+		if nameFile == "." && patternFile == "." {
+			return true, nil
+		} else if nameFile == "/" && patternFile == "/" {
+			return true, nil
+		} else if nameFile == "." || patternFile == "." || nameFile == "/" || patternFile == "/" {
+			return false, nil
+		}
+
+		match, err := filepath.Match(patternFile, nameFile)
+		if err != nil || !match {
+			return match, err
+		}
+	}
+}
diff --git a/cmd/diff_target_files/glob_test.go b/cmd/diff_target_files/glob_test.go
new file mode 100644
index 0000000..63df68d
--- /dev/null
+++ b/cmd/diff_target_files/glob_test.go
@@ -0,0 +1,158 @@
+// Copyright 2019 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 main
+
+import (
+	"testing"
+)
+
+func TestMatch(t *testing.T) {
+	testCases := []struct {
+		pattern, name string
+		match         bool
+	}{
+		{"a/*", "b/", false},
+		{"a/*", "b/a", false},
+		{"a/*", "b/b/", false},
+		{"a/*", "b/b/c", false},
+		{"a/**/*", "b/", false},
+		{"a/**/*", "b/a", false},
+		{"a/**/*", "b/b/", false},
+		{"a/**/*", "b/b/c", false},
+
+		{"a/*", "a/", false},
+		{"a/*", "a/a", true},
+		{"a/*", "a/b/", false},
+		{"a/*", "a/b/c", false},
+
+		{"a/*/", "a/", false},
+		{"a/*/", "a/a", false},
+		{"a/*/", "a/b/", true},
+		{"a/*/", "a/b/c", false},
+
+		{"a/**/*", "a/", false},
+		{"a/**/*", "a/a", true},
+		{"a/**/*", "a/b/", false},
+		{"a/**/*", "a/b/c", true},
+
+		{"a/**/*/", "a/", false},
+		{"a/**/*/", "a/a", false},
+		{"a/**/*/", "a/b/", true},
+		{"a/**/*/", "a/b/c", false},
+
+		{"**/*", "a/", false},
+		{"**/*", "a/a", true},
+		{"**/*", "a/b/", false},
+		{"**/*", "a/b/c", true},
+
+		{"**/*/", "a/", true},
+		{"**/*/", "a/a", false},
+		{"**/*/", "a/b/", true},
+		{"**/*/", "a/b/c", false},
+
+		{`a/\*\*/\*`, `a/**/*`, true},
+		{`a/\*\*/\*`, `a/a/*`, false},
+		{`a/\*\*/\*`, `a/**/a`, false},
+		{`a/\*\*/\*`, `a/a/a`, false},
+
+		{`a/**/\*`, `a/**/*`, true},
+		{`a/**/\*`, `a/a/*`, true},
+		{`a/**/\*`, `a/**/a`, false},
+		{`a/**/\*`, `a/a/a`, false},
+
+		{`a/\*\*/*`, `a/**/*`, true},
+		{`a/\*\*/*`, `a/a/*`, false},
+		{`a/\*\*/*`, `a/**/a`, true},
+		{`a/\*\*/*`, `a/a/a`, false},
+
+		{`*/**/a`, `a/a/a`, true},
+		{`*/**/a`, `*/a/a`, true},
+		{`*/**/a`, `a/**/a`, true},
+		{`*/**/a`, `*/**/a`, true},
+
+		{`\*/\*\*/a`, `a/a/a`, false},
+		{`\*/\*\*/a`, `*/a/a`, false},
+		{`\*/\*\*/a`, `a/**/a`, false},
+		{`\*/\*\*/a`, `*/**/a`, true},
+
+		{`a/?`, `a/?`, true},
+		{`a/?`, `a/a`, true},
+		{`a/\?`, `a/?`, true},
+		{`a/\?`, `a/a`, false},
+
+		{`a/?`, `a/?`, true},
+		{`a/?`, `a/a`, true},
+		{`a/\?`, `a/?`, true},
+		{`a/\?`, `a/a`, false},
+
+		{`a/[a-c]`, `a/b`, true},
+		{`a/[abc]`, `a/b`, true},
+
+		{`a/\[abc]`, `a/b`, false},
+		{`a/\[abc]`, `a/[abc]`, true},
+
+		{`a/\[abc\]`, `a/b`, false},
+		{`a/\[abc\]`, `a/[abc]`, true},
+
+		{`a/?`, `a/?`, true},
+		{`a/?`, `a/a`, true},
+		{`a/\?`, `a/?`, true},
+		{`a/\?`, `a/a`, false},
+
+		{"/a/*", "/a/", false},
+		{"/a/*", "/a/a", true},
+		{"/a/*", "/a/b/", false},
+		{"/a/*", "/a/b/c", false},
+
+		{"/a/*/", "/a/", false},
+		{"/a/*/", "/a/a", false},
+		{"/a/*/", "/a/b/", true},
+		{"/a/*/", "/a/b/c", false},
+
+		{"/a/**/*", "/a/", false},
+		{"/a/**/*", "/a/a", true},
+		{"/a/**/*", "/a/b/", false},
+		{"/a/**/*", "/a/b/c", true},
+
+		{"/**/*", "/a/", false},
+		{"/**/*", "/a/a", true},
+		{"/**/*", "/a/b/", false},
+		{"/**/*", "/a/b/c", true},
+
+		{"/**/*/", "/a/", true},
+		{"/**/*/", "/a/a", false},
+		{"/**/*/", "/a/b/", true},
+		{"/**/*/", "/a/b/c", false},
+
+		{`a`, `/a`, false},
+		{`/a`, `a`, false},
+		{`*`, `/a`, false},
+		{`/*`, `a`, false},
+		{`**/*`, `/a`, false},
+		{`/**/*`, `a`, false},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.pattern+","+test.name, func(t *testing.T) {
+			match, err := Match(test.pattern, test.name)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if match != test.match {
+				t.Errorf("want: %v, got %v", test.match, match)
+			}
+		})
+	}
+}
diff --git a/cmd/diff_target_files/known_nondeterminism.whitelist b/cmd/diff_target_files/known_nondeterminism.whitelist
new file mode 100644
index 0000000..6d71403
--- /dev/null
+++ b/cmd/diff_target_files/known_nondeterminism.whitelist
@@ -0,0 +1,10 @@
+// List of files that are known to be non-deterministic, along with the
+// bug number to tracking fixing the non-determinism.
+[
+  {
+    "Paths": [
+       // b/120039850
+      "system/framework/oat/*/services.art"
+    ]
+  }
+]
diff --git a/cmd/diff_target_files/props.whitelist b/cmd/diff_target_files/props.whitelist
new file mode 100644
index 0000000..9245b8b
--- /dev/null
+++ b/cmd/diff_target_files/props.whitelist
@@ -0,0 +1,18 @@
+[
+  // Ignore date, version and hostname properties in build.prop and prop.default files.
+  {
+    "Paths": [
+      "**/build.prop",
+      "**/prop.default"
+    ],
+    "IgnoreMatchingLines": [
+      "ro\\..*build\\.date=.*",
+      "ro\\..*build\\.date\\.utc=.*",
+      "ro\\..*build\\.version\\.incremental=.*",
+      "ro\\..*build\\.fingerprint=.*",
+      "ro\\.build\\.display\\.id=.*",
+      "ro\\.build\\.description=.*",
+      "ro\\.build\\.host=.*"
+    ]
+  }
+]
\ No newline at end of file
diff --git a/cmd/diff_target_files/target_files.go b/cmd/diff_target_files/target_files.go
new file mode 100644
index 0000000..8705ca7
--- /dev/null
+++ b/cmd/diff_target_files/target_files.go
@@ -0,0 +1,86 @@
+// Copyright 2019 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 main
+
+import (
+	"fmt"
+	"strings"
+)
+
+const targetFilesPattern = "*-target_files-*.zip"
+
+var targetZipPartitions = []string{
+	"BOOT/RAMDISK/",
+	"BOOT/",
+	"DATA/",
+	"ODM/",
+	"OEM/",
+	"PRODUCT/",
+	"PRODUCT_SERVICES/",
+	"ROOT/",
+	"SYSTEM/",
+	"SYSTEM_OTHER/",
+	"VENDOR/",
+}
+
+var targetZipFilter = []string{
+	"IMAGES/",
+	"OTA/",
+	"META/",
+	"PREBUILT_IMAGES/",
+	"RADIO/",
+}
+
+func filterTargetZipFiles(files []*ZipArtifactFile, artifact string, patterns []string) ([]*ZipArtifactFile, error) {
+	var ret []*ZipArtifactFile
+outer:
+	for _, f := range files {
+		if f.FileInfo().IsDir() {
+			continue
+		}
+
+		if artifact == targetFilesPattern {
+			found := false
+			for _, p := range targetZipPartitions {
+				if strings.HasPrefix(f.Name, p) {
+					f.Name = strings.ToLower(p) + strings.TrimPrefix(f.Name, p)
+					found = true
+				}
+			}
+			for _, filter := range targetZipFilter {
+				if strings.HasPrefix(f.Name, filter) {
+					continue outer
+				}
+			}
+
+			if !found {
+				return nil, fmt.Errorf("unmatched prefix for %s", f.Name)
+			}
+		}
+
+		if patterns != nil {
+			for _, pattern := range patterns {
+				match, _ := Match(pattern, f.Name)
+				if match {
+					ret = append(ret, f)
+				}
+			}
+		} else {
+			ret = append(ret, f)
+		}
+	}
+
+	return ret, nil
+}
diff --git a/cmd/diff_target_files/whitelist.go b/cmd/diff_target_files/whitelist.go
new file mode 100644
index 0000000..f00fc1e
--- /dev/null
+++ b/cmd/diff_target_files/whitelist.go
@@ -0,0 +1,251 @@
+// Copyright 2019 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 main
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"io"
+	"os"
+	"regexp"
+	"strings"
+	"unicode"
+)
+
+type jsonWhitelist struct {
+	Paths               []string
+	IgnoreMatchingLines []string
+}
+
+type whitelist struct {
+	path                string
+	ignoreMatchingLines []string
+}
+
+func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, error) {
+	var ret []whitelist
+
+	add := func(path string, ignoreMatchingLines []string) {
+		for _, x := range ret {
+			if x.path == path {
+				x.ignoreMatchingLines = append(x.ignoreMatchingLines, ignoreMatchingLines...)
+				return
+			}
+		}
+
+		ret = append(ret, whitelist{
+			path:                path,
+			ignoreMatchingLines: ignoreMatchingLines,
+		})
+	}
+
+	for _, file := range whitelistFiles {
+		newWhitelists, err := parseWhitelistFile(file)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, w := range newWhitelists {
+			add(w.path, w.ignoreMatchingLines)
+		}
+	}
+
+	for _, s := range whitelists {
+		colon := strings.IndexRune(s, ':')
+		var ignoreMatchingLines []string
+		if colon >= 0 {
+			ignoreMatchingLines = []string{s[colon+1:]}
+		}
+		add(s, ignoreMatchingLines)
+	}
+
+	return ret, nil
+}
+
+func parseWhitelistFile(file string) ([]whitelist, error) {
+	r, err := os.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+
+	d := json.NewDecoder(newJSONCommentStripper(r))
+
+	var jsonWhitelists []jsonWhitelist
+
+	err = d.Decode(&jsonWhitelists)
+
+	var whitelists []whitelist
+	for _, w := range jsonWhitelists {
+		for _, p := range w.Paths {
+			whitelists = append(whitelists, whitelist{
+				path:                p,
+				ignoreMatchingLines: w.IgnoreMatchingLines,
+			})
+		}
+	}
+
+	return whitelists, err
+}
+
+func filterModifiedPaths(l [][2]*ZipArtifactFile, whitelists []whitelist) ([][2]*ZipArtifactFile, error) {
+outer:
+	for i := 0; i < len(l); i++ {
+		for _, w := range whitelists {
+			if match, err := Match(w.path, l[i][0].Name); err != nil {
+				return l, err
+			} else if match {
+				if match, err := diffIgnoringMatchingLines(l[i][0], l[i][1], w.ignoreMatchingLines); err != nil {
+					return l, err
+				} else if match || len(w.ignoreMatchingLines) == 0 {
+					l = append(l[:i], l[i+1:]...)
+					i--
+				}
+				continue outer
+			}
+		}
+	}
+
+	if len(l) == 0 {
+		l = nil
+	}
+
+	return l, nil
+}
+
+func filterNewPaths(l []*ZipArtifactFile, whitelists []whitelist) ([]*ZipArtifactFile, error) {
+outer:
+	for i := 0; i < len(l); i++ {
+		for _, w := range whitelists {
+			if match, err := Match(w.path, l[i].Name); err != nil {
+				return l, err
+			} else if match && len(w.ignoreMatchingLines) == 0 {
+				l = append(l[:i], l[i+1:]...)
+				i--
+			}
+			continue outer
+		}
+	}
+
+	if len(l) == 0 {
+		l = nil
+	}
+
+	return l, nil
+}
+
+func diffIgnoringMatchingLines(a *ZipArtifactFile, b *ZipArtifactFile, ignoreMatchingLines []string) (match bool, err error) {
+	lineMatchesIgnores := func(b []byte) (bool, error) {
+		for _, m := range ignoreMatchingLines {
+			if match, err := regexp.Match(m, b); err != nil {
+				return false, err
+			} else if match {
+				return match, nil
+			}
+		}
+		return false, nil
+	}
+
+	filter := func(z *ZipArtifactFile) ([]byte, error) {
+		var ret []byte
+
+		r, err := z.Open()
+		if err != nil {
+			return nil, err
+		}
+		s := bufio.NewScanner(r)
+
+		for s.Scan() {
+			if match, err := lineMatchesIgnores(s.Bytes()); err != nil {
+				return nil, err
+			} else if !match {
+				ret = append(ret, "\n"...)
+				ret = append(ret, s.Bytes()...)
+			}
+		}
+
+		return ret, nil
+	}
+
+	bufA, err := filter(a)
+	if err != nil {
+		return false, err
+	}
+	bufB, err := filter(b)
+	if err != nil {
+		return false, err
+	}
+
+	return bytes.Compare(bufA, bufB) == 0, nil
+}
+
+func applyWhitelists(diff zipDiff, whitelists []whitelist) (zipDiff, error) {
+	var err error
+
+	diff.modified, err = filterModifiedPaths(diff.modified, whitelists)
+	if err != nil {
+		return diff, err
+	}
+	diff.onlyInA, err = filterNewPaths(diff.onlyInA, whitelists)
+	if err != nil {
+		return diff, err
+	}
+	diff.onlyInB, err = filterNewPaths(diff.onlyInB, whitelists)
+	if err != nil {
+		return diff, err
+	}
+
+	return diff, nil
+}
+
+func newJSONCommentStripper(r io.Reader) *jsonCommentStripper {
+	return &jsonCommentStripper{
+		r: bufio.NewReader(r),
+	}
+}
+
+type jsonCommentStripper struct {
+	r   *bufio.Reader
+	b   []byte
+	err error
+}
+
+func (j *jsonCommentStripper) Read(buf []byte) (int, error) {
+	for len(j.b) == 0 {
+		if j.err != nil {
+			return 0, j.err
+		}
+
+		j.b, j.err = j.r.ReadBytes('\n')
+
+		if isComment(j.b) {
+			j.b = nil
+		}
+	}
+
+	n := copy(buf, j.b)
+	j.b = j.b[n:]
+	return n, nil
+}
+
+var commentPrefix = []byte("//")
+
+func isComment(b []byte) bool {
+	for len(b) > 0 && unicode.IsSpace(rune(b[0])) {
+		b = b[1:]
+	}
+	return bytes.HasPrefix(b, commentPrefix)
+}
diff --git a/cmd/diff_target_files/whitelist_test.go b/cmd/diff_target_files/whitelist_test.go
new file mode 100644
index 0000000..4b19fdd
--- /dev/null
+++ b/cmd/diff_target_files/whitelist_test.go
@@ -0,0 +1,126 @@
+// Copyright 2019 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 main
+
+import (
+	"archive/zip"
+	"bytes"
+	"reflect"
+	"testing"
+)
+
+func bytesToZipArtifactFile(name string, data []byte) *ZipArtifactFile {
+	buf := &bytes.Buffer{}
+	w := zip.NewWriter(buf)
+	f, err := w.Create(name)
+	if err != nil {
+		panic(err)
+	}
+	_, err = f.Write(data)
+	if err != nil {
+		panic(err)
+	}
+
+	w.Close()
+
+	r, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
+	if err != nil {
+		panic(err)
+	}
+
+	return &ZipArtifactFile{r.File[0]}
+}
+
+var f1a = bytesToZipArtifactFile("dir/f1", []byte(`
+a
+foo: bar
+c
+`))
+
+var f1b = bytesToZipArtifactFile("dir/f1", []byte(`
+a
+foo: baz
+c
+`))
+
+var f2 = bytesToZipArtifactFile("dir/f2", nil)
+
+func Test_applyWhitelists(t *testing.T) {
+	type args struct {
+		diff       zipDiff
+		whitelists []whitelist
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    zipDiff
+		wantErr bool
+	}{
+		{
+			name: "simple",
+			args: args{
+				diff: zipDiff{
+					onlyInA: []*ZipArtifactFile{f1a, f2},
+				},
+				whitelists: []whitelist{{path: "dir/f1"}},
+			},
+			want: zipDiff{
+				onlyInA: []*ZipArtifactFile{f2},
+			},
+		},
+		{
+			name: "glob",
+			args: args{
+				diff: zipDiff{
+					onlyInA: []*ZipArtifactFile{f1a, f2},
+				},
+				whitelists: []whitelist{{path: "dir/*"}},
+			},
+			want: zipDiff{},
+		},
+		{
+			name: "modified",
+			args: args{
+				diff: zipDiff{
+					modified: [][2]*ZipArtifactFile{{f1a, f1b}},
+				},
+				whitelists: []whitelist{{path: "dir/*"}},
+			},
+			want: zipDiff{},
+		},
+		{
+			name: "matching lines",
+			args: args{
+				diff: zipDiff{
+					modified: [][2]*ZipArtifactFile{{f1a, f1b}},
+				},
+				whitelists: []whitelist{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}},
+			},
+			want: zipDiff{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := applyWhitelists(tt.args.diff, tt.args.whitelists)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("applyWhitelists() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("applyWhitelists() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/cmd/diff_target_files/zip_artifact.go b/cmd/diff_target_files/zip_artifact.go
new file mode 100644
index 0000000..08ce889
--- /dev/null
+++ b/cmd/diff_target_files/zip_artifact.go
@@ -0,0 +1,174 @@
+// Copyright 2019 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 main
+
+import (
+	"archive/zip"
+	"context"
+	"fmt"
+	"hash/crc32"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+// ZipArtifact represents a zip file that may be local or remote.
+type ZipArtifact interface {
+	// Files returns the list of files contained in the zip file.
+	Files() ([]*ZipArtifactFile, error)
+
+	// Close closes the zip file artifact.
+	Close()
+}
+
+// localZipArtifact is a handle to a local zip file artifact.
+type localZipArtifact struct {
+	zr    *zip.ReadCloser
+	files []*ZipArtifactFile
+}
+
+// NewLocalZipArtifact returns a ZipArtifact for a local zip file..
+func NewLocalZipArtifact(name string) (ZipArtifact, error) {
+	zr, err := zip.OpenReader(name)
+	if err != nil {
+		return nil, err
+	}
+
+	var files []*ZipArtifactFile
+	for _, zf := range zr.File {
+		files = append(files, &ZipArtifactFile{zf})
+	}
+
+	return &localZipArtifact{
+		zr:    zr,
+		files: files,
+	}, nil
+}
+
+// Files returns the list of files contained in the local zip file artifact.
+func (z *localZipArtifact) Files() ([]*ZipArtifactFile, error) {
+	return z.files, nil
+}
+
+// Close closes the buffered reader of the local zip file artifact.
+func (z *localZipArtifact) Close() {
+	z.zr.Close()
+}
+
+// ZipArtifactFile contains a zip.File handle to the data inside the remote *-target_files-*.zip
+// build artifact.
+type ZipArtifactFile struct {
+	*zip.File
+}
+
+// Extract begins extract a file from inside a ZipArtifact.  It returns an
+// ExtractedZipArtifactFile handle.
+func (zf *ZipArtifactFile) Extract(ctx context.Context, dir string,
+	limiter chan bool) *ExtractedZipArtifactFile {
+
+	d := &ExtractedZipArtifactFile{
+		initCh: make(chan struct{}),
+	}
+
+	go func() {
+		defer close(d.initCh)
+		limiter <- true
+		defer func() { <-limiter }()
+
+		zr, err := zf.Open()
+		if err != nil {
+			d.err = err
+			return
+		}
+		defer zr.Close()
+
+		crc := crc32.NewIEEE()
+		r := io.TeeReader(zr, crc)
+
+		if filepath.Clean(zf.Name) != zf.Name {
+			d.err = fmt.Errorf("invalid filename %q", zf.Name)
+			return
+		}
+		path := filepath.Join(dir, zf.Name)
+
+		err = os.MkdirAll(filepath.Dir(path), 0777)
+		if err != nil {
+			d.err = err
+			return
+		}
+
+		err = os.Remove(path)
+		if err != nil && !os.IsNotExist(err) {
+			d.err = err
+			return
+		}
+
+		if zf.Mode().IsRegular() {
+			w, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, zf.Mode())
+			if err != nil {
+				d.err = err
+				return
+			}
+			defer w.Close()
+
+			_, err = io.Copy(w, r)
+			if err != nil {
+				d.err = err
+				return
+			}
+		} else if zf.Mode()&os.ModeSymlink != 0 {
+			target, err := ioutil.ReadAll(r)
+			if err != nil {
+				d.err = err
+				return
+			}
+
+			err = os.Symlink(string(target), path)
+			if err != nil {
+				d.err = err
+				return
+			}
+		} else {
+			d.err = fmt.Errorf("unknown mode %q", zf.Mode())
+			return
+		}
+
+		if crc.Sum32() != zf.CRC32 {
+			d.err = fmt.Errorf("crc mismatch for %v", zf.Name)
+			return
+		}
+
+		d.path = path
+	}()
+
+	return d
+}
+
+// ExtractedZipArtifactFile is a handle to a downloaded file from a remoteZipArtifact.  The download
+// may still be in progress, and will be complete with Path() returns.
+type ExtractedZipArtifactFile struct {
+	initCh chan struct{}
+	err    error
+
+	path string
+}
+
+// Path returns the path to the downloaded file and any errors that occurred during the download.
+// It will block until the download is complete.
+func (d *ExtractedZipArtifactFile) Path() (string, error) {
+	<-d.initCh
+	return d.path, d.err
+}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 0af1886..4167edb 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -24,6 +24,7 @@
 	"path"
 	"path/filepath"
 	"strings"
+	"time"
 )
 
 var (
@@ -265,6 +266,15 @@
 		if err != nil {
 			return err
 		}
+
+		// Update the timestamp of the output file in case the tool wrote an old timestamp (for example, tar can extract
+		// files with old timestamps).
+		now := time.Now()
+		err = os.Chtimes(tempPath, now, now)
+		if err != nil {
+			return err
+		}
+
 		err = os.Rename(tempPath, destPath)
 		if err != nil {
 			return err
diff --git a/cmd/soong_env/soong_env.go b/cmd/soong_env/soong_env.go
index 933e525..d305d83 100644
--- a/cmd/soong_env/soong_env.go
+++ b/cmd/soong_env/soong_env.go
@@ -15,7 +15,7 @@
 // soong_glob is the command line tool that checks if the list of files matching a glob has
 // changed, and only updates the output file list if it has changed.  It is used to optimize
 // out build.ninja regenerations when non-matching files are added.  See
-// android/soong/common/glob.go for a longer description.
+// android/soong/android/glob.go for a longer description.
 package main
 
 import (
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/androidmk.go b/java/androidmk.go
index 5b4f738..908286a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -95,16 +95,21 @@
 	}
 }
 
+// Called for modules that are a component of a test suite.
+func testSuiteComponent(w io.Writer, test_suites []string) {
+	fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
+	if len(test_suites) > 0 {
+		fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+			strings.Join(test_suites, " "))
+	} else {
+		fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
+	}
+}
+
 func (j *Test) AndroidMk() android.AndroidMkData {
 	data := j.Library.AndroidMk()
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
-		if len(j.testProperties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(j.testProperties.Test_suites, " "))
-		} else {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
-		}
+		testSuiteComponent(w, j.testProperties.Test_suites)
 		if j.testConfig != nil {
 			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", j.testConfig.String())
 		}
@@ -115,6 +120,15 @@
 	return data
 }
 
+func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData {
+	data := j.Library.AndroidMk()
+	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+		testSuiteComponent(w, j.testHelperLibraryProperties.Test_suites)
+	})
+
+	return data
+}
+
 func (prebuilt *Import) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
 		Class:      "JAVA_LIBRARIES",
@@ -321,13 +335,7 @@
 func (a *AndroidTest) AndroidMk() android.AndroidMkData {
 	data := a.AndroidApp.AndroidMk()
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
-		if len(a.testProperties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(a.testProperties.Test_suites, " "))
-		} else {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
-		}
+		testSuiteComponent(w, a.testProperties.Test_suites)
 		if a.testConfig != nil {
 			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", a.testConfig.String())
 		}
@@ -340,13 +348,7 @@
 func (a *AndroidTestHelperApp) AndroidMk() android.AndroidMkData {
 	data := a.AndroidApp.AndroidMk()
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
-		if len(a.appTestHelperAppProperties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(a.appTestHelperAppProperties.Test_suites, " "))
-		} else {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
-		}
+		testSuiteComponent(w, a.appTestHelperAppProperties.Test_suites)
 	})
 
 	return data
diff --git a/java/app.go b/java/app.go
index b31f232..ab623e2 100644
--- a/java/app.go
+++ b/java/app.go
@@ -74,6 +74,11 @@
 	// Store dex files uncompressed in the APK and set the android:useEmbeddedDex="true" manifest attribute so that
 	// they are used from inside the APK at runtime.
 	Use_embedded_dex *bool
+
+	// Forces native libraries to always be packaged into the APK,
+	// Use_embedded_native_libs still selects whether they are stored uncompressed and aligned or compressed.
+	// True for android_test* modules.
+	AlwaysPackageNativeLibs bool `blueprint:"mutated"`
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -81,6 +86,9 @@
 	// The name of a certificate in the default certificate directory, blank to use the default product certificate,
 	// or an android_app_certificate module name in the form ":module".
 	Certificate *string
+
+	// the package name of this app. The package name in the manifest file is used if one was not given.
+	Package_name *string
 }
 
 type AndroidApp struct {
@@ -223,11 +231,12 @@
 		}
 	}
 
-	// TODO: LOCAL_PACKAGE_OVERRIDES
-	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
-
 	manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
-	if overridden {
+	if overridden || a.overridableAppProperties.Package_name != nil {
+		// The product override variable has a priority over the package_name property.
+		if !overridden {
+			manifestPackageName = *a.overridableAppProperties.Package_name
+		}
 		aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
 	}
 
@@ -281,7 +290,8 @@
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
 	var jniJarFile android.WritablePath
 	if len(jniLibs) > 0 {
-		embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs)
+		embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+			a.appProperties.AlwaysPackageNativeLibs
 		if embedJni {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
 			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
@@ -503,6 +513,7 @@
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
+	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
 
 	module.AddProperties(
@@ -543,6 +554,7 @@
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
+	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
 
 	module.AddProperties(
diff --git a/java/app_test.go b/java/app_test.go
index cf57c80..1f6297c 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -16,6 +16,8 @@
 
 import (
 	"android/soong/android"
+	"android/soong/cc"
+
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -537,43 +539,8 @@
 	}
 }
 
-func TestJNI(t *testing.T) {
-	ctx := testJava(t, `
-		toolchain_library {
-			name: "libcompiler_rt-extras",
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libatomic",
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libgcc",
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-aarch64-android",
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-arm-android",
-			src: "",
-		}
-
-		cc_object {
-			name: "crtbegin_so",
-			stl: "none",
-		}
-
-		cc_object {
-			name: "crtend_so",
-			stl: "none",
-		}
-
+func TestJNIABI(t *testing.T) {
+	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
 			name: "libjni",
 			system_shared_libs: [],
@@ -615,13 +582,6 @@
 		}
 		`)
 
-	// check the existence of the internal modules
-	ctx.ModuleForTests("test", "android_common")
-	ctx.ModuleForTests("test_first", "android_common")
-	ctx.ModuleForTests("test_both", "android_common")
-	ctx.ModuleForTests("test_32", "android_common")
-	ctx.ModuleForTests("test_64", "android_common")
-
 	testCases := []struct {
 		name string
 		abis []string
@@ -652,6 +612,90 @@
 	}
 }
 
+func TestJNIPackaging(t *testing.T) {
+	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+		cc_library {
+			name: "libjni",
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		android_app {
+			name: "app",
+			jni_libs: ["libjni"],
+		}
+
+		android_app {
+			name: "app_noembed",
+			jni_libs: ["libjni"],
+			use_embedded_native_libs: false,
+		}
+
+		android_app {
+			name: "app_embed",
+			jni_libs: ["libjni"],
+			use_embedded_native_libs: true,
+		}
+
+		android_test {
+			name: "test",
+			no_framework_libs: true,
+			jni_libs: ["libjni"],
+		}
+
+		android_test {
+			name: "test_noembed",
+			no_framework_libs: true,
+			jni_libs: ["libjni"],
+			use_embedded_native_libs: false,
+		}
+
+		android_test_helper_app {
+			name: "test_helper",
+			no_framework_libs: true,
+			jni_libs: ["libjni"],
+		}
+
+		android_test_helper_app {
+			name: "test_helper_noembed",
+			no_framework_libs: true,
+			jni_libs: ["libjni"],
+			use_embedded_native_libs: false,
+		}
+		`)
+
+	testCases := []struct {
+		name       string
+		packaged   bool
+		compressed bool
+	}{
+		{"app", false, false},
+		{"app_noembed", false, false},
+		{"app_embed", true, false},
+		{"test", true, false},
+		{"test_noembed", true, true},
+		{"test_helper", true, false},
+		{"test_helper_noembed", true, true},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(test.name, "android_common")
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
+			if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
+				t.Errorf("expected jni packaged %v, got %v", w, g)
+			}
+
+			if jniLibZip.Rule != nil {
+				if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
+					t.Errorf("expected jni compressed %v, got %v", w, g)
+				}
+			}
+		})
+	}
+
+}
+
 func TestCertificates(t *testing.T) {
 	testCases := []struct {
 		name                string
@@ -833,6 +877,7 @@
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
+			certificate: "expiredkey",
 			overrides: ["baz"],
 		}
 
@@ -846,6 +891,12 @@
 			name: "new_certificate",
 			certificate: "cert/new_cert",
 		}
+
+		override_android_app {
+			name: "baz",
+			base: "foo",
+			package_name: "org.dandroid.bp",
+		}
 		`)
 
 	expectedVariants := []struct {
@@ -854,18 +905,28 @@
 		apkPath     string
 		signFlag    string
 		overrides   []string
+		aaptFlag    string
 	}{
 		{
 			variantName: "android_common",
 			apkPath:     "/target/product/test_device/system/app/foo/foo.apk",
-			signFlag:    "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8",
+			signFlag:    "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
 			overrides:   []string{"baz"},
+			aaptFlag:    "",
 		},
 		{
 			variantName: "bar_android_common",
 			apkPath:     "/target/product/test_device/system/app/bar/bar.apk",
 			signFlag:    "cert/new_cert.x509.pem cert/new_cert.pk8",
 			overrides:   []string{"baz", "foo"},
+			aaptFlag:    "",
+		},
+		{
+			variantName: "baz_android_common",
+			apkPath:     "/target/product/test_device/system/app/baz/baz.apk",
+			signFlag:    "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
+			overrides:   []string{"baz", "foo"},
+			aaptFlag:    "--rename-manifest-package org.dandroid.bp",
 		},
 	}
 	for _, expected := range expectedVariants {
@@ -892,10 +953,18 @@
 			t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag)
 		}
 
+		// Check if the overrides field values are correctly aggregated.
 		mod := variant.Module().(*AndroidApp)
 		if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) {
 			t.Errorf("Incorrect overrides property value, expected: %q, got: %q",
 				expected.overrides, mod.appProperties.Overrides)
 		}
+
+		// Check the package renaming flag, if exists.
+		res := variant.Output("package-res.apk")
+		aapt2Flags := res.Args["flags"]
+		if !strings.Contains(aapt2Flags, expected.aaptFlag) {
+			t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
+		}
 	}
 }
diff --git a/java/builder.go b/java/builder.go
index d8b303e..ce9a5ee 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -133,7 +133,7 @@
 )
 
 func init() {
-	pctx.Import("android/soong/common")
+	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/java/config")
 }
 
@@ -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 1fd0a9e..0417dee 100644
--- a/java/java.go
+++ b/java/java.go
@@ -41,6 +41,7 @@
 	android.RegisterModuleType("java_binary", BinaryFactory)
 	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
 	android.RegisterModuleType("java_test", TestFactory)
+	android.RegisterModuleType("java_test_helper_library", TestHelperLibraryFactory)
 	android.RegisterModuleType("java_test_host", TestHostFactory)
 	android.RegisterModuleType("java_import", ImportFactory)
 	android.RegisterModuleType("java_import_host", ImportFactoryHost)
@@ -480,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)
 	}
@@ -767,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 {
@@ -1536,6 +1532,12 @@
 	Data []string `android:"path"`
 }
 
+type testHelperLibraryProperties struct {
+	// list of compatibility suites (for example "cts", "vts") that the module should be
+	// installed into.
+	Test_suites []string `android:"arch_variant"`
+}
+
 type Test struct {
 	Library
 
@@ -1545,6 +1547,12 @@
 	data       android.Paths
 }
 
+type TestHelperLibrary struct {
+	Library
+
+	testHelperLibraryProperties testHelperLibraryProperties
+}
+
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, j.testProperties.Test_suites)
 	j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
@@ -1552,6 +1560,10 @@
 	j.Library.GenerateAndroidBuildActions(ctx)
 }
 
+func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.Library.GenerateAndroidBuildActions(ctx)
+}
+
 // java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
 // creates an `AndroidTest.xml` file to allow running the test with `atest` or a `TEST_MAPPING` file.
 //
@@ -1577,6 +1589,21 @@
 	return module
 }
 
+// java_test_helper_library creates a java library and makes sure that it is added to the appropriate test suite.
+func TestHelperLibraryFactory() android.Module {
+	module := &TestHelperLibrary{}
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.deviceProperties,
+		&module.Module.dexpreoptProperties,
+		&module.Module.protoProperties,
+		&module.testHelperLibraryProperties)
+
+	InitJavaModule(module, android.HostAndDeviceSupported)
+	return module
+}
+
 // java_test_host builds a and links sources into a `.jar` file for the host, and creates an `AndroidTest.xml` file to
 // allow running the test with `atest` or a `TEST_MAPPING` file.
 //
diff --git a/java/java_test.go b/java/java_test.go
index ec6d27a..2546698 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -103,6 +103,7 @@
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
@@ -137,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 6924e26..7fa40a3 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 6febfa1..7d23d8f 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/builder.go b/python/builder.go
index e3b490c..36baecd 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -73,7 +73,7 @@
 
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
-	pctx.Import("android/soong/common")
+	pctx.Import("android/soong/android")
 
 	pctx.HostBinToolVariable("parCmd", "soong_zip")
 	pctx.HostBinToolVariable("mergeParCmd", "merge_zips")
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)
 		}
 	}
diff --git a/scripts/setup_go_workspace_for_soong.sh b/scripts/setup_go_workspace_for_soong.sh
index e2fb9fa..6374aae 100755
--- a/scripts/setup_go_workspace_for_soong.sh
+++ b/scripts/setup_go_workspace_for_soong.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 set -e
 
-# Copyright 2017 Google Inc. All rights reserved.
+# Copyright 2019 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.
@@ -15,23 +15,174 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#mounts the components of soong into a directory structure that Go tools and editors expect
+# Mounts the components of soong into a directory structure that Go tools
+# and editors expect.
 
-#move to the script's directory
-cd "$(dirname $0)"
-SCRIPT_PATH="$PWD"
 
-#find the root of the Repo checkout
-cd "${SCRIPT_PATH}"/../../..
-ANDROID_PATH="${PWD}"
-OUTPUT_PATH="$(echo ${GOPATH} | sed 's/\:.*//')" #if GOPATH contains multiple paths, use the first one
-
-if [ -z "${OUTPUT_PATH}" ]; then
-  echo "Error; could not determine the desired location at which to create a Go-compatible workspace. Please update GOPATH to specify the desired destination directory"
+#####################################################################
+# Print the message to stderr with the prefix ERROR and abort this
+# script.
+#####################################################################
+function log_FATAL() {
+  echo "ERROR:" "$*" >&2
   exit 1
-fi
+}
 
-function confirm() {
+#####################################################################
+# Print the message to stderr with the prefix WARN
+#####################################################################
+function log_WARN() {
+  echo "WARN:" "$*" >&2
+}
+
+
+#####################################################################
+# Print the message with the prefix INFO.
+#####################################################################
+function log_INFO() {
+  echo "INFO:" "$*"
+}
+
+
+#####################################################################
+# Find the root project directory of this repo. This is done by
+# finding the directory of where this script lives and then go up one
+# directory to check the ".repo" directory exist. If not, keep going
+# up until we find the ".repo" file or we reached to the filesystem
+# root. Project root directory is printed to stdout.
+#####################################################################
+function root_dir() (
+  local dir
+  if ! dir="$("${readlink}" -e $(dirname "$0"))"; then
+    log_FATAL "failed to read the script's current directory."
+  fi
+
+  dir=${dir}/../../..
+  if ! dir="$("${readlink}" -e "${dir}")"; then
+    log_FATAL "Cannot find the root project directory"
+  fi
+
+  echo "${dir}"
+)
+
+
+#####################################################################
+# executes a shell command by printing out to the screen first and
+# then evaluating the command.
+#####################################################################
+function execute() {
+  echo "$@"
+  eval "$@"
+}
+
+
+#####################################################################
+# Returns the source directory of a passed in path from BIND_PATHS
+# array.
+#####################################################################
+function bind_path_src_dir() (
+  local -r bind_path="$1"
+  echo "${bind_path/%|*/}"
+)
+
+
+#####################################################################
+# Returns the destination directory of a passed in path from
+# BIND_PATHS array.
+#####################################################################
+function bind_path_dst_dir() (
+  local -r bind_path="$1"
+  echo  "${bind_path/#*|}"
+)
+
+
+#####################################################################
+# Executes the bindfs command in linux. Expects $1 to be src
+# directory and $2 to be destination directory.
+#####################################################################
+function linux_bind_dir() (
+  execute bindfs "$1" "$2"
+)
+
+#####################################################################
+# Executes the fusermount -u command in linux. Expects $1 to be the
+# destination directory.
+#####################################################################
+function linux_unbind_dir() (
+  execute fusermount -u "$1"
+)
+
+#####################################################################
+# Executes the bindfs command in darwin. Expects $1 to be src
+# directory and $2 to be destination directory.
+#####################################################################
+function darwin_bind_dir() (
+  execute bindfs -o allow_recursion -n "$1" "$2"
+)
+
+
+#####################################################################
+# Execute the umount command in darwin to unbind a directory. Expects
+# $1 to be the destination directory
+#####################################################################
+function darwin_unbind_dir() (
+  execute umount -f "$1"
+)
+
+
+#####################################################################
+# Bind all the paths that are specified in the BIND_PATHS array.
+#####################################################################
+function bind_all() (
+  local src_dir
+  local dst_dir
+
+  for path in ${BIND_PATHS[@]}; do
+    src_dir=$(bind_path_src_dir "${path}")
+
+    dst_dir=$(bind_path_dst_dir "${path}")
+    mkdir -p "${dst_dir}"
+
+    "${bind_dir}" ${src_dir} "${dst_dir}"
+  done
+
+  echo
+  log_INFO "Created GOPATH-compatible directory structure at ${OUTPUT_PATH}."
+)
+
+
+#####################################################################
+# Unbind all the paths that are specified in the BIND_PATHS array.
+#####################################################################
+function unbind_all() (
+  local dst_dir
+  local exit_code=0
+
+  # need to go into reverse since several parent directory may have been
+  # first before the child one.
+  for (( i=${#BIND_PATHS[@]}-1; i>=0; i-- )); do
+    dst_dir=$(bind_path_dst_dir "${BIND_PATHS[$i]}")
+
+    # continue to unmount even one of them fails
+    if ! "${unbind_dir}" "${dst_dir}"; then
+      log_WARN "Failed to umount ${dst_dir}."
+      exit_code=1
+    fi
+  done
+
+  if [[ ${exit_code} -ne 0 ]]; then
+    exit ${exit_code}
+  fi
+
+  echo
+  log_INFO "Unmounted the GOPATH-compatible directory structure at ${OUTPUT_PATH}."
+)
+
+
+#####################################################################
+# Asks the user to create the GOPATH-compatible directory structure.
+#####################################################################
+function confirm() (
   while true; do
     echo "Will create GOPATH-compatible directory structure at ${OUTPUT_PATH}"
     echo -n "Ok [Y/n]?"
@@ -42,48 +193,162 @@
       if [ "${decision}" == "n" ]; then
         return 1
       else
-        echo "Invalid choice ${decision}; choose either 'y' or 'n'"
+        log_WARN "Invalid choice ${decision}; choose either 'y' or 'n'"
       fi
     fi
   done
+)
+
+
+#####################################################################
+# Help function.
+#####################################################################
+function help() (
+  cat <<EOF
+Mounts the components of soong into a directory structure that Go tools
+and editors expect.
+
+  --help
+    This help
+
+  --bind
+    Create the directory structure that Go tools and editors expect by
+    binding the one to aosp build directory.
+
+  --unbind
+    Reverse operation of bind.
+
+If no flags were specified, the --bind one is selected by default.
+EOF
+)
+
+
+#####################################################################
+# Parse the arguments passed in to this script.
+#####################################################################
+function parse_arguments() {
+  while [[ -n "$1" ]]; do
+    case "$1" in
+          --bind)
+            ACTION="bind"
+            shift
+            ;;
+          --unbind)
+            ACTION="unbind"
+            shift
+            ;;
+          --help )
+            help
+            shift
+            exit 0
+            ;;
+          *)
+            log_WARN "Unknown option: $1"
+            help
+            exit 1
+            ;;
+    esac
+  done
+
+  if [[ -z "${ACTION}" ]]; then
+    ACTION=bind
+  fi
 }
 
-function bindAll() {
-  bindOne "${ANDROID_PATH}/build/blueprint" "${OUTPUT_PATH}/src/github.com/google/blueprint"
-  bindOne "${ANDROID_PATH}/build/soong" "${OUTPUT_PATH}/src/android/soong"
 
-  bindOne "${ANDROID_PATH}/art/build" "${OUTPUT_PATH}/src/android/soong/art"
-  bindOne "${ANDROID_PATH}/external/golang-protobuf" "${OUTPUT_PATH}/src/github.com/golang/protobuf"
-  bindOne "${ANDROID_PATH}/external/llvm/soong" "${OUTPUT_PATH}/src/android/soong/llvm"
-  bindOne "${ANDROID_PATH}/external/clang/soong" "${OUTPUT_PATH}/src/android/soong/clang"
-  echo
-  echo "Created GOPATH-compatible directory structure at ${OUTPUT_PATH}"
-}
+#####################################################################
+# Verifies that a list of required binaries are installed in the
+# host in order to run this script.
+#####################################################################
+function check_exec_existence() (
+  function check() {
+    if ! hash "$1" &>/dev/null; then
+      log_FATAL "missing $1"
+    fi
+  }
 
-function bindOne() {
-  #causes $newPath to mirror $existingPath
-  existingPath="$1"
-  newPath="$2"
-  mkdir -p "$newPath"
-  case $(uname -s) in
+  local bins
+  case "${os_type}" in
     Darwin)
-      echoAndDo bindfs -o allow_recursion -n "${existingPath}" "${newPath}"
+      bins=("bindfs" "greadlink")
       ;;
     Linux)
-      echoAndDo bindfs "${existingPath}" "${newPath}"
+      bins=("bindfs" "fusermount")
       ;;
+    *)
+      log_FATAL "${os_type} is not a recognized system."
   esac
+
+  for bin in "${bins[@]}"; do
+    check "${bin}"
+  done
+)
+
+
+function main() {
+  parse_arguments "$@"
+
+  check_exec_existence
+
+  if [[ "${ACTION}" == "bind" ]]; then
+    if confirm; then
+      echo
+      bind_all
+    else
+      echo "skipping due to user request"
+      exit 1
+    fi
+  else
+    echo
+    unbind_all
+  fi
 }
 
-function echoAndDo() {
-  echo "$@"
-  eval "$@"
-}
+readonly os_type="$(uname -s)"
+case "${os_type}" in
+  Darwin)
+    bind_dir=darwin_bind_dir
+    unbind_dir=darwin_unbind_dir
+    readlink=greadlink
+    ;;
+  Linux)
+    bind_dir=linux_bind_dir
+    unbind_dir=linux_unbind_dir
+    readlink=readlink
+    ;;
+    *)
+    log_FATAL "${os_type} is not a recognized system."
+esac
+readonly bind_dir
+readonly unbind_dir
+readonly readlink
 
-if confirm; then
-  echo
-  bindAll
-else
-  echo "skipping due to user request"
-  exit 1
+
+if ! ANDROID_PATH="$(root_dir)"; then
+  log_FATAL "failed to find the root of the repo checkout"
 fi
+readonly ANDROID_PATH
+
+#if GOPATH contains multiple paths, use the first one
+if ! OUTPUT_PATH="$(echo ${GOPATH} | sed 's/\:.*//')"; then
+  log_FATAL "failed to extract the first GOPATH environment variable"
+fi
+readonly OUTPUT_PATH
+if [ -z "${OUTPUT_PATH}" ]; then
+  log_FATAL "Could not determine the desired location at which to create a" \
+            "Go-compatible workspace. Please update GOPATH to specify the" \
+            "desired destination directory."
+fi
+
+# Below are the paths to bind from src to dst. The paths are separated by |
+# where the left side is the source and the right side is destination.
+readonly BIND_PATHS=(
+  "${ANDROID_PATH}/build/blueprint|${OUTPUT_PATH}/src/github.com/google/blueprint"
+  "${ANDROID_PATH}/build/soong|${OUTPUT_PATH}/src/android/soong"
+  "${ANDROID_PATH}/art/build|${OUTPUT_PATH}/src/android/soong/art"
+  "${ANDROID_PATH}/external/golang-protobuf|${OUTPUT_PATH}/src/github.com/golang/protobuf"
+  "${ANDROID_PATH}/external/llvm/soong|${OUTPUT_PATH}/src/android/soong/llvm"
+  "${ANDROID_PATH}/external/clang/soong|${OUTPUT_PATH}/src/android/soong/clang"
+)
+
+main "$@"
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 79b0f4e..a7aff59 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -73,6 +73,7 @@
 	})
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
 	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
@@ -271,6 +272,25 @@
 			soc_specific: true,
 			static_libs: ["sysprop-platform", "sysprop-vendor"],
 		}
+
+		cc_library_headers {
+			name: "libbase_headers",
+			vendor_available: true,
+			recovery_available: true,
+		}
+
+		cc_library {
+			name: "liblog",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+
+		llndk_library {
+			name: "liblog",
+			symbol_file: "",
+		}
 		`)
 
 	for _, variant := range []string{