Merge "Print full diagnostics file when Java process crashes."
diff --git a/README.md b/README.md
index b0b61a8..8fdce4b 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,8 @@
 Maps may values of any type, including nested maps.  Lists and maps may have
 trailing commas after the last value.
 
+Strings can contain double quotes using `\"`, for example `"cat \"a b\""`.
+
 ### Operators
 
 Strings, lists of strings, and maps can be appended using the `+` operator.
@@ -195,8 +197,10 @@
 * `["//visibility:legacy_public"]`: The default visibility, behaves as
 `//visibility:public` for now. It is an error if it is used in a module.
 
-The visibility rules of `//visibility:public` and `//visibility:private` can
-not be combined with any other visibility specifications.
+The visibility rules of `//visibility:public` and `//visibility:private` can not
+be combined with any other visibility specifications, except
+`//visibility:public` is allowed to override visibility specifications imported
+through the `defaults` property.
 
 Packages outside `vendor/` cannot make themselves visible to specific packages
 in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
diff --git a/android/mutator.go b/android/mutator.go
index 085c055..0e80249 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -76,6 +76,7 @@
 	registerLoadHookMutator,
 	RegisterNamespaceMutator,
 	RegisterPrebuiltsPreArchMutators,
+	registerVisibilityRuleChecker,
 	RegisterDefaultsPreArchMutators,
 	registerVisibilityRuleGatherer,
 }
diff --git a/android/visibility.go b/android/visibility.go
index 36b6f35..c7ef1da 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -71,7 +71,17 @@
 	String() string
 }
 
-// A compositeRule is a visibility rule composed from other visibility rules.
+// A compositeRule is a visibility rule composed from a list of atomic visibility rules.
+//
+// The list corresponds to the list of strings in the visibility property after defaults expansion.
+// Even though //visibility:public is not allowed together with other rules in the visibility list
+// of a single module, it is allowed here to permit a module to override an inherited visibility
+// spec with public visibility.
+//
+// //visibility:private is not allowed in the same way, since we'd need to check for it during the
+// defaults expansion to make that work. No non-private visibility rules are allowed in a
+// compositeRule containing a privateRule.
+//
 // This array will only be [] if all the rules are invalid and will behave as if visibility was
 // ["//visibility:private"].
 type compositeRule []visibilityRule
@@ -126,6 +136,28 @@
 	return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
 }
 
+// visibilityRule for //visibility:public
+type publicRule struct{}
+
+func (r publicRule) matches(_ qualifiedModuleName) bool {
+	return true
+}
+
+func (r publicRule) String() string {
+	return "//visibility:public"
+}
+
+// visibilityRule for //visibility:private
+type privateRule struct{}
+
+func (r privateRule) matches(_ qualifiedModuleName) bool {
+	return false
+}
+
+func (r privateRule) String() string {
+	return "//visibility:private"
+}
+
 var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
 
 // The map from qualifiedModuleName to visibilityRule.
@@ -135,8 +167,15 @@
 	}).(*sync.Map)
 }
 
+// The rule checker needs to be registered before defaults expansion to correctly check that
+// //visibility:xxx isn't combined with other packages in the same list in any one module.
+func registerVisibilityRuleChecker(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
+}
+
 // Visibility is not dependent on arch so this must be registered before the arch phase to avoid
-// having to process multiple variants for each module.
+// having to process multiple variants for each module. This goes after defaults expansion to gather
+// the complete visibility lists from flat lists.
 func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
 }
@@ -146,11 +185,80 @@
 	ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
 }
 
-// Gathers the visibility rules, parses the visibility properties, stores them in a map by
-// qualifiedModuleName for retrieval during enforcement.
+// Checks the per-module visibility rule lists before defaults expansion.
+func visibilityRuleChecker(ctx BottomUpMutatorContext) {
+	qualified := createQualifiedModuleName(ctx)
+	if d, ok := ctx.Module().(Defaults); ok {
+		// Defaults modules don't store the payload properties in m.base().
+		for _, props := range d.properties() {
+			if cp, ok := props.(*commonProperties); ok {
+				if visibility := cp.Visibility; visibility != nil {
+					checkRules(ctx, qualified.pkg, visibility)
+				}
+			}
+		}
+	} else if m, ok := ctx.Module().(Module); ok {
+		if visibility := m.base().commonProperties.Visibility; visibility != nil {
+			checkRules(ctx, qualified.pkg, visibility)
+		}
+	}
+}
+
+func checkRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) {
+	ruleCount := len(visibility)
+	if ruleCount == 0 {
+		// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
+		// it could mean public visibility. Requiring at least one rule makes the owner's intent
+		// clearer.
+		ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
+		return
+	}
+
+	for _, v := range visibility {
+		ok, pkg, name := splitRule(ctx, v, currentPkg)
+		if !ok {
+			// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
+			// ensure all the rules on this module are checked.
+			ctx.PropertyErrorf("visibility",
+				"invalid visibility pattern %q must match"+
+					" //<package>:<module>, //<package> or :<module>",
+				v)
+			continue
+		}
+
+		if pkg == "visibility" {
+			switch name {
+			case "private", "public":
+			case "legacy_public":
+				ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
+				continue
+			default:
+				ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
+				continue
+			}
+			if ruleCount != 1 {
+				ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
+				continue
+			}
+		}
+
+		// If the current directory is not in the vendor tree then there are some additional
+		// restrictions on the rules.
+		if !isAncestor("vendor", currentPkg) {
+			if !isAllowedFromOutsideVendor(pkg, name) {
+				ctx.PropertyErrorf("visibility",
+					"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
+						" targets within //vendor, they can only use //vendor:__subpackages__.", v)
+				continue
+			}
+		}
+	}
+}
+
+// Gathers the flattened visibility rules after defaults expansion, parses the visibility
+// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement.
 //
 // See ../README.md#Visibility for information on the format of the visibility rules.
