Merge "Copy abidiffs into /abidiffs on abi breakages."
diff --git a/Android.bp b/Android.bp
index b57b0cc..d32c957 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,6 +64,7 @@
         "android/env.go",
     ],
     testSrcs: [
+        "android/config_test.go",
         "android/expand_test.go",
         "android/paths_test.go",
         "android/prebuilt_test.go",
@@ -212,6 +213,7 @@
         "java/app.go",
         "java/builder.go",
         "java/gen.go",
+        "java/jacoco.go",
         "java/java.go",
         "java/proto.go",
         "java/resources.go",
diff --git a/android/config_test.go b/android/config_test.go
new file mode 100644
index 0000000..5eb6ed5
--- /dev/null
+++ b/android/config_test.go
@@ -0,0 +1,86 @@
+// Copyright 2017 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 android
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func validateConfigAnnotations(configurable jsonConfigurable) (err error) {
+	reflectType := reflect.TypeOf(configurable)
+	reflectType = reflectType.Elem()
+	for i := 0; i < reflectType.NumField(); i++ {
+		field := reflectType.Field(i)
+		jsonTag := field.Tag.Get("json")
+		// Check for mistakes in the json tag
+		if jsonTag != "" && !strings.HasPrefix(jsonTag, ",") {
+			if !strings.Contains(jsonTag, ",") {
+				// Probably an accidental rename, most likely "omitempty" instead of ",omitempty"
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"Did you mean to use an annotation of %q?\n"+
+					"(Alternatively, to change the json name of the field, rename the field in source instead.)",
+					reflectType.Name(), field.Name, field.Tag, jsonTag, ","+jsonTag)
+			} else {
+				// Although this rename was probably intentional,
+				// a json annotation is still more confusing than renaming the source variable
+				requestedName := strings.Split(jsonTag, ",")[0]
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"To change the json name of the field, rename the field in source instead.",
+					reflectType.Name(), field.Name, field.Tag, requestedName)
+
+			}
+		}
+	}
+	return nil
+}
+
+type configType struct {
+	populateMe *bool `json:"omitempty"`
+}
+
+func (c *configType) SetDefaultConfig() {
+}
+
+// tests that ValidateConfigAnnotation works
+func TestValidateConfigAnnotations(t *testing.T) {
+	config := configType{}
+	err := validateConfigAnnotations(&config)
+	expectedError := `Field configType.populateMe has tag json:"omitempty" which specifies to change its json field name to "omitempty".
+Did you mean to use an annotation of ",omitempty"?
+(Alternatively, to change the json name of the field, rename the field in source instead.)`
+	if err.Error() != expectedError {
+		t.Errorf("Incorrect error; expected:\n"+
+			"%s\n"+
+			"got:\n"+
+			"%s",
+			expectedError, err.Error())
+	}
+}
+
+// run validateConfigAnnotations against each type that might have json annotations
+func TestProductConfigAnnotations(t *testing.T) {
+	err := validateConfigAnnotations(&productVariables{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	validateConfigAnnotations(&FileConfigurableOptions{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+}
diff --git a/android/testing.go b/android/testing.go
index e79562d..3d5e9d9 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -78,6 +79,25 @@
 	return TestingModule{module}
 }
 
+// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
+// filenames to contents stored as a byte slice.
+func (ctx *TestContext) MockFileSystem(files map[string][]byte) {
+	// no module list file specified; find every file named Blueprints or Android.bp
+	pathsToParse := []string{}
+	for candidate := range files {
+		base := filepath.Base(candidate)
+		if base == "Blueprints" || base == "Android.bp" {
+			pathsToParse = append(pathsToParse, candidate)
+		}
+	}
+	if len(pathsToParse) < 1 {
+		panic(fmt.Sprintf("No Blueprint or Android.bp files found in mock filesystem: %v\n", files))
+	}
+	files[blueprint.MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
+
+	ctx.Context.MockFileSystem(files)
+}
+
 type TestingModule struct {
 	module Module
 }
diff --git a/cc/cc.go b/cc/cc.go
index 384b240..e18b2cc 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -326,9 +326,12 @@
 	flags Flags
 
 	// When calling a linker, if module A depends on module B, then A must precede B in its command
-	// line invocation. staticDepsInLinkOrder stores the proper ordering of all of the transitive
+	// line invocation. depsInLinkOrder stores the proper ordering of all of the transitive
 	// deps of this module
-	staticDepsInLinkOrder android.Paths
+	depsInLinkOrder android.Paths
+
+	// only non-nil when this is a shared library that reuses the objects of a static library
+	staticVariant *Module
 }
 
 func (c *Module) Init() android.Module {
@@ -537,7 +540,8 @@
 // orderDeps reorders dependencies into a list such that if module A depends on B, then
 // A will precede B in the resultant list.
 // This is convenient for passing into a linker.
-func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
+// Note that directSharedDeps should be the analogous static library for each shared lib dep
+func orderDeps(directStaticDeps []android.Path, directSharedDeps []android.Path, allTransitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
 	// If A depends on B, then
 	//   Every list containing A will also contain B later in the list
 	//   So, after concatenating all lists, the final instance of B will have come from the same
@@ -545,38 +549,46 @@
 	//   So, the final instance of B will be later in the concatenation than the final A
 	//   So, keeping only the final instance of A and of B ensures that A is earlier in the output
 	//     list than B
-	for _, dep := range directDeps {
+	for _, dep := range directStaticDeps {
 		orderedAllDeps = append(orderedAllDeps, dep)
-		orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...)
+		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
+	}
+	for _, dep := range directSharedDeps {
+		orderedAllDeps = append(orderedAllDeps, dep)
+		orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
 	}
 
 	orderedAllDeps = android.LastUniquePaths(orderedAllDeps)
 
-	// We don't want to add any new dependencies into directDeps (to allow the caller to
+	// We don't want to add any new dependencies into directStaticDeps (to allow the caller to
 	// intentionally exclude or replace any unwanted transitive dependencies), so we limit the
-	// resultant list to only what the caller has chosen to include in directDeps
-	_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directDeps)
+	// resultant list to only what the caller has chosen to include in directStaticDeps
+	_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directStaticDeps)
 
 	return orderedAllDeps, orderedDeclaredDeps
 }
 
-func orderStaticModuleDeps(module *Module, deps []*Module) (results []android.Path) {
-	// make map of transitive dependencies
-	transitiveStaticDepNames := make(map[android.Path][]android.Path, len(deps))
-	for _, dep := range deps {
-		transitiveStaticDepNames[dep.outputFile.Path()] = dep.staticDepsInLinkOrder
+func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) {
+	// convert Module to Path
+	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
+	staticDepFiles := []android.Path{}
+	for _, dep := range staticDeps {
+		allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder
+		staticDepFiles = append(staticDepFiles, dep.outputFile.Path())
 	}
-	// get the output file for each declared dependency
-	depFiles := []android.Path{}
-	for _, dep := range deps {
-		depFiles = append(depFiles, dep.outputFile.Path())
+	sharedDepFiles := []android.Path{}
+	for _, sharedDep := range sharedDeps {
+		staticAnalogue := sharedDep.staticVariant
+		if staticAnalogue != nil {
+			allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder
+			sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path())
+		}
 	}
 
 	// reorder the dependencies based on transitive dependencies
-	module.staticDepsInLinkOrder, results = orderDeps(depFiles, transitiveStaticDepNames)
+	module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
 
 	return results
-
 }
 
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
@@ -1026,6 +1038,7 @@
 	var depPaths PathDeps
 
 	directStaticDeps := []*Module{}
+	directSharedDeps := []*Module{}
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
@@ -1092,6 +1105,7 @@
 		// re-exporting flags
 		if depTag == reuseObjTag {
 			if l, ok := ccDep.compiler.(libraryInterface); ok {
+				c.staticVariant = ccDep
 				objs, flags, deps := l.reuseObjs()
 				depPaths.Objs = depPaths.Objs.Append(objs)
 				depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
@@ -1130,6 +1144,7 @@
 			ptr = &depPaths.SharedLibs
 			depPtr = &depPaths.SharedLibsDeps
 			depFile = ccDep.linker.(libraryInterface).toc()
+			directSharedDeps = append(directSharedDeps, ccDep)
 		case lateSharedDepTag, ndkLateStubDepTag:
 			ptr = &depPaths.LateSharedLibs
 			depPtr = &depPaths.LateSharedLibsDeps
@@ -1221,7 +1236,7 @@
 	})
 
 	// use the ordered dependencies as this module's dependencies
-	depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps, directSharedDeps)...)
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index bdc8c17..148b4dd 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -289,7 +289,11 @@
 var staticLinkDepOrderTestCases = []struct {
 	// This is a string representation of a map[moduleName][]moduleDependency .
 	// It models the dependencies declared in an Android.bp file.
-	in string
+	inStatic string
+
+	// This is a string representation of a map[moduleName][]moduleDependency .
+	// It models the dependencies declared in an Android.bp file.
+	inShared string
 
 	// allOrdered is a string representation of a map[moduleName][]moduleDependency .
 	// The keys of allOrdered specify which modules we would like to check.
@@ -305,82 +309,99 @@
 }{
 	// Simple tests
 	{
-		in:         "",
+		inStatic:   "",
 		outOrdered: "",
 	},
 	{
-		in:         "a:",
+		inStatic:   "a:",
 		outOrdered: "a:",
 	},
 	{
-		in:         "a:b; b:",
+		inStatic:   "a:b; b:",
 		outOrdered: "a:b; b:",
 	},
 	// Tests of reordering
 	{
 		// diamond example
-		in:         "a:d,b,c; b:d; c:d; d:",
+		inStatic:   "a:d,b,c; b:d; c:d; d:",
 		outOrdered: "a:b,c,d; b:d; c:d; d:",
 	},
 	{
 		// somewhat real example
-		in:         "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
+		inStatic:   "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
 		outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
 	},
 	{
 		// multiple reorderings
-		in:         "a:b,c,d,e; d:b; e:c",
+		inStatic:   "a:b,c,d,e; d:b; e:c",
 		outOrdered: "a:d,b,e,c; d:b; e:c",
 	},
 	{
 		// should reorder without adding new transitive dependencies
-		in:         "bin:lib2,lib1;             lib1:lib2,liboptional",
+		inStatic:   "bin:lib2,lib1;             lib1:lib2,liboptional",
 		allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
 		outOrdered: "bin:lib1,lib2;             lib1:lib2,liboptional",
 	},
 	{
 		// multiple levels of dependencies
-		in:         "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
+		inStatic:   "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
 		allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
 		outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
 	},
+	// shared dependencies
+	{
+		// Note that this test doesn't recurse, to minimize the amount of logic it tests.
+		// So, we don't actually have to check that a shared dependency of c will change the order
+		// of a library that depends statically on b and on c.  We only need to check that if c has
+		// a shared dependency on b, that that shows up in allOrdered.
+		inShared:   "c:b",
+		allOrdered: "c:b",
+		outOrdered: "c:",
+	},
+	{
+		// This test doesn't actually include any shared dependencies but it's a reminder of what
+		// the second phase of the above test would look like
+		inStatic:   "a:b,c; c:b",
+		allOrdered: "a:c,b; c:b",
+		outOrdered: "a:c,b; c:b",
+	},
 	// tiebreakers for when two modules specifying different orderings and there is no dependency
 	// to dictate an order
 	{
 		// if the tie is between two modules at the end of a's deps, then a's order wins
-		in:         "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
+		inStatic:   "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
 		outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
 	},
 	{
 		// if the tie is between two modules at the start of a's deps, then c's order is used
-		in:         "a1:d,e,b1,c1; b1:d,e; c1:e,d;   a2:d,e,b2,c2; b2:d,e; c2:d,e",
+		inStatic:   "a1:d,e,b1,c1; b1:d,e; c1:e,d;   a2:d,e,b2,c2; b2:d,e; c2:d,e",
 		outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d;   a2:b2,c2,d,e; b2:d,e; c2:d,e",
 	},
 	// Tests involving duplicate dependencies
 	{
 		// simple duplicate
-		in:         "a:b,c,c,b",
+		inStatic:   "a:b,c,c,b",
 		outOrdered: "a:c,b",
 	},
 	{
 		// duplicates with reordering
-		in:         "a:b,c,d,c; c:b",
+		inStatic:   "a:b,c,d,c; c:b",
 		outOrdered: "a:d,c,b",
 	},
 	// Tests to confirm the nonexistence of infinite loops.
 	// These cases should never happen, so as long as the test terminates and the
 	// result is deterministic then that should be fine.
 	{
-		in:         "a:a",
+		inStatic:   "a:a",
 		outOrdered: "a:a",
 	},
 	{
-		in:         "a:b;   b:c;   c:a",
+		inStatic:   "a:b;   b:c;   c:a",
 		allOrdered: "a:b,c; b:c,a; c:a,b",
 		outOrdered: "a:b;   b:c;   c:a",
 	},
 	{
-		in:         "a:b,c;   b:c,a;   c:a,b",
+		inStatic:   "a:b,c;   b:c,a;   c:a,b",
 		allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
 		outOrdered: "a:c,b;   b:a,c;   c:b,a",
 	},
@@ -427,43 +448,47 @@
 	return modulesInOrder, allDeps
 }
 
-func TestStaticLinkDependencyOrdering(t *testing.T) {
+func TestLinkReordering(t *testing.T) {
 	for _, testCase := range staticLinkDepOrderTestCases {
 		errs := []string{}
 
 		// parse testcase
-		_, givenTransitiveDeps := parseModuleDeps(testCase.in)
+		_, givenTransitiveDeps := parseModuleDeps(testCase.inStatic)
 		expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
 		if testCase.allOrdered == "" {
 			// allow the test case to skip specifying allOrdered
 			testCase.allOrdered = testCase.outOrdered
 		}
 		_, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
+		_, givenAllSharedDeps := parseModuleDeps(testCase.inShared)
 
 		// For each module whose post-reordered dependencies were specified, validate that
 		// reordering the inputs produces the expected outputs.
 		for _, moduleName := range expectedModuleNames {
 			moduleDeps := givenTransitiveDeps[moduleName]
-			orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
+			givenSharedDeps := givenAllSharedDeps[moduleName]
+			orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenSharedDeps, givenTransitiveDeps)
 
 			correctAllOrdered := expectedAllDeps[moduleName]
 			if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
 				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
-					"\nInput:    %q"+
+					"\nin static:%q"+
+					"\nin shared:%q"+
 					"\nmodule:   %v"+
 					"\nexpected: %s"+
 					"\nactual:   %s",
-					testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
+					testCase.inStatic, testCase.inShared, moduleName, correctAllOrdered, orderedAllDeps))
 			}
 
 			correctOutputDeps := expectedTransitiveDeps[moduleName]
 			if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
 				errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
-					"\nInput:    %q"+
+					"\nin static:%q"+
+					"\nin shared:%q"+
 					"\nmodule:   %v"+
 					"\nexpected: %s"+
 					"\nactual:   %s",
-					testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
+					testCase.inStatic, testCase.inShared, moduleName, correctOutputDeps, orderedDeclaredDeps))
 			}
 		}
 
