Merge master@5406228 into qt-dev.
am: 996d82708d

Change-Id: I6b1eb68ffb4fedcc70d4ef1a73fc992b4f88da31
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/apex/apex.go b/apex/apex.go
index c1f52a6..e07fae0 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -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)
@@ -1283,3 +1284,113 @@
 	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
+		}
+	}
+
+	// the name of the apex_key module that contains the matching public key to be installed.
+	Key *string
+}
+
+func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if String(p.properties.Key) == "" {
+		ctx.ModuleErrorf("key is missing")
+		return
+	}
+	ctx.AddDependency(ctx.Module(), keyTag, *p.properties.Key)
+
+	// This is called before prebuilt_select and prebuilt_postdeps mutators
+	// The mutators requires that src to be set correctly for each arch so that
+	// arch variants are disabled when src is not provided for the arch.
+	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)
+				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(p.properties.Key))
+			},
+		},
+	}
+}
+
+// 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..1e8d5b4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -15,6 +15,8 @@
 package apex
 
 import (
+	"bufio"
+	"bytes"
 	"io/ioutil"
 	"os"
 	"strings"
@@ -36,11 +38,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 +59,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 +171,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)
@@ -1229,3 +1239,54 @@
 		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",
+				},
+			},
+			key: "myapex.key"
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+			product_specific: true,
+		}
+	`)
+
+	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())
+	}
+
+	// Check if the key module is added as a required module.
+	buf := &bytes.Buffer{}
+	prebuilt.AndroidMk().Extra[0](buf, nil)
+	found := false
+	scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
+	expected := "myapex.key"
+	for scanner.Scan() {
+		line := scanner.Text()
+		tok := strings.Split(line, " := ")
+		if tok[0] == "LOCAL_REQUIRED_MODULES" {
+			found = true
+			if tok[1] != "myapex.key" {
+				t.Errorf("Unexpected LOCAL_REQUIRED_MODULES '%s', expected '%s'", tok[1], expected)
+			}
+		}
+	}
+	if !found {
+		t.Errorf("Couldn't find a LOCAL_REQUIRED_MODULES entry")
+	}
+}
diff --git a/apex/key.go b/apex/key.go
index 848e8ce..fbd29bc 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -93,7 +93,7 @@
 	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
diff --git a/cc/binary.go b/cc/binary.go
index 7f7c600..51e68fc 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()
@@ -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..6dd7c05 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -70,6 +70,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")
 
diff --git a/cc/cc.go b/cc/cc.go
index c80d00c..f5a1567 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -267,6 +267,7 @@
 	isStubs() bool
 	bootstrap() bool
 	mustUseVendorVariant() bool
+	nativeCoverage() bool
 }
 
 type ModuleContext interface {
@@ -312,6 +313,8 @@
 	link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
 	appendLdflags([]string)
 	unstrippedOutputFilePath() android.Path
+
+	nativeCoverage() bool
 }
 
 type installer interface {
@@ -604,6 +607,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 +801,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,
@@ -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/compiler.go b/cc/compiler.go
index 0ab1f01..fe46a3c 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -226,7 +226,8 @@
 	}
 
 	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 16415ca..a87d569 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..cab75ac 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()
@@ -755,6 +761,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)
 
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/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/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..966ec36 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -108,6 +108,10 @@
 	return p.libraryDecorator.shared()
 }
 
+func (p *prebuiltLibraryLinker) nativeCoverage() bool {
+	return false
+}
+
 func prebuiltSharedLibraryFactory() android.Module {
 	module, _ := NewPrebuiltSharedLibrary(android.HostAndDeviceSupported)
 	return module.Init()
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/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/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/java.go b/java/java.go
index 1fd0a9e..beee1a5 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)
@@ -1536,6 +1537,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 +1552,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 +1565,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 +1594,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 f466499..ec4c100 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()
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{