-
 func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
@@ -169,74 +277,51 @@
 }
 
 func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
-	ruleCount := len(visibility)
-	if ruleCount == 0 {
-		// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
-		// it could mean public visibility. Requiring at least one rule makes the owner's intent
-		// clearer.
-		ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
-		return nil
-	}
-
-	rules := make(compositeRule, 0, ruleCount)
+	rules := make(compositeRule, 0, len(visibility))
+	hasPrivateRule := false
+	hasNonPrivateRule := false
 	for _, v := range visibility {
 		ok, pkg, name := splitRule(ctx, v, currentPkg)
 		if !ok {
-			// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
-			// ensure all the rules on this module are checked.
-			ctx.PropertyErrorf("visibility",
-				"invalid visibility pattern %q must match"+
-					" //<package>:<module>, //<package> or :<module>",
-				v)
 			continue
 		}
 
+		var r visibilityRule
+		isPrivateRule := false
 		if pkg == "visibility" {
-			if ruleCount != 1 {
-				ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
-				continue
-			}
 			switch name {
 			case "private":
-				rules = append(rules, packageRule{currentPkg})
-				continue
+				r = privateRule{}
+				isPrivateRule = true
 			case "public":
-				return nil
-			case "legacy_public":
-				ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
-				return nil
+				r = publicRule{}
+			}
+		} else {
+			switch name {
+			case "__pkg__":
+				r = packageRule{pkg}
+			case "__subpackages__":
+				r = subpackagesRule{pkg}
 			default:
-				ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
 				continue
 			}
 		}
 
-		// If the current directory is not in the vendor tree then there are some additional
-		// restrictions on the rules.
-		if !isAncestor("vendor", currentPkg) {
-			if !isAllowedFromOutsideVendor(pkg, name) {
-				ctx.PropertyErrorf("visibility",
-					"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
-						" targets within //vendor, they can only use //vendor:__subpackages__.", v)
-				continue
-			}
-		}
-
-		// Create the rule
-		var r visibilityRule
-		switch name {
-		case "__pkg__":
-			r = packageRule{pkg}
-		case "__subpackages__":
-			r = subpackagesRule{pkg}
-		default:
-			ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
-			continue
+		if isPrivateRule {
+			hasPrivateRule = true
+		} else {
+			hasNonPrivateRule = true
 		}
 
 		rules = append(rules, r)
 	}
 
+	if hasPrivateRule && hasNonPrivateRule {
+		ctx.PropertyErrorf("visibility",
+			"cannot mix \"//visibility:private\" with any other visibility rules")
+		return compositeRule{privateRule{}}
+	}
+
 	return rules
 }
 
@@ -274,8 +359,7 @@
 }
 
 func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
-	_, ok := ctx.Module().(Module)
-	if !ok {
+	if _, ok := ctx.Module().(Module); !ok {
 		return
 	}
 
@@ -297,9 +381,7 @@
 		rule, ok := moduleToVisibilityRule.Load(depQualified)
 		if ok {
 			if !rule.(compositeRule).matches(qualified) {
-				ctx.ModuleErrorf(
-					"depends on %s which is not visible to this module; %s is only visible to %s",
-					depQualified, depQualified, rule)
+				ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
 			}
 		}
 	})
diff --git a/android/visibility_test.go b/android/visibility_test.go
index ea5316c..09c5b1b 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -91,7 +91,7 @@
 		expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
 	},
 	{
-		name: "//visibility:public mixed",
+		name: "//visibility:xxx mixed",
 		fs: map[string][]byte{
 			"top/Blueprints": []byte(`
 				mock_library {
@@ -105,10 +105,10 @@
 				}`),
 		},
 		expectedErrors: []string{
-			`module "libother" variant "android_common": visibility: cannot mix "//visibility:private"` +
+			`module "libother": visibility: cannot mix "//visibility:private"` +
 				` with any other visibility rules`,
-			`module "libexample" variant "android_common": visibility: cannot mix` +
-				` "//visibility:public" with any other visibility rules`,
+			`module "libexample": visibility: cannot mix "//visibility:public"` +
+				` with any other visibility rules`,
 		},
 	},
 	{
@@ -121,7 +121,7 @@
 				}`),
 		},
 		expectedErrors: []string{
-			`module "libexample" variant "android_common": visibility: //visibility:legacy_public must` +
+			`module "libexample": visibility: //visibility:legacy_public must` +
 				` not be used`,
 		},
 	},