@@ -493,7 +518,7 @@
 	return paths
 }
 
-func TestLibDeps(t *testing.T) {
+func TestStaticLibDepReordering(t *testing.T) {
 	ctx := testCc(t, `
 	cc_library {
 		name: "a",
@@ -514,7 +539,7 @@
 
 	variant := "android_arm64_armv8-a_core_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := moduleA.staticDepsInLinkOrder
+	actual := moduleA.depsInLinkOrder
 	expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
 
 	if !reflect.DeepEqual(actual, expected) {
@@ -527,6 +552,37 @@
 	}
 }
 
+func TestStaticLibDepReorderingWithShared(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library {
+		name: "a",
+		static_libs: ["b", "c"],
+	}
+	cc_library {
+		name: "b",
+	}
+	cc_library {
+		name: "c",
+		shared_libs: ["b"],
+	}
+
+	`)
+
+	variant := "android_arm64_armv8-a_core_static"
+	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
+	actual := moduleA.depsInLinkOrder
+	expected := getOutputPaths(ctx, variant, []string{"c", "b"})
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Errorf("staticDeps orderings did not account for shared libs"+
+			"\nactual:   %v"+
+			"\nexpected: %v",
+			actual,
+			expected,
+		)
+	}
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
diff --git a/cc/compiler.go b/cc/compiler.go
index ca68a00..fc2eeec 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -206,6 +206,21 @@
 	return deps
 }
 
