Merge "AIDEGen: Collect the srcjar into out/soong/module_bp_java_deps.json"
diff --git a/Android.bp b/Android.bp
index e2d606e..c9a48b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -196,6 +196,7 @@
"cc/gen_test.go",
"cc/genrule_test.go",
"cc/library_test.go",
+ "cc/prebuilt_test.go",
"cc/proto_test.go",
"cc/test_data_test.go",
"cc/util_test.go",
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/androidmk.go b/android/androidmk.go
index 2bbd452..7d0aa3b 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -28,10 +28,6 @@
"github.com/google/blueprint/bootstrap"
)
-var (
- NativeBridgeSuffix = ".native_bridge"
-)
-
func init() {
RegisterSingletonType("androidmk", AndroidMkSingleton)
}
@@ -165,10 +161,6 @@
}
}
- if amod.Target().NativeBridge {
- a.SubName += NativeBridgeSuffix
- }
-
fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
// Collect make variable assignment entries.
diff --git a/android/arch.go b/android/arch.go
index c68fe46..68fc149 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1505,10 +1505,10 @@
return false
}
-// hasArmArch returns true if targets has at least arm Android arch
+// hasArmArch returns true if targets has at least non-native_bridge arm Android arch
func hasArmAndroidArch(targets []Target) bool {
for _, target := range targets {
- if target.Os == Android && target.Arch.ArchType == Arm {
+ if target.Os == Android && target.Arch.ArchType == Arm && target.NativeBridge == NativeBridgeDisabled {
return true
}
}
diff --git a/android/config.go b/android/config.go
index b142042..b0d8b7f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -235,20 +235,14 @@
}
func TestArchConfigNativeBridge(buildDir string, env map[string]string) Config {
- testConfig := TestConfig(buildDir, env)
+ testConfig := TestArchConfig(buildDir, env)
config := testConfig.config
- config.Targets = map[OsType][]Target{
- Android: []Target{
- {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
- {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled},
- },
- BuildOs: []Target{
- {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled},
- {BuildOs, Arch{ArchType: X86}, NativeBridgeDisabled},
- },
+ config.Targets[Android] = []Target{
+ {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled},
+ {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled},
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled},
}
return testConfig
@@ -286,8 +280,16 @@
},
}
+ if runtime.GOOS == "darwin" {
+ config.Targets[BuildOs] = config.Targets[BuildOs][:1]
+ }
+
config.BuildOsVariant = config.Targets[BuildOs][0].String()
config.BuildOsCommonVariant = getCommonTargets(config.Targets[BuildOs])[0].String()
+ config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
+ config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
+ config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
+ config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
return testConfig
}
@@ -369,14 +371,14 @@
}
func (c *config) fromEnv() error {
- switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
- case "", "1.8":
- // Nothing, we always use OpenJDK9
+ switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
+ case "":
+ // Nothing, this is the default
case "true":
- // Use OpenJDK9 and target 1.9
+ // Use -source 9 -target 9
c.targetOpenJDK9 = true
default:
- return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
+ return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
}
return nil
@@ -1100,3 +1102,27 @@
func (c *config) ProductCompatibleProperty() bool {
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)
+}
+
+func (c *deviceConfig) DeviceArch() string {
+ return String(c.config.productVariables.DeviceArch)
+}
+
+func (c *deviceConfig) DeviceArchVariant() string {
+ return String(c.config.productVariables.DeviceArchVariant)
+}
+
+func (c *deviceConfig) DeviceSecondaryArch() string {
+ return String(c.config.productVariables.DeviceSecondaryArch)
+}
+
+func (c *deviceConfig) DeviceSecondaryArchVariant() string {
+ return String(c.config.productVariables.DeviceSecondaryArchVariant)
+}
diff --git a/android/module.go b/android/module.go
index bcefca0..1c36279 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1299,6 +1299,10 @@
a.commonProperties.Product_services_specific = boolPtr(false)
}
+func (a *ModuleBase) EnableNativeBridgeSupportByDefault() {
+ a.commonProperties.Native_bridge_supported = boolPtr(true)
+}
+
func (a *androidModuleContext) InstallInData() bool {
return a.module.InstallInData()
}
diff --git a/android/mutator.go b/android/mutator.go
index 45954d3..0e80249 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -76,8 +76,8 @@
registerLoadHookMutator,
RegisterNamespaceMutator,
RegisterPrebuiltsPreArchMutators,
+ registerVisibilityRuleChecker,
RegisterDefaultsPreArchMutators,
- RegisterOverridePreArchMutators,
registerVisibilityRuleGatherer,
}
@@ -95,6 +95,7 @@
RegisterPrebuiltsPostDepsMutators,
registerVisibilityRuleEnforcer,
registerNeverallowMutator,
+ RegisterOverridePostDepsMutators,
}
func PreArchMutators(f RegisterMutatorFunc) {
diff --git a/android/onceper.go b/android/onceper.go
index 5ad17fa..ff865c2 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -40,7 +40,8 @@
}
// Once computes a value the first time it is called with a given key per OncePer, and returns the
-// value without recomputing when called with the same key. key must be hashable.
+// value without recomputing when called with the same key. key must be hashable. If value panics
+// the panic will be propagated but the next call to Once with the same key will return nil.
func (once *OncePer) Once(key OnceKey, value func() interface{}) interface{} {
// Fast path: check if the key is already in the map
if v, ok := once.values.Load(key); ok {
@@ -54,10 +55,15 @@
return once.maybeWaitFor(key, v)
}
- // The waiter is inserted, call the value constructor, store it, and signal the waiter
- v := value()
- once.values.Store(key, v)
- close(waiter)
+ // The waiter is inserted, call the value constructor, store it, and signal the waiter. Use defer in case
+ // the function panics.
+ var v interface{}
+ defer func() {
+ once.values.Store(key, v)
+ close(waiter)
+ }()
+
+ v = value()
return v
}
diff --git a/android/onceper_test.go b/android/onceper_test.go
index 95303ba..1a55ff4 100644
--- a/android/onceper_test.go
+++ b/android/onceper_test.go
@@ -175,3 +175,43 @@
t.Errorf(`reentrant Once should return "a": %q`, a)
}
}
+
+// Test that a recovered panic in a Once function doesn't deadlock
+func TestOncePerPanic(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ ch := make(chan interface{})
+
+ var a interface{}
+
+ go func() {
+ defer func() {
+ ch <- recover()
+ }()
+
+ a = once.Once(key, func() interface{} {
+ panic("foo")
+ })
+ }()
+
+ p := <-ch
+
+ if p.(string) != "foo" {
+ t.Errorf(`expected panic with "foo", got %#v`, p)
+ }
+
+ if a != nil {
+ t.Errorf(`expected a to be nil, got %#v`, a)
+ }
+
+ // If the call to Once that panicked leaves the key in a bad state this will deadlock
+ b := once.Once(key, func() interface{} {
+ return "bar"
+ })
+
+ // The second call to Once should return nil inserted by the first call that panicked.
+ if b != nil {
+ t.Errorf(`expected b to be nil, got %#v`, b)
+ }
+}
diff --git a/android/override_module.go b/android/override_module.go
index 119bca1..5a57c93 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -84,8 +84,13 @@
getOverrides() []OverrideModule
override(ctx BaseModuleContext, o OverrideModule)
+ getOverriddenBy() string
setOverridesProperty(overridesProperties *[]string)
+
+ // Due to complications with incoming dependencies, overrides are processed after DepsMutator.
+ // So, overridable properties need to be handled in a separate, dedicated deps mutator.
+ OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext)
}
// Base module struct for overridable module types
@@ -106,6 +111,8 @@
// set this to a pointer to the property through the InitOverridableModule function, so that
// override information is propagated and aggregated correctly.
overridesProperty *[]string
+
+ overriddenBy string
}
func InitOverridableModule(m OverridableModule, overridesProperty *[]string) {
@@ -153,14 +160,23 @@
}
}
}
+ b.overriddenBy = o.Name()
+}
+
+func (b *OverridableModuleBase) getOverriddenBy() string {
+ return b.overriddenBy
+}
+
+func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
}
// Mutators for override/overridable modules. All the fun happens in these functions. It is critical
// to keep them in this order and not put any order mutators between them.
-func RegisterOverridePreArchMutators(ctx RegisterMutatorsContext) {
+func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel()
ctx.TopDown("register_override", registerOverrideMutator).Parallel()
ctx.BottomUp("perform_override", performOverrideMutator).Parallel()
+ ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
}
type overrideBaseDependencyTag struct {
@@ -207,5 +223,22 @@
for i, o := range overrides {
mods[i+1].(OverridableModule).override(ctx, o)
}
+ } else if o, ok := ctx.Module().(OverrideModule); ok {
+ // Create a variant of the overriding module with its own name. This matches the above local
+ // variant name rule for overridden modules, and thus allows ReplaceDependencies to match the
+ // two.
+ ctx.CreateLocalVariations(o.Name())
+ }
+}
+
+func overridableModuleDepsMutator(ctx BottomUpMutatorContext) {
+ if b, ok := ctx.Module().(OverridableModule); ok {
+ if o := b.getOverriddenBy(); o != "" {
+ // Redirect dependencies on the overriding module to this overridden module. Overriding
+ // modules are basically pseudo modules, and all build actions are associated to overridden
+ // modules. Therefore, dependencies on overriding modules need to be forwarded there as well.
+ ctx.ReplaceDependencies(o)
+ }
+ b.OverridablePropertiesDepsMutator(ctx)
}
}
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index bec24c7..b13ce2a 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -23,6 +23,7 @@
RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+ RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -240,3 +241,12 @@
}
}
}
+
+// prebuilt_font installs a font in <partition>/fonts directory.
+func PrebuiltFontFactory() Module {
+ module := &PrebuiltEtc{installDirBase: "fonts"}
+ InitPrebuiltEtcModule(module)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+ return module
+}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index 08700ae..a5c4480 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -30,6 +30,7 @@
ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory))
ctx.RegisterModuleType("prebuilt_usr_share", ModuleFactoryAdaptor(PrebuiltUserShareFactory))
ctx.RegisterModuleType("prebuilt_usr_share_host", ModuleFactoryAdaptor(PrebuiltUserShareHostFactory))
+ ctx.RegisterModuleType("prebuilt_font", ModuleFactoryAdaptor(PrebuiltFontFactory))
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
})
@@ -219,3 +220,18 @@
t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
}
}
+
+func TestPrebuiltFontInstallDirPath(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, `
+ prebuilt_font {
+ name: "foo.conf",
+ src: "foo.conf",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+ expected := "target/product/test_device/system/fonts"
+ if p.installDirPath.RelPathString() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ }
+}
diff --git a/android/util.go b/android/util.go
index f9dce6f..f7a3437 100644
--- a/android/util.go
+++ b/android/util.go
@@ -52,6 +52,31 @@
return string(ret)
}
+func JoinWithSuffix(strs []string, suffix string, separator string) string {
+ if len(strs) == 0 {
+ return ""
+ }
+
+ if len(strs) == 1 {
+ return strs[0] + suffix
+ }
+
+ n := len(" ") * (len(strs) - 1)
+ for _, s := range strs {
+ n += len(suffix) + len(s)
+ }
+
+ ret := make([]byte, 0, n)
+ for i, s := range strs {
+ if i != 0 {
+ ret = append(ret, separator...)
+ }
+ ret = append(ret, s...)
+ ret = append(ret, suffix...)
+ }
+ return string(ret)
+}
+
func sortedKeys(m map[string][]string) []string {
s := make([]string, 0, len(m))
for k := range m {
diff --git a/android/variable.go b/android/variable.go
index c500671..d039a16 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -279,6 +279,8 @@
BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
BoardSepolicyM4Defs []string `json:",omitempty"`
+ BoardVndkRuntimeDisable *bool `json:",omitempty"`
+
VendorVars map[string]map[string]string `json:",omitempty"`
Ndk_abis *bool `json:",omitempty"`
@@ -304,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 6809914..09c5b1b 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1,10 +1,11 @@
package android
import (
- "github.com/google/blueprint"
"io/ioutil"
"os"
"testing"
+
+ "github.com/google/blueprint"
)
var visibilityTests = []struct {
@@ -90,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 {
@@ -104,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`,
},
},
{
@@ -120,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`,
},
},
@@ -152,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",
@@ -198,10 +172,17 @@
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; //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`,
},
},
{
@@ -223,10 +204,17 @@
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; //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`,
},
},
{
@@ -262,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`,
},
},
{
@@ -295,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`,
},
},
{
@@ -326,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`,
},
},
{
@@ -384,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) {
@@ -430,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()
@@ -451,6 +725,7 @@
type mockLibraryModule struct {
ModuleBase
+ DefaultableModuleBase
properties mockLibraryProperties
}
@@ -458,6 +733,7 @@
m := &mockLibraryModule{}
m.AddProperties(&m.properties)
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+ InitDefaultableModule(m)
return m
}
@@ -472,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 b54ad5e..24057af 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -123,6 +123,7 @@
"LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs",
"LOCAL_ASFLAGS": "asflags",
"LOCAL_CLANG_ASFLAGS": "clang_asflags",
+ "LOCAL_COMPATIBILITY_SUPPORT_FILES": "data",
"LOCAL_CONLYFLAGS": "conlyflags",
"LOCAL_CPPFLAGS": "cppflags",
"LOCAL_REQUIRED_MODULES": "required",
@@ -528,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,
}
@@ -936,6 +937,7 @@
"STATIC_LIBRARIES": "cc_prebuilt_library_static",
"EXECUTABLES": "cc_prebuilt_binary",
"JAVA_LIBRARIES": "java_import",
+ "APPS": "android_app_import",
"ETC": "prebuilt_etc",
}
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 34e673c..2eab0cc 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -809,6 +809,7 @@
LOCAL_PACKAGE_NAME := FooTest
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_CTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
include $(BUILD_CTS_PACKAGE)
`,
expected: `
@@ -817,6 +818,7 @@
defaults: ["cts_defaults"],
test_suites: ["cts"],
+ data: ["file1"],
}
`,
},
@@ -879,7 +881,6 @@
}
`,
},
-
{
desc: "prebuilt_etc_PRODUCT_OUT/system/etc",
in: `
@@ -1065,6 +1066,119 @@
`,
},
{
+ desc: "prebuilt_usr_share",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share {
+ name: "foo",
+
+ src: "foo.txt",
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share subdir_bar",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share {
+ name: "foo",
+
+ src: "foo.txt",
+ sub_dir: "bar",
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share_host",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share_host {
+ name: "foo",
+
+ src: "foo.txt",
+}
+`,
+ },
+ {
+ desc: "prebuilt_font",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_font {
+ name: "font.ttf",
+ src: "font.ttf",
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_font",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := font.ttf
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/fonts
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_font {
+ name: "font.ttf",
+ src: "font.ttf",
+ product_specific: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_usr_share_host subdir_bar",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(HOST_OUT)/usr/share/bar
+LOCAL_SRC_FILES := foo.txt
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_usr_share_host {
+ name: "foo",
+
+ src: "foo.txt",
+ sub_dir: "bar",
+}
+`,
+ },
+ {
desc: "vts_config",
in: `
include $(CLEAR_VARS)
@@ -1123,6 +1237,32 @@
}
`,
},
+ {
+ desc: "android_app_import",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := foo.apk
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_CLASS := APPS
+LOCAL_MODULE_TAGS := optional
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+android_app_import {
+ name: "foo",
+
+ privileged: true,
+
+ dex_preopt: {
+ enabled: false,
+ },
+ apk: "foo.apk",
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 68d0bc1..51d0718 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -521,6 +521,17 @@
a.properties.Multilib.Prefer32.Binaries, target.String(),
a.getImageVariation(config))
}
+
+ if strings.HasPrefix(ctx.ModuleName(), "com.android.runtime") && target.Os.Class == android.Device {
+ for _, sanitizer := range ctx.Config().SanitizeDevice() {
+ if sanitizer == "hwaddress" {
+ addDependenciesForNativeModules(ctx,
+ []string{"libclang_rt.hwasan-aarch64-android"},
+ nil, target.String(), a.getImageVariation(config))
+ break
+ }
+ }
+ }
}
}
diff --git a/bpf/Android.bp b/bpf/Android.bp
index 7bd4d44..882cd8a 100644
--- a/bpf/Android.bp
+++ b/bpf/Android.bp
@@ -21,10 +21,14 @@
"blueprint",
"blueprint-proptools",
"soong-android",
+ "soong-cc",
"soong-cc-config",
],
srcs: [
"bpf.go",
],
+ testSrcs: [
+ "bpf_test.go",
+ ],
pluginFor: ["soong_build"],
}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 13468c7..dcbf9ad 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -33,7 +33,7 @@
var (
pctx = android.NewPackageContext("android/soong/bpf")
- cc = pctx.AndroidGomaStaticRule("cc",
+ ccRule = pctx.AndroidGomaStaticRule("ccRule",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
@@ -82,7 +82,7 @@
obj := android.ObjPathWithExt(ctx, "", src, "o")
ctx.Build(pctx, android.BuildParams{
- Rule: cc,
+ Rule: ccRule,
Input: src,
Output: obj,
Args: map[string]string{
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index 1d53e41..cbb251f 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -20,7 +20,7 @@
"testing"
"android/soong/android"
- cc2 "android/soong/cc"
+ "android/soong/cc"
)
var buildDir string
@@ -49,115 +49,14 @@
}
func testContext(bp string) *android.TestContext {
- ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
- ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc2.TestFactory))
- ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc2.LibraryFactory))
- ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(cc2.LibraryStaticFactory))
- ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc2.ObjectFactory))
- ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc2.ToolchainLibraryFactory))
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("link", cc2.LinkageMutator).Parallel()
- })
- ctx.Register()
-
- // Add some modules that are required by the compiler and/or linker
- bp = bp + `
- toolchain_library {
- name: "libatomic",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-arm-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-aarch64-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libgcc",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- cc_library {
- name: "libc",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libm",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libdl",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
-
- cc_library {
- name: "libgtest",
- host_supported: true,
- vendor_available: true,
- }
-
- cc_library {
- name: "libgtest_main",
- host_supported: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtbegin_dynamic",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_android",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtbegin_so",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_so",
- recovery_available: true,
- vendor_available: true,
- }
- `
mockFS := map[string][]byte{
- "Android.bp": []byte(bp),
"bpf.c": nil,
"BpfTest.cpp": nil,
}
- ctx.MockFileSystem(mockFS)
+ ctx := cc.CreateTestContext(bp, mockFS, android.Android)
+ ctx.RegisterModuleType("bpf", android.ModuleFactoryAdaptor(bpfFactory))
+ ctx.Register()
return ctx
}
@@ -174,6 +73,7 @@
name: "vts_test_binary_bpf_module",
srcs: ["BpfTest.cpp"],
data: [":bpf.o"],
+ gtest: false,
}
`
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 706c0ec..17cff18 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -102,6 +102,10 @@
name: "rewriteAndroidTest",
fix: rewriteAndroidTest,
},
+ {
+ name: "rewriteAndroidAppImport",
+ fix: rewriteAndroidAppImport,
+ },
}
func NewFixRequest() FixRequest {
@@ -431,14 +435,6 @@
return ""
}
-// Create sub_dir: attribute for the given path
-func makePrebuiltEtcDestination(mod *parser.Module, path string) {
- mod.Properties = append(mod.Properties, &parser.Property{
- Name: "sub_dir",
- Value: &parser.String{Value: path},
- })
-}
-
// Set the value of the given attribute to the error message
func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
msg := fmt.Sprintf(format, a...)
@@ -464,18 +460,54 @@
return val
}
-// A prefix to strip before setting 'filename' attribute and an array of boolean attributes to set.
-type filenamePrefixToFlags struct {
+// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
+// * changing the module type from prebuilt_etc to a different one
+// * stripping the prefix of the install path based on the module type
+// * appending additional boolean properties to the prebuilt module
+type etcPrebuiltModuleUpdate struct {
+ // The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
+ // before setting the 'filename' attribute.
prefix string
- flags []string
+
+ // There is only one prebuilt module type in makefiles. In Soong, there are multiple versions of
+ // prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An
+ // example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is
+ // considered as prebuilt_usr_share.
+ modType string
+
+ // Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute
+ // has a value of true.
+ flags []string
}
-var localModulePathRewrite = map[string][]filenamePrefixToFlags{
- "HOST_OUT": {{prefix: "/etc"}},
+func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool {
+ updated := false
+ if path == f.prefix {
+ updated = true
+ } else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
+ m.Properties = append(m.Properties, &parser.Property{
+ Name: "sub_dir",
+ Value: &parser.String{Value: trimmedPath},
+ })
+ updated = true
+ }
+ if updated {
+ for _, flag := range f.flags {
+ m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
+ }
+ if f.modType != "" {
+ m.Type = f.modType
+ }
+ }
+ return updated
+}
+
+var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{
+ "HOST_OUT": {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}},
"PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
- "TARGET_OUT": {{prefix: "/etc"}},
+ "TARGET_OUT": {{prefix: "/etc"}, {prefix: "/usr/share", modType: "prebuilt_usr_share"}, {prefix: "/fonts", modType: "prebuilt_font"}},
"TARGET_OUT_ETC": {{prefix: ""}},
- "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}},
+ "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}},
"TARGET_OUT_PRODUCT_ETC": {{prefix: "", flags: []string{"product_specific"}}},
"TARGET_OUT_ODM": {{prefix: "/etc", flags: []string{"device_specific"}}},
"TARGET_OUT_PRODUCT_SERVICES": {{prefix: "/etc", flags: []string{"product_services_specific"}}},
@@ -497,27 +529,8 @@
continue
}
- // The rewriter converts LOCAL_SRC_FILES to `srcs` attribute. Convert
- // it to 'src' attribute (which is where the file is installed). If the
- // value 'srcs' is a list, we can convert it only if it contains a single
- // element.
- if srcs, ok := mod.GetProperty("srcs"); ok {
- if srcList, ok := srcs.Value.(*parser.List); ok {
- removeProperty(mod, "srcs")
- if len(srcList.Values) == 1 {
- mod.Properties = append(mod.Properties,
- &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcList.Values[0])})
- } else if len(srcList.Values) > 1 {
- indicateAttributeError(mod, "src", "LOCAL_SRC_FILES should contain at most one item")
- }
- } else if _, ok = srcs.Value.(*parser.Variable); ok {
- removeProperty(mod, "srcs")
- mod.Properties = append(mod.Properties,
- &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcs.Value)})
- } else {
- renameProperty(mod, "srcs", "src")
- }
- }
+ // 'srcs' --> 'src' conversion
+ convertToSingleSource(mod, "src")
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
@@ -526,37 +539,23 @@
if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
removeProperty(mod, local_module_path)
prefixVariableName := getStringProperty(prop_local_module_path, "var")
- path := getStringProperty(prop_local_module_path, "fixed")
- if prefixRewrites, ok := localModulePathRewrite[prefixVariableName]; ok {
- rewritten := false
- for _, prefixRewrite := range prefixRewrites {
- if path == prefixRewrite.prefix {
- rewritten = true
- } else if trimmedPath := strings.TrimPrefix(path, prefixRewrite.prefix+"/"); trimmedPath != path {
- makePrebuiltEtcDestination(mod, trimmedPath)
- rewritten = true
- }
- if rewritten {
- for _, flag := range prefixRewrite.flags {
- mod.Properties = append(mod.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
- }
- break
- }
+ if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok {
+ path := getStringProperty(prop_local_module_path, "fixed")
+ updated := false
+ for i := 0; i < len(moduleUpdates) && !updated; i++ {
+ updated = moduleUpdates[i].update(mod, path)
}
- if !rewritten {
+ if !updated {
expectedPrefices := ""
sep := ""
- for _, prefixRewrite := range prefixRewrites {
+ for _, moduleUpdate := range moduleUpdates {
expectedPrefices += sep
sep = ", "
- expectedPrefices += prefixRewrite.prefix
+ expectedPrefices += moduleUpdate.prefix
}
return indicateAttributeError(mod, "filename",
"LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
}
- if prefixVariableName == "HOST_OUT" {
- mod.Type = "prebuilt_etc_host"
- }
} else {
return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
}
@@ -589,6 +588,62 @@
return nil
}
+func rewriteAndroidAppImport(f *Fixer) error {
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !(ok && mod.Type == "android_app_import") {
+ continue
+ }
+ // 'srcs' --> 'apk' conversion
+ convertToSingleSource(mod, "apk")
+ // Handle special certificate value, "PRESIGNED".
+ if cert, ok := mod.GetProperty("certificate"); ok {
+ if certStr, ok := cert.Value.(*parser.String); ok {
+ if certStr.Value == "PRESIGNED" {
+ removeProperty(mod, "certificate")
+ prop := &parser.Property{
+ Name: "presigned",
+ Value: &parser.Bool{
+ Value: true,
+ },
+ }
+ mod.Properties = append(mod.Properties, prop)
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// Converts the default source list property, 'srcs', to a single source property with a given name.
+// "LOCAL_MODULE" reference is also resolved during the conversion process.
+func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
+ if srcs, ok := mod.GetProperty("srcs"); ok {
+ if srcList, ok := srcs.Value.(*parser.List); ok {
+ removeProperty(mod, "srcs")
+ if len(srcList.Values) == 1 {
+ mod.Properties = append(mod.Properties,
+ &parser.Property{
+ Name: srcPropertyName,
+ NamePos: srcs.NamePos,
+ ColonPos: srcs.ColonPos,
+ Value: resolveLocalModule(mod, srcList.Values[0])})
+ } else if len(srcList.Values) > 1 {
+ indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item")
+ }
+ } else if _, ok = srcs.Value.(*parser.Variable); ok {
+ removeProperty(mod, "srcs")
+ mod.Properties = append(mod.Properties,
+ &parser.Property{Name: srcPropertyName,
+ NamePos: srcs.NamePos,
+ ColonPos: srcs.ColonPos,
+ Value: resolveLocalModule(mod, srcs.Value)})
+ } else {
+ renameProperty(mod, "srcs", "apk")
+ }
+ }
+}
+
func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
return func(f *Fixer) error {
// Make sure all the offsets are accurate
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 459cd36..5e0b817 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -784,3 +784,52 @@
})
}
}
+
+func TestRewriteAndroidAppImport(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "android_app_import apk",
+ in: `
+ android_app_import {
+ name: "foo",
+ srcs: ["package.apk"],
+ }
+ `,
+ out: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ }
+ `,
+ },
+ {
+ name: "android_app_import presigned",
+ in: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ certificate: "PRESIGNED",
+ }
+ `,
+ out: `
+ android_app_import {
+ name: "foo",
+ apk: "package.apk",
+ presigned: true,
+
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, func(fixer *Fixer) error {
+ return rewriteAndroidAppImport(fixer)
+ })
+ })
+ }
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index c7883e2..32ccf4c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,8 +24,9 @@
)
var (
- vendorSuffix = ".vendor"
- recoverySuffix = ".recovery"
+ nativeBridgeSuffix = ".native_bridge"
+ vendorSuffix = ".vendor"
+ recoverySuffix = ".recovery"
)
type AndroidMkContext interface {
@@ -89,6 +90,9 @@
fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
if c.useVndk() {
fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+ if c.isVndk() && !c.static() {
+ fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
+ }
}
},
},
@@ -105,6 +109,10 @@
}
c.subAndroidMk(&ret, c.installer)
+ if c.Target().NativeBridge == android.NativeBridgeEnabled {
+ ret.SubName += nativeBridgeSuffix
+ }
+
if c.useVndk() && c.hasVendorVariant() {
// .vendor suffix is added only when we will have two variants: core and vendor.
// The suffix is not added for vendor-only module.
@@ -134,6 +142,18 @@
}
}
+func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string {
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ var result []string
+ for _, override := range overrides {
+ result = append(result, override+nativeBridgeSuffix)
+ }
+ return result
+ }
+
+ return overrides
+}
+
func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
exportedFlags := library.exportedFlags()
if len(exportedFlags) > 0 {
@@ -166,7 +186,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
}
if len(library.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
}
if len(library.post_install_cmds) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
@@ -241,7 +261,7 @@
}
if len(binary.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(binary.Properties.Overrides, " "))
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
}
if len(binary.post_install_cmds) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
diff --git a/cc/binary.go b/cc/binary.go
index 51e68fc..93d1de2 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -440,8 +440,8 @@
// Bionic binaries (e.g. linker) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- if isBionic(ctx.baseModuleName()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
- if ctx.Device() {
+ if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && ctx.Arch().Native && ctx.apexName() == "" && !ctx.inRecovery() {
+ if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
binary.baseInstaller.subDir = "bootstrap"
diff --git a/cc/builder.go b/cc/builder.go
index c99e461..7cf5c29 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -123,12 +123,25 @@
_ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
_ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz")
+ // b/132822437: objcopy uses a file descriptor per .o file when called on .a files, which runs the system out of
+ // file descriptors on darwin. Limit concurrent calls to 5 on darwin.
+ darwinStripPool = func() blueprint.Pool {
+ if runtime.GOOS == "darwin" {
+ return pctx.StaticPool("darwinStripPool", blueprint.PoolParams{
+ Depth: 5,
+ })
+ } else {
+ return nil
+ }
+ }()
+
strip = pctx.AndroidStaticRule("strip",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath", "$xzCmd"},
+ Pool: darwinStripPool,
},
"args", "crossCompile")
@@ -254,11 +267,12 @@
groupStaticLibs bool
- stripKeepSymbols bool
- stripKeepSymbolsList string
- stripKeepMiniDebugInfo bool
- stripAddGnuDebuglink bool
- stripUseGnuStrip bool
+ stripKeepSymbols bool
+ stripKeepSymbolsList string
+ stripKeepSymbolsAndDebugFrame bool
+ stripKeepMiniDebugInfo bool
+ stripAddGnuDebuglink bool
+ stripUseGnuStrip bool
proto android.ProtoFlags
protoC bool
@@ -839,6 +853,9 @@
if flags.stripKeepSymbolsList != "" {
args += " -k" + flags.stripKeepSymbolsList
}
+ if flags.stripKeepSymbolsAndDebugFrame {
+ args += " --keep-symbols-and-debug-frame"
+ }
if flags.stripUseGnuStrip {
args += " --use-gnu-strip"
}
diff --git a/cc/cc.go b/cc/cc.go
index eaf41d8..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()
@@ -534,6 +537,13 @@
return false
}
+func (c *Module) vndkVersion() string {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.Properties.Vndk.Version
+ }
+ return ""
+}
+
func (c *Module) isPgoCompile() bool {
if pgo := c.pgo; pgo != nil {
return pgo.Properties.PgoCompile
@@ -600,6 +610,9 @@
if library, ok := c.linker.(*libraryDecorator); ok {
return len(library.Properties.Stubs.Versions) > 0
}
+ if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ return len(library.Properties.Stubs.Versions) > 0
+ }
return false
}
@@ -619,6 +632,13 @@
return false
}
+func installToBootstrap(name string, config android.Config) bool {
+ if name == "libclang_rt.hwasan-aarch64-android" {
+ return inList("hwaddress", config.SanitizeDevice())
+ }
+ return isBionic(name)
+}
+
type baseModuleContext struct {
android.BaseContext
moduleContextImpl
@@ -909,7 +929,7 @@
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
- c.makeLinkType = c.getMakeLinkType(actx.Config())
+ c.makeLinkType = c.getMakeLinkType(actx)
ctx := &moduleContext{
ModuleContext: actx,
@@ -1011,7 +1031,7 @@
}
}
- if c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid() {
+ if c.installable() {
c.installer.install(ctx, c.outputFile.Path())
if ctx.Failed() {
return
@@ -1816,7 +1836,7 @@
} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
return libName + recoverySuffix
} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
- return libName + android.NativeBridgeSuffix
+ return libName + nativeBridgeSuffix
} else {
return libName
}
@@ -1930,19 +1950,22 @@
return false
}
-func (c *Module) getMakeLinkType(config android.Config) string {
+func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
+ name := actx.ModuleName()
if c.useVndk() {
- if inList(c.Name(), *vndkCoreLibraries(config)) ||
- inList(c.Name(), *vndkSpLibraries(config)) ||
- inList(c.Name(), *llndkLibraries(config)) {
- if inList(c.Name(), *vndkPrivateLibraries(config)) {
- return "native:vndk_private"
- } else {
+ if lib, ok := c.linker.(*llndkStubDecorator); ok {
+ if Bool(lib.Properties.Vendor_available) {
return "native:vndk"
}
- } else {
- return "native:vendor"
+ return "native:vndk_private"
}
+ if c.isVndk() && !c.isVndkExt() {
+ if Bool(c.VendorProperties.Vendor_available) {
+ return "native:vndk"
+ }
+ return "native:vndk_private"
+ }
+ return "native:vendor"
} else if c.inRecovery() {
return "native:recovery"
} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
@@ -1950,7 +1973,7 @@
// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
//family, link := getNdkStlFamilyAndLinkType(c)
//return fmt.Sprintf("native:ndk:%s:%s", family, link)
- } else if inList(c.Name(), *vndkUsingCoreVariantLibraries(config)) {
+ } else if inList(name, *vndkUsingCoreVariantLibraries(actx.Config())) {
return "native:platform_vndk"
} else {
return "native:platform"
@@ -1968,6 +1991,10 @@
return false
}
+func (c *Module) installable() bool {
+ return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
+}
+
func (c *Module) imageVariation() string {
variation := "core"
if c.useVndk() {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index f3d5e60..997e11e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
"fmt"
"io/ioutil"
"os"
+ "path/filepath"
"reflect"
"sort"
"strings"
@@ -51,55 +52,14 @@
os.Exit(run())
}
-func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
- ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
- ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
- ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
- ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
- ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
- ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
- ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
- ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
- ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
- ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
- ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
- ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", ImageMutator).Parallel()
- ctx.BottomUp("link", LinkageMutator).Parallel()
- ctx.BottomUp("vndk", VndkMutator).Parallel()
- ctx.BottomUp("version", VersionMutator).Parallel()
- ctx.BottomUp("begin", BeginMutator).Parallel()
- })
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
- })
- ctx.Register()
-
- // add some modules that are required by the compiler and/or linker
- bp = bp + GatherRequiredDepsForTest(os)
-
- ctx.MockFileSystem(map[string][]byte{
- "Android.bp": []byte(bp),
- "foo.c": nil,
- "bar.c": nil,
- "a.proto": nil,
- "b.aidl": nil,
- "my_include": nil,
- "foo.map.txt": nil,
- })
-
- return ctx
-}
-
func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
return testCcWithConfigForOs(t, bp, config, android.Android)
}
func testCcWithConfigForOs(t *testing.T, bp string, config android.Config, os android.OsType) *android.TestContext {
t.Helper()
- ctx := createTestContext(t, config, bp, os)
+ ctx := CreateTestContext(bp, nil, os)
+ ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -132,7 +92,8 @@
config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
- ctx := createTestContext(t, config, bp, android.Android)
+ ctx := CreateTestContext(bp, nil, android.Android)
+ ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
if len(errs) > 0 {
@@ -286,8 +247,28 @@
}
}
+func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, name, subDir, variant string) {
+ vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+
+ snapshotPath := filepath.Join(subDir, name+".so")
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+ if !mod.outputFile.Valid() {
+ t.Errorf("%q must have output\n", name)
+ return
+ }
+
+ out := vndkSnapshot.Output(snapshotPath)
+ if out.Input != mod.outputFile.Path() {
+ t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), mod.outputFile.String())
+ }
+}
+
func TestVndk(t *testing.T) {
- ctx := testCc(t, `
+ config := android.TestArchConfig(buildDir, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ ctx := testCcWithConfig(t, `
cc_library {
name: "libvndk",
vendor_available: true,
@@ -325,12 +306,35 @@
},
nocrt: true,
}
- `)
+ `, config)
checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+
+ // Check VNDK snapshot output.
+
+ snapshotDir := "vndk-snapshot"
+ snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+
+ vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+ "arm64", "armv8-a"))
+ vndkLib2ndPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
+ "arm", "armv7-a-neon"))
+
+ vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+ vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+ vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+ vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+
+ variant := "android_arm64_armv8-a_vendor_shared"
+ variant2nd := "android_arm_armv7-a-neon_vendor_shared"
+
+ checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant)
+ checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
+ checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLibPath, variant)
+ checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd)
}
func TestVndkDepError(t *testing.T) {
@@ -1259,6 +1263,110 @@
`)
}
+func TestMakeLinkType(t *testing.T) {
+ config := android.TestArchConfig(buildDir, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ // native:vndk
+ ctx := testCcWithConfig(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ }
+ cc_library {
+ name: "libvndksp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ }
+ cc_library {
+ name: "libvndkprivate",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ cc_library {
+ name: "libvndkext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ }
+ vndk_prebuilt_shared {
+ name: "prevndk",
+ version: "27",
+ target_arch: "arm",
+ binder32bit: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ arch: {
+ arm: {
+ srcs: ["liba.so"],
+ },
+ },
+ }
+ cc_library {
+ name: "libllndk",
+ }
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libllndkprivate",
+ }
+ llndk_library {
+ name: "libllndkprivate",
+ vendor_available: false,
+ symbol_file: "",
+ }`, config)
+
+ assertArrayString(t, *vndkCoreLibraries(config),
+ []string{"libvndk", "libvndkprivate"})
+ assertArrayString(t, *vndkSpLibraries(config),
+ []string{"libc++", "libvndksp"})
+ assertArrayString(t, *llndkLibraries(config),
+ []string{"libc", "libdl", "libllndk", "libllndkprivate", "libm"})
+ assertArrayString(t, *vndkPrivateLibraries(config),
+ []string{"libllndkprivate", "libvndkprivate"})
+
+ tests := []struct {
+ variant string
+ name string
+ expected string
+ }{
+ {vendorVariant, "libvndk", "native:vndk"},
+ {vendorVariant, "libvndksp", "native:vndk"},
+ {vendorVariant, "libvndkprivate", "native:vndk_private"},
+ {vendorVariant, "libvendor", "native:vendor"},
+ {vendorVariant, "libvndkext", "native:vendor"},
+ {vendorVariant, "prevndk.vndk.27.arm.binder32", "native:vndk"},
+ {vendorVariant, "libllndk.llndk", "native:vndk"},
+ {coreVariant, "libvndk", "native:platform"},
+ {coreVariant, "libvndkprivate", "native:platform"},
+ {coreVariant, "libllndk", "native:platform"},
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ module := ctx.ModuleForTests(test.name, test.variant).Module().(*Module)
+ assertString(t, module.makeLinkType, test.expected)
+ })
+ }
+}
+
var (
str11 = "01234567891"
str10 = str11[:10]
@@ -2155,3 +2263,25 @@
)
}
}
+
+func assertString(t *testing.T, got, expected string) {
+ t.Helper()
+ if got != expected {
+ t.Errorf("expected %q got %q", expected, got)
+ }
+}
+
+func assertArrayString(t *testing.T, got, expected []string) {
+ t.Helper()
+ if len(got) != len(expected) {
+ t.Errorf("expected %d (%q) got (%d) %q", len(expected), expected, len(got), got)
+ return
+ }
+ for i := range got {
+ if got[i] != expected[i] {
+ t.Errorf("expected %d-th %q (%q) got %q (%q)",
+ i, expected[i], expected, got[i], got)
+ return
+ }
+ }
+}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 94a8257..47b60e7 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -108,6 +108,9 @@
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
+ // Enable the new pass manager.
+ "-fexperimental-new-pass-manager",
+
// Disable overly aggressive warning for macros defined with a leading underscore
// This happens in AndroidConfig.h, which is included nearly everywhere.
// TODO: can we remove this now?
diff --git a/cc/library.go b/cc/library.go
index c2ab098..3053831 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -23,7 +23,6 @@
"strings"
"sync"
- "github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"android/soong/android"
@@ -962,8 +961,8 @@
// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- if isBionic(ctx.baseModuleName()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
- if ctx.Device() {
+ if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && ctx.Arch().Native && !ctx.inRecovery() {
+ if ctx.Device() && isBionic(ctx.baseModuleName()) {
library.installSymlinkToRuntimeApex(ctx, file)
}
library.baseInstaller.subDir = "bootstrap"
@@ -1106,10 +1105,28 @@
func LinkageMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
- if library, ok := m.linker.(libraryInterface); ok {
- var modules []blueprint.Module
+ switch library := m.linker.(type) {
+ case prebuiltLibraryInterface:
+ // Always create both the static and shared variants for prebuilt libraries, and then disable the one
+ // that is not being used. This allows them to share the name of a cc_library module, which requires that
+ // all the variants of the cc_library also exist on the prebuilt.
+ modules := mctx.CreateLocalVariations("static", "shared")
+ static := modules[0].(*Module)
+ shared := modules[1].(*Module)
+
+ static.linker.(prebuiltLibraryInterface).setStatic()
+ shared.linker.(prebuiltLibraryInterface).setShared()
+
+ if !library.buildStatic() {
+ static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+ if !library.buildShared() {
+ shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+ }
+
+ case libraryInterface:
if library.buildStatic() && library.buildShared() {
- modules = mctx.CreateLocalVariations("static", "shared")
+ modules := mctx.CreateLocalVariations("static", "shared")
static := modules[0].(*Module)
shared := modules[1].(*Module)
@@ -1119,10 +1136,10 @@
reuseStaticLibrary(mctx, static, shared)
} else if library.buildStatic() {
- modules = mctx.CreateLocalVariations("static")
+ modules := mctx.CreateLocalVariations("static")
modules[0].(*Module).linker.(libraryInterface).setStatic()
} else if library.buildShared() {
- modules = mctx.CreateLocalVariations("shared")
+ modules := mctx.CreateLocalVariations("shared")
modules[0].(*Module).linker.(libraryInterface).setShared()
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 3c24f34..a71f479 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -96,7 +96,20 @@
ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " "))
ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " "))
- ctx.Strict("LLNDK_LIBRARIES", strings.Join(*llndkLibraries(ctx.Config()), " "))
+
+ // Make uses LLNDK_LIBRARIES to determine which libraries to install.
+ // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+ // Therefore, by removing the library here, we cause it to only be installed if libc
+ // depends on it.
+ installedLlndkLibraries := []string{}
+ for _, lib := range *llndkLibraries(ctx.Config()) {
+ if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
+ continue
+ }
+ installedLlndkLibraries = append(installedLlndkLibraries, lib)
+ }
+ ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
+
ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c63b200..ff990b5 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -38,9 +38,12 @@
ndkLibrarySuffix = ".ndk"
ndkPrebuiltSharedLibs = []string{
+ "aaudio",
+ "amidi",
"android",
"binder_ndk",
"c",
+ "camera2ndk",
"dl",
"EGL",
"GLESv1_CM",
@@ -49,6 +52,7 @@
"jnigraphics",
"log",
"mediandk",
+ "nativewindow",
"m",
"OpenMAXAL",
"OpenSLES",
@@ -382,5 +386,6 @@
func ndkLibraryFactory() android.Module {
module := newStubLibrary()
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module
}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 8451295..026ff22 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -70,6 +70,7 @@
// ./prebuilts/ndk/current/platforms/android-<sdk_version>/arch-$(HOST_ARCH)/usr/lib/<NAME>.o.
func ndkPrebuiltObjectFactory() android.Module {
module := newBaseModule(android.DeviceSupported, android.MultilibBoth)
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
module.linker = &ndkPrebuiltObjectLinker{
objectLinker: objectLinker{
baseLinker: NewBaseLinker(nil),
@@ -134,6 +135,7 @@
}
module.installer = nil
module.Properties.HideFromMake = true
+ module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module.Init()
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 5ffeb32..48e4667 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -53,12 +53,19 @@
return p.properties.Srcs
}
+type prebuiltLibraryInterface interface {
+ libraryInterface
+ prebuiltLinkerInterface
+ disablePrebuilt()
+}
+
type prebuiltLibraryLinker struct {
*libraryDecorator
prebuiltLinker
}
var _ prebuiltLinkerInterface = (*prebuiltLibraryLinker)(nil)
+var _ prebuiltLibraryInterface = (*prebuiltLibraryLinker)(nil)
func (p *prebuiltLibraryLinker) linkerInit(ctx BaseModuleContext) {}
@@ -116,6 +123,10 @@
return false
}
+func (p *prebuiltLibraryLinker) disablePrebuilt() {
+ p.properties.Srcs = nil
+}
+
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func prebuiltSharedLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
new file mode 100644
index 0000000..98d78e8
--- /dev/null
+++ b/cc/prebuilt_test.go
@@ -0,0 +1,126 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "testing"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+func TestPrebuilt(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "liba",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "liba",
+ srcs: ["liba.so"],
+ }
+
+ cc_library {
+ name: "libb",
+ }
+
+ cc_prebuilt_library_static {
+ name: "libb",
+ srcs: ["libb.a"],
+ }
+
+ cc_library_shared {
+ name: "libd",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libd",
+ srcs: ["libd.so"],
+ }
+
+ cc_library_static {
+ name: "libe",
+ }
+
+ cc_prebuilt_library_static {
+ name: "libe",
+ srcs: ["libe.a"],
+ }
+ `
+
+ fs := map[string][]byte{
+ "liba.so": nil,
+ "libb.a": nil,
+ "libd.so": nil,
+ "libe.a": nil,
+ }
+
+ config := android.TestArchConfig(buildDir, nil)
+
+ ctx := CreateTestContext(bp, fs, android.Android)
+
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(prebuiltSharedLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(prebuiltStaticLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_binary", android.ModuleFactoryAdaptor(prebuiltBinaryFactory))
+
+ ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+ ctx.PostDepsMutators(android.RegisterPrebuiltsPostDepsMutators)
+
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ // Verify that all the modules exist and that their dependencies were connected correctly
+ liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_core_shared").Module()
+ libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_core_static").Module()
+ libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_core_shared").Module()
+ libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_core_static").Module()
+
+ prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_core_shared").Module()
+ prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_core_static").Module()
+ prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_core_shared").Module()
+ prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_core_static").Module()
+
+ hasDep := func(m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ if !hasDep(liba, prebuiltLiba) {
+ t.Errorf("liba missing dependency on prebuilt_liba")
+ }
+
+ if !hasDep(libb, prebuiltLibb) {
+ t.Errorf("libb missing dependency on prebuilt_libb")
+ }
+
+ if !hasDep(libd, prebuiltLibd) {
+ t.Errorf("libd missing dependency on prebuilt_libd")
+ }
+
+ if !hasDep(libe, prebuiltLibe) {
+ t.Errorf("libe missing dependency on prebuilt_libe")
+ }
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index acf2bef..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
}
}
@@ -392,6 +391,11 @@
if ctx.Device() {
if Bool(sanitize.Properties.Sanitize.Address) {
deps.StaticLibs = append(deps.StaticLibs, asanLibs...)
+ // Compiling asan and having libc_scudo in the same
+ // executable will cause the executable to crash.
+ // Remove libc_scudo since it is only used to override
+ // allocation functions which asan already overrides.
+ _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
}
}
@@ -456,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) {
@@ -492,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")
@@ -568,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))
}
@@ -578,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:
@@ -604,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))
}
@@ -788,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
@@ -926,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
@@ -991,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/cc/strip.go b/cc/strip.go
index 7122585..4daa759 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -22,11 +22,12 @@
type StripProperties struct {
Strip struct {
- None *bool `android:"arch_variant"`
- All *bool `android:"arch_variant"`
- Keep_symbols *bool `android:"arch_variant"`
- Keep_symbols_list []string `android:"arch_variant"`
- Use_gnu_strip *bool `android:"arch_variant"`
+ None *bool `android:"arch_variant"`
+ All *bool `android:"arch_variant"`
+ Keep_symbols *bool `android:"arch_variant"`
+ Keep_symbols_list []string `android:"arch_variant"`
+ Keep_symbols_and_debug_frame *bool `android:"arch_variant"`
+ Use_gnu_strip *bool `android:"arch_variant"`
} `android:"arch_variant"`
}
@@ -46,6 +47,8 @@
} else {
if Bool(stripper.StripProperties.Strip.Keep_symbols) {
flags.stripKeepSymbols = true
+ } else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
+ flags.stripKeepSymbolsAndDebugFrame = true
} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
} else if !Bool(stripper.StripProperties.Strip.All) {
diff --git a/cc/testing.go b/cc/testing.go
index 8d76c2f..d9be900 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -148,6 +148,12 @@
}
cc_object {
+ name: "crtbegin_dynamic",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_object {
name: "crtbegin_static",
recovery_available: true,
vendor_available: true,
@@ -183,3 +189,56 @@
}
return ret
}
+
+func CreateTestContext(bp string, fs map[string][]byte,
+ os android.OsType) *android.TestContext {
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
+ ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
+ ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+ ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
+ ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
+ ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(TestFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
+ ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
+ ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
+ ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
+ ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+ ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(vndkPrebuiltSharedFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("image", ImageMutator).Parallel()
+ ctx.BottomUp("link", LinkageMutator).Parallel()
+ ctx.BottomUp("vndk", VndkMutator).Parallel()
+ ctx.BottomUp("version", VersionMutator).Parallel()
+ ctx.BottomUp("begin", BeginMutator).Parallel()
+ })
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+ })
+ ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton))
+
+ // add some modules that are required by the compiler and/or linker
+ bp = bp + GatherRequiredDepsForTest(os)
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "foo.c": nil,
+ "bar.c": nil,
+ "a.proto": nil,
+ "b.aidl": nil,
+ "my_include": nil,
+ "foo.map.txt": nil,
+ "liba.so": nil,
+ }
+
+ for k, v := range fs {
+ mockFS[k] = v
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
diff --git a/cc/vndk.go b/cc/vndk.go
index 7859fa2..60a3d78 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -16,6 +16,8 @@
import (
"errors"
+ "fmt"
+ "path/filepath"
"sort"
"strings"
"sync"
@@ -47,6 +49,10 @@
// Extending another module
Extends *string
+
+ // for vndk_prebuilt_shared, this is set by "version" property.
+ // Otherwise, this is set as PLATFORM_VNDK_VERSION.
+ Version string `blueprint:"mutated"`
}
}
@@ -197,9 +203,20 @@
llndkLibrariesKey = android.NewOnceKey("llndkLibrarires")
vndkPrivateLibrariesKey = android.NewOnceKey("vndkPrivateLibrarires")
vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
+ modulePathsKey = android.NewOnceKey("modulePaths")
+ vndkSnapshotOutputsKey = android.NewOnceKey("vndkSnapshotOutputs")
vndkLibrariesLock sync.Mutex
)
+type vndkSnapshotOutputPaths struct {
+ configs android.Paths
+ notices android.Paths
+ vndkCoreLibs android.Paths
+ vndkCoreLibs2nd android.Paths
+ vndkSpLibs android.Paths
+ vndkSpLibs2nd android.Paths
+}
+
func vndkCoreLibraries(config android.Config) *[]string {
return config.Once(vndkCoreLibrariesKey, func() interface{} {
return &[]string{}
@@ -230,66 +247,304 @@
}).(*[]string)
}
-// gather list of vndk-core, vndk-sp, and ll-ndk libs
-func VndkMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok && m.Enabled() {
- if lib, ok := m.linker.(*llndkStubDecorator); ok {
- vndkLibrariesLock.Lock()
- defer vndkLibrariesLock.Unlock()
+func modulePaths(config android.Config) map[string]string {
+ return config.Once(modulePathsKey, func() interface{} {
+ return make(map[string]string)
+ }).(map[string]string)
+}
- llndkLibraries := llndkLibraries(mctx.Config())
- vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+func vndkSnapshotOutputs(config android.Config) *vndkSnapshotOutputPaths {
+ return config.Once(vndkSnapshotOutputsKey, func() interface{} {
+ return &vndkSnapshotOutputPaths{}
+ }).(*vndkSnapshotOutputPaths)
+}
- name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
- if !inList(name, *llndkLibraries) {
- *llndkLibraries = append(*llndkLibraries, name)
- sort.Strings(*llndkLibraries)
- }
- if !Bool(lib.Properties.Vendor_available) {
- if !inList(name, *vndkPrivateLibraries) {
- *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
- sort.Strings(*vndkPrivateLibraries)
- }
- }
- } else {
- lib, is_lib := m.linker.(*libraryDecorator)
- prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
- if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
- name := strings.TrimPrefix(m.Name(), "prebuilt_")
- if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
- vndkLibrariesLock.Lock()
- defer vndkLibrariesLock.Unlock()
+func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+ lib := m.linker.(*llndkStubDecorator)
+ name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
- vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
- vndkSpLibraries := vndkSpLibraries(mctx.Config())
- vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
- vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+ vndkLibrariesLock.Lock()
+ defer vndkLibrariesLock.Unlock()
- if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
- if !inList(name, *vndkUsingCoreVariantLibraries) {
- *vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
- sort.Strings(*vndkUsingCoreVariantLibraries)
- }
- }
- if m.vndkdep.isVndkSp() {
- if !inList(name, *vndkSpLibraries) {
- *vndkSpLibraries = append(*vndkSpLibraries, name)
- sort.Strings(*vndkSpLibraries)
- }
- } else {
- if !inList(name, *vndkCoreLibraries) {
- *vndkCoreLibraries = append(*vndkCoreLibraries, name)
- sort.Strings(*vndkCoreLibraries)
- }
- }
- if !Bool(m.VendorProperties.Vendor_available) {
- if !inList(name, *vndkPrivateLibraries) {
- *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
- sort.Strings(*vndkPrivateLibraries)
- }
- }
- }
- }
+ llndkLibraries := llndkLibraries(mctx.Config())
+ if !inList(name, *llndkLibraries) {
+ *llndkLibraries = append(*llndkLibraries, name)
+ sort.Strings(*llndkLibraries)
+ }
+ if !Bool(lib.Properties.Vendor_available) {
+ vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+ if !inList(name, *vndkPrivateLibraries) {
+ *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+ sort.Strings(*vndkPrivateLibraries)
}
}
}
+
+func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
+ name := strings.TrimPrefix(m.Name(), "prebuilt_")
+
+ vndkLibrariesLock.Lock()
+ defer vndkLibrariesLock.Unlock()
+
+ modulePaths := modulePaths(mctx.Config())
+ if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
+ vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
+ if !inList(name, *vndkUsingCoreVariantLibraries) {
+ *vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
+ sort.Strings(*vndkUsingCoreVariantLibraries)
+ }
+ }
+ if m.vndkdep.isVndkSp() {
+ vndkSpLibraries := vndkSpLibraries(mctx.Config())
+ if !inList(name, *vndkSpLibraries) {
+ *vndkSpLibraries = append(*vndkSpLibraries, name)
+ sort.Strings(*vndkSpLibraries)
+ modulePaths[name] = mctx.ModuleDir()
+ }
+ } else {
+ vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
+ if !inList(name, *vndkCoreLibraries) {
+ *vndkCoreLibraries = append(*vndkCoreLibraries, name)
+ sort.Strings(*vndkCoreLibraries)
+ modulePaths[name] = mctx.ModuleDir()
+ }
+ }
+ if !Bool(m.VendorProperties.Vendor_available) {
+ vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
+ if !inList(name, *vndkPrivateLibraries) {
+ *vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
+ sort.Strings(*vndkPrivateLibraries)
+ }
+ }
+}
+
+// gather list of vndk-core, vndk-sp, and ll-ndk libs
+func VndkMutator(mctx android.BottomUpMutatorContext) {
+ m, ok := mctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ if !m.Enabled() {
+ return
+ }
+
+ if m.isVndk() {
+ if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ m.vndkdep.Properties.Vndk.Version = lib.version()
+ } else {
+ m.vndkdep.Properties.Vndk.Version = mctx.DeviceConfig().PlatformVndkVersion()
+ }
+ }
+
+ if _, ok := m.linker.(*llndkStubDecorator); ok {
+ processLlndkLibrary(mctx, m)
+ return
+ }
+
+ lib, is_lib := m.linker.(*libraryDecorator)
+ prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+ if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
+ if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
+ processVndkLibrary(mctx, m)
+ return
+ }
+ }
+}
+
+func init() {
+ android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+ android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
+ outputs := vndkSnapshotOutputs(ctx.Config())
+
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CONFIGS", strings.Join(outputs.configs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_NOTICES", strings.Join(outputs.notices.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS", strings.Join(outputs.vndkCoreLibs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS", strings.Join(outputs.vndkSpLibs.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_CORE_LIBS_2ND", strings.Join(outputs.vndkCoreLibs2nd.Strings(), " "))
+ ctx.Strict("SOONG_VNDK_SNAPSHOT_SP_LIBS_2ND", strings.Join(outputs.vndkSpLibs2nd.Strings(), " "))
+ })
+}
+
+func VndkSnapshotSingleton() android.Singleton {
+ return &vndkSnapshotSingleton{}
+}
+
+type vndkSnapshotSingleton struct{}
+
+func installVndkSnapshotLib(ctx android.SingletonContext, name string, module *Module, dir string) android.Path {
+ if !module.outputFile.Valid() {
+ panic(fmt.Errorf("module %s has no outputFile\n", name))
+ }
+
+ out := android.PathForOutput(ctx, dir, name+".so")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: module.outputFile.Path(),
+ Output: out,
+ Description: "vndk snapshot " + dir + "/" + name + ".so",
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+
+ return out
+}
+
+func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
+ if ctx.DeviceConfig().VndkVersion() != "current" {
+ return
+ }
+
+ if ctx.DeviceConfig().PlatformVndkVersion() == "" {
+ return
+ }
+
+ if ctx.DeviceConfig().BoardVndkRuntimeDisable() {
+ return
+ }
+
+ outputs := vndkSnapshotOutputs(ctx.Config())
+
+ snapshotDir := "vndk-snapshot"
+
+ var vndkLibPath, vndkLib2ndPath string
+
+ snapshotVariantPath := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+ if ctx.DeviceConfig().BinderBitness() == "32" {
+ vndkLibPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+ vndkLib2ndPath = filepath.Join(snapshotVariantPath, "binder32", fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+ } else {
+ vndkLibPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceArchVariant()))
+ vndkLib2ndPath = filepath.Join(snapshotVariantPath, fmt.Sprintf(
+ "arch-%s-%s", ctx.DeviceConfig().DeviceSecondaryArch(), ctx.DeviceConfig().DeviceSecondaryArchVariant()))
+ }
+
+ vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
+ vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
+ vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
+ vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
+ noticePath := filepath.Join(snapshotVariantPath, "NOTICE_FILES")
+ noticeBuilt := make(map[string]bool)
+
+ tryBuildNotice := func(m *Module) {
+ name := ctx.ModuleName(m)
+
+ if _, ok := noticeBuilt[name]; ok {
+ return
+ }
+
+ noticeBuilt[name] = true
+
+ if m.NoticeFile().Valid() {
+ out := android.PathForOutput(ctx, noticePath, name+".so.txt")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: m.NoticeFile().Path(),
+ Output: out,
+ Description: "vndk snapshot notice " + name + ".so.txt",
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+ outputs.notices = append(outputs.notices, out)
+ }
+ }
+
+ vndkCoreLibraries := vndkCoreLibraries(ctx.Config())
+ vndkSpLibraries := vndkSpLibraries(ctx.Config())
+ vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config())
+
+ ctx.VisitAllModules(func(module android.Module) {
+ m, ok := module.(*Module)
+ if !ok || !m.Enabled() || !m.useVndk() || !m.installable() {
+ return
+ }
+
+ lib, is_lib := m.linker.(*libraryDecorator)
+ prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+
+ if !(is_lib && lib.shared()) && !(is_prebuilt_lib && prebuilt_lib.shared()) {
+ return
+ }
+
+ is_2nd := m.Target().Arch.ArchType != ctx.Config().DevicePrimaryArchType()
+
+ name := ctx.ModuleName(module)
+
+ if inList(name, *vndkCoreLibraries) {
+ if is_2nd {
+ out := installVndkSnapshotLib(ctx, name, m, vndkCoreLib2ndPath)
+ outputs.vndkCoreLibs2nd = append(outputs.vndkCoreLibs2nd, out)
+ } else {
+ out := installVndkSnapshotLib(ctx, name, m, vndkCoreLibPath)
+ outputs.vndkCoreLibs = append(outputs.vndkCoreLibs, out)
+ }
+ tryBuildNotice(m)
+ } else if inList(name, *vndkSpLibraries) {
+ if is_2nd {
+ out := installVndkSnapshotLib(ctx, name, m, vndkSpLib2ndPath)
+ outputs.vndkSpLibs2nd = append(outputs.vndkSpLibs2nd, out)
+ } else {
+ out := installVndkSnapshotLib(ctx, name, m, vndkSpLibPath)
+ outputs.vndkSpLibs = append(outputs.vndkSpLibs, out)
+ }
+ tryBuildNotice(m)
+ }
+ })
+
+ configsPath := filepath.Join(snapshotVariantPath, "configs")
+ vndkCoreTxt := android.PathForOutput(ctx, configsPath, "vndkcore.libraries.txt")
+ vndkPrivateTxt := android.PathForOutput(ctx, configsPath, "vndkprivate.libraries.txt")
+ modulePathTxt := android.PathForOutput(ctx, configsPath, "module_paths.txt")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: vndkCoreTxt,
+ Description: "vndk snapshot vndkcore.libraries.txt",
+ Args: map[string]string{
+ "content": android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
+ },
+ })
+ outputs.configs = append(outputs.configs, vndkCoreTxt)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: vndkPrivateTxt,
+ Description: "vndk snapshot vndkprivate.libraries.txt",
+ Args: map[string]string{
+ "content": android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
+ },
+ })
+ outputs.configs = append(outputs.configs, vndkPrivateTxt)
+
+ var modulePathTxtBuilder strings.Builder
+
+ first := true
+ for lib, dir := range modulePaths(ctx.Config()) {
+ if first {
+ first = false
+ } else {
+ modulePathTxtBuilder.WriteString("\\n")
+ }
+ modulePathTxtBuilder.WriteString(lib)
+ modulePathTxtBuilder.WriteString(".so ")
+ modulePathTxtBuilder.WriteString(dir)
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: modulePathTxt,
+ Description: "vndk snapshot module_paths.txt",
+ Args: map[string]string{
+ "content": modulePathTxtBuilder.String(),
+ },
+ })
+ outputs.configs = append(outputs.configs, modulePathTxt)
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3b77042..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
@@ -176,7 +175,7 @@
// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It is used directly in Soong
// and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make.
-func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) {
+func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byte, error) {
type GlobalJSONConfig struct {
GlobalConfig
@@ -187,21 +186,21 @@
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
}
}
config := GlobalJSONConfig{}
- err := loadConfig(ctx, path, &config)
+ data, err := loadConfig(ctx, path, &config)
if err != nil {
- return config.GlobalConfig, err
+ return config.GlobalConfig, nil, err
}
// Construct paths that require a PathContext.
@@ -214,10 +213,10 @@
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, nil
+ return config.GlobalConfig, data, nil
}
// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which
@@ -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
@@ -241,7 +241,7 @@
config := ModuleJSONConfig{}
- err := loadConfig(ctx, path, &config)
+ _, err := loadConfig(ctx, path, &config)
if err != nil {
return config.ModuleConfig, err
}
@@ -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)
@@ -259,24 +260,24 @@
return config.ModuleConfig, nil
}
-func loadConfig(ctx android.PathContext, path string, config interface{}) error {
+func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) {
r, err := ctx.Fs().Open(path)
if err != nil {
- return err
+ return nil, err
}
defer r.Close()
data, err := ioutil.ReadAll(r)
if err != nil {
- return err
+ return nil, err
}
err = json.Unmarshal(data, config)
if err != nil {
- return err
+ return nil, err
}
- return nil
+ return data, nil
}
func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
@@ -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_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index c72f684..d54ddb1 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -78,7 +78,7 @@
ctx := &pathContext{android.TestConfig(*outDir, nil)}
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
+ globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath)
if err != nil {
fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err)
os.Exit(2)
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/aar.go b/java/aar.go
index 7332e76..65a7c2a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -84,6 +84,7 @@
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
+ sdkLibraries []string
splitNames []string
splits []split
@@ -194,13 +195,15 @@
}
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
+
+ transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ aaptLibs(ctx, sdkContext)
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext,
+ manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex)
a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
@@ -303,7 +306,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
- staticRRODirs []rroDir, deps android.Paths, flags []string) {
+ staticRRODirs []rroDir, deps android.Paths, flags []string, sdkLibraries []string) {
var sharedLibs android.Paths
@@ -322,7 +325,16 @@
switch ctx.OtherModuleDependencyTag(module) {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
- case libTag, frameworkResTag:
+ case libTag:
+ if exportPackage != nil {
+ sharedLibs = append(sharedLibs, exportPackage)
+ }
+
+ if _, ok := module.(SdkLibraryDependency); ok {
+ sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module))
+ }
+
+ case frameworkResTag:
if exportPackage != nil {
sharedLibs = append(sharedLibs, exportPackage)
}
@@ -331,6 +343,7 @@
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
+ sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
outer:
for _, d := range aarDep.ExportedRRODirs() {
@@ -358,8 +371,9 @@
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
+ sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
- return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags
+ return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
}
type AndroidLibrary struct {
@@ -393,6 +407,7 @@
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
+ a.aapt.sdkLibraries = a.exportedSdkLibs
a.aapt.buildActions(ctx, sdkContext(a))
ctx.CheckbuildFile(a.proguardOptionsFile)
@@ -603,10 +618,12 @@
linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
linkDeps = append(linkDeps, a.manifest)
- transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ aaptLibs(ctx, sdkContext(a))
_ = staticLibManifests
_ = staticRRODirs
+ _ = sdkLibraries
linkDeps = append(linkDeps, libDeps...)
linkFlags = append(linkFlags, libFlags...)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 7b378cd..b5921be 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -41,8 +41,18 @@
},
"args", "libs")
+// These two libs are added as optional dependencies (<uses-library> with
+// android:required set to false). This is because they haven't existed in pre-P
+// devices, but classes in them were in bootclasspath jars, etc. So making them
+// hard dependencies (android:required=true) would prevent apps from being
+// installed to such legacy devices.
+var optionalUsesLibs = []string{
+ "android.test.base",
+ "android.test.mock",
+}
+
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex bool) android.Path {
var args []string
@@ -66,7 +76,15 @@
}
if useEmbeddedDex {
- args = append(args, "--use-embedded-dex=true")
+ args = append(args, "--use-embedded-dex")
+ }
+
+ for _, usesLib := range sdkLibraries {
+ if inList(usesLib, optionalUsesLibs) {
+ args = append(args, "--optional-uses-library", usesLib)
+ } else {
+ args = append(args, "--uses-library", usesLib)
+ }
}
var deps android.Paths
diff --git a/java/app.go b/java/app.go
index 849af5b..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"
@@ -85,6 +86,9 @@
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
+ // STL library to use for JNI libraries.
+ Stl *string `android:"arch_variant"`
+
// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
// flag so that they are used from inside the APK at runtime. Defaults to true for android_test modules unless
// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
@@ -116,6 +120,8 @@
aapt
android.OverridableModuleBase
+ usesLibrary usesLibrary
+
certificate Certificate
appProperties appProperties
@@ -149,10 +155,15 @@
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
+ if String(a.appProperties.Stl) == "c++_shared" && a.sdkVersion() == "" {
+ ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
+ }
+
if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
a.aapt.deps(ctx, sdkContext(a))
}
+ embedJni := a.shouldEmbedJnis(ctx)
for _, jniTarget := range ctx.MultiTargets() {
variation := []blueprint.Variation{
{Mutator: "arch", Variation: jniTarget.String()},
@@ -162,8 +173,17 @@
target: jniTarget,
}
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
+ if String(a.appProperties.Stl) == "c++_shared" {
+ if embedJni {
+ ctx.AddFarVariationDependencies(variation, tag, "libc++")
+ }
+ }
}
+ a.usesLibrary.deps(ctx, Bool(a.properties.No_framework_libs))
+}
+
+func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
cert := android.SrcIsModule(a.getCertString(ctx))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
@@ -215,6 +235,11 @@
return shouldUncompressDex(ctx, &a.dexpreopter)
}
+func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
+ return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+ a.appProperties.AlwaysPackageNativeLibs
+}
+
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
@@ -256,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...)
@@ -288,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" {
@@ -303,9 +337,7 @@
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
var jniJarFile android.WritablePath
if len(jniLibs) > 0 {
- embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
- a.appProperties.AlwaysPackageNativeLibs
- if embedJni {
+ if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
} else {
@@ -350,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)
@@ -373,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)
}
@@ -465,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()
@@ -541,6 +581,7 @@
&module.appProperties,
&module.appTestProperties,
&module.overridableAppProperties,
+ &module.usesLibrary.usesLibraryProperties,
&module.testProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -581,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)
@@ -632,7 +674,7 @@
m := &OverrideAndroidApp{}
m.AddProperties(&overridableAppProperties{})
- android.InitAndroidModule(m)
+ android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
android.InitOverrideModule(m)
return m
}
@@ -648,6 +690,8 @@
certificate *Certificate
dexpreopter
+
+ usesLibrary usesLibrary
}
type AndroidAppImportProperties struct {
@@ -735,6 +779,8 @@
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
+
+ a.usesLibrary.deps(ctx, false)
}
func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
@@ -764,6 +810,19 @@
return shouldUncompressDex(ctx, &a.dexpreopter)
}
+func (a *AndroidAppImport) uncompressDex(
+ ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+ rule := android.NewRuleBuilder()
+ rule.Command().
+ Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, inputPath).
+ Tool(ctx.Config().HostToolPath(ctx, "zip2zip")).
+ FlagWithInput("-i ", inputPath).
+ FlagWithOutput("-o ", outputPath).
+ FlagWithArg("-0 ", "'classes*.dex'").
+ Textf(`; else cp -f %s %s; fi`, inputPath, outputPath)
+ rule.Build(pctx, ctx, "uncompress-dex", "Uncompress dex files")
+}
+
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
@@ -777,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
@@ -790,7 +854,18 @@
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")
+ a.uncompressDex(ctx, dexOutput, dexUncompressed.OutputPath)
+ dexOutput = dexUncompressed
+ }
// Sign or align the package
// TODO: Handle EXTERNAL
@@ -830,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..348c8b4 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -31,7 +31,7 @@
var (
Signapk = pctx.AndroidStaticRule("signapk",
blueprint.RuleParams{
- Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
+ Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
`-jar $signapkCmd $flags $certificates $in $out`,
CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
},
@@ -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 bc35e21..559afcc 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -881,7 +881,7 @@
name: "foo",
srcs: ["a.java"],
certificate: "expiredkey",
- overrides: ["baz"],
+ overrides: ["qux"],
}
override_android_app {
@@ -903,6 +903,7 @@
`)
expectedVariants := []struct {
+ moduleName string
variantName string
apkName string
apkPath string
@@ -911,24 +912,27 @@
aaptFlag string
}{
{
+ moduleName: "foo",
variantName: "android_common",
apkPath: "/target/product/test_device/system/app/foo/foo.apk",
signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- overrides: []string{"baz"},
+ overrides: []string{"qux"},
aaptFlag: "",
},
{
- variantName: "bar_android_common",
+ moduleName: "bar",
+ variantName: "android_common_bar",
apkPath: "/target/product/test_device/system/app/bar/bar.apk",
signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
- overrides: []string{"baz", "foo"},
+ overrides: []string{"qux", "foo"},
aaptFlag: "",
},
{
- variantName: "baz_android_common",
+ moduleName: "baz",
+ variantName: "android_common_baz",
apkPath: "/target/product/test_device/system/app/baz/baz.apk",
signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- overrides: []string{"baz", "foo"},
+ overrides: []string{"qux", "foo"},
aaptFlag: "--rename-manifest-package org.dandroid.bp",
},
}
@@ -972,6 +976,47 @@
}
}
+func TestOverrideAndroidAppDependency(t *testing.T) {
+ ctx := testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ package_name: "org.dandroid.bp",
+ }
+
+ android_test {
+ name: "baz",
+ srcs: ["b.java"],
+ instrumentation_for: "foo",
+ }
+
+ android_test {
+ name: "qux",
+ srcs: ["b.java"],
+ instrumentation_for: "bar",
+ }
+ `)
+
+ // Verify baz, which depends on the overridden module foo, has the correct classpath javac arg.
+ javac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+ fooTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
+ if !strings.Contains(javac.Args["classpath"], fooTurbine) {
+ t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine)
+ }
+
+ // Verify qux, which depends on the overriding module bar, has the correct classpath javac arg.
+ javac = ctx.ModuleForTests("qux", "android_common").Rule("javac")
+ barTurbine := filepath.Join(buildDir, ".intermediates", "foo", "android_common_bar", "turbine-combined", "foo.jar")
+ if !strings.Contains(javac.Args["classpath"], barTurbine) {
+ t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
+ }
+}
+
func TestAndroidAppImport(t *testing.T) {
ctx := testJava(t, `
android_app_import {
@@ -1133,3 +1178,144 @@
}
}
}
+
+func TestStl(t *testing.T) {
+ ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+ cc_library {
+ name: "libjni",
+ }
+
+ android_test {
+ name: "stl",
+ jni_libs: ["libjni"],
+ compile_multilib: "both",
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ android_test {
+ name: "system",
+ jni_libs: ["libjni"],
+ compile_multilib: "both",
+ sdk_version: "current",
+ }
+ `)
+
+ testCases := []struct {
+ name string
+ jnis []string
+ }{
+ {"stl",
+ []string{
+ "libjni.so",
+ "libc++.so",
+ },
+ },
+ {"system",
+ []string{
+ "libjni.so",
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ app := ctx.ModuleForTests(test.name, "android_common")
+ jniLibZip := app.Output("jnilibs.zip")
+ var jnis []string
+ args := strings.Fields(jniLibZip.Args["jarArgs"])
+ for i := 0; i < len(args); i++ {
+ if args[i] == "-f" {
+ jnis = append(jnis, args[i+1])
+ i += 1
+ }
+ }
+ jnisJoined := strings.Join(jnis, " ")
+ for _, jni := range test.jnis {
+ if !strings.Contains(jnisJoined, jni) {
+ t.Errorf("missing jni %q in %q", jni, jnis)
+ }
+ }
+ })
+ }
+}
+
+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/builder.go b/java/builder.go
index d257d1d..e1a912b 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -43,7 +43,8 @@
Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
- `${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
+ `${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ` +
+ `${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
`-source $javaVersion -target $javaVersion ` +
`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
@@ -64,7 +65,7 @@
turbine = pctx.AndroidStaticRule("turbine",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `${config.JavaCmd} -jar ${config.TurbineJar} --output $out.tmp ` +
+ `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` +
`--temp_dir "$outDir" --sources @$out.rsp --source_jars $srcJars ` +
`--javacopts ${config.CommonJdkFlags} ` +
`$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` +
@@ -108,7 +109,7 @@
jarjar = pctx.AndroidStaticRule("jarjar",
blueprint.RuleParams{
- Command: "${config.JavaCmd} -jar ${config.JarjarCmd} process $rulesFile $in $out",
+ Command: "${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JarjarCmd} process $rulesFile $in $out",
CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
},
"rulesFile")
@@ -124,7 +125,7 @@
jetifier = pctx.AndroidStaticRule("jetifier",
blueprint.RuleParams{
- Command: "${config.JavaCmd} -jar ${config.JetifierJar} -l error -o $out -i $in",
+ Command: "${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JetifierJar} -l error -o $out -i $in",
CommandDeps: []string{"${config.JavaCmd}", "${config.JetifierJar}"},
},
)
diff --git a/java/config/config.go b/java/config/config.go
index 46cd361..529f1e6 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -69,6 +69,8 @@
// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
`-XDstringConcat=inline`,
}, " "))
+ pctx.StaticVariable("JavaVmFlags", "-XX:OnError=\"cat hs_err_pid%p.log\"")
+ pctx.StaticVariable("JavacVmFlags", "-J-XX:OnError=\"cat hs_err_pid%p.log\"")
pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
@@ -142,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 6881caf..ead298a 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -39,8 +39,8 @@
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
- ctx.Strict("JAVA", "${JavaCmd}")
- ctx.Strict("JAVAC", "${JavacCmd}")
+ ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
+ ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
ctx.Strict("JAR", "${JarCmd}")
ctx.Strict("JAR_ARGS", "${JarArgsCmd}")
ctx.Strict("JAVADOC", "${JavadocCmd}")
@@ -58,8 +58,8 @@
ctx.Strict("ERROR_PRONE_CHECKS", "${ErrorProneChecks}")
}
- ctx.Strict("TARGET_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
- ctx.Strict("HOST_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
+ ctx.Strict("TARGET_JAVAC", "${JavacCmd} ${JavacVmFlags} ${CommonJdkFlags}")
+ ctx.Strict("HOST_JAVAC", "${JavacCmd} ${JavacVmFlags} ${CommonJdkFlags}")
ctx.Strict("JLINK", "${JlinkCmd}")
ctx.Strict("JMOD", "${JmodCmd}")
@@ -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/device_host_converter.go b/java/device_host_converter.go
index b92f4d7..030b010 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -53,7 +53,7 @@
// java_device_for_host makes the classes.jar output of a device java_library module available to host
// java_library modules.
//
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
func DeviceForHostFactory() android.Module {
module := &DeviceForHost{}
@@ -70,7 +70,7 @@
// java_host_for_device makes the classes.jar output of a host java_library module available to device
// java_library modules.
//
-// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
func HostForDeviceFactory() android.Module {
module := &HostForDevice{}
@@ -126,7 +126,7 @@
if len(d.headerJars) > 1 {
outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, outputFile, "turbine combine", d.headerJars,
- android.OptionalPath{}, false, nil, nil)
+ android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"})
d.combinedHeaderJar = outputFile
} else {
d.combinedHeaderJar = d.headerJars[0]
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/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f48428f..2a1a901 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -115,6 +115,8 @@
type dexpreoptBootJars struct {
defaultBootImage *bootImage
otherImages []*bootImage
+
+ dexpreoptConfigForMake android.WritablePath
}
// dexpreoptBoot singleton rules
@@ -123,6 +125,9 @@
return
}
+ d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
+ writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
+
global := dexpreoptGlobalConfig(ctx)
// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@@ -453,8 +458,24 @@
}
+func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
+ data := dexpreoptGlobalConfigRaw(ctx).data
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: path,
+ Args: map[string]string{
+ "content": string(data),
+ },
+ })
+}
+
// Export paths for default boot image to Make
func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
+ if d.dexpreoptConfigForMake != nil {
+ ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
+ }
+
image := d.defaultBootImage
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 270fcb4..d903f45 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,40 +15,50 @@
package java
import (
- "android/soong/android"
- "android/soong/dexpreopt"
"path/filepath"
"strings"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
)
// dexpreoptGlobalConfig returns the global dexpreopt.config. It is loaded once the first time it is called for any
// ctx.Config(), and returns the same data for all future calls with the same ctx.Config(). A value can be inserted
// for tests using setDexpreoptTestGlobalConfig.
func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
+ return dexpreoptGlobalConfigRaw(ctx).global
+}
+
+type globalConfigAndRaw struct {
+ global dexpreopt.GlobalConfig
+ data []byte
+}
+
+func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
ctx.AddNinjaFileDeps(f)
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f)
+ globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f)
if err != nil {
panic(err)
}
- return globalConfig
+ return globalConfigAndRaw{globalConfig, data}
}
// No global config filename set, see if there is a test config set
return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
// Nope, return a config with preopting disabled
- return dexpreopt.GlobalConfig{
+ return globalConfigAndRaw{dexpreopt.GlobalConfig{
DisablePreopt: true,
- }
+ }, nil}
})
- }).(dexpreopt.GlobalConfig)
+ }).(globalConfigAndRaw)
}
// setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return. It must
// be called before the first call to dexpreoptGlobalConfig for the config.
func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
- config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig })
+ config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
}
var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 4af2f5c..7d0109f 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -52,14 +52,26 @@
}`,
enabled: true,
},
-
{
name: "app without sources",
bp: `
android_app {
name: "foo",
}`,
- // TODO(ccross): this should probably be false
+ enabled: false,
+ },
+ {
+ name: "app with libraries",
+ bp: `
+ android_app {
+ name: "foo",
+ static_libs: ["lib"],
+ }
+
+ java_library {
+ name: "lib",
+ srcs: ["a.java"],
+ }`,
enabled: true,
},
{
@@ -69,10 +81,8 @@
name: "foo",
installable: true,
}`,
- // TODO(ccross): this should probably be false
- enabled: true,
+ enabled: false,
},
-
{
name: "static java library",
bp: `
diff --git a/java/droiddoc.go b/java/droiddoc.go
index fd7e2a4..b41825e 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -73,7 +73,7 @@
Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
+ `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
`$opts && ` +
`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
@@ -95,7 +95,7 @@
blueprint.RuleParams{
Command: `( rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
+ `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.MetalavaJar} -encoding UTF-8 -source $javaVersion @$out.rsp @$srcJarDir/list ` +
`$bootclasspathArgs $classpathArgs $sourcepathArgs --no-banner --color --quiet --format=v2 ` +
`$opts && touch $out && rm -rf "$srcJarDir") || ` +
`( echo -e "$msg" ; exit 38 )`,
@@ -120,7 +120,7 @@
Command: `rm -rf "$outDir" "$srcJarDir" "$stubsDir" && ` +
`mkdir -p "$outDir" "$srcJarDir" "$stubsDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.JavaCmd} -jar ${config.DokkaJar} $srcJarDir ` +
+ `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.DokkaJar} $srcJarDir ` +
`$classpathArgs -format dac -dacRoot /reference/kotlin -output $outDir $opts && ` +
`${config.SoongZipCmd} -write_if_changed -d -o $docZip -C $outDir -D $outDir && ` +
`${config.SoongZipCmd} -write_if_changed -jar -o $out -C $stubsDir -D $stubsDir && ` +
@@ -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/jacoco.go b/java/jacoco.go
index 8b6d4ac..bce9822 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -31,7 +31,7 @@
jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
Command: `rm -rf $tmpDir && mkdir -p $tmpDir && ` +
`${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
- `${config.JavaCmd} -jar ${config.JacocoCLIJar} ` +
+ `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JacocoCLIJar} ` +
` instrument --quiet --dest $tmpDir $strippedJar && ` +
`${config.Ziptime} $tmpJar && ` +
`${config.MergeZipsCmd} --ignore-duplicates -j $out $tmpJar $in`,
diff --git a/java/java.go b/java/java.go
index 1c455f9..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 {
@@ -517,7 +518,8 @@
if j.hasSrcExt(".kt") {
// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
// Kotlin files
- ctx.AddVariationDependencies(nil, kotlinStdlibTag, "kotlin-stdlib")
+ ctx.AddVariationDependencies(nil, kotlinStdlibTag,
+ "kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
if len(j.properties.Plugins) > 0 {
ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
}
@@ -639,7 +641,7 @@
switch {
case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
name == "stub-annotations" || name == "private-stub-annotations-jar" ||
- name == "core-lambda-stubs":
+ name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
return javaCore, true
case ver == "core_current":
return javaCore, false
@@ -793,7 +795,7 @@
deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage)
}
case kotlinStdlibTag:
- deps.kotlinStdlib = dep.HeaderJars()
+ deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
case kotlinAnnotationsTag:
deps.kotlinAnnotations = dep.HeaderJars()
}
@@ -854,7 +856,7 @@
ret = javaVersion
} else if ctx.Device() && sdk <= 23 {
ret = "1.7"
- } else if ctx.Device() && sdk <= 28 || !ctx.Config().TargetOpenJDK9() {
+ } else if ctx.Device() && sdk <= 29 || !ctx.Config().TargetOpenJDK9() {
ret = "1.8"
} else if ctx.Device() && sdkContext.sdkVersion() != "" && sdk == android.FutureApiLevel {
// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
@@ -962,7 +964,9 @@
return flags
}
-func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
+func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
+
+ hasSrcs := false
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
@@ -978,10 +982,15 @@
}
srcFiles = j.genSources(ctx, srcFiles, flags)
+ if len(srcFiles) > 0 {
+ hasSrcs = true
+ }
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
- srcJars = append(srcJars, extraSrcJars...)
+ if aaptSrcJar != nil {
+ srcJars = append(srcJars, aaptSrcJar)
+ }
// Collect source files from compiledJavaSrcs, compiledSrcJars and filter out Exclude_srcs
// that IDEInfo struct will use
@@ -1170,7 +1179,10 @@
j.resourceJar = resourceJars[0]
}
- jars = append(jars, deps.staticJars...)
+ if len(deps.staticJars) > 0 {
+ jars = append(jars, deps.staticJars...)
+ hasSrcs = true
+ }
manifest := j.overrideManifest
if !manifest.Valid() && j.properties.Manifest != nil {
@@ -1281,7 +1293,8 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
+ if ctx.Device() && hasSrcs &&
+ (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
// Dex compilation
var dexOutputFile android.ModuleOutPath
dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
@@ -1289,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 {
@@ -1380,7 +1395,7 @@
// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
- false, nil, []string{"META-INF"})
+ false, nil, []string{"META-INF/TRANSITIVE"})
headerJar = combinedJar
if j.expandJarjarRules != nil {
@@ -1515,7 +1530,7 @@
j.dexpreopter.isInstallable = Bool(j.properties.Installable)
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
- j.compile(ctx)
+ j.compile(ctx, nil)
if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
diff --git a/java/java_test.go b/java/java_test.go
index 3d8baee..3a7ed4e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -93,10 +93,10 @@
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(android.RegisterOverridePreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
})
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
@@ -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,
@@ -1007,8 +1009,8 @@
}
`
- t.Run("1.8", func(t *testing.T) {
- // Test default javac 1.8
+ t.Run("Java language level 8", func(t *testing.T) {
+ // Test default javac -source 1.8 -target 1.8
ctx := testJava(t, bp)
checkPatchModuleFlag(t, ctx, "foo", "")
@@ -1016,9 +1018,9 @@
checkPatchModuleFlag(t, ctx, "baz", "")
})
- t.Run("1.9", func(t *testing.T) {
- // Test again with javac 1.9
- config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ t.Run("Java language level 9", func(t *testing.T) {
+ // Test again with javac -source 9 -target 9
+ config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
ctx := testContext(config, bp, nil)
run(t, ctx, config)
diff --git a/java/kotlin.go b/java/kotlin.go
index 54c6b0e..33167ba 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -18,6 +18,7 @@
"bytes"
"encoding/base64"
"encoding/binary"
+ "path/filepath"
"strings"
"android/soong/android"
@@ -30,7 +31,7 @@
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@@ -50,7 +51,8 @@
Rspfile: "$out.rsp",
RspfileContent: `$in`,
},
- "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir")
+ "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile",
+ "emptyDir", "name")
// kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -61,6 +63,9 @@
deps = append(deps, flags.kotlincClasspath...)
deps = append(deps, srcJars...)
+ kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+ kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
ctx.Build(pctx, android.BuildParams{
Rule: kotlinc,
Description: "kotlinc",
@@ -77,6 +82,7 @@
"emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
// http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
"kotlinJvmTarget": "1.8",
+ "name": kotlinName,
},
})
}
@@ -85,7 +91,7 @@
blueprint.RuleParams{
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -111,7 +117,7 @@
RspfileContent: `$in`,
},
"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
- "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile")
+ "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name")
// kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs
// annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be
@@ -138,6 +144,9 @@
{"-target", flags.javaVersion},
})
+ kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
+ kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+
ctx.Build(pctx, android.BuildParams{
Rule: kapt,
Description: "kapt",
@@ -154,6 +163,7 @@
"kaptProcessor": kaptProcessor,
"kaptDir": android.PathForModuleOut(ctx, "kapt/gen").String(),
"encodedJavacFlags": encodedJavacFlags,
+ "name": kotlinName,
},
})
}
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/sdk_library.go b/java/sdk_library.go
index 72c5cfc..5b65c0c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -126,6 +126,9 @@
// If set to true, the path of dist files is apistubs/core. Defaults to false.
Core_lib *bool
+ // don't create dist rules.
+ No_dist *bool `blueprint:"mutated"`
+
// TODO: determines whether to create HTML doc or not
//Html_doc *bool
}
@@ -212,52 +215,54 @@
android.WriteAndroidMkData(w, data)
module.Library.AndroidMkHostDex(w, name, data)
- // Create a phony module that installs the impl library, for the case when this lib is
- // in PRODUCT_PACKAGES.
- owner := module.ModuleBase.Owner()
- if owner == "" {
- if Bool(module.sdkLibraryProperties.Core_lib) {
- owner = "core"
- } else {
- owner = "android"
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ // Create a phony module that installs the impl library, for the case when this lib is
+ // in PRODUCT_PACKAGES.
+ owner := module.ModuleBase.Owner()
+ if owner == "" {
+ if Bool(module.sdkLibraryProperties.Core_lib) {
+ owner = "core"
+ } else {
+ owner = "android"
+ }
}
- }
- // Create dist rules to install the stubs libs to the dist dir
- if len(module.publicApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "public",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.systemApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "system",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.testApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "test",
- module.BaseModuleName()+".jar")+")")
- }
- if module.publicApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "public", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.systemApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "system", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.testApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "test", "api",
- module.BaseModuleName()+".txt")+")")
+ // Create dist rules to install the stubs libs to the dist dir
+ if len(module.publicApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "public",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.systemApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "system",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.testApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "test",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if module.publicApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "public", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.systemApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "system", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.testApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "test", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
}
}
return data
@@ -641,6 +646,10 @@
}
}
+func (module *SdkLibrary) SetNoDist() {
+ module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true)
+}
+
var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
func javaSdkLibraries(config android.Config) *[]string {
diff --git a/java/sdk_test.go b/java/sdk_test.go
index e446129..cc4da2e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -272,8 +272,8 @@
}
}
- t.Run("1.8", func(t *testing.T) {
- // Test default javac 1.8
+ t.Run("Java language level 8", func(t *testing.T) {
+ // Test default javac -source 1.8 -target 1.8
config := testConfig(nil)
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
@@ -299,9 +299,9 @@
}
})
- // Test again with javac 1.9
- t.Run("1.9", func(t *testing.T) {
- config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ // Test again with javac -source 9 -target 9
+ t.Run("Java language level 9", func(t *testing.T) {
+ config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
}
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 1be3768..fc7842d 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -44,6 +44,8 @@
"core.current.stubs",
"core.platform.api.stubs",
"kotlin-stdlib",
+ "kotlin-stdlib-jdk7",
+ "kotlin-stdlib-jdk8",
"kotlin-annotations",
}
@@ -75,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 4f3e0de..8021e55 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -65,18 +65,6 @@
warnings: []string{"overriding commands for target"},
},
{
- name: "BUILD_BROKEN_ANDROIDMK_EXPORTS",
- behavior: DefaultDeprecated,
- warnings: []string{"export_keyword"},
- },
- {
- name: "BUILD_BROKEN_ENG_DEBUG_TAGS",
- behavior: DefaultDeprecated,
- warnings: []string{
- "Changes.md#LOCAL_MODULE_TAGS",
- },
- },
- {
name: "BUILD_BROKEN_USES_NETWORK",
behavior: DefaultDeprecated,
},
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
index 1e03f72..177ca1b 100755
--- a/scripts/gen-kotlin-build-file.sh
+++ b/scripts/gen-kotlin-build-file.sh
@@ -17,7 +17,7 @@
# Generates kotlinc module xml file to standard output based on rsp files
if [[ -z "$1" ]]; then
- echo "usage: $0 <classpath> <outDir> <rspFiles>..." >&2
+ echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
exit 1
fi
@@ -27,8 +27,9 @@
fi;
classpath=$1
-out_dir=$2
-shift 2
+name=$2
+out_dir=$3
+shift 3
# Path in the build file may be relative to the build file, we need to make them
# absolute
@@ -44,7 +45,7 @@
}
# Print preamble
-echo "<modules><module name=\"name\" type=\"java-production\" outputDir=\"${out_dir}\">"
+echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
# Print classpath entries
for file in $(echo "$classpath" | tr ":" "\n"); do
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 4ad9afa..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
@@ -231,7 +231,7 @@
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
- manifest_fixer.add_uses_libraries(doc, new_uses_libraries)
+ manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
output = StringIO.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -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/scripts/strip.sh b/scripts/strip.sh
index 0f77da8..bd62619 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -28,6 +28,7 @@
# --add-gnu-debuglink
# --keep-mini-debug-info
# --keep-symbols
+# --keep-symbols-and-debug-frame
# --use-gnu-strip
# --remove-build-id
@@ -39,11 +40,12 @@
cat <<EOF
Usage: strip.sh [options] -k symbols -i in-file -o out-file -d deps-file
Options:
- --add-gnu-debuglink Add a gnu-debuglink section to out-file
- --keep-mini-debug-info Keep compressed debug info in out-file
- --keep-symbols Keep symbols in out-file
- --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
- --remove-build-id Remove the gnu build-id section in out-file
+ --add-gnu-debuglink Add a gnu-debuglink section to out-file
+ --keep-mini-debug-info Keep compressed debug info in out-file
+ --keep-symbols Keep symbols in out-file
+ --keep-symbols-and-debug-frame Keep symbols and .debug_frame in out-file
+ --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
+ --remove-build-id Remove the gnu build-id section in out-file
EOF
exit 1
}
@@ -63,6 +65,15 @@
fi
}
+do_strip_keep_symbols_and_debug_frame() {
+ REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {if ($2 != ".debug_frame") {print "--remove-section " $2}}' | xargs`
+ if [ -z "${use_gnu_strip}" ]; then
+ "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+ else
+ "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
+ fi
+}
+
do_strip_keep_symbols() {
REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
if [ -z "${use_gnu_strip}" ]; then
@@ -148,6 +159,7 @@
add-gnu-debuglink) add_gnu_debuglink=true ;;
keep-mini-debug-info) keep_mini_debug_info=true ;;
keep-symbols) keep_symbols=true ;;
+ keep-symbols-and-debug-frame) keep_symbols_and_debug_frame=true ;;
remove-build-id) remove_build_id=true ;;
use-gnu-strip) use_gnu_strip=true ;;
*) echo "Unknown option --${OPTARG}"; usage ;;
@@ -177,6 +189,16 @@
usage
fi
+if [ ! -z "${keep_symbols}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+ echo "--keep-symbols and --keep-symbols-and-debug-frame cannot be used together"
+ usage
+fi
+
+if [ ! -z "${keep_mini_debug_info}" -a ! -z "${keep_symbols_and_debug_frame}" ]; then
+ echo "--keep-symbols-mini-debug-info and --keep-symbols-and-debug-frame cannot be used together"
+ usage
+fi
+
if [ ! -z "${symbols_to_keep}" -a ! -z "${keep_symbols}" ]; then
echo "--keep-symbols and -k cannot be used together"
usage
@@ -195,6 +217,8 @@
do_strip_keep_symbol_list
elif [ ! -z "${keep_mini_debug_info}" ]; then
do_strip_keep_mini_debug_info
+elif [ ! -z "${keep_symbols_and_debug_frame}" ]; then
+ do_strip_keep_symbols_and_debug_frame
else
do_strip
fi
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 0313ecd..3f2709e 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -72,6 +72,7 @@
&m.syspropLibraryProperties,
)
m.InitSdkLibraryProperties()
+ m.SetNoDist()
android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
android.AddLoadHook(m, func(ctx android.LoadHookContext) { m.SdkLibrary.CreateInternalModules(ctx) })
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index c6e5ddc..4335667 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -205,8 +205,6 @@
// Not used, but useful to be in the soong.log
"BOARD_VNDK_VERSION",
- "BUILD_BROKEN_ANDROIDMK_EXPORTS",
- "BUILD_BROKEN_ENG_DEBUG_TAGS",
"DEFAULT_WARNING_BUILD_MODULE_TYPES",
"DEFAULT_ERROR_BUILD_MODULE_TYPES",
diff --git a/ui/build/proc_sync.go b/ui/build/proc_sync.go
index 857786d..0cfe798 100644
--- a/ui/build/proc_sync.go
+++ b/ui/build/proc_sync.go
@@ -34,6 +34,14 @@
if err != nil {
ctx.Logger.Fatal(err)
}
+ lockfilePollDuration := time.Second
+ lockfileTimeout := time.Second * 10
+ if envTimeout := os.Getenv("SOONG_LOCK_TIMEOUT"); envTimeout != "" {
+ lockfileTimeout, err = time.ParseDuration(envTimeout)
+ if err != nil {
+ ctx.Logger.Fatalf("failure parsing SOONG_LOCK_TIMEOUT %q: %s", envTimeout, err)
+ }
+ }
err = lockSynchronous(*lockingInfo, newSleepWaiter(lockfilePollDuration, lockfileTimeout), ctx.Logger)
if err != nil {
ctx.Logger.Fatal(err)
@@ -41,9 +49,6 @@
return lockingInfo
}
-var lockfileTimeout = time.Second * 10
-var lockfilePollDuration = time.Second
-
type lockable interface {
tryLock() error
Unlock() error
@@ -80,15 +85,18 @@
return nil
}
- waited = true
-
done, description := waiter.checkDeadline()
+ if !waited {
+ logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
+ }
+
+ waited = true
+
if done {
return fmt.Errorf("Tried to lock %s, but timed out %s . Make sure no other Soong process is using it",
lock.description(), waiter.summarize())
} else {
- logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
waiter.wait()
}
}