@@ -153,33 +153,6 @@
 		},
 	},
 	{
-		// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
-		// the current directory, a nested directory and a directory in a separate tree.
-		name: "//visibility:public",
-		fs: map[string][]byte{
-			"top/Blueprints": []byte(`
-				mock_library {
-					name: "libexample",
-					visibility: ["//visibility:public"],
-				}
-	
-				mock_library {
-					name: "libsamepackage",
-					deps: ["libexample"],
-				}`),
-			"top/nested/Blueprints": []byte(`
-				mock_library {
-					name: "libnested",
-					deps: ["libexample"],
-				}`),
-			"other/Blueprints": []byte(`
-				mock_library {
-					name: "libother",
-					deps: ["libexample"],
-				}`),
-		},
-	},
-	{
 		// Verify that //visibility:private allows the module to be referenced from the current
 		// directory only.
 		name: "//visibility:private",
@@ -207,9 +180,9 @@
 		},
 		expectedErrors: []string{
 			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+				` visible to this module`,
 			`module "libother" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+				` visible to this module`,
 		},
 	},
 	{
@@ -239,9 +212,9 @@
 		},
 		expectedErrors: []string{
 			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+				` visible to this module`,
 			`module "libother" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
+				` visible to this module`,
 		},
 	},
 	{
@@ -277,9 +250,9 @@
 		},
 		expectedErrors: []string{
 			`module "libother" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
+				` visible to this module`,
 			`module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
+				` visible to this module`,
 		},
 	},
 	{
@@ -310,7 +283,7 @@
 		},
 		expectedErrors: []string{
 			`module "libother" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to \[//top:__subpackages__\]`,
+				` visible to this module`,
 		},
 	},
 	{
@@ -341,8 +314,7 @@
 		},
 		expectedErrors: []string{
 			`module "libother" variant "android_common": depends on //top:libexample which is not` +
-				` visible to this module; //top:libexample is only visible to` +
-				` \[//top/nested:__subpackages__, //other:__pkg__\]`,
+				` visible to this module`,
 		},
 	},
 	{
@@ -399,11 +371,295 @@
 				}`),
 		},
 		expectedErrors: []string{
-			`module "libsamepackage" variant "android_common": visibility: "//vendor/apps/AcmeSettings"` +
+			`module "libsamepackage": visibility: "//vendor/apps/AcmeSettings"` +
 				` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
 				` targets within //vendor, they can only use //vendor:__subpackages__.`,
 		},
 	},