+// Return true if the module is in the WarningAllowedProjects.
+func warningsAreAllowed(subdir string) bool {
+	subdir += "/"
+	for _, prefix := range config.WarningAllowedProjects {
+		if strings.HasPrefix(subdir, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+func addToModuleList(ctx ModuleContext, list string, module string) {
+	getWallWerrorMap(ctx.AConfig(), list).Store(module, true)
+}
+
 // Create a Flags struct that collects the compile flags from global values,
 // per-target values, module type values, and per-module Blueprints properties
 func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -464,6 +479,21 @@
 		flags = rsFlags(ctx, flags, &compiler.Properties)
 	}
 
+	if len(compiler.Properties.Srcs) > 0 {
+		module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+		if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
+			addToModuleList(ctx, modulesUsingWnoError, module)
+		} else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
+			if warningsAreAllowed(ctx.ModuleDir()) {
+				addToModuleList(ctx, modulesAddedWall, module)
+				flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
+			} else {
+				addToModuleList(ctx, modulesAddedWerror, module)
+				flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
+			}
+		}
+	}
+
 	return flags
 }
 
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0f28d1e..fda4f9d 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -115,7 +115,9 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"kryo": []string{
-			"-mcpu=cortex-a15",
+			// Use cortex-a53 because the GNU assembler doesn't recognize -mcpu=kryo
+			// even though clang does.
+			"-mcpu=cortex-a53",
 			"-mfpu=neon-fp-armv8",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
@@ -158,10 +160,9 @@
 	android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
 	android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon")
 
-	// Krait and Kryo targets are not supported by GCC, but are supported by Clang,
-	// so override the definitions when building modules with Clang.
+	// Krait is not supported by GCC, but is supported by Clang, so
+	// override the definitions when building modules with Clang.
 	replaceFirst(armClangCpuVariantCflags["krait"], "-mcpu=cortex-a15", "-mcpu=krait")
-	replaceFirst(armClangCpuVariantCflags["kryo"], "-mcpu=cortex-a15", "-mcpu=krait")
 
 	// The reason we use "-march=armv8-a+crc", instead of "-march=armv8-a", for
 	// gcc is the latter would conflict with any specified/supported -mcpu!
diff --git a/cc/config/global.go b/cc/config/global.go
index 44ad30b..4322436 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -118,6 +118,51 @@
 	ClangDefaultBase         = "prebuilts/clang/host"
 	ClangDefaultVersion      = "clang-4393122"
 	ClangDefaultShortVersion = "5.0.1"
+
+	WarningAllowedProjects = []string{
+		"external/boringssl/",
+		"external/libese/third_party/NXPNFC_P61_JCOP_Kit/",
+		"external/mdnsresponder/",
+		"external/protobuf/",
+		"external/skia/",
+		"device/",
+		"frameworks/av/media/libeffects/factory/",
+		"frameworks/av/media/libstagefright/codecs/",
+		"frameworks/base/tools/streaming_proto/",
+		"frameworks/ml/nn/",
+		"frameworks/native/libs/vr/libbufferhub/",
+		"frameworks/native/libs/vr/libbufferhubqueue/",
+		"frameworks/native/libs/vr/libdvr/tests/",
+		"frameworks/native/services/surfaceflinger/tests/",
+		"frameworks/native/services/vr/",
+		"hardware/interfaces/audio/effect/",
+		"hardware/interfaces/biometrics/fingerprint/",
+		"vendor/",
+	}
+
+	// Some Android.mk files still have warnings.
+	WarningAllowedOldProjects = []string{
+		"cts/hostsidetests/security/securityPatch/",
+		"cts/tests/tests/permission/jni/",
+		"development/tutorials/ReverseDebug/",
+		"external/freetype/",
+		"frameworks/av/drm/mediacas/plugins/",
+		"frameworks/av/media/libaaudio/examples/",
+		"frameworks/av/services/mediaextractor/",
+		"frameworks/base/core/tests/webkit/apk_with_native_libs/jni/",
+		"frameworks/base/tests/backup/",
+		"frameworks/native/cmds/cmd/",
+		"frameworks/webview/chromium/",
+		"hardware/interfaces/audio/2.0/",
+		"hardware/libhardware/modules/",
+		"hardware/libhardware/tests/",
+		"hardware/qcom/",
+		"sdk/emulator/mksdcard/",
+		"system/vold/tests/",
+		"test/vts-testcase/kernel/api/qtaguid/",
+		"test/vts-testcase/security/poc/target/",
+		"tools/adt/idea/android/ultimate/get_modification_time/jni/",
+	}
 )
 
 var pctx = android.NewPackageContext("android/soong/cc/config")
