Merge "Revert "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/config.go b/android/config.go
index 1507c25..b0d8b7f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1103,6 +1103,10 @@
return Bool(c.productVariables.ProductCompatibleProperty)
}
+func (c *config) MissingUsesLibraries() []string {
+ return c.productVariables.MissingUsesLibraries
+}
+
func (c *deviceConfig) BoardVndkRuntimeDisable() bool {
return Bool(c.config.productVariables.BoardVndkRuntimeDisable)
}
diff --git a/android/module.go b/android/module.go
index 3906fd7..1c36279 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1740,4 +1740,5 @@
Jars []string `json:"jars,omitempty"`
Classes []string `json:"class,omitempty"`
Installed_paths []string `json:"installed,omitempty"`
+ SrcJars []string `json:"srcjars,omitempty"`
}
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/variable.go b/android/variable.go
index ff3ebaf..d039a16 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -306,6 +306,8 @@
ProductCompatibleProperty *bool `json:",omitempty"`
TargetFSConfigGen []string `json:",omitempty"`
+
+ MissingUsesLibraries []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
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/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index cb71725..24057af 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -529,7 +529,7 @@
ctx.file.errorf(ctx.mkvalue, "unsupported sanitize expression")
case *bpparser.String:
switch v.Value {
- case "never", "address", "coverage", "thread", "undefined", "cfi":
+ case "never", "address", "fuzzer", "thread", "undefined", "cfi":
bpTrue := &bpparser.Bool{
Value: true,
}
diff --git a/cc/cc.go b/cc/cc.go
index 4600a15..09496fc 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -52,6 +52,9 @@
ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
+ ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(fuzzer))
+ ctx.BottomUp("fuzzer", sanitizerMutator(fuzzer)).Parallel()
+
ctx.TopDown("cfi_deps", sanitizerDepsMutator(cfi))
ctx.BottomUp("cfi", sanitizerMutator(cfi)).Parallel()
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 4486d2e..fdda7be 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -77,6 +77,7 @@
intOverflow
cfi
scs
+ fuzzer
)
// Name of the sanitizer variation for this sanitizer type
@@ -94,6 +95,8 @@
return "cfi"
case scs:
return "scs"
+ case fuzzer:
+ return "fuzzer"
default:
panic(fmt.Errorf("unknown sanitizerType %d", t))
}
@@ -114,6 +117,8 @@
return "cfi"
case scs:
return "shadow-call-stack"
+ case fuzzer:
+ return "fuzzer"
default:
panic(fmt.Errorf("unknown sanitizerType %d", t))
}
@@ -133,7 +138,7 @@
Undefined *bool `android:"arch_variant"`
All_undefined *bool `android:"arch_variant"`
Misc_undefined []string `android:"arch_variant"`
- Coverage *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
Safestack *bool `android:"arch_variant"`
Cfi *bool `android:"arch_variant"`
Integer_overflow *bool `android:"arch_variant"`
@@ -223,22 +228,16 @@
s.Undefined = boolPtr(true)
}
- if found, globalSanitizers = removeFromList("address", globalSanitizers); found {
- if s.Address == nil {
- s.Address = boolPtr(true)
- } else if *s.Address == false {
- // Coverage w/o address is an error. If globalSanitizers includes both, and the module
- // disables address, then disable coverage as well.
- _, globalSanitizers = removeFromList("coverage", globalSanitizers)
- }
+ if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
+ s.Address = boolPtr(true)
}
if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
s.Thread = boolPtr(true)
}
- if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found && s.Coverage == nil {
- s.Coverage = boolPtr(true)
+ if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
+ s.Fuzzer = boolPtr(true)
}
if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
@@ -346,7 +345,7 @@
if ctx.staticBinary() {
s.Address = nil
- s.Coverage = nil
+ s.Fuzzer = nil
s.Thread = nil
}
@@ -362,7 +361,7 @@
}
if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
- Bool(s.Coverage) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
+ Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs)) {
sanitize.Properties.SanitizerEnabled = true
}
@@ -377,10 +376,10 @@
s.Thread = nil
}
- if Bool(s.Coverage) {
- if !Bool(s.Address) {
- ctx.ModuleErrorf(`Use of "coverage" also requires "address"`)
- }
+ // TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
+ // mutually incompatible.
+ if Bool(s.Fuzzer) {
+ s.Cfi = nil
}
}
@@ -461,8 +460,13 @@
flags.CFlags = append(flags.CFlags, hwasanCflags...)
}
- if Bool(sanitize.Properties.Sanitize.Coverage) {
- flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp")
+ if Bool(sanitize.Properties.Sanitize.Fuzzer) {
+ flags.CFlags = append(flags.CFlags, "-fsanitize=fuzzer-no-link")
+ flags.LdFlags = append(flags.LdFlags, "-fsanitize=fuzzer-no-link")
+
+ // TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
+ _, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
+ flags.LdFlags = append(flags.LdFlags, "-fno-lto")
}
if Bool(sanitize.Properties.Sanitize.Cfi) {
@@ -497,20 +501,26 @@
flags.CFlags = append(flags.CFlags, sanitizeArg)
flags.AsFlags = append(flags.AsFlags, sanitizeArg)
if ctx.Host() {
- flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
- flags.LdFlags = append(flags.LdFlags, sanitizeArg)
// Host sanitizers only link symbols in the final executable, so
// there will always be undefined symbols in intermediate libraries.
_, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags)
+ flags.LdFlags = append(flags.LdFlags, sanitizeArg)
} else {
- flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
-
if enableMinimalRuntime(sanitize) {
flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " "))
flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
}
}
+
+ if Bool(sanitize.Properties.Sanitize.Fuzzer) {
+ // When fuzzing, we wish to crash with diagnostics on any bug.
+ flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
+ } else if ctx.Host() {
+ flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
+ } else {
+ flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
+ }
// http://b/119329758, Android core does not boot up with this sanitizer yet.
if toDisableImplicitIntegerChange(flags.CFlags) {
flags.CFlags = append(flags.CFlags, "-fno-sanitize=implicit-integer-sign-change")
@@ -573,6 +583,8 @@
return sanitize.Properties.Sanitize.Cfi
case scs:
return sanitize.Properties.Sanitize.Scs
+ case fuzzer:
+ return sanitize.Properties.Sanitize.Fuzzer
default:
panic(fmt.Errorf("unknown sanitizerType %d", t))
}
@@ -583,22 +595,21 @@
!sanitize.isSanitizerEnabled(hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
- !sanitize.isSanitizerEnabled(scs)
+ !sanitize.isSanitizerEnabled(scs) &&
+ !sanitize.isSanitizerEnabled(fuzzer)
}
func (sanitize *sanitize) isVariantOnProductionDevice() bool {
return !sanitize.isSanitizerEnabled(asan) &&
!sanitize.isSanitizerEnabled(hwasan) &&
- !sanitize.isSanitizerEnabled(tsan)
+ !sanitize.isSanitizerEnabled(tsan) &&
+ !sanitize.isSanitizerEnabled(fuzzer)
}
func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
switch t {
case asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
- if !b {
- sanitize.Properties.Sanitize.Coverage = nil
- }
case hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
case tsan:
@@ -609,6 +620,8 @@
sanitize.Properties.Sanitize.Cfi = boolPtr(b)
case scs:
sanitize.Properties.Sanitize.Scs = boolPtr(b)
+ case fuzzer:
+ sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
default:
panic(fmt.Errorf("unknown sanitizerType %d", t))
}
@@ -793,6 +806,10 @@
sanitizers = append(sanitizers, "shadow-call-stack")
}
+ if Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
+ sanitizers = append(sanitizers, "fuzzer-no-link")
+ }
+
// Save the list of sanitizers. These will be used again when generating
// the build rules (for Cflags, etc.)
c.sanitize.Properties.Sanitizers = sanitizers
@@ -931,6 +948,19 @@
modules[1].(*Module).Properties.HideFromMake = true
}
}
+ } else if t == fuzzer {
+ // TODO(b/131771163): CFI and fuzzer support are mutually incompatible
+ // as CFI pulls in LTO.
+ if mctx.Device() {
+ modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
+ }
+ 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 if t == hwasan {
if mctx.Device() {
// CFI and HWASAN are currently mutually exclusive so disable
@@ -996,6 +1026,7 @@
func enableMinimalRuntime(sanitize *sanitize) bool {
if !Bool(sanitize.Properties.Sanitize.Address) &&
!Bool(sanitize.Properties.Sanitize.Hwaddress) &&
+ !Bool(sanitize.Properties.Sanitize.Fuzzer) &&
(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
len(sanitize.Properties.Sanitize.Misc_undefined) > 0) &&
!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 1e0f862..5a1bd74 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -65,8 +65,6 @@
AlwaysOtherDebugInfo bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
NeverOtherDebugInfo bool // never generate mini debug info for non-system server modules (overrides NoDebugInfo=true)
- MissingUsesLibraries []string // libraries that may be listed in OptionalUsesLibraries but will not be installed by the product
-
IsEng bool // build is a eng variant
SanitizeLite bool // build is the second phase of a SANITIZE_LITE build
@@ -95,14 +93,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 +108,7 @@
DexLocation string // dex location on device
BuildPath android.OutputPath
DexPath android.Path
+ ManifestPath android.Path
UncompressedDex bool
HasApkLibraries bool
PreoptFlags []string
@@ -117,10 +116,10 @@
ProfileClassListing android.OptionalPath
ProfileIsTextListing bool
- EnforceUsesLibraries bool
- OptionalUsesLibraries []string
- UsesLibraries []string
- LibraryPaths map[string]android.Path
+ EnforceUsesLibraries bool
+ PresentOptionalUsesLibraries []string
+ UsesLibraries []string
+ LibraryPaths map[string]android.Path
Archs []android.ArchType
DexPreoptImages []android.Path
@@ -187,14 +186,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 +213,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 +230,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 +249,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)
@@ -307,7 +308,6 @@
NeverSystemServerDebugInfo: false,
AlwaysOtherDebugInfo: false,
NeverOtherDebugInfo: false,
- MissingUsesLibraries: nil,
IsEng: false,
SanitizeLite: false,
DefaultAppImages: false,
@@ -324,13 +324,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..0be37d0 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -226,15 +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
- var filteredOptionalUsesLibs []string
-
// The class loader context using paths in the build
var classLoaderContextHost android.Paths
@@ -252,14 +243,10 @@
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...)
+ usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
// Create class loader context for dex2oat from uses libraries and filtered optional libraries
- for _, l := range filteredUsesLibs {
+ for _, l := range usesLibs {
classLoaderContextHost = append(classLoaderContextHost,
pathForLibrary(module, l))
@@ -270,11 +257,13 @@
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)
+ // 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.
+ module.LibraryPaths[httpLegacyImpl] = module.LibraryPaths[httpLegacy]
- if !contains(verifyUsesLibs, httpLegacy) && !contains(verifyOptionalUsesLibs, httpLegacy) {
+ if !contains(module.UsesLibraries, httpLegacy) && !contains(module.PresentOptionalUsesLibraries, httpLegacy) {
conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
pathForLibrary(module, httpLegacyImpl))
conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
@@ -284,6 +273,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 +301,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 +331,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/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6dfa9d2..0402f87 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -33,7 +33,7 @@
ProfileClassListing: android.OptionalPath{},
ProfileIsTextListing: false,
EnforceUsesLibraries: false,
- OptionalUsesLibraries: nil,
+ PresentOptionalUsesLibraries: nil,
UsesLibraries: nil,
LibraryPaths: nil,
Archs: []android.ArchType{android.Arm},
diff --git a/java/app.go b/java/app.go
index f7f08a8..2d817fe 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,12 +17,13 @@
// This file contains the module types for compiling Android apps.
import (
- "github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
"path/filepath"
"reflect"
"strings"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc"
"android/soong/tradefed"
@@ -119,6 +120,8 @@
aapt
android.OverridableModuleBase
+ usesLibrary usesLibrary
+
certificate Certificate
appProperties appProperties
@@ -176,6 +179,8 @@
}
}
}
+
+ a.usesLibrary.deps(ctx, Bool(a.properties.No_framework_libs))
}
func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -276,6 +281,7 @@
aaptLinkFlags = append(aaptLinkFlags, a.additionalAaptFlags...)
a.aapt.splitNames = a.appProperties.Package_splits
+ a.aapt.sdkLibraries = a.exportedSdkLibs
a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
@@ -308,9 +314,17 @@
} else {
installDir = filepath.Join("app", a.installApkName)
}
+
a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
a.dexpreopter.isInstallable = Bool(a.properties.Installable)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+
+ a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+ a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
+ a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
+ a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+ a.dexpreopter.manifestFile = a.mergedManifestFile
+
a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex
if ctx.ModuleName() != "framework-res" {
@@ -368,12 +382,19 @@
}
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
+ var apkDeps android.Paths
+
// Check if the install APK name needs to be overridden.
a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
+ if a.usesLibrary.enforceUsesLibraries() {
+ manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
+ apkDeps = append(apkDeps, manifestCheckFile)
+ }
+
a.proguardBuildActions(ctx)
dexJarFile := a.dexBuildActions(ctx)
@@ -391,13 +412,13 @@
// Build a final signed app package.
// TODO(jungjw): Consider changing this to installApkName.
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
- CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates)
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
a.outputFile = packageFile
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
- CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates)
+ CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
}
@@ -483,7 +504,8 @@
&module.Module.protoProperties,
&module.aaptProperties,
&module.appProperties,
- &module.overridableAppProperties)
+ &module.overridableAppProperties,
+ &module.usesLibrary.usesLibraryProperties)
module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
return class == android.Device && ctx.Config().DevicePrefer32BitApps()
@@ -559,6 +581,7 @@
&module.appProperties,
&module.appTestProperties,
&module.overridableAppProperties,
+ &module.usesLibrary.usesLibraryProperties,
&module.testProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -599,7 +622,8 @@
&module.aaptProperties,
&module.appProperties,
&module.appTestHelperAppProperties,
- &module.overridableAppProperties)
+ &module.overridableAppProperties,
+ &module.usesLibrary.usesLibraryProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
@@ -666,6 +690,8 @@
certificate *Certificate
dexpreopter
+
+ usesLibrary usesLibrary
}
type AndroidAppImportProperties struct {
@@ -753,6 +779,8 @@
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
+
+ a.usesLibrary.deps(ctx, false)
}
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
@@ -808,7 +836,12 @@
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_PACKAGE_SPLITS
- srcApk := android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+ var srcApk android.Path
+ srcApk = android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx))
+
+ if a.usesLibrary.enforceUsesLibraries() {
+ srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+ }
// TODO: Install or embed JNI libraries
@@ -821,6 +854,12 @@
a.dexpreopter.isInstallable = true
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+
+ a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
+ a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
+ a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
+ a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+
dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
if a.dexpreopter.uncompressedDex {
dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
@@ -866,9 +905,129 @@
module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface()
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
+ module.AddProperties(&module.usesLibrary.usesLibraryProperties)
InitJavaModule(module, android.DeviceSupported)
android.InitSingleSourcePrebuiltModule(module, &module.properties.Apk)
return module
}
+
+type UsesLibraryProperties struct {
+ // A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
+ Uses_libs []string
+
+ // A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file with
+ // required=false.
+ Optional_uses_libs []string
+
+ // If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file. Defaults
+ // to true if either uses_libs or optional_uses_libs is set. Will unconditionally default to true in the future.
+ Enforce_uses_libs *bool
+}
+
+// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
+// <uses-library> tags that end up in the manifest of an APK match the ones known to the build system through the
+// uses_libs and optional_uses_libs properties. The build system's values are used by dexpreopt to preopt apps
+// with knowledge of their shared libraries.
+type usesLibrary struct {
+ usesLibraryProperties UsesLibraryProperties
+}
+
+func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, noFrameworkLibs bool) {
+ ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
+ ctx.AddVariationDependencies(nil, usesLibTag, u.presentOptionalUsesLibs(ctx)...)
+ if !noFrameworkLibs {
+ // dexpreopt/dexpreopt.go needs the paths to the dex jars of these libraries in case construct_context.sh needs
+ // to pass them to dex2oat. Add them as a dependency so we can determine the path to the dex jar of each
+ // library to dexpreopt.
+ ctx.AddVariationDependencies(nil, usesLibTag,
+ "org.apache.http.legacy",
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java")
+ }
+}
+
+// presentOptionalUsesLibs returns optional_uses_libs after filtering out MissingUsesLibraries, which don't exist in the
+// build.
+func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
+ optionalUsesLibs, _ := android.FilterList(u.usesLibraryProperties.Optional_uses_libs, ctx.Config().MissingUsesLibraries())
+ return optionalUsesLibs
+}
+
+// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars.
+func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path {
+ usesLibPaths := make(map[string]android.Path)
+
+ if !ctx.Config().UnbundledBuild() {
+ ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
+ if lib, ok := m.(Dependency); ok {
+ if dexJar := lib.DexJar(); dexJar != nil {
+ usesLibPaths[ctx.OtherModuleName(m)] = dexJar
+ } else {
+ ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?",
+ ctx.OtherModuleName(m))
+ }
+ } else if ctx.Config().AllowMissingDependencies() {
+ ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)})
+ } else {
+ ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library",
+ ctx.OtherModuleName(m))
+ }
+ })
+ }
+
+ return usesLibPaths
+}
+
+// enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs
+// properties. Defaults to true if either of uses_libs or optional_uses_libs is specified. Will default to true
+// unconditionally in the future.
+func (u *usesLibrary) enforceUsesLibraries() bool {
+ defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs) > 0 ||
+ len(u.usesLibraryProperties.Optional_uses_libs) > 0
+ return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
+}
+
+// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
+// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest.
+func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
+ outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
+
+ rule := android.NewRuleBuilder()
+ cmd := rule.Command().Tool(ctx.Config().HostToolPath(ctx, "manifest_check")).
+ Flag("--enforce-uses-libraries").
+ Input(manifest).
+ FlagWithOutput("-o ", outputFile)
+
+ for _, lib := range u.usesLibraryProperties.Uses_libs {
+ cmd.FlagWithArg("--uses-library ", lib)
+ }
+
+ for _, lib := range u.usesLibraryProperties.Optional_uses_libs {
+ cmd.FlagWithArg("--optional-uses-library ", lib)
+ }
+
+ rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+
+ return outputFile
+}
+
+// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the ones specified
+// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the APK.
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+ outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
+
+ rule := android.NewRuleBuilder()
+ aapt := ctx.Config().HostToolPath(ctx, "aapt")
+ rule.Command().
+ Textf("aapt_binary=%s", aapt.String()).Implicit(aapt).
+ Textf(`uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Uses_libs, " ")).
+ Textf(`optional_uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Optional_uses_libs, " ")).
+ Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk)
+ rule.Command().Text("cp -f").Input(apk).Output(outputFile)
+
+ rule.Build(pctx, ctx, "verify_uses_libraries", "verify <uses-library>")
+
+ return outputFile
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index 82a390f..fa77bbf 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -63,7 +63,7 @@
})
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
- packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate) {
+ packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -78,9 +78,10 @@
}
ctx.Build(pctx, android.BuildParams{
- Rule: combineApk,
- Inputs: inputs,
- Output: unsignedApk,
+ Rule: combineApk,
+ Inputs: inputs,
+ Output: unsignedApk,
+ Implicits: deps,
})
SignAppPackage(ctx, outputFile, unsignedApk, certificates)
diff --git a/java/app_test.go b/java/app_test.go
index 40a64af..559afcc 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1239,3 +1239,83 @@
})
}
}
+
+func TestUsesLibraries(t *testing.T) {
+ bp := `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ }
+
+ java_sdk_library {
+ name: "bar",
+ srcs: ["a.java"],
+ api_packages: ["bar"],
+ }
+
+ android_app {
+ name: "app",
+ srcs: ["a.java"],
+ uses_libs: ["foo"],
+ optional_uses_libs: [
+ "bar",
+ "baz",
+ ],
+ }
+
+ android_app_import {
+ name: "prebuilt",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ uses_libs: ["foo"],
+ optional_uses_libs: [
+ "bar",
+ "baz",
+ ],
+ }
+ `
+
+ config := testConfig(nil)
+ config.TestProductVariables.MissingUsesLibraries = []string{"baz"}
+
+ ctx := testAppContext(config, bp, nil)
+
+ run(t, ctx, config)
+
+ app := ctx.ModuleForTests("app", "android_common")
+ prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
+
+ // Test that all libraries are verified
+ cmd := app.Rule("verify_uses_libraries").RuleParams.Command
+ if w := "--uses-library foo"; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ if w := "--optional-uses-library bar --optional-uses-library baz"; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ cmd = prebuilt.Rule("verify_uses_libraries").RuleParams.Command
+
+ if w := `uses_library_names="foo"`; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ if w := `optional_uses_library_names="bar baz"`; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ // Test that only present libraries are preopted
+ cmd = app.Rule("dexpreopt").RuleParams.Command
+
+ if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+
+ if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+}
diff --git a/java/config/config.go b/java/config/config.go
index 46cd361..f9552d5 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -142,7 +142,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 6881caf..9c78511 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/dexpreopt.go b/java/dexpreopt.go
index 08fd06e..23d2aa6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -29,6 +29,12 @@
isInstallable bool
isPresignedPrebuilt bool
+ manifestFile android.Path
+ usesLibs []string
+ optionalUsesLibs []string
+ enforceUsesLibs bool
+ libraryPaths map[string]android.Path
+
builtInstalled string
}
@@ -154,6 +160,7 @@
DexLocation: dexLocation,
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
DexPath: dexJarFile,
+ ManifestPath: d.manifestFile,
UncompressedDex: d.uncompressedDex,
HasApkLibraries: false,
PreoptFlags: nil,
@@ -161,10 +168,10 @@
ProfileClassListing: profileClassListing,
ProfileIsTextListing: profileIsTextListing,
- EnforceUsesLibraries: false,
- OptionalUsesLibraries: nil,
- UsesLibraries: nil,
- LibraryPaths: nil,
+ EnforceUsesLibraries: d.enforceUsesLibs,
+ PresentOptionalUsesLibraries: d.optionalUsesLibs,
+ UsesLibraries: d.usesLibs,
+ LibraryPaths: d.libraryPaths,
Archs: archs,
DexPreoptImages: images,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index fd7e2a4..57da6b6 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..31c6afe 100644
--- a/java/java.go
+++ b/java/java.go
@@ -420,6 +420,7 @@
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
+ usesLibTag = dependencyTag{name: "uses-library"}
)
type sdkDep struct {
@@ -1301,9 +1302,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 {
@@ -1481,6 +1484,7 @@
func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
dpInfo.Srcs = append(dpInfo.Srcs, j.expandIDEInfoCompiledSrcs...)
+ dpInfo.SrcJars = append(dpInfo.SrcJars, j.compiledSrcJars.Strings()...)
dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
if j.expandJarjarRules != nil {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
diff --git a/java/java_test.go b/java/java_test.go
index 50b1c34..3a7ed4e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -174,6 +174,8 @@
"build/soong/scripts/jar-wrapper.sh": nil,
+ "build/make/core/verify_uses_libraries.sh": nil,
+
"build/make/core/proguard.flags": nil,
"build/make/core/proguard_basic_keeps.flags": nil,
diff --git a/java/jdeps.go b/java/jdeps.go
index 18498be..fccc40f 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -72,6 +72,7 @@
dpInfo.Aidl_include_dirs = android.FirstUniqueStrings(dpInfo.Aidl_include_dirs)
dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
+ dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
moduleInfos[name] = dpInfo
mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/robolectric.go b/java/robolectric.go
index 26f1e9d..b87ee0d 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -39,7 +39,7 @@
Test_options struct {
// Timeout in seconds when running the tests.
- Timeout *string
+ Timeout *int64
}
}
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/java/testing.go b/java/testing.go
index 22831c9..fc7842d 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -77,6 +77,33 @@
name: "framework-res",
no_framework_libs: true,
}
+
+ java_library {
+ name: "android.hidl.base-V1.0-java",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ installable: true,
+ }
+
+ java_library {
+ name: "android.hidl.manager-V1.0-java",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ installable: true,
+ }
+
+ java_library {
+ name: "org.apache.http.legacy",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ installable: true,
+ }
`
systemModules := []string{
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",