+
+	// Defaults propagation tests
+	{
+		// Check that visibility is the union of the defaults modules.
+		name: "defaults union, basic",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//other"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//top/nested"],
+					defaults: ["libexample_defaults"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "defaults union, multiple defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//other"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//top/nested"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "//visibility:public mixed with other in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:public", "//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample_defaults": visibility: cannot mix "//visibility:public"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:public overriding defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:public"],
+					defaults: ["libexample_defaults"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:public mixed with other from different defaults 1",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//namespace"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//visibility:public"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:public mixed with other from different defaults 2",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//visibility:public"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+	},
+	{
+		name: "//visibility:private in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}
+				mock_library {
+					name: "libsamepackage",
+					deps: ["libexample"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libnested" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+			`module "libother" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "//visibility:private mixed with other in defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private", "//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample_defaults": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private overriding defaults",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//namespace"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private in defaults overridden",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//namespace"],
+					defaults: ["libexample_defaults"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "libexample": visibility: cannot mix "//visibility:private"` +
+				` with any other visibility rules`,
+		},
+	},
+	{
+		name: "//visibility:private mixed with itself",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "libexample_defaults_1",
+					visibility: ["//visibility:private"],
+				}
+				mock_defaults {
+					name: "libexample_defaults_2",
+					visibility: ["//visibility:private"],
+				}
+				mock_library {
+					name: "libexample",
+					visibility: ["//visibility:private"],
+					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -445,7 +701,10 @@
 
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("mock_library", ModuleFactoryAdaptor(newMockLibraryModule))
-	ctx.PreDepsMutators(registerVisibilityRuleGatherer)
+	ctx.RegisterModuleType("mock_defaults", ModuleFactoryAdaptor(defaultsFactory))
+	ctx.PreArchMutators(registerVisibilityRuleChecker)
+	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(registerVisibilityRuleGatherer)
 	ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
 	ctx.Register()
 
@@ -466,6 +725,7 @@
 
 type mockLibraryModule struct {
 	ModuleBase
+	DefaultableModuleBase
 	properties mockLibraryProperties
 }
 
@@ -473,6 +733,7 @@
 	m := &mockLibraryModule{}
 	m.AddProperties(&m.properties)
 	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	InitDefaultableModule(m)
 	return m
 }
 
@@ -487,3 +748,17 @@
 
 func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
+
+type mockDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func defaultsFactory() Module {
+	m := &mockDefaults{}
+	InitDefaultsModule(m)
+	return m
+}
+
+func (*mockDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 1e0f862..e11e33a 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -95,14 +95,14 @@
 // Tools contains paths to tools possibly used by the generated commands.  If you add a new tool here you MUST add it
 // to the order-only dependency list in DEXPREOPT_GEN_DEPS.
 type Tools struct {
-	Profman  android.Path
-	Dex2oat  android.Path
-	Aapt     android.Path
-	SoongZip android.Path
-	Zip2zip  android.Path
+	Profman       android.Path
+	Dex2oat       android.Path
+	Aapt          android.Path
+	SoongZip      android.Path
+	Zip2zip       android.Path
+	ManifestCheck android.Path
 
-	VerifyUsesLibraries android.Path
-	ConstructContext    android.Path
+	ConstructContext android.Path
 }
 
 type ModuleConfig struct {
@@ -110,6 +110,7 @@
 	DexLocation     string // dex location on device
 	BuildPath       android.OutputPath
 	DexPath         android.Path
+	ManifestPath    android.Path
 	UncompressedDex bool
 	HasApkLibraries bool
 	PreoptFlags     []string
@@ -187,14 +188,14 @@
 		BootImageProfiles []string
 
 		Tools struct {
-			Profman  string
-			Dex2oat  string
-			Aapt     string
-			SoongZip string
-			Zip2zip  string
+			Profman       string
+			Dex2oat       string
+			Aapt          string
+			SoongZip      string
+			Zip2zip       string
+			ManifestCheck string
 
-			VerifyUsesLibraries string
-			ConstructContext    string
+			ConstructContext string
 		}
 	}
 
@@ -214,7 +215,7 @@
 	config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt)
 	config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip)
 	config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip)
-	config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries)
+	config.GlobalConfig.Tools.ManifestCheck = constructPath(ctx, config.Tools.ManifestCheck)
 	config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext)
 
 	return config.GlobalConfig, data, nil
@@ -231,6 +232,7 @@
 		// used to construct the real value manually below.
 		BuildPath                   string
 		DexPath                     string
+		ManifestPath                string
 		ProfileClassListing         string
 		LibraryPaths                map[string]string
 		DexPreoptImages             []string
@@ -249,6 +251,7 @@
 	// Construct paths that require a PathContext.
 	config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath)
 	config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
+	config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
 	config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
 	config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
 	config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
@@ -324,13 +327,13 @@
 		Dex2oatImageXmx:                    "",
 		Dex2oatImageXms:                    "",
 		Tools: Tools{
-			Profman:             android.PathForTesting("profman"),
-			Dex2oat:             android.PathForTesting("dex2oat"),
-			Aapt:                android.PathForTesting("aapt"),
-			SoongZip:            android.PathForTesting("soong_zip"),
-			Zip2zip:             android.PathForTesting("zip2zip"),
-			VerifyUsesLibraries: android.PathForTesting("verify_uses_libraries.sh"),
-			ConstructContext:    android.PathForTesting("construct_context.sh"),
+			Profman:          android.PathForTesting("profman"),
+			Dex2oat:          android.PathForTesting("dex2oat"),
+			Aapt:             android.PathForTesting("aapt"),
+			SoongZip:         android.PathForTesting("soong_zip"),
+			Zip2zip:          android.PathForTesting("zip2zip"),
+			ManifestCheck:    android.PathForTesting("manifest_check"),
+			ConstructContext: android.PathForTesting("construct_context.sh"),
 		},
 	}
 }
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 5b658d9..2d521da 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -226,10 +226,6 @@
 		bootImageLocation = PathToLocation(bootImage, arch)
 	}
 
-	// Lists of used and optional libraries from the build config to be verified against the manifest in the APK
-	var verifyUsesLibs []string
-	var verifyOptionalUsesLibs []string
-
 	// Lists of used and optional libraries from the build config, with optional libraries that are known to not
 	// be present in the current product removed.
 	var filteredUsesLibs []string
@@ -252,9 +248,6 @@
 	var classLoaderContextHostString string
 
 	if module.EnforceUsesLibraries {
-		verifyUsesLibs = copyOf(module.UsesLibraries)
-		verifyOptionalUsesLibs = copyOf(module.OptionalUsesLibraries)
-
 		filteredOptionalUsesLibs = filterOut(global.MissingUsesLibraries, module.OptionalUsesLibraries)
 		filteredUsesLibs = append(copyOf(module.UsesLibraries), filteredOptionalUsesLibs...)
 
@@ -270,11 +263,11 @@
 		const httpLegacy = "org.apache.http.legacy"
 		const httpLegacyImpl = "org.apache.http.legacy.impl"
 
-		// Fix up org.apache.http.legacy.impl since it should be org.apache.http.legacy in the manifest.
-		replace(verifyUsesLibs, httpLegacyImpl, httpLegacy)
-		replace(verifyOptionalUsesLibs, httpLegacyImpl, httpLegacy)
-
-		if !contains(verifyUsesLibs, httpLegacy) && !contains(verifyOptionalUsesLibs, httpLegacy) {
+		// org.apache.http.legacy contains classes that were in the default classpath until API 28.  If the
+		// targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly depend on
+		// org.apache.http.legacy, then implicitly add the classes to the classpath for dexpreopt.  One the
+		// device the classes will be in a file called org.apache.http.legacy.impl.jar.
+		if !contains(module.UsesLibraries, httpLegacy) && !contains(module.OptionalUsesLibraries, httpLegacy) {
 			conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
 				pathForLibrary(module, httpLegacyImpl))
 			conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
@@ -284,6 +277,9 @@
 		const hidlBase = "android.hidl.base-V1.0-java"
 		const hidlManager = "android.hidl.manager-V1.0-java"
 
+		// android.hidl.base-V1.0-java and android.hidl.manager-V1.0 contain classes that were in the default
+		// classpath until API 29.  If the targetSdkVersion in the manifest or APK is < 29 then implicitly add
+		// the classes to the classpath for dexpreopt.
 		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
 			pathForLibrary(module, hidlManager))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
@@ -309,9 +305,21 @@
 	rule.Command().Text(`stored_class_loader_context_arg=""`)
 
 	if module.EnforceUsesLibraries {
-		rule.Command().Textf(`uses_library_names="%s"`, strings.Join(verifyUsesLibs, " "))
-		rule.Command().Textf(`optional_uses_library_names="%s"`, strings.Join(verifyOptionalUsesLibs, " "))
-		rule.Command().Textf(`aapt_binary="%s"`, global.Tools.Aapt)
+		if module.ManifestPath != nil {
+			rule.Command().Text(`target_sdk_version="$(`).
+				Tool(global.Tools.ManifestCheck).
+				Flag("--extract-target-sdk-version").
+				Input(module.ManifestPath).
+				Text(`)"`)
+		} else {
+			// No manifest to extract targetSdkVersion from, hope that DexJar is an APK
+			rule.Command().Text(`target_sdk_version="$(`).
+				Tool(global.Tools.Aapt).
+				Flag("dump badging").
+				Input(module.DexPath).
+				Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
+				Text(`)"`)
+		}
 		rule.Command().Textf(`dex_preopt_host_libraries="%s"`,
 			strings.Join(classLoaderContextHost.Strings(), " ")).
 			Implicits(classLoaderContextHost)
@@ -327,8 +335,7 @@
 			Implicits(conditionalClassLoaderContextHost29)
 		rule.Command().Textf(`conditional_target_libs_29="%s"`,
 			strings.Join(conditionalClassLoaderContextTarget29, " "))
-		rule.Command().Text("source").Tool(global.Tools.VerifyUsesLibraries).Input(module.DexPath)
-		rule.Command().Text("source").Tool(global.Tools.ConstructContext)
+		rule.Command().Text("source").Tool(global.Tools.ConstructContext).Input(module.DexPath)
 	}
 
 	// Devices that do not have a product partition use a symlink from /product to /system/product.
diff --git a/java/config/config.go b/java/config/config.go
index 28c8995..529f1e6 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -144,7 +144,8 @@
 
 	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
 
-	pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
+	pctx.HostBinToolVariable("ManifestCheckCmd", "manifest_check")
+	pctx.HostBinToolVariable("ManifestFixerCmd", "manifest_fixer")
 
 	pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
 
diff --git a/java/config/makevars.go b/java/config/makevars.go
index fc90b36..ead298a 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -73,6 +73,7 @@
 
 	ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
 
+	ctx.Strict("MANIFEST_CHECK", "${ManifestCheckCmd}")
 	ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
 
 	ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}")
diff --git a/java/droiddoc.go b/java/droiddoc.go
index b881538..b41825e 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -211,6 +211,7 @@
 	// Available variables for substitution:
 	//
 	//  $(location <label>): the path to the arg_files with name <label>
+	//  $$: a literal $
 	Args *string
 
 	// names of the output files used in args that will be generated
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 9627dc6..b1ddab4 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -61,7 +61,7 @@
 	stubFlagsRule(ctx)
 
 	// These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
-	if ctx.Config().FrameworksBaseDirExists(ctx) {
+	if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().UnbundledBuild() {
 		h.flags = flagsRule(ctx)
 		h.metadata = metadataRule(ctx)
 	} else {
diff --git a/java/java.go b/java/java.go
index 4483083..8dbdfb6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1301,9 +1301,11 @@
 			return
 		}
 
-		// Hidden API CSV generation and dex encoding
-		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
-			j.deviceProperties.UncompressDex)
+		if !ctx.Config().UnbundledBuild() {
+			// Hidden API CSV generation and dex encoding
+			dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+				j.deviceProperties.UncompressDex)
+		}
 
 		// merge dex jar with resources if necessary
 		if j.resourceJar != nil {
diff --git a/java/system_modules.go b/java/system_modules.go
index 9ee0307..8005360 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -87,11 +87,13 @@
 	module := &SystemModules{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
 	return module
 }
 
 type SystemModules struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties SystemModulesProperties
 
diff --git a/scripts/Android.bp b/scripts/Android.bp
new file mode 100644
index 0000000..31f5922
--- /dev/null
+++ b/scripts/Android.bp
@@ -0,0 +1,71 @@
+python_binary_host {
+    name: "manifest_fixer",
+    main: "manifest_fixer.py",
+    srcs: [
+        "manifest_fixer.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+python_test_host {
+    name: "manifest_fixer_test",
+    main: "manifest_fixer_test.py",
+    srcs: [
+        "manifest_fixer_test.py",
+        "manifest_fixer.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
+
+python_binary_host {
+    name: "manifest_check",
+    main: "manifest_check.py",
+    srcs: [
+        "manifest_check.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+python_test_host {
+    name: "manifest_check_test",
+    main: "manifest_check_test.py",
+    srcs: [
+        "manifest_check_test.py",
+        "manifest_check.py",
+        "manifest.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
diff --git a/scripts/TEST_MAPPING b/scripts/TEST_MAPPING
new file mode 100644
index 0000000..1b0a229
--- /dev/null
+++ b/scripts/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit" : [
+    {
+      "name": "manifest_check_test",
+      "host": true
+    },
+    {
+      "name": "manifest_fixer_test",
+      "host": true
+    }    
+  ]
+}
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index bdd4b2a..8021e55 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -65,11 +65,6 @@
 		warnings: []string{"overriding commands for target"},
 	},
 	{
-		name:     "BUILD_BROKEN_ANDROIDMK_EXPORTS",
-		behavior: DefaultDeprecated,
-		warnings: []string{"export_keyword"},
-	},
-	{
 		name:     "BUILD_BROKEN_USES_NETWORK",
 		behavior: DefaultDeprecated,
 	},
diff --git a/scripts/manifest.py b/scripts/manifest.py
new file mode 100755
index 0000000..4c75f8b
--- /dev/null
+++ b/scripts/manifest.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+"""A tool for inserting values from the build system into a manifest."""
+
+from __future__ import print_function
+from xml.dom import minidom
+
+
+android_ns = 'http://schemas.android.com/apk/res/android'
+
+
+def get_children_with_tag(parent, tag_name):
+  children = []
+  for child in  parent.childNodes:
+    if child.nodeType == minidom.Node.ELEMENT_NODE and \
+       child.tagName == tag_name:
+      children.append(child)
+  return children
+
+
+def find_child_with_attribute(element, tag_name, namespace_uri,
+                              attr_name, value):
+  for child in get_children_with_tag(element, tag_name):
+    attr = child.getAttributeNodeNS(namespace_uri, attr_name)
+    if attr is not None and attr.value == value:
+      return child
+  return None
+
+
+def parse_manifest(doc):
+  """Get the manifest element."""
+
+  manifest = doc.documentElement
+  if manifest.tagName != 'manifest':
+    raise RuntimeError('expected manifest tag at root')
+  return manifest
+
+
+def ensure_manifest_android_ns(doc):
+  """Make sure the manifest tag defines the android namespace."""
+
+  manifest = parse_manifest(doc)
+
+  ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
+  if ns is None:
+    attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
+    attr.value = android_ns
+    manifest.setAttributeNode(attr)
+  elif ns.value != android_ns:
+    raise RuntimeError('manifest tag has incorrect android namespace ' +
+                       ns.value)
+
+
+def as_int(s):
+  try:
+    i = int(s)
+  except ValueError:
+    return s, False
+  return i, True
+
+
+def compare_version_gt(a, b):
+  """Compare two SDK versions.
+
+  Compares a and b, treating codenames like 'Q' as higher
+  than numerical versions like '28'.
+
+  Returns True if a > b
+
+  Args:
+    a: value to compare
+    b: value to compare
+  Returns:
+    True if a is a higher version than b
+  """
+
+  a, a_is_int = as_int(a.upper())
+  b, b_is_int = as_int(b.upper())
+
+  if a_is_int == b_is_int:
+    # Both are codenames or both are versions, compare directly
+    return a > b
+  else:
+    # One is a codename, the other is not.  Return true if
+    # b is an integer version
+    return b_is_int
+
+
+def get_indent(element, default_level):
+  indent = ''
+  if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
+    text = element.nodeValue
+    indent = text[:len(text)-len(text.lstrip())]
+  if not indent or indent == '\n':
+    # 1 indent = 4 space
+    indent = '\n' + (' ' * default_level * 4)
+  return indent
+
+
+def write_xml(f, doc):
+  f.write('<?xml version="1.0" encoding="utf-8"?>\n')
+  for node in doc.childNodes:
+    f.write(node.toxml(encoding='utf-8') + '\n')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
new file mode 100755
index 0000000..9122da1
--- /dev/null
+++ b/scripts/manifest_check.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+"""A tool for checking that a manifest agrees with the build system."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+from xml.dom import minidom
+
+
+from manifest import android_ns
+from manifest import get_children_with_tag
+from manifest import parse_manifest
+from manifest import write_xml
+
+
+class ManifestMismatchError(Exception):
+  pass
+
+
+def parse_args():
+  """Parse commandline arguments."""
+
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--uses-library', dest='uses_libraries',
+                      action='append',
+                      help='specify uses-library entries known to the build system')
+  parser.add_argument('--optional-uses-library',
+                      dest='optional_uses_libraries',
+                      action='append',
+                      help='specify uses-library entries known to the build system with required:false')
+  parser.add_argument('--enforce-uses-libraries',
+                      dest='enforce_uses_libraries',
+                      action='store_true',
+                      help='check the uses-library entries known to the build system against the manifest')
+  parser.add_argument('--extract-target-sdk-version',
+                      dest='extract_target_sdk_version',
+                      action='store_true',
+                      help='print the targetSdkVersion from the manifest')
+  parser.add_argument('--output', '-o', dest='output', help='output AndroidManifest.xml file')
+  parser.add_argument('input', help='input AndroidManifest.xml file')
+  return parser.parse_args()
+
+
+def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries):
+  """Verify that the <uses-library> tags in the manifest match those provided by the build system.
+
+  Args:
+    doc: The XML document.
+    uses_libraries: The names of <uses-library> tags known to the build system
+    optional_uses_libraries: The names of <uses-library> tags with required:fals
+      known to the build system
+  Raises:
+    RuntimeError: Invalid manifest
+    ManifestMismatchError: Manifest does not match
+  """
+
+  manifest = parse_manifest(doc)
+  elems = get_children_with_tag(manifest, 'application')
+  application = elems[0] if len(elems) == 1 else None
+  if len(elems) > 1:
+    raise RuntimeError('found multiple <application> tags')
+  elif not elems:
+    if uses_libraries or optional_uses_libraries:
+      raise ManifestMismatchError('no <application> tag found')
+    return
+
+  verify_uses_library(application, uses_libraries, optional_uses_libraries)
+
+
+def verify_uses_library(application, uses_libraries, optional_uses_libraries):
+  """Verify that the uses-library values known to the build system match the manifest.
+
+  Args:
+    application: the <application> tag in the manifest.
+    uses_libraries: the names of expected <uses-library> tags.
+    optional_uses_libraries: the names of expected <uses-library> tags with required="false".
+  Raises:
+    ManifestMismatchError: Manifest does not match
+  """
+
+  if uses_libraries is None:
+    uses_libraries = []
+
+  if optional_uses_libraries is None:
+    optional_uses_libraries = []
+
+  manifest_uses_libraries, manifest_optional_uses_libraries = parse_uses_library(application)
+
+  err = []
+  if manifest_uses_libraries != uses_libraries:
+    err.append('Expected required <uses-library> tags "%s", got "%s"' %
+               (', '.join(uses_libraries), ', '.join(manifest_uses_libraries)))
+
+  if manifest_optional_uses_libraries != optional_uses_libraries:
+    err.append('Expected optional <uses-library> tags "%s", got "%s"' %
+               (', '.join(optional_uses_libraries), ', '.join(manifest_optional_uses_libraries)))
+
+  if err:
+    raise ManifestMismatchError('\n'.join(err))
+
+
+def parse_uses_library(application):
+  """Extract uses-library tags from the manifest.
+
+  Args:
+    application: the <application> tag in the manifest.
+  """
+
+  libs = get_children_with_tag(application, 'uses-library')
+
+  uses_libraries = [uses_library_name(x) for x in libs if uses_library_required(x)]
+  optional_uses_libraries = [uses_library_name(x) for x in libs if not uses_library_required(x)]
+
+  return first_unique_elements(uses_libraries), first_unique_elements(optional_uses_libraries)
+
+
+def first_unique_elements(l):
+  result = []
+  [result.append(x) for x in l if x not in result]
+  return result
+
+
+def uses_library_name(lib):
+  """Extract the name attribute of a uses-library tag.
+
+  Args:
+    lib: a <uses-library> tag.
+  """
+  name = lib.getAttributeNodeNS(android_ns, 'name')
+  return name.value if name is not None else ""
+
+
+def uses_library_required(lib):
+  """Extract the required attribute of a uses-library tag.
+
+  Args:
+    lib: a <uses-library> tag.
+  """
+  required = lib.getAttributeNodeNS(android_ns, 'required')
+  return (required.value == 'true') if required is not None else True
+
+
+def extract_target_sdk_version(doc):
+  """Returns the targetSdkVersion from the manifest.
+
+  Args:
+    doc: The XML document.
+  Raises:
+    RuntimeError: invalid manifest
+  """
+
+  manifest = parse_manifest(doc)
+
+  # Get or insert the uses-sdk element
+  uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
+  if len(uses_sdk) > 1:
+    raise RuntimeError('found multiple uses-sdk elements')
+  elif len(uses_sdk) == 0:
+    raise RuntimeError('missing uses-sdk element')
+
+  uses_sdk = uses_sdk[0]
+
+  min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
+  if min_attr is None:
+    raise RuntimeError('minSdkVersion is not specified')
+
+  target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
+  if target_attr is None:
+    target_attr = min_attr
+
+  return target_attr.value
+
+
+def main():
+  """Program entry point."""
+  try:
+    args = parse_args()
+
+    doc = minidom.parse(args.input)
+
+    if args.enforce_uses_libraries:
+      enforce_uses_libraries(doc,
+                             args.uses_libraries,
+                             args.optional_uses_libraries)
+
+    if args.extract_target_sdk_version:
+      print(extract_target_sdk_version(doc))
+
+    if args.output:
+      with open(args.output, 'wb') as f:
+        write_xml(f, doc)
+
+  # pylint: disable=broad-except
+  except Exception as err:
+    print('error: ' + str(err), file=sys.stderr)
+    sys.exit(-1)
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
new file mode 100755
index 0000000..7baad5d
--- /dev/null
+++ b/scripts/manifest_check_test.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+"""Unit tests for manifest_fixer.py."""
+
+import sys
+import unittest
+from xml.dom import minidom
+
+import manifest_check
+
+sys.dont_write_bytecode = True
+
+
+def uses_library(name, attr=''):
+  return '<uses-library android:name="%s"%s />' % (name, attr)
+
+
+def required(value):
+  return ' android:required="%s"' % ('true' if value else 'false')
+
+
+class EnforceUsesLibrariesTest(unittest.TestCase):
+  """Unit tests for add_extract_native_libs function."""
+
+  def run_test(self, input_manifest, uses_libraries=None, optional_uses_libraries=None):
+    doc = minidom.parseString(input_manifest)
+    try:
+      manifest_check.enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries)
+      return True
+    except manifest_check.ManifestMismatchError:
+      return False
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <application>\n'
+      '    %s\n'
+      '    </application>\n'
+      '</manifest>\n')
+
+  def test_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_uses_library_required(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(True)))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_expected_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_expected_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_missing_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('')
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_missing_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('')
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertFalse(matches)
+
+  def test_extra_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo'))
+    matches = self.run_test(manifest_input)
+    self.assertFalse(matches)
+
+  def test_extra_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+    matches = self.run_test(manifest_input)
+    self.assertFalse(matches)
+
+  def test_multiple_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar')]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo', 'bar'])
+    self.assertTrue(matches)
+
+  def test_multiple_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo', 'bar'])
+    self.assertTrue(matches)
+
+  def test_order_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar')]))
+    matches = self.run_test(manifest_input, uses_libraries=['bar', 'foo'])
+    self.assertFalse(matches)
+
+  def test_order_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['bar', 'foo'])
+    self.assertFalse(matches)
+
+  def test_duplicate_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('foo')]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_duplicate_optional_uses_library(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+                                                      uses_library('foo', required(False))]))
+    matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+    self.assertTrue(matches)
+
+  def test_mixed(self):
+    manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+                                                      uses_library('bar', required(False))]))
+    matches = self.run_test(manifest_input, uses_libraries=['foo'],
+                            optional_uses_libraries=['bar'])
+    self.assertTrue(matches)
+
+
+class ExtractTargetSdkVersionTest(unittest.TestCase):
+  def test_target_sdk_version(self):
+    manifest = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" />\n'
+      '</manifest>\n')
+    doc = minidom.parseString(manifest)
+    target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+    self.assertEqual(target_sdk_version, '29')
+
+  def test_min_sdk_version(self):
+    manifest = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <uses-sdk android:minSdkVersion="28" />\n'
+      '</manifest>\n')
+    doc = minidom.parseString(manifest)
+    target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+    self.assertEqual(target_sdk_version, '28')
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 83868e6..bb14851 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -17,30 +17,20 @@
 """A tool for inserting values from the build system into a manifest."""
 
 from __future__ import print_function
+
 import argparse
 import sys
 from xml.dom import minidom
 
 
-android_ns = 'http://schemas.android.com/apk/res/android'
-
-
-def get_children_with_tag(parent, tag_name):
-  children = []
-  for child in  parent.childNodes:
-    if child.nodeType == minidom.Node.ELEMENT_NODE and \
-       child.tagName == tag_name:
-      children.append(child)
-  return children
-
-
-def find_child_with_attribute(element, tag_name, namespace_uri,
-                              attr_name, value):
-  for child in get_children_with_tag(element, tag_name):
-    attr = child.getAttributeNodeNS(namespace_uri, attr_name)
-    if attr is not None and attr.value == value:
-      return child
-  return None
+from manifest import android_ns
+from manifest import compare_version_gt
+from manifest import ensure_manifest_android_ns
+from manifest import find_child_with_attribute
+from manifest import get_children_with_tag
+from manifest import get_indent
+from manifest import parse_manifest
+from manifest import write_xml
 
 
 def parse_args():
@@ -74,76 +64,6 @@
   return parser.parse_args()
 
 
-def parse_manifest(doc):
-  """Get the manifest element."""
-
-  manifest = doc.documentElement
-  if manifest.tagName != 'manifest':
-    raise RuntimeError('expected manifest tag at root')
-  return manifest
-
-
-def ensure_manifest_android_ns(doc):
-  """Make sure the manifest tag defines the android namespace."""
-
-  manifest = parse_manifest(doc)
-
-  ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
-  if ns is None:
-    attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
-    attr.value = android_ns
-    manifest.setAttributeNode(attr)
-  elif ns.value != android_ns:
-    raise RuntimeError('manifest tag has incorrect android namespace ' +
-                       ns.value)
-
-
-def as_int(s):
-  try:
-    i = int(s)
-  except ValueError:
-    return s, False
-  return i, True
-
-
-def compare_version_gt(a, b):
-  """Compare two SDK versions.
-
-  Compares a and b, treating codenames like 'Q' as higher
-  than numerical versions like '28'.
-
-  Returns True if a > b
-
-  Args:
-    a: value to compare
-    b: value to compare
-  Returns:
-    True if a is a higher version than b
-  """
-
-  a, a_is_int = as_int(a.upper())
-  b, b_is_int = as_int(b.upper())
-
-  if a_is_int == b_is_int:
-    # Both are codenames or both are versions, compare directly
-    return a > b
-  else:
-    # One is a codename, the other is not.  Return true if
-    # b is an integer version
-    return b_is_int
-
-
-def get_indent(element, default_level):
-  indent = ''
-  if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
-    text = element.nodeValue
-    indent = text[:len(text)-len(text.lstrip())]
-  if not indent or indent == '\n':
-    # 1 indent = 4 space
-    indent = '\n' + (' ' * default_level * 4)
-  return indent
-
-
 def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library):
   """Ensure the manifest contains a <uses-sdk> tag with a minSdkVersion.
 
@@ -151,6 +71,7 @@
     doc: The XML document.  May be modified by this function.
     min_sdk_version: The requested minSdkVersion attribute.
     target_sdk_version: The requested targetSdkVersion attribute.
+    library: True if the manifest is for a library.
   Raises:
     RuntimeError: invalid manifest
   """
@@ -249,6 +170,7 @@
     indent = get_indent(application.previousSibling, 1)
     application.appendChild(doc.createTextNode(indent))
 
+
 def add_uses_non_sdk_api(doc):
   """Add android:usesNonSdkApi=true attribute to <application>.
 
@@ -323,12 +245,6 @@
                        (attr.value, value))
 
 
-def write_xml(f, doc):
-  f.write('<?xml version="1.0" encoding="utf-8"?>\n')
-  for node in doc.childNodes:
-    f.write(node.toxml(encoding='utf-8') + '\n')
-
-
 def main():
   """Program entry point."""
   try:
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 7ec8999..2035421 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-"""Unit tests for manifest_fixer_test.py."""
+"""Unit tests for manifest_fixer.py."""
 
 import StringIO
 import sys
@@ -393,10 +393,10 @@
     return output.getvalue()
 
   manifest_tmpl = (
-    '<?xml version="1.0" encoding="utf-8"?>\n'
-    '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
-    '    <application%s/>\n'
-    '</manifest>\n')
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '    <application%s/>\n'
+      '</manifest>\n')
 
   def extract_native_libs(self, value):
     return ' android:extractNativeLibs="%s"' % value
@@ -425,4 +425,4 @@
 
 
 if __name__ == '__main__':
-  unittest.main()
+  unittest.main(verbosity=2)
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 9fd6f67..4335667 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -205,7 +205,6 @@
 
 		// Not used, but useful to be in the soong.log
 		"BOARD_VNDK_VERSION",
-		"BUILD_BROKEN_ANDROIDMK_EXPORTS",
 
 		"DEFAULT_WARNING_BUILD_MODULE_TYPES",
 		"DEFAULT_ERROR_BUILD_MODULE_TYPES",