diff --git a/cc/makevars.go b/cc/makevars.go
index 7befb11..f7f8b60 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -18,15 +18,51 @@
 	"fmt"
 	"sort"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/cc/config"
 )
 
+const (
+	modulesAddedWall     = "ModulesAddedWall"
+	modulesAddedWerror   = "ModulesAddedWerror"
+	modulesUsingWnoError = "ModulesUsingWnoError"
+)
+
 func init() {
 	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
 }
 
+func getWallWerrorMap(config android.Config, name string) *sync.Map {
+	return config.Once(name, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+func makeStringOfKeys(ctx android.MakeVarsContext, setName string) string {
+	set := getWallWerrorMap(ctx.Config(), setName)
+	keys := []string{}
+	set.Range(func(key interface{}, value interface{}) bool {
+		keys = append(keys, key.(string))
+		return true
+	})
+	sort.Strings(keys)
+	return strings.Join(keys, " ")
+}
+
+func makeStringOfWarningAllowedProjects() string {
+	allProjects := append([]string{}, config.WarningAllowedProjects...)
+	allProjects = append(allProjects, config.WarningAllowedOldProjects...)
+	sort.Strings(allProjects)
+	// Makefile rules use pattern "path/%" to match module paths.
+	if len(allProjects) > 0 {
+		return strings.Join(allProjects, "% ") + "%"
+	} else {
+		return ""
+	}
+}
+
 func makeVarsProvider(ctx android.MakeVarsContext) {
 	ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
 	ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
@@ -64,6 +100,11 @@
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
 
+	ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
+	ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
+	ctx.Strict("SOONG_MODULES_ADDED_WERROR", makeStringOfKeys(ctx, modulesAddedWerror))
+	ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
+
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c517523..96a90fb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -251,6 +251,8 @@
 		"-Wno-incompatible-library-redeclaration",
 		"-Wno-builtin-requires-header",
 		"-Wno-invalid-noreturn",
+		"-Wall",
+		"-Werror",
 		// These libraries aren't actually used. Don't worry about unwinding
 		// (avoids the need to link an unwinder into a fake library).
 		"-fno-unwind-tables",
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 70aa412..fcea4ef 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"io"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/cc/config"
@@ -36,9 +37,10 @@
 		"-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"}
 	cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
 		"-Wl,-plugin-opt,O1"}
-	cfiArflags        = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
-	cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
-	cfiExportsMap     android.Path
+	cfiArflags         = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
+	cfiExportsMapPath  = "build/soong/cc/config/cfi_exports.map"
+	cfiExportsMap      android.Path
+	cfiStaticLibsMutex sync.Mutex
 
 	intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
 )
@@ -122,6 +124,10 @@
 	androidMkRuntimeLibrary string
 }
 
+func init() {
+	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
+}
+
 func (sanitize *sanitize) props() []interface{} {
 	return []interface{}{&sanitize.Properties}
 }
@@ -243,6 +249,12 @@
 		s.Diag.Cfi = nil
 	}
 
+	// Also disable CFI for host builds.
+	if ctx.Host() {
+		s.Cfi = nil
+		s.Diag.Cfi = nil
+	}
+
 	if ctx.staticBinary() {
 		s.Address = nil
 		s.Coverage = nil
@@ -474,12 +486,11 @@
 			fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary)
 		}
 	})
-	if ctx.Target().Os.Class == android.Device {
-		if Bool(sanitize.Properties.Sanitize.Cfi) {
-			ret.SubName += ".cfi"
-		} else if Bool(sanitize.Properties.Sanitize.Address) {
-			ret.SubName += ".asan"
-		}
+
+	// Add a suffix for CFI-enabled static libraries to allow surfacing both to make without a
+	// name conflict.
+	if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Cfi) {
+		ret.SubName += ".cfi"
 	}
 }
 
@@ -584,27 +595,44 @@
 
 				modules[0].(*Module).sanitize.Properties.SanitizeDep = false
 				modules[1].(*Module).sanitize.Properties.SanitizeDep = false
-				if mctx.Device() {
-					// CFI and ASAN are currently mutually exclusive so disable
-					// CFI if this is an ASAN variant.
-					if t == asan {
+
+				// We don't need both variants active for anything but CFI-enabled
+				// target static libraries, so suppress the appropriate variant in
+				// all other cases.
+				if t == cfi {
+					if c.static() {
+						if !mctx.Device() {
+							if isSanitizerEnabled {
+								modules[0].(*Module).Properties.PreventInstall = true
+								modules[0].(*Module).Properties.HideFromMake = true
+							} else {
+								modules[1].(*Module).Properties.PreventInstall = true
+								modules[1].(*Module).Properties.HideFromMake = true
+							}
+						} else {
+							cfiStaticLibs := cfiStaticLibs(mctx.AConfig())
+
+							cfiStaticLibsMutex.Lock()
+							*cfiStaticLibs = append(*cfiStaticLibs, c.Name())
+							cfiStaticLibsMutex.Unlock()
+						}
+					} else {
+						modules[0].(*Module).Properties.PreventInstall = true
+						modules[0].(*Module).Properties.HideFromMake = true
+					}
+				} else if t == asan {
+					if mctx.Device() {
+						// CFI and ASAN are currently mutually exclusive so disable
+						// CFI if this is an ASAN variant.
 						modules[1].(*Module).sanitize.Properties.InSanitizerDir = true
 						modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
 					}
-				} else {
-					if mctx.AConfig().EmbeddedInMake() {
-						if isSanitizerEnabled {
-							modules[0].(*Module).Properties.HideFromMake = true
-						} else {
-							modules[1].(*Module).Properties.HideFromMake = true
-						}
-					}
-				}
-				if !mctx.AConfig().EmbeddedInMake() || !mctx.Device() {
 					if isSanitizerEnabled {
 						modules[0].(*Module).Properties.PreventInstall = true
+						modules[0].(*Module).Properties.HideFromMake = true
 					} else {
 						modules[1].(*Module).Properties.PreventInstall = true
+						modules[1].(*Module).Properties.HideFromMake = true
 					}
 				}
 			}
@@ -612,3 +640,14 @@
 		}
 	}
 }
+
+func cfiStaticLibs(config android.Config) *[]string {
+	return config.Once("cfiStaticLibs", func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
+	cfiStaticLibs := cfiStaticLibs(ctx.Config())
+	ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " "))
+}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 207b161..556dad0 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -54,13 +54,14 @@
 }
 
 var (
-	sortEntries     = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
-	emulateJar      = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
-	stripDirs       fileList
-	stripFiles      fileList
-	zipsToNotStrip  = make(zipsToNotStripSet)
-	stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
-	manifest        = flag.String("m", "", "manifest file to insert in jar")
+	sortEntries      = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
+	emulateJar       = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+	stripDirs        fileList
+	stripFiles       fileList
+	zipsToNotStrip   = make(zipsToNotStripSet)
+	stripDirEntries  = flag.Bool("D", false, "strip directory entries from the output zip file")
+	manifest         = flag.String("m", "", "manifest file to insert in jar")
+	ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
 )
 
 func init() {
@@ -118,7 +119,7 @@
 	}
 
 	// do merge
-	err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries)
+	err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries, *ignoreDuplicates)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -210,7 +211,7 @@
 }
 
 func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest string,
-	sortEntries, emulateJar, stripDirEntries bool) error {
+	sortEntries, emulateJar, stripDirEntries, ignoreDuplicates bool) error {
 
 	sourceByDest := make(map[string]zipSource, 0)
 	orderedMappings := []fileMapping{}
@@ -266,6 +267,9 @@
 					return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
 						dest, existingSource, source)
 				}
+				if ignoreDuplicates {
+					continue
+				}
 				if emulateJar &&
 					file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
 					// Skip manifest and module info files that are not from the first input file
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 6420219..68d8bc7 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -15,8 +15,9 @@
 blueprint_go_binary {
     name: "zip2zip",
     deps: [
-      "android-archive-zip",
-      "soong-jar",
+        "android-archive-zip",
+        "blueprint-pathtools",
+        "soong-jar",
     ],
     srcs: [
         "zip2zip.go",
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index f48d458..e8ea9b9 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -24,6 +24,8 @@
 	"strings"
 	"time"
 
+	"github.com/google/blueprint/pathtools"
+
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
@@ -36,8 +38,14 @@
 	setTime   = flag.Bool("t", false, "set timestamps to 2009-01-01 00:00:00")
 
 	staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
+
+	excludes excludeArgs
 )
 
+func init() {
+	flag.Var(&excludes, "x", "exclude a filespec from the output")
+}
+
 func main() {
 	flag.Usage = func() {
 		fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [-s|-j] [-t] [filespec]...")
@@ -45,15 +53,14 @@
 		fmt.Fprintln(os.Stderr, "  filespec:")
 		fmt.Fprintln(os.Stderr, "    <name>")
 		fmt.Fprintln(os.Stderr, "    <in_name>:<out_name>")
-		fmt.Fprintln(os.Stderr, "    <glob>:<out_dir>/")
+		fmt.Fprintln(os.Stderr, "    <glob>[:<out_dir>]")
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://golang.org/pkg/path/filepath/#Match")
-		fmt.Fprintln(os.Stderr, "As a special exception, '**' is supported to specify all files in the input zip.")
+		fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://godoc.org/github.com/google/blueprint/pathtools/#Match")
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, "Files will be copied with their existing compression from the input zipfile to")
 		fmt.Fprintln(os.Stderr, "the output zipfile, in the order of filespec arguments.")
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "If no filepsec is provided all files are copied (equivalent to '**').")
+		fmt.Fprintln(os.Stderr, "If no filepsec is provided all files and directories are copied.")
 	}
 
 	flag.Parse()
@@ -85,7 +92,9 @@
 		}
 	}()
 
-	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime, flag.Args()); err != nil {
+	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime,
+		flag.Args(), excludes); err != nil {
+
 		log.Fatal(err)
 	}
 }
@@ -95,91 +104,126 @@
 	newName string
 }
 
-func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, sortJava, setTime bool, args []string) error {
-	if len(args) == 0 {
-		// If no filespec is provided, default to copying everything
-		args = []string{"**"}
-	}
-	for _, arg := range args {
-		var input string
-		var output string
+func zip2zip(reader *zip.Reader, writer *zip.Writer, sortOutput, sortJava, setTime bool,
+	includes []string, excludes []string) error {
 
+	matches := []pair{}
+
+	sortMatches := func(matches []pair) {
+		if sortJava {
+			sort.SliceStable(matches, func(i, j int) bool {
+				return jar.EntryNamesLess(matches[i].newName, matches[j].newName)
+			})
+		} else if sortOutput {
+			sort.SliceStable(matches, func(i, j int) bool {
+				return matches[i].newName < matches[j].newName
+			})
+		}
+	}
+
+	for _, include := range includes {
 		// Reserve escaping for future implementation, so make sure no
 		// one is using \ and expecting a certain behavior.
-		if strings.Contains(arg, "\\") {
+		if strings.Contains(include, "\\") {
 			return fmt.Errorf("\\ characters are not currently supported")
 		}
 
-		args := strings.SplitN(arg, ":", 2)
-		input = args[0]
-		if len(args) == 2 {
-			output = args[1]
-		}
+		input, output := includeSplit(include)
 
-		matches := []pair{}
-		if strings.IndexAny(input, "*?[") >= 0 {
-			matchAll := input == "**"
-			if !matchAll && strings.Contains(input, "**") {
-				return fmt.Errorf("** is only supported on its own, not with other characters")
-			}
+		var includeMatches []pair
 
-			for _, file := range reader.File {
-				match := matchAll
-
-				if !match {
-					var err error
-					match, err = filepath.Match(input, file.Name)
-					if err != nil {
-						return err
-					}
-				}
-
-				if match {
-					var newName string
-					if output == "" {
-						newName = file.Name
-					} else {
+		for _, file := range reader.File {
+			var newName string
+			if match, err := pathtools.Match(input, file.Name); err != nil {
+				return err
+			} else if match {
+				if output == "" {
+					newName = file.Name
+				} else {
+					if pathtools.IsGlob(input) {
+						// If the input is a glob then the output is a directory.
 						_, name := filepath.Split(file.Name)
 						newName = filepath.Join(output, name)
+					} else {
+						// Otherwise it is a file.
+						newName = output
 					}
-					matches = append(matches, pair{file, newName})
 				}
-			}
-
-			if sortJava {
-				jarSort(matches)
-			} else if sortGlobs {
-				sort.SliceStable(matches, func(i, j int) bool {
-					return matches[i].newName < matches[j].newName
-				})
-			}
-		} else {
-			if output == "" {
-				output = input
-			}
-			for _, file := range reader.File {
-				if input == file.Name {
-					matches = append(matches, pair{file, output})
-					break
-				}
+				includeMatches = append(includeMatches, pair{file, newName})
 			}
 		}
 
-		for _, match := range matches {
-			if setTime {
-				match.File.SetModTime(staticTime)
-			}
-			if err := writer.CopyFrom(match.File, match.newName); err != nil {
+		sortMatches(includeMatches)
+		matches = append(matches, includeMatches...)
+	}
+
+	if len(includes) == 0 {
+		// implicitly match everything
+		for _, file := range reader.File {
+			matches = append(matches, pair{file, file.Name})
+		}
+		sortMatches(matches)
+	}
+
+	var matchesAfterExcludes []pair
+	seen := make(map[string]*zip.File)
+
+	for _, match := range matches {
+		// Filter out matches whose original file name matches an exclude filter
+		excluded := false
+		for _, exclude := range excludes {
+			if excludeMatch, err := pathtools.Match(exclude, match.File.Name); err != nil {
 				return err
+			} else if excludeMatch {
+				excluded = true
+				break
 			}
 		}
+
+		if excluded {
+			continue
+		}
+
+		// Check for duplicate output names, ignoring ones that come from the same input zip entry.
+		if prev, exists := seen[match.newName]; exists {
+			if prev != match.File {
+				return fmt.Errorf("multiple entries for %q with different contents", match.newName)
+			}
+			continue
+		}
+		seen[match.newName] = match.File
+
+		matchesAfterExcludes = append(matchesAfterExcludes, match)
+	}
+
+	for _, match := range matchesAfterExcludes {
+		if setTime {
+			match.File.SetModTime(staticTime)
+		}
+		if err := writer.CopyFrom(match.File, match.newName); err != nil {
+			return err
+		}
 	}
 
 	return nil
 }
 
-func jarSort(files []pair) {
-	sort.SliceStable(files, func(i, j int) bool {
-		return jar.EntryNamesLess(files[i].newName, files[j].newName)
-	})
+func includeSplit(s string) (string, string) {
+	split := strings.SplitN(s, ":", 2)
+	if len(split) == 2 {
+		return split[0], split[1]
+	} else {
+		return split[0], ""
+	}
+}
+
+type excludeArgs []string
+
+func (e *excludeArgs) String() string {
+	return strings.Join(*e, " ")
+}
+
+func (e *excludeArgs) Set(s string) error {
+	*e = append(*e, s)
+	return nil
 }
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 53c8ce2..212ab28 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -30,6 +30,7 @@
 	sortGlobs  bool
 	sortJava   bool
 	args       []string
+	excludes   []string
 
 	outputFiles []string
 	err         error
@@ -41,13 +42,6 @@
 
 		err: fmt.Errorf("\\ characters are not currently supported"),
 	},
-	{
-		name: "unsupported **",
-
-		args: []string{"a/**:b"},
-
-		err: fmt.Errorf("** is only supported on its own, not with other characters"),
-	},
 	{ // This is modelled after the update package build rules in build/make/core/Makefile
 		name: "filter globs",
 
@@ -95,16 +89,19 @@
 		name: "sort all",
 
 		inputFiles: []string{
+			"RADIO/",
 			"RADIO/a",
+			"IMAGES/",
 			"IMAGES/system.img",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/b",
 			"OTA/android-info.txt",
 		},
 		sortGlobs: true,
-		args:      []string{"**"},
+		args:      []string{"**/*"},
 
 		outputFiles: []string{
 			"IMAGES/b.txt",
@@ -120,11 +117,14 @@
 		name: "sort all implicit",
 
 		inputFiles: []string{
+			"RADIO/",
 			"RADIO/a",
+			"IMAGES/",
 			"IMAGES/system.img",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/b",
 			"OTA/android-info.txt",
 		},
@@ -132,12 +132,15 @@
 		args:      nil,
 
 		outputFiles: []string{
+			"IMAGES/",
 			"IMAGES/b.txt",
 			"IMAGES/recovery.img",
 			"IMAGES/system.img",
 			"IMAGES/vendor.img",
+			"OTA/",
 			"OTA/android-info.txt",
 			"OTA/b",
+			"RADIO/",
 			"RADIO/a",
 		},
 	},
@@ -177,7 +180,7 @@
 			"b",
 			"a",
 		},
-		args: []string{"a:a2", "**"},
+		args: []string{"a:a2", "**/*"},
 
 		outputFiles: []string{
 			"a2",
@@ -185,6 +188,69 @@
 			"a",
 		},
 	},
+	{
+		name: "multiple matches",
+
+		inputFiles: []string{
+			"a/a",
+		},
+		args: []string{"a/a", "a/*"},
+
+		outputFiles: []string{
+			"a/a",
+		},
+	},
+	{
+		name: "multiple conflicting matches",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args: []string{"a/b:a/a", "a/*"},
+
+		err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
+	},
+	{
+		name: "excludes",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     nil,
+		excludes: []string{"a/a"},
+
+		outputFiles: []string{
+			"a/b",
+		},
+	},
+	{
+		name: "excludes with include",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     []string{"a/*"},
+		excludes: []string{"a/a"},
+
+		outputFiles: []string{
+			"a/b",
+		},
+	},
+	{
+		name: "excludes with glob",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		args:     []string{"a/*"},
+		excludes: []string{"a/*"},
+
+		outputFiles: nil,
+	},
 }
 
 func errorString(e error) string {
@@ -216,7 +282,7 @@
 			}
 
 			outputWriter := zip.NewWriter(outputBuf)
-			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args)
+			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args, testCase.excludes)
 			if errorString(testCase.err) != errorString(err) {
 				t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
 			}
diff --git a/java/androidmk.go b/java/androidmk.go
index 1c0526a..df83faa 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -36,12 +36,16 @@
 				}
 				if library.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
-					if library.deviceProperties.Dex_preopt == nil || *library.deviceProperties.Dex_preopt == false {
+					if library.deviceProperties.Dex_preopt != nil && *library.deviceProperties.Dex_preopt == false {
 						fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
 					}
 				}
 				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", String(library.deviceProperties.Sdk_version))
 				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
+
+				if library.jacocoReportClassesFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String())
+				}
 			},
 		},
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
diff --git a/java/app.go b/java/app.go
index 05cc975..68e4d5c 100644
--- a/java/app.go
+++ b/java/app.go
@@ -54,6 +54,8 @@
 	// list of directories relative to the Blueprints file containing
 	// Android resources
 	Resource_dirs []string
+
+	Instrumentation_for *string
 }
 
 type AndroidApp struct {
@@ -119,6 +121,10 @@
 	//	a.properties.Proguard.Enabled = true
 	//}
 
+	if String(a.appProperties.Instrumentation_for) == "" {
+		a.properties.Instrument = true
+	}
+
 	a.Module.compile(ctx)
 
 	aaptPackageFlags := append([]string(nil), aaptFlags...)
diff --git a/java/config/config.go b/java/config/config.go
index 3cd2841..49481be 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -28,6 +28,16 @@
 	DefaultBootclasspathLibraries = []string{"core-oj", "core-libart"}
 	DefaultSystemModules          = "core-system-modules"
 	DefaultLibraries              = []string{"ext", "framework", "okhttp"}
+
+	DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+
+	InstrumentFrameworkModules = []string{
+		"framework",
+		"telephony-common",
+		"services",
+		"android.car",
+		"android.car7",
+	}
 )
 
 func init() {
@@ -74,6 +84,7 @@
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 	pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
+	pctx.HostBinToolVariable("Zip2ZipCmd", "zip2zip")
 	pctx.VariableFunc("DxCmd", func(config interface{}) (string, error) {
 		if config.(android.Config).IsEnvFalse("USE_D8") {
 			if config.(android.Config).UnbundledBuild() || config.(android.Config).IsPdkBuild() {
@@ -117,4 +128,6 @@
 		}
 		return "", nil
 	})
+
+	pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
 }
diff --git a/java/config/makevars.go b/java/config/makevars.go
index dabf2e7..b9009f3 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -62,4 +62,7 @@
 
 	ctx.Strict("SOONG_JAVAC_WRAPPER", "${SoongJavacWrapper}")
 	ctx.Strict("EXTRACT_SRCJARS", "${ExtractSrcJarsCmd}")
+
+	ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}")
+	ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
 }
diff --git a/java/jacoco.go b/java/jacoco.go
new file mode 100644
index 0000000..b26b046
--- /dev/null
+++ b/java/jacoco.go
@@ -0,0 +1,108 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+// Rules for instrumenting classes using jacoco
+
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var (
+	jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
+		Command: `${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
+			`${config.JavaCmd} -jar ${config.JacocoCLIJar} instrument -quiet -dest $instrumentedJar $strippedJar && ` +
+			`${config.Ziptime} $instrumentedJar && ` +
+			`${config.MergeZipsCmd} --ignore-duplicates -j $out $instrumentedJar $in`,
+		CommandDeps: []string{
+			"${config.Zip2ZipCmd}",
+			"${config.JavaCmd}",
+			"${config.JacocoCLIJar}",
+			"${config.Ziptime}",
+			"${config.MergeZipsCmd}",
+		},
+	},
+		"strippedJar", "stripSpec", "instrumentedJar")
+)
+
+func jacocoInstrumentJar(ctx android.ModuleContext, outputJar, strippedJar android.WritablePath,
+	inputJar android.Path, stripSpec string) {
+	instrumentedJar := android.PathForModuleOut(ctx, "jacoco/instrumented.jar")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:           jacoco,
+		Description:    "jacoco",
+		Output:         outputJar,
+		ImplicitOutput: strippedJar,
+		Input:          inputJar,
+		Args: map[string]string{
+			"strippedJar":     strippedJar.String(),
+			"stripSpec":       stripSpec,
+			"instrumentedJar": instrumentedJar.String(),
+		},
+	})
+}
+
+func (j *Module) jacocoStripSpecs(ctx android.ModuleContext) string {
+	includes := jacocoFiltersToSpecs(ctx,
+		j.properties.Jacoco.Include_filter, "jacoco.include_filter")
+	excludes := jacocoFiltersToSpecs(ctx,
+		j.properties.Jacoco.Exclude_filter, "jacoco.exclude_filter")
+
+	specs := ""
+	if len(excludes) > 0 {
+		specs += android.JoinWithPrefix(excludes, "-x") + " "
+	}
+
+	if len(includes) > 0 {
+		specs += strings.Join(includes, " ")
+	} else {
+		specs += "**/*.class"
+	}
+
+	return specs
+}
+
+func jacocoFiltersToSpecs(ctx android.ModuleContext, filters []string, property string) []string {
+	specs := make([]string, len(filters))
+	for i, f := range filters {
+		specs[i] = jacocoFilterToSpec(ctx, f, property)
+	}
+	return specs
+}
+
+func jacocoFilterToSpec(ctx android.ModuleContext, filter string, property string) string {
+	wildcard := strings.HasSuffix(filter, "*")
+	filter = strings.TrimSuffix(filter, "*")
+	recursiveWildcard := wildcard && (strings.HasSuffix(filter, ".") || filter == "")
+
+	if strings.ContainsRune(filter, '*') {
+		ctx.PropertyErrorf(property, "'*' is only supported as the last character in a filter")
+	}
+
+	spec := strings.Replace(filter, ".", "/", -1)
+
+	if recursiveWildcard {
+		spec += "**/*.class"
+	} else if wildcard {
+		spec += "*.class"
+	}
+
+	return spec
+}
diff --git a/java/java.go b/java/java.go
index b2bd2b0..417cf74 100644
--- a/java/java.go
+++ b/java/java.go
@@ -51,9 +51,6 @@
 //  Renderscript
 // Post-jar passes:
 //  Proguard
-//  Jacoco
-//  Jarjar
-//  Dex
 // Rmtypedefs
 // DroidDoc
 // Findbugs
@@ -127,6 +124,26 @@
 		// List of javac flags that should only be used when passing -source 1.9
 		Javacflags []string
 	}
+
+	Jacoco struct {
+		// List of classes to include for instrumentation with jacoco to collect coverage
+		// information at runtime when building with coverage enabled.  If unset defaults to all
+		// classes.
+		// Supports '*' as the last character of an entry in the list as a wildcard match.
+		// If preceded by '.' it matches all classes in the package and subpackages, otherwise
+		// it matches classes in the package that have the class name as a prefix.
+		Include_filter []string
+
+		// List of classes to exclude from instrumentation with jacoco to collect coverage
+		// information at runtime when building with coverage enabled.  Overrides classes selected
+		// by the include_filter property.
+		// Supports '*' as the last character of an entry in the list as a wildcard match.
+		// If preceded by '.' it matches all classes in the package and subpackages, otherwise
+		// it matches classes in the package that have the class name as a prefix.
+		Exclude_filter []string
+	}
+
+	Instrument bool `blueprint:"mutated"`
 }
 
 type CompilerDeviceProperties struct {
@@ -177,6 +194,9 @@
 	// output file containing classes.dex
 	dexJarFile android.Path
 
+	// output file containing uninstrumented classes that will be instrumented by jacoco
+	jacocoReportClassesFile android.Path
+
 	// output file suitable for installing or running
 	outputFile android.Path
 
@@ -718,6 +738,20 @@
 	}
 
 	if ctx.Device() && j.installable() {
+		outputFile = j.desugar(ctx, flags, outputFile, jarName)
+	}
+
+	if ctx.AConfig().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+		if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
+			j.properties.Instrument = true
+		}
+	}
+
+	if ctx.AConfig().IsEnvTrue("EMMA_INSTRUMENT") && j.properties.Instrument {
+		outputFile = j.instrument(ctx, flags, outputFile, jarName)
+	}
+
+	if ctx.Device() && j.installable() {
 		outputFile = j.compileDex(ctx, flags, outputFile, jarName)
 		if ctx.Failed() {
 			return
@@ -766,6 +800,42 @@
 	return headerJar
 }
 
+func (j *Module) desugar(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	desugarFlags := []string{
+		"--min_sdk_version " + j.minSdkVersionNumber(ctx),
+		"--desugar_try_with_resources_if_needed=false",
+		"--allow_empty_bootclasspath",
+	}
+
+	if inList("--core-library", j.deviceProperties.Dxflags) {
+		desugarFlags = append(desugarFlags, "--core_library")
+	}
+
+	flags.desugarFlags = strings.Join(desugarFlags, " ")
+
+	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
+	TransformDesugar(ctx, desugarJar, classesJar, flags)
+
+	return desugarJar
+}
+
+func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	specs := j.jacocoStripSpecs(ctx)
+
+	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
+	instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
+
+	jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
+
+	j.jacocoReportClassesFile = jacocoReportClassesFile
+
+	return instrumentedJar
+}
+
 func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
 	classesJar android.Path, jarName string) android.Path {
 
@@ -792,47 +862,29 @@
 			"--dump-width=1000")
 	}
 
-	var minSdkVersion string
-	switch String(j.deviceProperties.Sdk_version) {
-	case "", "current", "test_current", "system_current":
-		minSdkVersion = strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
-	default:
-		minSdkVersion = String(j.deviceProperties.Sdk_version)
-	}
-
-	dxFlags = append(dxFlags, "--min-sdk-version="+minSdkVersion)
+	dxFlags = append(dxFlags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
 
 	flags.dxFlags = strings.Join(dxFlags, " ")
 
-	desugarFlags := []string{
-		"--min_sdk_version " + minSdkVersion,
-		"--desugar_try_with_resources_if_needed=false",
-		"--allow_empty_bootclasspath",
-	}
-
-	if inList("--core-library", dxFlags) {
-		desugarFlags = append(desugarFlags, "--core_library")
-	}
-
-	flags.desugarFlags = strings.Join(desugarFlags, " ")
-
-	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
-	TransformDesugar(ctx, desugarJar, classesJar, flags)
-	if ctx.Failed() {
-		return nil
-	}
-
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
-	TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
-	if ctx.Failed() {
-		return nil
-	}
+	TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
 
 	j.dexJarFile = javalibJar
 	return javalibJar
 }
 
+// Returns a sdk version as a string that is guaranteed to be a parseable as a number.  For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns "10000".
+func (j *Module) minSdkVersionNumber(ctx android.ModuleContext) string {
+	switch String(j.deviceProperties.Sdk_version) {
+	case "", "current", "test_current", "system_current":
+		return strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
+	default:
+		return String(j.deviceProperties.Sdk_version)
+	}
+}
+
 func (j *Module) installable() bool {
 	return j.properties.Installable == nil || *j.properties.Installable
 }
diff --git a/java/java_test.go b/java/java_test.go
index e1c90ee..143e82c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -52,10 +52,11 @@
 	os.Exit(run())
 }
 func testJava(t *testing.T, bp string) *android.TestContext {
-	return testJavaWithEnv(t, bp, nil)
+	return testJavaWithEnvFs(t, bp, nil, nil)
 }
 
-func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.TestContext {
+func testJavaWithEnvFs(t *testing.T, bp string,
+	env map[string]string, fs map[string][]byte) *android.TestContext {
 	config := android.TestArchConfig(buildDir, env)
 
 	ctx := android.NewTestArchContext()
@@ -112,17 +113,17 @@
 		}
 	}
 
-	ctx.MockFileSystem(map[string][]byte{
-		"Android.bp": []byte(bp),
-		"a.java":     nil,
-		"b.java":     nil,
-		"c.java":     nil,
-		"b.kt":       nil,
-		"a.jar":      nil,
-		"b.jar":      nil,
-		"res/a":      nil,
-		"res/b":      nil,
-		"res2/a":     nil,
+	mockFS := map[string][]byte{
+		"Android.bp":  []byte(bp),
+		"a.java":      nil,
+		"b.java":      nil,
+		"c.java":      nil,
+		"b.kt":        nil,
+		"a.jar":       nil,
+		"b.jar":       nil,
+		"java-res/a":  nil,
+		"java-res/b":  nil,
+		"java-res2/a": nil,
 
 		"prebuilts/sdk/14/android.jar":                nil,
 		"prebuilts/sdk/14/framework.aidl":             nil,
@@ -132,7 +133,13 @@
 		"prebuilts/sdk/system_current/framework.aidl": nil,
 		"prebuilts/sdk/test_current/android.jar":      nil,
 		"prebuilts/sdk/test_current/framework.aidl":   nil,
-	})
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	fail(t, errs)
@@ -394,7 +401,7 @@
 
 			// Test again with javac 1.9
 			t.Run("1.9", func(t *testing.T) {
-				ctx := testJavaWithEnv(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+				ctx := testJavaWithEnvFs(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"}, nil)
 
 				javac := ctx.ModuleForTests("foo", variant).Rule("javac")
 				got := javac.Args["bootClasspath"]
@@ -497,14 +504,14 @@
 		{
 			// Test that a module with java_resource_dirs includes the files
 			name: "resource dirs",
-			prop: `java_resource_dirs: ["res"]`,
-			args: "-C res -f res/a -f res/b",
+			prop: `java_resource_dirs: ["java-res"]`,
+			args: "-C java-res -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with java_resources includes the files
 			name: "resource files",
-			prop: `java_resources: ["res/a", "res/b"]`,
-			args: "-C . -f res/a -f res/b",
+			prop: `java_resources: ["java-res/a", "java-res/b"]`,
+			args: "-C . -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with a filegroup in java_resources includes the files with the
@@ -514,10 +521,10 @@
 			extra: `
 				filegroup {
 					name: "foo-res",
-					path: "res",
-					srcs: ["res/a", "res/b"],
+					path: "java-res",
+					srcs: ["java-res/a", "java-res/b"],
 				}`,
-			args: "-C res -f res/a -f res/b",
+			args: "-C java-res -f java-res/a -f java-res/b",
 		},
 		{
 			// Test that a module with "include_srcs: true" includes its source files in the resources jar
@@ -562,21 +569,21 @@
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
-			java_resource_dirs: ["res", "res2"],
-			exclude_java_resource_dirs: ["res2"],
+			java_resource_dirs: ["java-res", "java-res2"],
+			exclude_java_resource_dirs: ["java-res2"],
 		}
 
 		java_library {
 			name: "bar",
 			srcs: ["a.java"],
-			java_resources: ["res/*"],
-			exclude_java_resources: ["res/b"],
+			java_resources: ["java-res/*"],
+			exclude_java_resources: ["java-res/b"],
 		}
 	`)
 
 	fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
 
-	expected := "-C res -f res/a -f res/b"
+	expected := "-C java-res -f java-res/a -f java-res/b"
 	if fooRes.Args["jarArgs"] != expected {
 		t.Errorf("foo resource jar args %q is not %q",
 			fooRes.Args["jarArgs"], expected)
@@ -585,7 +592,7 @@
 
 	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
 
-	expected = "-C . -f res/a"
+	expected = "-C . -f java-res/a"
 	if barRes.Args["jarArgs"] != expected {
 		t.Errorf("bar resource jar args %q is not %q",
 			barRes.Args["jarArgs"], expected)
@@ -606,7 +613,7 @@
 
 		genrule {
 			name: "gen",
-			tool_files: ["res/a"],
+			tool_files: ["java-res/a"],
 			out: ["gen.java"],
 		}
 	`)