Merge "Add static_libs field to target.vendor"
diff --git a/Android.bp b/Android.bp
index 0382ee2..2a4653a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -36,6 +36,7 @@
"blueprint",
"blueprint-bootstrap",
"soong",
+ "soong-android-soongconfig",
"soong-env",
"soong-shared",
],
@@ -73,6 +74,7 @@
"android/sdk.go",
"android/sh_binary.go",
"android/singleton.go",
+ "android/soong_config_modules.go",
"android/testing.go",
"android/util.go",
"android/variable.go",
@@ -101,6 +103,7 @@
"android/prebuilt_test.go",
"android/prebuilt_etc_test.go",
"android/rule_builder_test.go",
+ "android/soong_config_modules_test.go",
"android/util_test.go",
"android/variable_test.go",
"android/visibility_test.go",
@@ -109,6 +112,20 @@
}
bootstrap_go_package {
+ name: "soong-android-soongconfig",
+ pkgPath: "android/soong/android/soongconfig",
+ deps: [
+ "blueprint",
+ "blueprint-parser",
+ "blueprint-proptools",
+ ],
+ srcs: [
+ "android/soongconfig/config.go",
+ "android/soongconfig/modules.go",
+ ],
+}
+
+bootstrap_go_package {
name: "soong-cc-config",
pkgPath: "android/soong/cc/config",
deps: [
@@ -169,14 +186,15 @@
"cc/rs.go",
"cc/sanitize.go",
"cc/sabi.go",
+ "cc/snapshot_utils.go",
"cc/stl.go",
"cc/strip.go",
"cc/sysprop.go",
"cc/tidy.go",
"cc/util.go",
+ "cc/vendor_snapshot.go",
"cc/vndk.go",
"cc/vndk_prebuilt.go",
- "cc/xom.go",
"cc/cflag_artifacts.go",
"cc/cmakelists.go",
@@ -186,6 +204,7 @@
"cc/linker.go",
"cc/binary.go",
+ "cc/binary_sdk_member.go",
"cc/fuzz.go",
"cc/library.go",
"cc/library_sdk_member.go",
@@ -473,6 +492,7 @@
],
testSrcs: [
"apex/apex_test.go",
+ "apex/vndk_test.go",
],
pluginFor: ["soong_build"],
}
@@ -548,6 +568,7 @@
name: "libatomic",
defaults: ["linux_bionic_supported"],
vendor_available: true,
+ ramdisk_available: true,
recovery_available: true,
native_bridge_supported: true,
@@ -594,8 +615,10 @@
name: "libgcc_stripped",
defaults: ["linux_bionic_supported"],
vendor_available: true,
+ ramdisk_available: true,
recovery_available: true,
native_bridge_supported: true,
+ sdk_version: "current",
arch: {
arm: {
diff --git a/README.md b/README.md
index b6fda50..b1bb425 100644
--- a/README.md
+++ b/README.md
@@ -376,36 +376,14 @@
be resolved by hand to a single module with any differences inside
`target: { android: { }, host: { } }` blocks.
-## Build logic
+### Conditionals
-The build logic is written in Go using the
-[blueprint](http://godoc.org/github.com/google/blueprint) framework. Build
-logic receives module definitions parsed into Go structures using reflection
-and produces build rules. The build rules are collected by blueprint and
-written to a [ninja](http://ninja-build.org) build file.
-
-## Other documentation
-
-* [Best Practices](docs/best_practices.md)
-* [Build Performance](docs/perf.md)
-* [Generating CLion Projects](docs/clion.md)
-* [Generating YouCompleteMe/VSCode compile\_commands.json file](docs/compdb.md)
-* Make-specific documentation: [build/make/README.md](https://android.googlesource.com/platform/build/+/master/README.md)
-
-## FAQ
-
-### How do I write conditionals?
-
-Soong deliberately does not support conditionals in Android.bp files. We
+Soong deliberately does not support most conditionals in Android.bp files. We
suggest removing most conditionals from the build. See
[Best Practices](docs/best_practices.md#removing-conditionals) for some
examples on how to remove conditionals.
-In cases where build time conditionals are unavoidable, complexity in build
-rules that would require conditionals are handled in Go through Soong plugins.
-This allows Go language features to be used for better readability and
-testability, and implicit dependencies introduced by conditionals can be
-tracked. Most conditionals supported natively by Soong are converted to a map
+Most conditionals supported natively by Soong are converted to a map
property. When building the module one of the properties in the map will be
selected, and its values appended to the property with the same name at the
top level of the module.
@@ -430,6 +408,106 @@
be built. When building for x86 the `generic.cpp` and 'x86.cpp' sources will
be built.
+#### Soong Config Variables
+
+When converting vendor modules that contain conditionals, simple conditionals
+can be supported through Soong config variables using `soong_config_*`
+modules that describe the module types, variables and possible values:
+
+```
+soong_config_module_type {
+ name: "acme_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "acme",
+ variables: ["board", "feature"],
+ properties: ["cflags", "srcs"],
+}
+
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b"],
+}
+
+soong_config_bool_variable {
+ name: "feature",
+}
+```
+
+This example describes a new `acme_cc_defaults` module type that extends the
+`cc_defaults` module type, with two additional conditionals based on variables
+`board` and `feature`, which can affect properties `cflags` and `srcs`.
+
+The values of the variables can be set from a product's `BoardConfig.mk` file:
+```
+SOONG_CONFIG_NAMESPACES += acme
+SOONG_CONFIG_acme += \
+ board \
+ feature \
+
+SOONG_CONFIG_acme_board := soc_a
+SOONG_CONFIG_acme_feature := true
+```
+
+The `acme_cc_defaults` module type can be used anywhere after the definition in
+the file where it is defined, or can be imported into another file with:
+```
+soong_config_module_type_import {
+ from: "device/acme/Android.bp",
+ module_types: ["acme_cc_defaults"],
+}
+```
+
+It can used like any other module type:
+```
+acme_cc_defaults {
+ name: "acme_defaults",
+ cflags: ["-DGENERIC"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ },
+ feature: {
+ cflags: ["-DFEATURE"],
+ },
+ },
+}
+
+cc_library {
+ name: "libacme_foo",
+ defaults: ["acme_defaults"],
+ srcs: ["*.cpp"],
+}
+```
+
+With the `BoardConfig.mk` snippet above, libacme_foo would build with
+cflags "-DGENERIC -DSOC_A -DFEATURE".
+
+`soong_config_module_type` modules will work best when used to wrap defaults
+modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
+by all of the vendor's other modules using the normal namespace and visibility
+rules.
+
+## Build logic
+
+The build logic is written in Go using the
+[blueprint](http://godoc.org/github.com/google/blueprint) framework. Build
+logic receives module definitions parsed into Go structures using reflection
+and produces build rules. The build rules are collected by blueprint and
+written to a [ninja](http://ninja-build.org) build file.
+
+## Other documentation
+
+* [Best Practices](docs/best_practices.md)
+* [Build Performance](docs/perf.md)
+* [Generating CLion Projects](docs/clion.md)
+* [Generating YouCompleteMe/VSCode compile\_commands.json file](docs/compdb.md)
+* Make-specific documentation: [build/make/README.md](https://android.googlesource.com/platform/build/+/master/README.md)
+
## Developing for Soong
To load Soong code in a Go-aware IDE, create a directory outside your android tree and then:
diff --git a/android/apex.go b/android/apex.go
index 0b901ae..43a42df 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,14 @@
"sync"
)
+type ApexInfo struct {
+ // Name of the apex variant that this module is mutated into
+ ApexName string
+
+ // Whether this apex variant needs to target Android 10
+ LegacyAndroid10Support bool
+}
+
// ApexModule is the interface that a module type is expected to implement if
// the module has to be built differently depending on whether the module
// is destined for an apex or not (installed to one of the regular partitions).
@@ -38,9 +46,12 @@
Module
apexModuleBase() *ApexModuleBase
- // Marks that this module should be built for the APEX of the specified name.
+ // Marks that this module should be built for the specified APEXes.
// Call this before apex.apexMutator is run.
- BuildForApex(apexName string)
+ BuildForApexes(apexes []ApexInfo)
+
+ // Returns the APEXes that this module will be built for
+ ApexVariations() []ApexInfo
// Returns the name of APEX that this module will be built for. Empty string
// is returned when 'IsForPlatform() == true'. Note that a module can be
@@ -66,13 +77,9 @@
IsInstallableToApex() bool
// Mutate this module into one or more variants each of which is built
- // for an APEX marked via BuildForApex().
+ // for an APEX marked via BuildForApexes().
CreateApexVariations(mctx BottomUpMutatorContext) []Module
- // Sets the name of the apex variant of this module. Called inside
- // CreateApexVariations.
- setApexName(apexName string)
-
// Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) bool
@@ -82,15 +89,16 @@
}
type ApexProperties struct {
- // Availability of this module in APEXes. Only the listed APEXes can include this module.
+ // Availability of this module in APEXes. Only the listed APEXes can contain
+ // this module. If the module has stubs then other APEXes and the platform may
+ // access it through them (subject to visibility).
+ //
// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
// "//apex_available:platform" refers to non-APEX partitions like "system.img".
- // Default is ["//apex_available:platform", "//apex_available:anyapex"].
- // TODO(b/128708192) change the default to ["//apex_available:platform"]
+ // Default is ["//apex_available:platform"].
Apex_available []string
- // Name of the apex variant that this module is mutated into
- ApexName string `blueprint:"mutated"`
+ Info ApexInfo `blueprint:"mutated"`
}
// Provides default implementation for the ApexModule interface. APEX-aware
@@ -101,31 +109,37 @@
canHaveApexVariants bool
apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
- apexVariations []string
+ apexVariations []ApexInfo
}
func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
return m
}
-func (m *ApexModuleBase) BuildForApex(apexName string) {
+func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock()
- if !InList(apexName, m.apexVariations) {
- m.apexVariations = append(m.apexVariations, apexName)
+nextApex:
+ for _, apex := range apexes {
+ for _, v := range m.apexVariations {
+ if v.ApexName == apex.ApexName {
+ continue nextApex
+ }
+ }
+ m.apexVariations = append(m.apexVariations, apex)
}
}
+func (m *ApexModuleBase) ApexVariations() []ApexInfo {
+ return m.apexVariations
+}
+
func (m *ApexModuleBase) ApexName() string {
- return m.ApexProperties.ApexName
+ return m.ApexProperties.Info.ApexName
}
func (m *ApexModuleBase) IsForPlatform() bool {
- return m.ApexProperties.ApexName == ""
-}
-
-func (m *ApexModuleBase) setApexName(apexName string) {
- m.ApexProperties.ApexName = apexName
+ return m.ApexProperties.Info.ApexName == ""
}
func (m *ApexModuleBase) CanHaveApexVariants() bool {
@@ -174,25 +188,35 @@
}
}
+type byApexName []ApexInfo
+
+func (a byApexName) Len() int { return len(a) }
+func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
+
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
if len(m.apexVariations) > 0 {
m.checkApexAvailableProperty(mctx)
- sort.Strings(m.apexVariations)
+
+ sort.Sort(byApexName(m.apexVariations))
variations := []string{}
- availableForPlatform := mctx.Module().(ApexModule).AvailableFor(AvailableToPlatform) || mctx.Host()
- if availableForPlatform {
- variations = append(variations, "") // Original variation for platform
+ variations = append(variations, "") // Original variation for platform
+ for _, apex := range m.apexVariations {
+ variations = append(variations, apex.ApexName)
}
- variations = append(variations, m.apexVariations...)
defaultVariation := ""
mctx.SetDefaultDependencyVariation(&defaultVariation)
+
modules := mctx.CreateVariations(variations...)
- for i, m := range modules {
- if availableForPlatform && i == 0 {
- continue
+ for i, mod := range modules {
+ platformVariation := i == 0
+ if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
+ mod.SkipInstall()
}
- m.(ApexModule).setApexName(variations[i])
+ if !platformVariation {
+ mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
+ }
}
return modules
}
@@ -216,18 +240,20 @@
}
// Update the map to mark that a module named moduleName is directly or indirectly
-// depended on by an APEX named apexName. Directly depending means that a module
+// depended on by the specified APEXes. Directly depending means that a module
// is explicitly listed in the build definition of the APEX via properties like
// native_shared_libs, java_libs, etc.
-func UpdateApexDependency(apexName string, moduleName string, directDep bool) {
+func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
- apexNames, ok := apexNamesMap()[moduleName]
- if !ok {
- apexNames = make(map[string]bool)
- apexNamesMap()[moduleName] = apexNames
+ for _, apex := range apexes {
+ apexesForModule, ok := apexNamesMap()[moduleName]
+ if !ok {
+ apexesForModule = make(map[string]bool)
+ apexNamesMap()[moduleName] = apexesForModule
+ }
+ apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
}
- apexNames[apexName] = apexNames[apexName] || directDep
}
// TODO(b/146393795): remove this when b/146393795 is fixed
diff --git a/android/arch.go b/android/arch.go
index b5b8a8f..73a490d 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -765,7 +765,7 @@
}
if len(moduleOSList) == 0 {
- base.commonProperties.Enabled = boolPtr(false)
+ base.Disable()
return
}
@@ -838,8 +838,8 @@
osTargets = targets
}
- // only the primary arch in the recovery partition
- if os == Android && module.InstallInRecovery() {
+ // only the primary arch in the ramdisk / recovery partition
+ if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk()) {
osTargets = []Target{osTargets[0]}
}
@@ -869,7 +869,7 @@
}
if len(targets) == 0 {
- base.commonProperties.Enabled = boolPtr(false)
+ base.Disable()
return
}
@@ -926,16 +926,31 @@
return targets
}
-// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of
-// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib,
-// etc.
-func createArchType(props reflect.Type) []reflect.Type {
- propShards, _ := proptools.FilterPropertyStructSharded(props, filterArchStruct)
+type archPropTypeDesc struct {
+ arch, multilib, target reflect.Type
+}
+
+type archPropRoot struct {
+ Arch, Multilib, Target interface{}
+}
+
+// createArchPropTypeDesc takes a reflect.Type that is either a struct or a pointer to a struct, and
+// returns lists of reflect.Types that contains the arch-variant properties inside structs for each
+// arch, multilib and target property.
+func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
+ // Each property struct shard will be nested many times under the runtime generated arch struct,
+ // which can hit the limit of 64kB for the name of runtime generated structs. They are nested
+ // 97 times now, which may grow in the future, plus there is some overhead for the containing
+ // type. This number may need to be reduced if too many are added, but reducing it too far
+ // could cause problems if a single deeply nested property no longer fits in the name.
+ const maxArchTypeNameSize = 500
+
+ propShards, _ := proptools.FilterPropertyStructSharded(props, maxArchTypeNameSize, filterArchStruct)
if len(propShards) == 0 {
return nil
}
- var ret []reflect.Type
+ var ret []archPropTypeDesc
for _, props := range propShards {
variantFields := func(names []string) []reflect.StructField {
@@ -1011,20 +1026,12 @@
}
targetType := reflect.StructOf(variantFields(targets))
- ret = append(ret, reflect.StructOf([]reflect.StructField{
- {
- Name: "Arch",
- Type: archType,
- },
- {
- Name: "Multilib",
- Type: multilibType,
- },
- {
- Name: "Target",
- Type: targetType,
- },
- }))
+
+ ret = append(ret, archPropTypeDesc{
+ arch: reflect.PtrTo(archType),
+ multilib: reflect.PtrTo(multilibType),
+ target: reflect.PtrTo(targetType),
+ })
}
return ret
}
@@ -1036,11 +1043,20 @@
// 16-bit limit on structure name length. The name is constructed
// based on the Go source representation of the structure, so
// the tag names count towards that length.
- //
- // TODO: handle the uncommon case of other tags being involved
- if field.Tag == `android:"arch_variant"` {
- field.Tag = ""
+
+ androidTag := field.Tag.Get("android")
+ values := strings.Split(androidTag, ",")
+
+ if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
+ panic(fmt.Errorf("unexpected tag format %q", field.Tag))
}
+ // these tags don't need to be present in the runtime generated struct type.
+ values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
+ if len(values) > 0 {
+ panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
+ }
+
+ field.Tag = ""
return true, field
}
return false, field
@@ -1069,12 +1085,16 @@
}
archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
- return createArchType(t)
- }).([]reflect.Type)
+ return createArchPropTypeDesc(t)
+ }).([]archPropTypeDesc)
var archProperties []interface{}
for _, t := range archPropTypes {
- archProperties = append(archProperties, reflect.New(t).Interface())
+ archProperties = append(archProperties, &archPropRoot{
+ Arch: reflect.Zero(t.arch).Interface(),
+ Multilib: reflect.Zero(t.multilib).Interface(),
+ Target: reflect.Zero(t.target).Interface(),
+ })
}
base.archProperties = append(base.archProperties, archProperties)
m.AddProperties(archProperties...)
@@ -1088,6 +1108,13 @@
func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
+ if src.Kind() == reflect.Ptr {
+ if src.IsNil() {
+ return src
+ }
+ src = src.Elem()
+ }
+
src = src.FieldByName(field)
if !src.IsValid() {
ctx.ModuleErrorf("field %q does not exist", srcPrefix)
@@ -1134,7 +1161,7 @@
for _, archProperties := range m.archProperties[i] {
archPropValues := reflect.ValueOf(archProperties).Elem()
- targetProp := archPropValues.FieldByName("Target")
+ targetProp := archPropValues.FieldByName("Target").Elem()
// Handle host-specific properties in the form:
// target: {
@@ -1229,9 +1256,9 @@
for _, archProperties := range m.archProperties[i] {
archPropValues := reflect.ValueOf(archProperties).Elem()
- archProp := archPropValues.FieldByName("Arch")
- multilibProp := archPropValues.FieldByName("Multilib")
- targetProp := archPropValues.FieldByName("Target")
+ archProp := archPropValues.FieldByName("Arch").Elem()
+ multilibProp := archPropValues.FieldByName("Multilib").Elem()
+ targetProp := archPropValues.FieldByName("Target").Elem()
// Handle arch-specific properties in the form:
// arch: {
@@ -1494,12 +1521,7 @@
// hasArmAbi returns true if arch has at least one arm ABI
func hasArmAbi(arch Arch) bool {
- for _, abi := range arch.Abi {
- if strings.HasPrefix(abi, "arm") {
- return true
- }
- }
- return false
+ return PrefixInList(arch.Abi, "arm")
}
// hasArmArch returns true if targets has at least non-native_bridge arm Android arch
@@ -1595,7 +1617,7 @@
func getNdkAbisConfig() []archConfig {
return []archConfig{
- {"arm", "armv7-a", "", []string{"armeabi"}},
+ {"arm", "armv7-a", "", []string{"armeabi-v7a"}},
{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
{"x86", "", "", []string{"x86"}},
{"x86_64", "", "", []string{"x86_64"}},
diff --git a/android/arch_test.go b/android/arch_test.go
index 98b0534..b987d56 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -55,6 +55,24 @@
filtered: true,
},
{
+ name: "tags",
+ in: &struct {
+ A *string `android:"arch_variant"`
+ B *string `android:"arch_variant,path"`
+ C *string `android:"arch_variant,path,variant_prepend"`
+ D *string `android:"path,variant_prepend,arch_variant"`
+ E *string `android:"path"`
+ F *string
+ }{},
+ out: &struct {
+ A *string
+ B *string
+ C *string
+ D *string
+ }{},
+ filtered: true,
+ },
+ {
name: "all filtered",
in: &struct {
A *string
diff --git a/android/config.go b/android/config.go
index 3c49c1a..32e32ae 100644
--- a/android/config.go
+++ b/android/config.go
@@ -29,11 +29,14 @@
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android/soongconfig"
)
var Bool = proptools.Bool
var String = proptools.String
-var FutureApiLevel = 10000
+
+const FutureApiLevel = 10000
// The configuration file name
const configFileName = "soong.config"
@@ -66,19 +69,7 @@
*deviceConfig
}
-type VendorConfig interface {
- // Bool interprets the variable named `name` as a boolean, returning true if, after
- // lowercasing, it matches one of "1", "y", "yes", "on", or "true". Unset, or any other
- // value will return false.
- Bool(name string) bool
-
- // String returns the string value of `name`. If the variable was not set, it will
- // return the empty string.
- String(name string) string
-
- // IsSet returns whether the variable `name` was set by Make.
- IsSet(name string) bool
-}
+type VendorConfig soongconfig.SoongConfig
type config struct {
FileConfigurableOptions
@@ -128,8 +119,6 @@
OncePer
}
-type vendorConfig map[string]string
-
type jsonConfigurable interface {
SetDefaultConfig()
}
@@ -276,7 +265,7 @@
config.Targets = map[OsType][]Target{
Fuchsia: []Target{
- {Fuchsia, Arch{ArchType: Arm64, ArchVariant: ""}, NativeBridgeDisabled, "", ""},
+ {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
},
BuildOs: []Target{
{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
@@ -801,14 +790,6 @@
return Bool(c.productVariables.DisableScudo)
}
-func (c *config) EnableXOM() bool {
- if c.productVariables.EnableXOM == nil {
- return true
- } else {
- return Bool(c.productVariables.EnableXOM)
- }
-}
-
func (c *config) Android64() bool {
for _, t := range c.Targets[Android] {
if t.Arch.ArchType.Multilib == "lib64" {
@@ -827,6 +808,22 @@
return Bool(c.productVariables.UseRBE)
}
+func (c *config) UseRBEJAVAC() bool {
+ return Bool(c.productVariables.UseRBEJAVAC)
+}
+
+func (c *config) UseRBER8() bool {
+ return Bool(c.productVariables.UseRBER8)
+}
+
+func (c *config) UseRBED8() bool {
+ return Bool(c.productVariables.UseRBED8)
+}
+
+func (c *config) UseRemoteBuild() bool {
+ return c.UseGoma() || c.UseRBE()
+}
+
func (c *config) RunErrorProne() bool {
return c.IsEnvTrue("RUN_ERROR_PRONE")
}
@@ -835,6 +832,14 @@
return c.Getenv("XREF_CORPUS")
}
+// Returns Compilation Unit encoding to use. Can be 'json' (default), 'proto' or 'all'.
+func (c *config) XrefCuEncoding() string {
+ if enc := c.Getenv("KYTHE_KZIP_ENCODING"); enc != "" {
+ return enc
+ }
+ return "json"
+}
+
func (c *config) EmitXrefRules() bool {
return c.XrefCorpusName() != ""
}
@@ -885,11 +890,7 @@
func (c *config) EnforceRROExcludedOverlay(path string) bool {
excluded := c.productVariables.EnforceRROExcludedOverlays
if excluded != nil {
- for _, exclude := range excluded {
- if strings.HasPrefix(path, exclude) {
- return true
- }
- }
+ return HasAnyPrefix(path, excluded)
}
return false
}
@@ -910,8 +911,23 @@
return c.productVariables.ModulesLoadedByPrivilegedModules
}
+// Expected format for apexJarValue = <apex name>:<jar name>
+func SplitApexJarPair(apexJarValue string) (string, string) {
+ var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
+ if apexJarPair == nil || len(apexJarPair) != 2 {
+ panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
+ apexJarValue))
+ }
+ return apexJarPair[0], apexJarPair[1]
+}
+
func (c *config) BootJars() []string {
- return c.productVariables.BootJars
+ jars := c.productVariables.BootJars
+ for _, p := range c.productVariables.UpdatableBootJars {
+ _, jar := SplitApexJarPair(p)
+ jars = append(jars, jar)
+ }
+ return jars
}
func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
@@ -1015,19 +1031,27 @@
return c.config.productVariables.DeviceKernelHeaders
}
+func (c *config) NativeLineCoverage() bool {
+ return Bool(c.productVariables.NativeLineCoverage)
+}
+
func (c *deviceConfig) NativeCoverageEnabled() bool {
- return Bool(c.config.productVariables.NativeCoverage)
+ return Bool(c.config.productVariables.Native_coverage) || Bool(c.config.productVariables.NativeLineCoverage)
+}
+
+func (c *deviceConfig) ClangCoverageEnabled() bool {
+ return Bool(c.config.productVariables.ClangCoverage)
}
func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
coverage := false
if c.config.productVariables.CoveragePaths != nil {
- if InList("*", c.config.productVariables.CoveragePaths) || PrefixInList(path, c.config.productVariables.CoveragePaths) {
+ if InList("*", c.config.productVariables.CoveragePaths) || HasAnyPrefix(path, c.config.productVariables.CoveragePaths) {
coverage = true
}
}
if coverage && c.config.productVariables.CoverageExcludePaths != nil {
- if PrefixInList(path, c.config.productVariables.CoverageExcludePaths) {
+ if HasAnyPrefix(path, c.config.productVariables.CoverageExcludePaths) {
coverage = false
}
}
@@ -1100,46 +1124,25 @@
if c.productVariables.IntegerOverflowExcludePaths == nil {
return false
}
- return PrefixInList(path, c.productVariables.IntegerOverflowExcludePaths)
+ return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
}
func (c *config) CFIDisabledForPath(path string) bool {
if c.productVariables.CFIExcludePaths == nil {
return false
}
- return PrefixInList(path, c.productVariables.CFIExcludePaths)
+ return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
}
func (c *config) CFIEnabledForPath(path string) bool {
if c.productVariables.CFIIncludePaths == nil {
return false
}
- return PrefixInList(path, c.productVariables.CFIIncludePaths)
-}
-
-func (c *config) XOMDisabledForPath(path string) bool {
- if c.productVariables.XOMExcludePaths == nil {
- return false
- }
- return PrefixInList(path, c.productVariables.XOMExcludePaths)
+ return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
}
func (c *config) VendorConfig(name string) VendorConfig {
- return vendorConfig(c.productVariables.VendorVars[name])
-}
-
-func (c vendorConfig) Bool(name string) bool {
- v := strings.ToLower(c[name])
- return v == "1" || v == "y" || v == "yes" || v == "on" || v == "true"
-}
-
-func (c vendorConfig) String(name string) string {
- return c[name]
-}
-
-func (c vendorConfig) IsSet(name string) bool {
- _, ok := c[name]
- return ok
+ return soongconfig.Config(c.productVariables.VendorVars[name])
}
func (c *config) NdkAbis() bool {
@@ -1225,3 +1228,7 @@
func (c *deviceConfig) DeviceSecondaryArchVariant() string {
return String(c.config.productVariables.DeviceSecondaryArchVariant)
}
+
+func (c *deviceConfig) BoardUsesRecoveryAsBoot() bool {
+ return Bool(c.config.productVariables.BoardUsesRecoveryAsBoot)
+}
diff --git a/android/defaults.go b/android/defaults.go
index 7597446..fd707a4 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "reflect"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -30,16 +32,18 @@
}
type DefaultableModuleBase struct {
- defaultsProperties defaultsProperties
- defaultableProperties []interface{}
+ defaultsProperties defaultsProperties
+ defaultableProperties []interface{}
+ defaultableVariableProperties interface{}
}
func (d *DefaultableModuleBase) defaults() *defaultsProperties {
return &d.defaultsProperties
}
-func (d *DefaultableModuleBase) setProperties(props []interface{}) {
+func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
d.defaultableProperties = props
+ d.defaultableVariableProperties = variableProperties
}
// Interface that must be supported by any module to which defaults can be applied.
@@ -48,7 +52,7 @@
defaults() *defaultsProperties
// Set the property structures into which defaults will be added.
- setProperties([]interface{})
+ setProperties(props []interface{}, variableProperties interface{})
// Apply defaults from the supplied Defaults to the property structures supplied to
// setProperties(...).
@@ -63,7 +67,10 @@
var _ Defaultable = (*DefaultableModuleBase)(nil)
func InitDefaultableModule(module DefaultableModule) {
- module.setProperties(module.(Module).GetProperties())
+ if module.(Module).base().module == nil {
+ panic("InitAndroidModule must be called before InitDefaultableModule")
+ }
+ module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
module.AddProperties(module.defaults())
}
@@ -114,6 +121,8 @@
// Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
+ productVariableProperties() interface{}
+
// Return the defaults common properties.
common() *commonProperties
@@ -134,6 +143,10 @@
return d.defaultableProperties
}
+func (d *DefaultsModuleBase) productVariableProperties() interface{} {
+ return d.defaultableVariableProperties
+}
+
func (d *DefaultsModuleBase) common() *commonProperties {
return &d.commonProperties
}
@@ -151,9 +164,10 @@
module.AddProperties(
&hostAndDeviceProperties{},
commonProperties,
- &variableProperties{},
&ApexProperties{})
+ initAndroidModuleBase(module)
+ initProductVariableModule(module)
InitArchModule(module)
InitDefaultableModule(module)
@@ -185,16 +199,57 @@
for _, defaults := range defaultsList {
for _, prop := range defaultable.defaultableProperties {
- for _, def := range defaults.properties() {
- if proptools.TypeEqual(prop, def) {
- err := proptools.PrependProperties(prop, def, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
+ if prop == defaultable.defaultableVariableProperties {
+ defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
+ } else {
+ defaultable.applyDefaultProperties(ctx, defaults, prop)
+ }
+ }
+ }
+}
+
+// Product variable properties need special handling, the type of the filtered product variable
+// property struct may not be identical between the defaults module and the defaultable module.
+// Use PrependMatchingProperties to apply whichever properties match.
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
+ if defaultableProp == nil {
+ return
+ }
+
+ defaultsProp := defaults.productVariableProperties()
+ if defaultsProp == nil {
+ return
+ }
+
+ dst := []interface{}{
+ defaultableProp,
+ // Put an empty copy of the src properties into dst so that properties in src that are not in dst
+ // don't cause a "failed to find property to extend" error.
+ proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
+ }
+
+ err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
+}
+
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
+
+ for _, def := range defaults.properties() {
+ if proptools.TypeEqual(defaultableProp, def) {
+ err := proptools.PrependProperties(defaultableProp, def, nil)
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
}
}
}
diff --git a/android/defaults_test.go b/android/defaults_test.go
index ba607ef..d096b2f 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -15,6 +15,7 @@
package android
import (
+ "reflect"
"testing"
"github.com/google/blueprint/proptools"
@@ -40,8 +41,8 @@
func defaultsTestModuleFactory() Module {
module := &defaultsTestModule{}
module.AddProperties(&module.properties)
- InitDefaultableModule(module)
InitAndroidModule(module)
+ InitDefaultableModule(module)
return module
}
@@ -57,6 +58,49 @@
return defaults
}
+func TestDefaults(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ foo: ["transitive"],
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ foo: ["defaults"],
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults"],
+ foo: ["module"],
+ }
+ `
+
+ config := TestConfig(buildDir, nil, bp, nil)
+
+ ctx := NewTestContext()
+
+ ctx.RegisterModuleType("test", defaultsTestModuleFactory)
+ ctx.RegisterModuleType("defaults", defaultsTestDefaultsFactory)
+
+ ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ foo := ctx.ModuleForTests("foo", "").Module().(*defaultsTestModule)
+
+ if g, w := foo.properties.Foo, []string{"transitive", "defaults", "module"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("expected foo %q, got %q", w, g)
+ }
+}
+
func TestDefaultsAllowMissingDependencies(t *testing.T) {
bp := `
defaults {
diff --git a/android/defs.go b/android/defs.go
index 4890c66..5c815e6 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -99,6 +99,9 @@
// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
localPool = blueprint.NewBuiltinPool("local_pool")
+
+ // Used for processes that need significant RAM to ensure there are not too many running in parallel.
+ highmemPool = blueprint.NewBuiltinPool("highmem_pool")
)
func init() {
diff --git a/android/hooks.go b/android/hooks.go
index 04ba69e..47f69d1 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -34,6 +34,9 @@
AppendProperties(...interface{})
PrependProperties(...interface{})
CreateModule(ModuleFactory, ...interface{}) Module
+
+ registerScopedModuleType(name string, factory blueprint.ModuleFactory)
+ moduleFactories() map[string]blueprint.ModuleFactory
}
func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
@@ -52,6 +55,10 @@
module Module
}
+func (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory {
+ return l.bp.ModuleFactories()
+}
+
func (l *loadHookContext) AppendProperties(props ...interface{}) {
for _, p := range props {
err := proptools.AppendMatchingProperties(l.Module().base().customizableProperties,
@@ -90,7 +97,7 @@
module.base().variableProperties,
// Put an empty copy of the src properties into dst so that properties in src that are not in dst
// don't cause a "failed to find property to extend" error.
- proptools.CloneEmptyProperties(reflect.ValueOf(src).Elem()).Interface(),
+ proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(),
}
err := proptools.AppendMatchingProperties(dst, src, nil)
if err != nil {
@@ -101,6 +108,10 @@
return module
}
+func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {
+ l.bp.RegisterScopedModuleType(name, factory)
+}
+
type InstallHookContext interface {
ModuleContext
Path() InstallPath
diff --git a/android/image.go b/android/image.go
index 5291ce3..061bfa5 100644
--- a/android/image.go
+++ b/android/image.go
@@ -22,6 +22,10 @@
// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
CoreVariantNeeded(ctx BaseModuleContext) bool
+ // RamdiskVariantNeeded should return true if the module needs a ramdisk variant (installed on the
+ // ramdisk partition).
+ RamdiskVariantNeeded(ctx BaseModuleContext) bool
+
// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
// recovery partition).
RecoveryVariantNeeded(ctx BaseModuleContext) bool
@@ -46,6 +50,9 @@
// RecoveryVariation means a module to be installed to recovery image.
RecoveryVariation string = "recovery"
+
+ // RamdiskVariation means a module to be installed to ramdisk image.
+ RamdiskVariation string = "ramdisk"
)
// imageMutator creates variants for modules that implement the ImageInterface that
@@ -63,6 +70,9 @@
if m.CoreVariantNeeded(ctx) {
variations = append(variations, CoreVariation)
}
+ if m.RamdiskVariantNeeded(ctx) {
+ variations = append(variations, RamdiskVariation)
+ }
if m.RecoveryVariantNeeded(ctx) {
variations = append(variations, RecoveryVariation)
}
diff --git a/android/module.go b/android/module.go
index 67d1f12..fd3fec3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -62,6 +62,7 @@
ModuleName() string
ModuleDir() string
ModuleType() string
+ BlueprintsFile() string
ContainsProperty(name string) bool
Errorf(pos scanner.Position, fmt string, args ...interface{})
@@ -167,6 +168,7 @@
InstallInData() bool
InstallInTestcases() bool
InstallInSanitizerDir() bool
+ InstallInRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -202,16 +204,20 @@
DepsMutator(BottomUpMutatorContext)
base() *ModuleBase
+ Disable()
Enabled() bool
Target() Target
InstallInData() bool
InstallInTestcases() bool
InstallInSanitizerDir() bool
+ InstallInRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
SkipInstall()
ExportedToMake() bool
+ InitRc() Paths
+ VintfFragments() Paths
NoticeFile() OptionalPath
AddProperties(props ...interface{})
@@ -288,6 +294,12 @@
type commonProperties struct {
// emit build rules for this module
+ //
+ // Disabling a module should only be done for those modules that cannot be built
+ // in the current environment. Modules that can build in the current environment
+ // but are not usually required (e.g. superceded by a prebuilt) should not be
+ // disabled as that will prevent them from being built by the checkbuild target
+ // and so prevent early detection of changes that have broken those modules.
Enabled *bool `android:"arch_variant"`
// Controls the visibility of this module to other modules. Allowable values are one or more of
@@ -384,6 +396,9 @@
// Whether this module is installed to recovery partition
Recovery *bool
+ // Whether this module is installed to ramdisk
+ Ramdisk *bool
+
// Whether this module is built for non-native architecures (also known as native bridge binary)
Native_bridge_supported *bool `android:"arch_variant"`
@@ -519,24 +534,19 @@
}
}
+func initAndroidModuleBase(m Module) {
+ m.base().module = m
+}
+
func InitAndroidModule(m Module) {
+ initAndroidModuleBase(m)
base := m.base()
- base.module = m
m.AddProperties(
&base.nameProperties,
&base.commonProperties)
- // Allow tests to override the default product variables
- if base.variableProperties == nil {
- base.variableProperties = zeroProductVariables
- }
-
- // Filter the product variables properties to the ones that exist on this module
- base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
- if base.variableProperties != nil {
- m.AddProperties(base.variableProperties)
- }
+ initProductVariableModule(m)
base.generalProperties = m.GetProperties()
base.customizableProperties = m.GetProperties()
@@ -652,6 +662,9 @@
ruleParams map[blueprint.Rule]blueprint.RuleParams
variables map[string]string
+ initRcPaths Paths
+ vintfFragmentsPaths Paths
+
prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
}
@@ -824,6 +837,10 @@
return *m.commonProperties.Enabled
}
+func (m *ModuleBase) Disable() {
+ m.commonProperties.Enabled = proptools.BoolPtr(false)
+}
+
func (m *ModuleBase) SkipInstall() {
m.commonProperties.SkipInstall = true
}
@@ -867,6 +884,10 @@
return false
}
+func (m *ModuleBase) InstallInRamdisk() bool {
+ return Bool(m.commonProperties.Ramdisk)
+}
+
func (m *ModuleBase) InstallInRecovery() bool {
return Bool(m.commonProperties.Recovery)
}
@@ -898,6 +919,10 @@
}
}
+func (m *ModuleBase) InRamdisk() bool {
+ return m.base().commonProperties.ImageVariation == RamdiskVariation
+}
+
func (m *ModuleBase) InRecovery() bool {
return m.base().commonProperties.ImageVariation == RecoveryVariation
}
@@ -914,6 +939,14 @@
return m.base().commonProperties.Target_required
}
+func (m *ModuleBase) InitRc() Paths {
+ return append(Paths{}, m.initRcPaths...)
+}
+
+func (m *ModuleBase) VintfFragments() Paths {
+ return append(Paths{}, m.vintfFragmentsPaths...)
+}
+
func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
allInstalledFiles := Paths{}
allCheckbuildFiles := Paths{}
@@ -1079,6 +1112,9 @@
if !ctx.PrimaryArch() {
suffix = append(suffix, ctx.Arch().ArchType.String())
}
+ if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() {
+ suffix = append(suffix, apex.ApexName())
+ }
ctx.Variable(pctx, "moduleDesc", desc)
@@ -1130,6 +1166,8 @@
m.installFiles = append(m.installFiles, ctx.installFiles...)
m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
+ m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+ m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
} else if ctx.Config().AllowMissingDependencies() {
// If the module is not enabled it will not create any build rules, nothing will call
// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1338,7 +1376,7 @@
func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
- if (m.config.UseGoma() || m.config.UseRBE()) && params.Pool == nil {
+ if m.config.UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
// jobs to the local parallelism value
params.Pool = localPool
@@ -1649,6 +1687,10 @@
return m.module.InstallInSanitizerDir()
}
+func (m *moduleContext) InstallInRamdisk() bool {
+ return m.module.InstallInRamdisk()
+}
+
func (m *moduleContext) InstallInRecovery() bool {
return m.module.InstallInRecovery()
}
@@ -1746,7 +1788,7 @@
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
Output: fullInstallPath,
- OrderOnly: Paths{srcPath},
+ Input: srcPath,
Default: !m.Config().EmbeddedInMake(),
Args: map[string]string{
"fromPath": relPath,
diff --git a/android/mutator.go b/android/mutator.go
index f2f9663..a46d4be 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -27,6 +27,7 @@
// run Pre-deps mutators
// run depsMutator
// run PostDeps mutators
+// run FinalDeps mutators (CreateVariations disallowed in this phase)
// continue on to GenerateAndroidBuildActions
func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
@@ -43,7 +44,7 @@
}
}
-func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps []RegisterMutatorFunc) {
+func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
mctx := ®isterMutatorsContext{}
register := func(funcs []RegisterMutatorFunc) {
@@ -60,11 +61,15 @@
register(postDeps)
+ mctx.finalPhase = true
+ register(finalDeps)
+
registerMutatorsToContext(ctx, mctx.mutators)
}
type registerMutatorsContext struct {
- mutators []*mutator
+ mutators []*mutator
+ finalPhase bool
}
type RegisterMutatorsContext interface {
@@ -102,6 +107,8 @@
RegisterOverridePostDepsMutators,
}
+var finalDeps = []RegisterMutatorFunc{}
+
func PreArchMutators(f RegisterMutatorFunc) {
preArch = append(preArch, f)
}
@@ -114,6 +121,10 @@
postDeps = append(postDeps, f)
}
+func FinalDepsMutators(f RegisterMutatorFunc) {
+ finalDeps = append(finalDeps, f)
+}
+
type TopDownMutator func(TopDownMutatorContext)
type TopDownMutatorContext interface {
@@ -156,14 +167,17 @@
type bottomUpMutatorContext struct {
bp blueprint.BottomUpMutatorContext
baseModuleContext
+ finalPhase bool
}
func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
+ finalPhase := x.finalPhase
f := func(ctx blueprint.BottomUpMutatorContext) {
if a, ok := ctx.Module().(Module); ok {
actx := &bottomUpMutatorContext{
bp: ctx,
baseModuleContext: a.base().baseModuleContextFactory(ctx),
+ finalPhase: finalPhase,
}
m(actx)
}
@@ -256,7 +270,7 @@
module.base().variableProperties,
// Put an empty copy of the src properties into dst so that properties in src that are not in dst
// don't cause a "failed to find property to extend" error.
- proptools.CloneEmptyProperties(reflect.ValueOf(src).Elem()).Interface(),
+ proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(),
}
err := proptools.AppendMatchingProperties(dst, src, nil)
if err != nil {
@@ -285,6 +299,10 @@
}
func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []Module {
+ if b.finalPhase {
+ panic("CreateVariations not allowed in FinalDepsMutators")
+ }
+
modules := b.bp.CreateVariations(variations...)
aModules := make([]Module, len(modules))
@@ -299,6 +317,10 @@
}
func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []Module {
+ if b.finalPhase {
+ panic("CreateLocalVariations not allowed in FinalDepsMutators")
+ }
+
modules := b.bp.CreateLocalVariations(variations...)
aModules := make([]Module, len(modules))
diff --git a/android/mutator_test.go b/android/mutator_test.go
index d179f9d..191b535 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -15,9 +15,12 @@
package android
import (
+ "fmt"
"reflect"
+ "strings"
"testing"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -185,3 +188,110 @@
t.Errorf("want module String() values:\n%q\ngot:\n%q", want, moduleStrings)
}
}
+
+func TestFinalDepsPhase(t *testing.T) {
+ ctx := NewTestContext()
+
+ finalGot := map[string]int{}
+
+ dep1Tag := struct {
+ blueprint.BaseDependencyTag
+ }{}
+ dep2Tag := struct {
+ blueprint.BaseDependencyTag
+ }{}
+
+ ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("far_deps_1", func(ctx BottomUpMutatorContext) {
+ if !strings.HasPrefix(ctx.ModuleName(), "common_dep") {
+ ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep1Tag, "common_dep_1")
+ }
+ })
+ ctx.BottomUp("variant", func(ctx BottomUpMutatorContext) {
+ ctx.CreateLocalVariations("a", "b")
+ })
+ })
+
+ ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("far_deps_2", func(ctx BottomUpMutatorContext) {
+ if !strings.HasPrefix(ctx.ModuleName(), "common_dep") {
+ ctx.AddFarVariationDependencies([]blueprint.Variation{}, dep2Tag, "common_dep_2")
+ }
+ })
+ ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
+ finalGot[ctx.Module().String()] += 1
+ ctx.VisitDirectDeps(func(mod Module) {
+ finalGot[fmt.Sprintf("%s -> %s", ctx.Module().String(), mod)] += 1
+ })
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+
+ bp := `
+ test {
+ name: "common_dep_1",
+ }
+ test {
+ name: "common_dep_2",
+ }
+ test {
+ name: "foo",
+ }
+ `
+
+ config := TestConfig(buildDir, nil, bp, nil)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ finalWant := map[string]int{
+ "common_dep_1{variant:a}": 1,
+ "common_dep_1{variant:b}": 1,
+ "common_dep_2{variant:a}": 1,
+ "common_dep_2{variant:b}": 1,
+ "foo{variant:a}": 1,
+ "foo{variant:a} -> common_dep_1{variant:a}": 1,
+ "foo{variant:a} -> common_dep_2{variant:a}": 1,
+ "foo{variant:b}": 1,
+ "foo{variant:b} -> common_dep_1{variant:b}": 1,
+ "foo{variant:b} -> common_dep_2{variant:a}": 1,
+ }
+
+ if !reflect.DeepEqual(finalWant, finalGot) {
+ t.Errorf("want:\n%q\ngot:\n%q", finalWant, finalGot)
+ }
+}
+
+func TestNoCreateVariationsInFinalDeps(t *testing.T) {
+ ctx := NewTestContext()
+
+ checkErr := func() {
+ if err := recover(); err == nil || !strings.Contains(fmt.Sprintf("%s", err), "not allowed in FinalDepsMutators") {
+ panic("Expected FinalDepsMutators consistency check to fail")
+ }
+ }
+
+ ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("vars", func(ctx BottomUpMutatorContext) {
+ defer checkErr()
+ ctx.CreateVariations("a", "b")
+ })
+ ctx.BottomUp("local_vars", func(ctx BottomUpMutatorContext) {
+ defer checkErr()
+ ctx.CreateLocalVariations("a", "b")
+ })
+ })
+
+ ctx.RegisterModuleType("test", mutatorTestModuleFactory)
+ config := TestConfig(buildDir, nil, `test {name: "foo"}`, nil)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+}
diff --git a/android/namespace.go b/android/namespace.go
index 64ad7e9..9d7e8ac 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -162,6 +162,12 @@
return namespace
}
+// A NamelessModule can never be looked up by name. It must still implement Name(), but the return
+// value doesn't have to be unique.
+type NamelessModule interface {
+ Nameless()
+}
+
func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
// if this module is a namespace, then save it to our list of namespaces
newNamespace, ok := module.(*NamespaceModule)
@@ -173,6 +179,10 @@
return nil, nil
}
+ if _, ok := module.(NamelessModule); ok {
+ return nil, nil
+ }
+
// if this module is not a namespace, then save it into the appropriate namespace
ns := r.findNamespaceFromCtx(ctx)
diff --git a/android/neverallow.go b/android/neverallow.go
index cef73fb..0cb2029 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -111,7 +111,9 @@
// TODO(b/67974785): always enforce the manifest
NeverAllow().
- Without("name", "libhidltransport-impl-internal").
+ Without("name", "libhidlbase-combined-impl").
+ Without("name", "libhidlbase").
+ Without("name", "libhidlbase_pgo").
With("product_variables.enforce_vintf_manifest.cflags", "*").
Because("manifest enforcement should be independent of ."),
@@ -405,8 +407,8 @@
}
func (r *rule) appliesToPath(dir string) bool {
- includePath := len(r.paths) == 0 || hasAnyPrefix(dir, r.paths)
- excludePath := hasAnyPrefix(dir, r.unlessPaths)
+ includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths)
+ excludePath := HasAnyPrefix(dir, r.unlessPaths)
return includePath && !excludePath
}
@@ -472,15 +474,6 @@
return names
}
-func hasAnyPrefix(s string, prefixes []string) bool {
- for _, prefix := range prefixes {
- if strings.HasPrefix(s, prefix) {
- return true
- }
- }
- return false
-}
-
func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
for _, v := range props {
if hasProperty(properties, v) {
diff --git a/android/package_ctx.go b/android/package_ctx.go
index a228910..5a43ea9 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -109,7 +109,7 @@
if len(ctx.errors) > 0 {
return params, ctx.errors[0]
}
- if (ctx.Config().UseGoma() || ctx.Config().UseRBE()) && params.Pool == nil {
+ if ctx.Config().UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by
// goma/RBE, restrict jobs to the local parallelism value
params.Pool = localPool
@@ -232,16 +232,32 @@
}, argNames...)
}
-// RemoteRuleSupports selects if a AndroidRemoteStaticRule supports goma, RBE, or both.
-type RemoteRuleSupports int
+// RBEExperimentalFlag indicates which flag should be set for the AndroidRemoteStaticRule
+// to use RBE.
+type RBEExperimentalFlag int
const (
- SUPPORTS_NONE = 0
- SUPPORTS_GOMA = 1 << iota
- SUPPORTS_RBE = 1 << iota
- SUPPORTS_BOTH = SUPPORTS_GOMA | SUPPORTS_RBE
+ // RBE_NOT_EXPERIMENTAL indicates the rule should use RBE in every build that has
+ // UseRBE set.
+ RBE_NOT_EXPERIMENTAL RBEExperimentalFlag = iota
+ // RBE_JAVAC indicates the rule should use RBE only if the RBE_JAVAC variable is
+ // set in an RBE enabled build.
+ RBE_JAVAC
+ // RBE_R8 indicates the rule should use RBE only if the RBE_R8 variable is set in
+ // an RBE enabled build.
+ RBE_R8
+ // RBE_D8 indicates the rule should use RBE only if the RBE_D8 variable is set in
+ // an RBE enabled build.
+ RBE_D8
)
+// RemoteRuleSupports configures rules with whether they have Goma and/or RBE support.
+type RemoteRuleSupports struct {
+ Goma bool
+ RBE bool
+ RBEFlag RBEExperimentalFlag
+}
+
// AndroidRemoteStaticRule wraps blueprint.StaticRule but uses goma or RBE's parallelism if goma or RBE are enabled
// and the appropriate SUPPORTS_* flag is set.
func (p PackageContext) AndroidRemoteStaticRule(name string, supports RemoteRuleSupports, params blueprint.RuleParams,
@@ -249,18 +265,30 @@
return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
ctx := &configErrorWrapper{p, config.(Config), nil}
- if ctx.Config().UseGoma() && supports&SUPPORTS_GOMA == 0 {
+ if ctx.Config().UseGoma() && !supports.Goma {
// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
// local parallelism value
params.Pool = localPool
}
- if ctx.Config().UseRBE() && supports&SUPPORTS_RBE == 0 {
+ if ctx.Config().UseRBE() && !supports.RBE {
// When USE_RBE=true is set and the rule is not supported by RBE, restrict jobs to the
// local parallelism value
params.Pool = localPool
}
+ if ctx.Config().UseRBE() && supports.RBE {
+ if supports.RBEFlag == RBE_JAVAC && !ctx.Config().UseRBEJAVAC() {
+ params.Pool = localPool
+ }
+ if supports.RBEFlag == RBE_R8 && !ctx.Config().UseRBER8() {
+ params.Pool = localPool
+ }
+ if supports.RBEFlag == RBE_D8 && !ctx.Config().UseRBED8() {
+ params.Pool = localPool
+ }
+ }
+
return params, nil
}, argNames...)
}
diff --git a/android/paths.go b/android/paths.go
index 02f56d0..66725c6 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -49,6 +49,7 @@
InstallInData() bool
InstallInTestcases() bool
InstallInSanitizerDir() bool
+ InstallInRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -842,10 +843,12 @@
// OutputPath is a Path representing an intermediates file path rooted from the build directory
type OutputPath struct {
basePath
+ fullPath string
}
func (p OutputPath) withRel(rel string) OutputPath {
p.basePath = p.basePath.withRel(rel)
+ p.fullPath = filepath.Join(p.fullPath, rel)
return p
}
@@ -869,7 +872,9 @@
if err != nil {
reportPathError(ctx, err)
}
- return OutputPath{basePath{path, ctx.Config(), ""}}
+ fullPath := filepath.Join(ctx.Config().buildDir, path)
+ path = fullPath[len(fullPath)-len(path):]
+ return OutputPath{basePath{path, ctx.Config(), ""}, fullPath}
}
// PathsForOutput returns Paths rooted from buildDir
@@ -884,7 +889,7 @@
func (p OutputPath) writablePath() {}
func (p OutputPath) String() string {
- return filepath.Join(p.config.buildDir, p.path)
+ return p.fullPath
}
// Join creates a new OutputPath with paths... joined with the current path. The
@@ -1254,6 +1259,15 @@
partition = "data"
} else if ctx.InstallInTestcases() {
partition = "testcases"
+ } else if ctx.InstallInRamdisk() {
+ if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
+ partition = "recovery/root/first_stage_ramdisk"
+ } else {
+ partition = "ramdisk"
+ }
+ if !ctx.InstallInRoot() {
+ partition += "/system"
+ }
} else if ctx.InstallInRecovery() {
if ctx.InstallInRoot() {
partition = "recovery/root"
diff --git a/android/paths_test.go b/android/paths_test.go
index 46e3e1f..7a32026 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -202,6 +202,7 @@
inData bool
inTestcases bool
inSanitizerDir bool
+ inRamdisk bool
inRecovery bool
inRoot bool
}
@@ -224,6 +225,10 @@
return m.inSanitizerDir
}
+func (m moduleInstallPathContextImpl) InstallInRamdisk() bool {
+ return m.inRamdisk
+}
+
func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
return m.inRecovery
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index c780cb2..2d16f65 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -62,6 +62,10 @@
return "prebuilt_" + name
}
+func (p *Prebuilt) ForcePrefer() {
+ p.properties.Prefer = proptools.BoolPtr(true)
+}
+
// The below source-related functions and the srcs, src fields are based on an assumption that
// prebuilt modules have a static source property at the moment. Currently there is only one
// exception, android_app_import, which chooses a source file depending on the product's DPI
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 388d17f..3dea6d8 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -41,6 +41,9 @@
// is the same as the file name of the source file.
Filename_from_src *bool `android:"arch_variant"`
+ // Make this module available when building for ramdisk.
+ Ramdisk_available *bool
+
// Make this module available when building for recovery.
Recovery_available *bool
@@ -69,6 +72,18 @@
additionalDependencies *Paths
}
+func (p *PrebuiltEtc) inRamdisk() bool {
+ return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) onlyInRamdisk() bool {
+ return p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) InstallInRamdisk() bool {
+ return p.inRamdisk()
+}
+
func (p *PrebuiltEtc) inRecovery() bool {
return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
}
@@ -86,7 +101,11 @@
func (p *PrebuiltEtc) ImageMutatorBegin(ctx BaseModuleContext) {}
func (p *PrebuiltEtc) CoreVariantNeeded(ctx BaseModuleContext) bool {
- return !p.ModuleBase.InstallInRecovery()
+ return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx BaseModuleContext) bool {
+ return Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
}
func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx BaseModuleContext) bool {
@@ -167,6 +186,9 @@
func (p *PrebuiltEtc) AndroidMkEntries() []AndroidMkEntries {
nameSuffix := ""
+ if p.inRamdisk() && !p.onlyInRamdisk() {
+ nameSuffix = ".ramdisk"
+ }
if p.inRecovery() && !p.onlyInRecovery() {
nameSuffix = ".recovery"
}
diff --git a/android/register.go b/android/register.go
index d5aa1a5..ccfe01e 100644
--- a/android/register.go
+++ b/android/register.go
@@ -102,7 +102,7 @@
ctx.RegisterSingletonType(t.name, t.factory)
}
- registerMutators(ctx.Context, preArch, preDeps, postDeps)
+ registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
// Register makevars after other singletons so they can export values through makevars
ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))
@@ -135,6 +135,7 @@
PreDepsMutators(f RegisterMutatorFunc)
PostDepsMutators(f RegisterMutatorFunc)
+ FinalDepsMutators(f RegisterMutatorFunc)
}
// Used to register build components from an init() method, e.g.
@@ -197,3 +198,7 @@
func (ctx *initRegistrationContext) PostDepsMutators(f RegisterMutatorFunc) {
PostDepsMutators(f)
}
+
+func (ctx *initRegistrationContext) FinalDepsMutators(f RegisterMutatorFunc) {
+ FinalDepsMutators(f)
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 6f04672..b4f144a 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -33,6 +33,8 @@
temporariesSet map[WritablePath]bool
restat bool
sbox bool
+ highmem bool
+ remoteable RemoteRuleSupports
sboxOutDir WritablePath
missingDeps []string
}
@@ -87,6 +89,19 @@
return r
}
+// HighMem marks the rule as a high memory rule, which will limit how many run in parallel with other high memory
+// rules.
+func (r *RuleBuilder) HighMem() *RuleBuilder {
+ r.highmem = true
+ return r
+}
+
+// Remoteable marks the rule as supporting remote execution.
+func (r *RuleBuilder) Remoteable(supports RemoteRuleSupports) *RuleBuilder {
+ r.remoteable = supports
+ return r
+}
+
// Sbox marks the rule as needing to be wrapped by sbox. The WritablePath should point to the output
// directory that sbox will wipe. It should not be written to by any other rule. sbox will ensure
// that all outputs have been written, and will discard any output files that were not specified.
@@ -401,6 +416,17 @@
rspFileContent = "$in"
}
+ var pool blueprint.Pool
+ if ctx.Config().UseGoma() && r.remoteable.Goma {
+ // When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
+ } else if ctx.Config().UseRBE() && r.remoteable.RBE {
+ // When USE_RBE=true is set and the rule is supported by RBE, allow jobs to run outside the local pool.
+ } else if r.highmem {
+ pool = highmemPool
+ } else if ctx.Config().UseRemoteBuild() {
+ pool = localPool
+ }
+
ctx.Build(pctx, BuildParams{
Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
Command: commandString,
@@ -408,6 +434,7 @@
Restat: r.restat,
Rspfile: rspFile,
RspfileContent: rspFileContent,
+ Pool: pool,
}),
Inputs: rspFileInputs,
Implicits: r.Inputs(),
diff --git a/android/sdk.go b/android/sdk.go
index 9e6ad16..d13ad7d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -180,8 +180,19 @@
// will only be used if the equivalently named non-prebuilt module is not
// present.
AddPrebuiltModule(member SdkMember, moduleType string) BpModule
+
+ // The property tag to use when adding a property to a BpModule that contains
+ // references to other sdk members. Using this will ensure that the reference
+ // is correctly output for both versioned and unversioned prebuilts in the
+ // snapshot.
+ //
+ // e.g.
+ // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
+ SdkMemberReferencePropertyTag() BpPropertyTag
}
+type BpPropertyTag interface{}
+
// A set of properties for use in a .bp file.
type BpPropertySet interface {
// Add a property, the value can be one of the following types:
@@ -190,9 +201,12 @@
// * bool
// * BpPropertySet
//
- // It is an error is multiples properties with the same name are added.
+ // It is an error if multiple properties with the same name are added.
AddProperty(name string, value interface{})
+ // Add a property with an associated tag
+ AddPropertyWithTag(name string, value interface{}, tag BpPropertyTag)
+
// Add a property set with the specified name and return so that additional
// properties can be added.
AddPropertySet(name string) BpPropertySet
@@ -213,6 +227,25 @@
Variants() []SdkAware
}
+type SdkMemberTypeDependencyTag interface {
+ blueprint.DependencyTag
+
+ SdkMemberType() SdkMemberType
+}
+
+type sdkMemberDependencyTag struct {
+ blueprint.BaseDependencyTag
+ memberType SdkMemberType
+}
+
+func (t *sdkMemberDependencyTag) SdkMemberType() SdkMemberType {
+ return t.memberType
+}
+
+func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag {
+ return &sdkMemberDependencyTag{memberType: memberType}
+}
+
// Interface that must be implemented for every type that can be a member of an
// sdk.
//
@@ -240,6 +273,13 @@
// True if the member type supports the sdk/sdk_snapshot, false otherwise.
UsableWithSdkAndSdkSnapshot() bool
+ // Return true if modules of this type can have dependencies which should be
+ // treated as if they are sdk members.
+ //
+ // Any dependency that is to be treated as a member of the sdk needs to implement
+ // SdkAware and be added with an SdkMemberTypeDependencyTag tag.
+ HasTransitiveSdkMembers() bool
+
// Add dependencies from the SDK module to all the variants the member
// contributes to the SDK. The exact set of variants required is determined
// by the SDK and its properties. The dependencies must be added with the
@@ -267,8 +307,9 @@
// Base type for SdkMemberType implementations.
type SdkMemberTypeBase struct {
- PropertyName string
- SupportsSdk bool
+ PropertyName string
+ SupportsSdk bool
+ TransitiveSdkMembers bool
}
func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -279,6 +320,10 @@
return b.SupportsSdk
}
+func (b *SdkMemberTypeBase) HasTransitiveSdkMembers() bool {
+ return b.TransitiveSdkMembers
+}
+
// Encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
diff --git a/android/singleton.go b/android/singleton.go
index 91268ad..45a9b82 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -128,7 +128,7 @@
}
func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
- if (s.Config().UseGoma() || s.Config().UseRBE()) && params.Pool == nil {
+ if s.Config().UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
// jobs to the local parallelism value
params.Pool = localPool
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
new file mode 100644
index 0000000..198108d
--- /dev/null
+++ b/android/soong_config_modules.go
@@ -0,0 +1,368 @@
+// 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 android
+
+// This file provides module types that implement wrapper module types that add conditionals on
+// Soong config variables.
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+ "text/scanner"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/parser"
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android/soongconfig"
+)
+
+func init() {
+ RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
+ RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
+ RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
+ RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+}
+
+type soongConfigModuleTypeImport struct {
+ ModuleBase
+ properties soongConfigModuleTypeImportProperties
+}
+
+type soongConfigModuleTypeImportProperties struct {
+ From string
+ Module_types []string
+}
+
+// soong_config_module_type_import imports module types with conditionals on Soong config
+// variables from another Android.bp file. The imported module type will exist for all
+// modules after the import in the Android.bp file.
+//
+// For example, an Android.bp file could have:
+//
+// soong_config_module_type_import {
+// from: "device/acme/Android.bp",
+// module_types: ["acme_cc_defaults"],
+// }
+//
+// acme_cc_defaults {
+// name: "acme_defaults",
+// cflags: ["-DGENERIC"],
+// soong_config_variables: {
+// board: {
+// soc_a: {
+// cflags: ["-DSOC_A"],
+// },
+// soc_b: {
+// cflags: ["-DSOC_B"],
+// },
+// },
+// feature: {
+// cflags: ["-DFEATURE"],
+// },
+// },
+// }
+//
+// cc_library {
+// name: "libacme_foo",
+// defaults: ["acme_defaults"],
+// srcs: ["*.cpp"],
+// }
+//
+// And device/acme/Android.bp could have:
+//
+// soong_config_module_type {
+// name: "acme_cc_defaults",
+// module_type: "cc_defaults",
+// config_namespace: "acme",
+// variables: ["board", "feature"],
+// properties: ["cflags", "srcs"],
+// }
+//
+// soong_config_string_variable {
+// name: "board",
+// values: ["soc_a", "soc_b"],
+// }
+//
+// soong_config_bool_variable {
+// name: "feature",
+// }
+//
+// If an acme BoardConfig.mk file contained:
+//
+// SOONG_CONFIG_NAMESPACES += acme
+// SOONG_CONFIG_acme += \
+// board \
+// feature \
+//
+// SOONG_CONFIG_acme_board := soc_a
+// SOONG_CONFIG_acme_feature := true
+//
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
+func soongConfigModuleTypeImportFactory() Module {
+ module := &soongConfigModuleTypeImport{}
+
+ module.AddProperties(&module.properties)
+ AddLoadHook(module, func(ctx LoadHookContext) {
+ importModuleTypes(ctx, module.properties.From, module.properties.Module_types...)
+ })
+
+ initAndroidModuleBase(module)
+ return module
+}
+
+func (m *soongConfigModuleTypeImport) Name() string {
+ return "soong_config_module_type_import_" + soongconfig.CanonicalizeToProperty(m.properties.From)
+}
+
+func (*soongConfigModuleTypeImport) Nameless() {}
+func (*soongConfigModuleTypeImport) GenerateAndroidBuildActions(ModuleContext) {}
+
+// Create dummy modules for soong_config_module_type and soong_config_*_variable
+
+type soongConfigModuleTypeModule struct {
+ ModuleBase
+ properties soongconfig.ModuleTypeProperties
+}
+
+// soong_config_module_type defines module types with conditionals on Soong config
+// variables. The new module type will exist for all modules after the definition
+// in an Android.bp file, and can be imported into other Android.bp files using
+// soong_config_module_type_import.
+//
+// For example, an Android.bp file could have:
+//
+// soong_config_module_type {
+// name: "acme_cc_defaults",
+// module_type: "cc_defaults",
+// config_namespace: "acme",
+// variables: ["board", "feature"],
+// properties: ["cflags", "srcs"],
+// }
+//
+// soong_config_string_variable {
+// name: "board",
+// values: ["soc_a", "soc_b"],
+// }
+//
+// soong_config_bool_variable {
+// name: "feature",
+// }
+//
+// acme_cc_defaults {
+// name: "acme_defaults",
+// cflags: ["-DGENERIC"],
+// soong_config_variables: {
+// board: {
+// soc_a: {
+// cflags: ["-DSOC_A"],
+// },
+// soc_b: {
+// cflags: ["-DSOC_B"],
+// },
+// },
+// feature: {
+// cflags: ["-DFEATURE"],
+// },
+// },
+// }
+//
+// cc_library {
+// name: "libacme_foo",
+// defaults: ["acme_defaults"],
+// srcs: ["*.cpp"],
+// }
+//
+// If an acme BoardConfig.mk file contained:
+//
+// SOONG_CONFIG_NAMESPACES += acme
+// SOONG_CONFIG_acme += \
+// board \
+// feature \
+//
+// SOONG_CONFIG_acme_board := soc_a
+// SOONG_CONFIG_acme_feature := true
+//
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
+func soongConfigModuleTypeFactory() Module {
+ module := &soongConfigModuleTypeModule{}
+
+ module.AddProperties(&module.properties)
+
+ AddLoadHook(module, func(ctx LoadHookContext) {
+ // A soong_config_module_type module should implicitly import itself.
+ importModuleTypes(ctx, ctx.BlueprintsFile(), module.properties.Name)
+ })
+
+ initAndroidModuleBase(module)
+
+ return module
+}
+
+func (m *soongConfigModuleTypeModule) Name() string {
+ return m.properties.Name
+}
+func (*soongConfigModuleTypeModule) Nameless() {}
+func (*soongConfigModuleTypeModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+type soongConfigStringVariableDummyModule struct {
+ ModuleBase
+ properties soongconfig.VariableProperties
+ stringProperties soongconfig.StringVariableProperties
+}
+
+type soongConfigBoolVariableDummyModule struct {
+ ModuleBase
+ properties soongconfig.VariableProperties
+}
+
+// soong_config_string_variable defines a variable and a set of possible string values for use
+// in a soong_config_module_type definition.
+func soongConfigStringVariableDummyFactory() Module {
+ module := &soongConfigStringVariableDummyModule{}
+ module.AddProperties(&module.properties, &module.stringProperties)
+ initAndroidModuleBase(module)
+ return module
+}
+
+// soong_config_string_variable defines a variable with true or false values for use
+// in a soong_config_module_type definition.
+func soongConfigBoolVariableDummyFactory() Module {
+ module := &soongConfigBoolVariableDummyModule{}
+ module.AddProperties(&module.properties)
+ initAndroidModuleBase(module)
+ return module
+}
+
+func (m *soongConfigStringVariableDummyModule) Name() string {
+ return m.properties.Name
+}
+func (*soongConfigStringVariableDummyModule) Nameless() {}
+func (*soongConfigStringVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+func (m *soongConfigBoolVariableDummyModule) Name() string {
+ return m.properties.Name
+}
+func (*soongConfigBoolVariableDummyModule) Nameless() {}
+func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
+ from = filepath.Clean(from)
+ if filepath.Ext(from) != ".bp" {
+ ctx.PropertyErrorf("from", "%q must be a file with extension .bp", from)
+ return
+ }
+
+ if strings.HasPrefix(from, "../") {
+ ctx.PropertyErrorf("from", "%q must not use ../ to escape the source tree",
+ from)
+ return
+ }
+
+ moduleTypeDefinitions := loadSoongConfigModuleTypeDefinition(ctx, from)
+ if moduleTypeDefinitions == nil {
+ return
+ }
+ for _, moduleType := range moduleTypes {
+ if factory, ok := moduleTypeDefinitions[moduleType]; ok {
+ ctx.registerScopedModuleType(moduleType, factory)
+ } else {
+ ctx.PropertyErrorf("module_types", "module type %q not defined in %q",
+ moduleType, from)
+ }
+ }
+}
+
+// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
+// result so each file is only parsed once.
+func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[string]blueprint.ModuleFactory {
+ type onceKeyType string
+ key := NewCustomOnceKey(onceKeyType(filepath.Clean(from)))
+
+ reportErrors := func(ctx LoadHookContext, filename string, errs ...error) {
+ for _, err := range errs {
+ if parseErr, ok := err.(*parser.ParseError); ok {
+ ctx.Errorf(parseErr.Pos, "%s", parseErr.Err)
+ } else {
+ ctx.Errorf(scanner.Position{Filename: filename}, "%s", err)
+ }
+ }
+ }
+
+ return ctx.Config().Once(key, func() interface{} {
+ ctx.AddNinjaFileDeps(from)
+ r, err := ctx.Config().fs.Open(from)
+ if err != nil {
+ ctx.PropertyErrorf("from", "failed to open %q: %s", from, err)
+ return (map[string]blueprint.ModuleFactory)(nil)
+ }
+
+ mtDef, errs := soongconfig.Parse(r, from)
+
+ if len(errs) > 0 {
+ reportErrors(ctx, from, errs...)
+ return (map[string]blueprint.ModuleFactory)(nil)
+ }
+
+ globalModuleTypes := ctx.moduleFactories()
+
+ factories := make(map[string]blueprint.ModuleFactory)
+
+ for name, moduleType := range mtDef.ModuleTypes {
+ factory := globalModuleTypes[moduleType.BaseModuleType]
+ if factory != nil {
+ factories[name] = soongConfigModuleFactory(factory, moduleType)
+ } else {
+ reportErrors(ctx, from,
+ fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
+ }
+ }
+
+ if ctx.Failed() {
+ return (map[string]blueprint.ModuleFactory)(nil)
+ }
+
+ return factories
+ }).(map[string]blueprint.ModuleFactory)
+}
+
+// soongConfigModuleFactory takes an existing soongConfigModuleFactory and a ModuleType and returns
+// a new soongConfigModuleFactory that wraps the existing soongConfigModuleFactory and adds conditional on Soong config
+// variables.
+func soongConfigModuleFactory(factory blueprint.ModuleFactory,
+ moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
+
+ conditionalFactoryProps := soongconfig.CreateProperties(factory, moduleType)
+ if conditionalFactoryProps.IsValid() {
+ return func() (blueprint.Module, []interface{}) {
+ module, props := factory()
+
+ conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
+ props = append(props, conditionalProps.Interface())
+
+ AddLoadHook(module, func(ctx LoadHookContext) {
+ config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
+ for _, ps := range soongconfig.PropertiesToApply(moduleType, conditionalProps, config) {
+ ctx.AppendProperties(ps)
+ }
+ })
+
+ return module, props
+ }
+ } else {
+ return factory
+ }
+}
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
new file mode 100644
index 0000000..6ad88a2
--- /dev/null
+++ b/android/soong_config_modules_test.go
@@ -0,0 +1,141 @@
+// 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 android
+
+import (
+ "reflect"
+ "testing"
+)
+
+type soongConfigTestModule struct {
+ ModuleBase
+ props soongConfigTestModuleProperties
+}
+
+type soongConfigTestModuleProperties struct {
+ Cflags []string
+}
+
+func soongConfigTestModuleFactory() Module {
+ m := &soongConfigTestModule{}
+ m.AddProperties(&m.props)
+ InitAndroidModule(m)
+ return m
+}
+
+func (t soongConfigTestModule) GenerateAndroidBuildActions(ModuleContext) {}
+
+func TestSoongConfigModule(t *testing.T) {
+ configBp := `
+ soong_config_module_type {
+ name: "acme_test_defaults",
+ module_type: "test_defaults",
+ config_namespace: "acme",
+ variables: ["board", "feature1", "feature2", "FEATURE3"],
+ properties: ["cflags", "srcs"],
+ }
+
+ soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b"],
+ }
+
+ soong_config_bool_variable {
+ name: "feature1",
+ }
+
+ soong_config_bool_variable {
+ name: "feature2",
+ }
+
+ soong_config_bool_variable {
+ name: "FEATURE3",
+ }
+ `
+
+ importBp := `
+ soong_config_module_type_import {
+ from: "SoongConfig.bp",
+ module_types: ["acme_test_defaults"],
+ }
+ `
+
+ bp := `
+ acme_test_defaults {
+ name: "foo",
+ cflags: ["-DGENERIC"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ },
+ feature1: {
+ cflags: ["-DFEATURE1"],
+ },
+ feature2: {
+ cflags: ["-DFEATURE2"],
+ },
+ FEATURE3: {
+ cflags: ["-DFEATURE3"],
+ },
+ },
+ }
+ `
+
+ run := func(t *testing.T, bp string, fs map[string][]byte) {
+ config := TestConfig(buildDir, nil, bp, fs)
+
+ config.TestProductVariables.VendorVars = map[string]map[string]string{
+ "acme": map[string]string{
+ "board": "soc_a",
+ "feature1": "true",
+ "feature2": "false",
+ // FEATURE3 unset
+ },
+ }
+
+ ctx := NewTestContext()
+ ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("test_defaults", soongConfigTestModuleFactory)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseBlueprintsFiles("Android.bp")
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
+ if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("wanted foo cflags %q, got %q", w, g)
+ }
+ }
+
+ t.Run("single file", func(t *testing.T) {
+ run(t, configBp+bp, nil)
+ })
+
+ t.Run("import", func(t *testing.T) {
+ run(t, importBp+bp, map[string][]byte{
+ "SoongConfig.bp": []byte(configBp),
+ })
+ })
+}
diff --git a/android/soongconfig/config.go b/android/soongconfig/config.go
new file mode 100644
index 0000000..39a776c
--- /dev/null
+++ b/android/soongconfig/config.go
@@ -0,0 +1,51 @@
+// Copyright 2020 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 soongconfig
+
+import "strings"
+
+type SoongConfig interface {
+ // Bool interprets the variable named `name` as a boolean, returning true if, after
+ // lowercasing, it matches one of "1", "y", "yes", "on", or "true". Unset, or any other
+ // value will return false.
+ Bool(name string) bool
+
+ // String returns the string value of `name`. If the variable was not set, it will
+ // return the empty string.
+ String(name string) string
+
+ // IsSet returns whether the variable `name` was set by Make.
+ IsSet(name string) bool
+}
+
+func Config(vars map[string]string) SoongConfig {
+ return soongConfig(vars)
+}
+
+type soongConfig map[string]string
+
+func (c soongConfig) Bool(name string) bool {
+ v := strings.ToLower(c[name])
+ return v == "1" || v == "y" || v == "yes" || v == "on" || v == "true"
+}
+
+func (c soongConfig) String(name string) string {
+ return c[name]
+}
+
+func (c soongConfig) IsSet(name string) bool {
+ _, ok := c[name]
+ return ok
+}
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
new file mode 100644
index 0000000..aa4f5c5
--- /dev/null
+++ b/android/soongconfig/modules.go
@@ -0,0 +1,517 @@
+// Copyright 2020 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 soongconfig
+
+import (
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/parser"
+ "github.com/google/blueprint/proptools"
+)
+
+var soongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
+
+// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
+// result so each file is only parsed once.
+func Parse(r io.Reader, from string) (*SoongConfigDefinition, []error) {
+ scope := parser.NewScope(nil)
+ file, errs := parser.ParseAndEval(from, r, scope)
+
+ if len(errs) > 0 {
+ return nil, errs
+ }
+
+ mtDef := &SoongConfigDefinition{
+ ModuleTypes: make(map[string]*ModuleType),
+ variables: make(map[string]soongConfigVariable),
+ }
+
+ for _, def := range file.Defs {
+ switch def := def.(type) {
+ case *parser.Module:
+ newErrs := processImportModuleDef(mtDef, def)
+
+ if len(newErrs) > 0 {
+ errs = append(errs, newErrs...)
+ }
+
+ case *parser.Assignment:
+ // Already handled via Scope object
+ default:
+ panic("unknown definition type")
+ }
+ }
+
+ if len(errs) > 0 {
+ return nil, errs
+ }
+
+ for name, moduleType := range mtDef.ModuleTypes {
+ for _, varName := range moduleType.variableNames {
+ if v, ok := mtDef.variables[varName]; ok {
+ moduleType.Variables = append(moduleType.Variables, v)
+ } else {
+ return nil, []error{
+ fmt.Errorf("unknown variable %q in module type %q", varName, name),
+ }
+ }
+ }
+ }
+
+ return mtDef, nil
+}
+
+func processImportModuleDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
+ switch def.Type {
+ case "soong_config_module_type":
+ return processModuleTypeDef(v, def)
+ case "soong_config_string_variable":
+ return processStringVariableDef(v, def)
+ case "soong_config_bool_variable":
+ return processBoolVariableDef(v, def)
+ default:
+ // Unknown module types will be handled when the file is parsed as a normal
+ // Android.bp file.
+ }
+
+ return nil
+}
+
+type ModuleTypeProperties struct {
+ // the name of the new module type. Unlike most modules, this name does not need to be unique,
+ // although only one module type with any name will be importable into an Android.bp file.
+ Name string
+
+ // the module type that this module type will extend.
+ Module_type string
+
+ // the SOONG_CONFIG_NAMESPACE value from a BoardConfig.mk that this module type will read
+ // configuration variables from.
+ Config_namespace string
+
+ // the list of SOONG_CONFIG variables that this module type will read
+ Variables []string
+
+ // the list of properties that this module type will extend.
+ Properties []string
+}
+
+func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
+
+ props := &ModuleTypeProperties{}
+
+ _, errs = proptools.UnpackProperties(def.Properties, props)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ if props.Name == "" {
+ errs = append(errs, fmt.Errorf("name property must be set"))
+ }
+
+ if props.Config_namespace == "" {
+ errs = append(errs, fmt.Errorf("config_namespace property must be set"))
+ }
+
+ if props.Module_type == "" {
+ errs = append(errs, fmt.Errorf("module_type property must be set"))
+ }
+
+ if len(errs) > 0 {
+ return errs
+ }
+
+ mt := &ModuleType{
+ affectableProperties: props.Properties,
+ ConfigNamespace: props.Config_namespace,
+ BaseModuleType: props.Module_type,
+ variableNames: props.Variables,
+ }
+ v.ModuleTypes[props.Name] = mt
+
+ return nil
+}
+
+type VariableProperties struct {
+ Name string
+}
+
+type StringVariableProperties struct {
+ Values []string
+}
+
+func processStringVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
+ stringProps := &StringVariableProperties{}
+
+ base, errs := processVariableDef(def, stringProps)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ if len(stringProps.Values) == 0 {
+ return []error{fmt.Errorf("values property must be set")}
+ }
+
+ v.variables[base.variable] = &stringVariable{
+ baseVariable: base,
+ values: CanonicalizeToProperties(stringProps.Values),
+ }
+
+ return nil
+}
+
+func processBoolVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
+ base, errs := processVariableDef(def)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ v.variables[base.variable] = &boolVariable{
+ baseVariable: base,
+ }
+
+ return nil
+}
+
+func processVariableDef(def *parser.Module,
+ extraProps ...interface{}) (cond baseVariable, errs []error) {
+
+ props := &VariableProperties{}
+
+ allProps := append([]interface{}{props}, extraProps...)
+
+ _, errs = proptools.UnpackProperties(def.Properties, allProps...)
+ if len(errs) > 0 {
+ return baseVariable{}, errs
+ }
+
+ if props.Name == "" {
+ return baseVariable{}, []error{fmt.Errorf("name property must be set")}
+ }
+
+ return baseVariable{
+ variable: props.Name,
+ }, nil
+}
+
+type SoongConfigDefinition struct {
+ ModuleTypes map[string]*ModuleType
+
+ variables map[string]soongConfigVariable
+}
+
+// CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
+// property layout for the Soong config variables, with each possible value an interface{} that
+// contains a nil pointer to another newly constructed type that contains the affectable properties.
+// The reflect.Value will be cloned for each call to the Soong config module type's factory method.
+//
+// For example, the acme_cc_defaults example above would
+// produce a reflect.Value whose type is:
+// *struct {
+// Soong_config_variables struct {
+// Board struct {
+// Soc_a interface{}
+// Soc_b interface{}
+// }
+// }
+// }
+// And whose value is:
+// &{
+// Soong_config_variables: {
+// Board: {
+// Soc_a: (*struct{ Cflags []string })(nil),
+// Soc_b: (*struct{ Cflags []string })(nil),
+// },
+// },
+// }
+func CreateProperties(factory blueprint.ModuleFactory, moduleType *ModuleType) reflect.Value {
+ var fields []reflect.StructField
+
+ _, factoryProps := factory()
+ affectablePropertiesType := createAffectablePropertiesType(moduleType.affectableProperties, factoryProps)
+ if affectablePropertiesType == nil {
+ return reflect.Value{}
+ }
+
+ for _, c := range moduleType.Variables {
+ fields = append(fields, reflect.StructField{
+ Name: proptools.FieldNameForProperty(c.variableProperty()),
+ Type: c.variableValuesType(),
+ })
+ }
+
+ typ := reflect.StructOf([]reflect.StructField{{
+ Name: soongConfigProperty,
+ Type: reflect.StructOf(fields),
+ }})
+
+ props := reflect.New(typ)
+ structConditions := props.Elem().FieldByName(soongConfigProperty)
+
+ for i, c := range moduleType.Variables {
+ c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
+ }
+
+ return props
+}
+
+// createAffectablePropertiesType creates a reflect.Type of a struct that has a field for each affectable property
+// that exists in factoryProps.
+func createAffectablePropertiesType(affectableProperties []string, factoryProps []interface{}) reflect.Type {
+ affectableProperties = append([]string(nil), affectableProperties...)
+ sort.Strings(affectableProperties)
+
+ var recurse func(prefix string, aps []string) ([]string, reflect.Type)
+ recurse = func(prefix string, aps []string) ([]string, reflect.Type) {
+ var fields []reflect.StructField
+
+ for len(affectableProperties) > 0 {
+ p := affectableProperties[0]
+ if !strings.HasPrefix(affectableProperties[0], prefix) {
+ break
+ }
+ affectableProperties = affectableProperties[1:]
+
+ nestedProperty := strings.TrimPrefix(p, prefix)
+ if i := strings.IndexRune(nestedProperty, '.'); i >= 0 {
+ var nestedType reflect.Type
+ nestedPrefix := nestedProperty[:i+1]
+
+ affectableProperties, nestedType = recurse(prefix+nestedPrefix, affectableProperties)
+
+ if nestedType != nil {
+ nestedFieldName := proptools.FieldNameForProperty(strings.TrimSuffix(nestedPrefix, "."))
+
+ fields = append(fields, reflect.StructField{
+ Name: nestedFieldName,
+ Type: nestedType,
+ })
+ }
+ } else {
+ typ := typeForPropertyFromPropertyStructs(factoryProps, p)
+ if typ != nil {
+ fields = append(fields, reflect.StructField{
+ Name: proptools.FieldNameForProperty(nestedProperty),
+ Type: typ,
+ })
+ }
+ }
+ }
+
+ var typ reflect.Type
+ if len(fields) > 0 {
+ typ = reflect.StructOf(fields)
+ }
+ return affectableProperties, typ
+ }
+
+ affectableProperties, typ := recurse("", affectableProperties)
+ if len(affectableProperties) > 0 {
+ panic(fmt.Errorf("didn't handle all affectable properties"))
+ }
+
+ if typ != nil {
+ return reflect.PtrTo(typ)
+ }
+
+ return nil
+}
+
+func typeForPropertyFromPropertyStructs(psList []interface{}, property string) reflect.Type {
+ for _, ps := range psList {
+ if typ := typeForPropertyFromPropertyStruct(ps, property); typ != nil {
+ return typ
+ }
+ }
+
+ return nil
+}
+
+func typeForPropertyFromPropertyStruct(ps interface{}, property string) reflect.Type {
+ v := reflect.ValueOf(ps)
+ for len(property) > 0 {
+ if !v.IsValid() {
+ return nil
+ }
+
+ if v.Kind() == reflect.Interface {
+ if v.IsNil() {
+ return nil
+ } else {
+ v = v.Elem()
+ }
+ }
+
+ if v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ v = reflect.Zero(v.Type().Elem())
+ } else {
+ v = v.Elem()
+ }
+ }
+
+ if v.Kind() != reflect.Struct {
+ return nil
+ }
+
+ if index := strings.IndexRune(property, '.'); index >= 0 {
+ prefix := property[:index]
+ property = property[index+1:]
+
+ v = v.FieldByName(proptools.FieldNameForProperty(prefix))
+ } else {
+ f := v.FieldByName(proptools.FieldNameForProperty(property))
+ if !f.IsValid() {
+ return nil
+ }
+ return f.Type()
+ }
+ }
+ return nil
+}
+
+// PropertiesToApply returns the applicable properties from a ModuleType that should be applied
+// based on SoongConfig values.
+func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) []interface{} {
+ var ret []interface{}
+ props = props.Elem().FieldByName(soongConfigProperty)
+ for i, c := range moduleType.Variables {
+ if ps := c.PropertiesToApply(config, props.Field(i)); ps != nil {
+ ret = append(ret, ps)
+ }
+ }
+ return ret
+}
+
+type ModuleType struct {
+ BaseModuleType string
+ ConfigNamespace string
+ Variables []soongConfigVariable
+
+ affectableProperties []string
+ variableNames []string
+}
+
+type soongConfigVariable interface {
+ // variableProperty returns the name of the variable.
+ variableProperty() string
+
+ // conditionalValuesType returns a reflect.Type that contains an interface{} for each possible value.
+ variableValuesType() reflect.Type
+
+ // initializeProperties is passed a reflect.Value of the reflect.Type returned by conditionalValuesType and a
+ // reflect.Type of the affectable properties, and should initialize each interface{} in the reflect.Value with
+ // the zero value of the affectable properties type.
+ initializeProperties(v reflect.Value, typ reflect.Type)
+
+ // PropertiesToApply should return one of the interface{} values set by initializeProperties to be applied
+ // to the module.
+ PropertiesToApply(config SoongConfig, values reflect.Value) interface{}
+}
+
+type baseVariable struct {
+ variable string
+}
+
+func (c *baseVariable) variableProperty() string {
+ return CanonicalizeToProperty(c.variable)
+}
+
+type stringVariable struct {
+ baseVariable
+ values []string
+}
+
+func (s *stringVariable) variableValuesType() reflect.Type {
+ var fields []reflect.StructField
+
+ for _, v := range s.values {
+ fields = append(fields, reflect.StructField{
+ Name: proptools.FieldNameForProperty(v),
+ Type: emptyInterfaceType,
+ })
+ }
+
+ return reflect.StructOf(fields)
+}
+
+func (s *stringVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
+ for i := range s.values {
+ v.Field(i).Set(reflect.Zero(typ))
+ }
+}
+
+func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+ for j, v := range s.values {
+ if config.String(s.variable) == v {
+ return values.Field(j).Interface()
+ }
+ }
+
+ return nil
+}
+
+type boolVariable struct {
+ baseVariable
+}
+
+func (b boolVariable) variableValuesType() reflect.Type {
+ return emptyInterfaceType
+}
+
+func (b boolVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
+ v.Set(reflect.Zero(typ))
+}
+
+func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+ if config.Bool(b.variable) {
+ return values.Interface()
+ }
+
+ return nil
+}
+
+func CanonicalizeToProperty(v string) string {
+ return strings.Map(func(r rune) rune {
+ switch {
+ case r >= 'A' && r <= 'Z',
+ r >= 'a' && r <= 'z',
+ r >= '0' && r <= '9',
+ r == '_':
+ return r
+ default:
+ return '_'
+ }
+ }, v)
+}
+
+func CanonicalizeToProperties(values []string) []string {
+ ret := make([]string, len(values))
+ for i, v := range values {
+ ret[i] = CanonicalizeToProperty(v)
+ }
+ return ret
+}
+
+type emptyInterfaceStruct struct {
+ i interface{}
+}
+
+var emptyInterfaceType = reflect.TypeOf(emptyInterfaceStruct{}).Field(0).Type
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
new file mode 100644
index 0000000..4190016
--- /dev/null
+++ b/android/soongconfig/modules_test.go
@@ -0,0 +1,249 @@
+// Copyright 2020 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 soongconfig
+
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_CanonicalizeToProperty(t *testing.T) {
+ tests := []struct {
+ name string
+ arg string
+ want string
+ }{
+ {
+ name: "lowercase",
+ arg: "board",
+ want: "board",
+ },
+ {
+ name: "uppercase",
+ arg: "BOARD",
+ want: "BOARD",
+ },
+ {
+ name: "numbers",
+ arg: "BOARD123",
+ want: "BOARD123",
+ },
+ {
+ name: "underscore",
+ arg: "TARGET_BOARD",
+ want: "TARGET_BOARD",
+ },
+ {
+ name: "dash",
+ arg: "TARGET-BOARD",
+ want: "TARGET_BOARD",
+ },
+ {
+ name: "unicode",
+ arg: "boardλ",
+ want: "board_",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := CanonicalizeToProperty(tt.arg); got != tt.want {
+ t.Errorf("canonicalizeToProperty() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_typeForPropertyFromPropertyStruct(t *testing.T) {
+ tests := []struct {
+ name string
+ ps interface{}
+ property string
+ want string
+ }{
+ {
+ name: "string",
+ ps: struct {
+ A string
+ }{},
+ property: "a",
+ want: "string",
+ },
+ {
+ name: "list",
+ ps: struct {
+ A []string
+ }{},
+ property: "a",
+ want: "[]string",
+ },
+ {
+ name: "missing",
+ ps: struct {
+ A []string
+ }{},
+ property: "b",
+ want: "",
+ },
+ {
+ name: "nested",
+ ps: struct {
+ A struct {
+ B string
+ }
+ }{},
+ property: "a.b",
+ want: "string",
+ },
+ {
+ name: "missing nested",
+ ps: struct {
+ A struct {
+ B string
+ }
+ }{},
+ property: "a.c",
+ want: "",
+ },
+ {
+ name: "not a struct",
+ ps: struct {
+ A string
+ }{},
+ property: "a.b",
+ want: "",
+ },
+ {
+ name: "nested pointer",
+ ps: struct {
+ A *struct {
+ B string
+ }
+ }{},
+ property: "a.b",
+ want: "string",
+ },
+ {
+ name: "nested interface",
+ ps: struct {
+ A interface{}
+ }{
+ A: struct {
+ B string
+ }{},
+ },
+ property: "a.b",
+ want: "string",
+ },
+ {
+ name: "nested interface pointer",
+ ps: struct {
+ A interface{}
+ }{
+ A: &struct {
+ B string
+ }{},
+ },
+ property: "a.b",
+ want: "string",
+ },
+ {
+ name: "nested interface nil pointer",
+ ps: struct {
+ A interface{}
+ }{
+ A: (*struct {
+ B string
+ })(nil),
+ },
+ property: "a.b",
+ want: "string",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ typ := typeForPropertyFromPropertyStruct(tt.ps, tt.property)
+ got := ""
+ if typ != nil {
+ got = typ.String()
+ }
+ if got != tt.want {
+ t.Errorf("typeForPropertyFromPropertyStruct() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_createAffectablePropertiesType(t *testing.T) {
+ tests := []struct {
+ name string
+ affectableProperties []string
+ factoryProps interface{}
+ want string
+ }{
+ {
+ name: "string",
+ affectableProperties: []string{"cflags"},
+ factoryProps: struct {
+ Cflags string
+ }{},
+ want: "*struct { Cflags string }",
+ },
+ {
+ name: "list",
+ affectableProperties: []string{"cflags"},
+ factoryProps: struct {
+ Cflags []string
+ }{},
+ want: "*struct { Cflags []string }",
+ },
+ {
+ name: "string pointer",
+ affectableProperties: []string{"cflags"},
+ factoryProps: struct {
+ Cflags *string
+ }{},
+ want: "*struct { Cflags *string }",
+ },
+ {
+ name: "subset",
+ affectableProperties: []string{"cflags"},
+ factoryProps: struct {
+ Cflags string
+ Ldflags string
+ }{},
+ want: "*struct { Cflags string }",
+ },
+ {
+ name: "none",
+ affectableProperties: []string{"cflags"},
+ factoryProps: struct {
+ Ldflags string
+ }{},
+ want: "",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ typ := createAffectablePropertiesType(tt.affectableProperties, []interface{}{tt.factoryProps})
+ got := ""
+ if typ != nil {
+ got = typ.String()
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("createAffectablePropertiesType() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/android/testing.go b/android/testing.go
index c07af7f..9aff039 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -50,9 +50,9 @@
type TestContext struct {
*Context
- preArch, preDeps, postDeps []RegisterMutatorFunc
- NameResolver *NameResolver
- config Config
+ preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
+ NameResolver *NameResolver
+ config Config
}
func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -72,12 +72,16 @@
ctx.postDeps = append(ctx.postDeps, f)
}
+func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) {
+ ctx.finalDeps = append(ctx.finalDeps, f)
+}
+
func (ctx *TestContext) Register(config Config) {
ctx.SetFs(config.fs)
if config.mockBpList != "" {
ctx.SetModuleListFile(config.mockBpList)
}
- registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
+ registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
ctx.RegisterSingletonType("env", EnvSingleton)
diff --git a/android/util.go b/android/util.go
index 81f481d..ade851e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -121,8 +121,19 @@
return IndexList(s, list) != -1
}
-func PrefixInList(s string, list []string) bool {
- for _, prefix := range list {
+// Returns true if the given string s is prefixed with any string in the given prefix list.
+func HasAnyPrefix(s string, prefixList []string) bool {
+ for _, prefix := range prefixList {
+ if strings.HasPrefix(s, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+// Returns true if any string in the given list has the given prefix.
+func PrefixInList(list []string, prefix string) bool {
+ for _, s := range list {
if strings.HasPrefix(s, prefix) {
return true
}
diff --git a/android/util_test.go b/android/util_test.go
index 90fefee..1f9ca36 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -252,7 +252,7 @@
for _, testCase := range testcases {
t.Run(testCase.str, func(t *testing.T) {
- out := PrefixInList(testCase.str, prefixes)
+ out := HasAnyPrefix(testCase.str, prefixes)
if out != testCase.expected {
t.Errorf("incorrect output:")
t.Errorf(" str: %#v", testCase.str)
diff --git a/android/variable.go b/android/variable.go
index 2bf84dd..9cbe624 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -25,7 +25,7 @@
func init() {
PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("variable", variableMutator).Parallel()
+ ctx.BottomUp("variable", VariableMutator).Parallel()
})
}
@@ -43,8 +43,10 @@
} `android:"arch_variant"`
Malloc_not_svelte struct {
- Cflags []string `android:"arch_variant"`
- Shared_libs []string `android:"arch_variant"`
+ Cflags []string `android:"arch_variant"`
+ Shared_libs []string `android:"arch_variant"`
+ Whole_static_libs []string `android:"arch_variant"`
+ Exclude_static_libs []string `android:"arch_variant"`
} `android:"arch_variant"`
Safestack struct {
@@ -123,10 +125,16 @@
Experimental_mte struct {
Cflags []string `android:"arch_variant"`
} `android:"arch_variant"`
+
+ Native_coverage struct {
+ Src *string `android:"arch_variant"`
+ Srcs []string `android:"arch_variant"`
+ Exclude_srcs []string `android:"arch_variant"`
+ } `android:"arch_variant"`
} `android:"arch_variant"`
}
-var zeroProductVariables interface{} = variableProperties{}
+var defaultProductVariables interface{} = variableProperties{}
type productVariables struct {
// Suffix to add to generated Makefiles
@@ -204,6 +212,9 @@
Binder32bit *bool `json:",omitempty"`
UseGoma *bool `json:",omitempty"`
UseRBE *bool `json:",omitempty"`
+ UseRBEJAVAC *bool `json:",omitempty"`
+ UseRBER8 *bool `json:",omitempty"`
+ UseRBED8 *bool `json:",omitempty"`
Debuggable *bool `json:",omitempty"`
Eng *bool `json:",omitempty"`
Treble_linker_namespaces *bool `json:",omitempty"`
@@ -219,7 +230,8 @@
UncompressPrivAppDex *bool `json:",omitempty"`
ModulesLoadedByPrivilegedModules []string `json:",omitempty"`
- BootJars []string `json:",omitempty"`
+ BootJars []string `json:",omitempty"`
+ UpdatableBootJars []string `json:",omitempty"`
IntegerOverflowExcludePaths []string `json:",omitempty"`
@@ -229,9 +241,6 @@
DisableScudo *bool `json:",omitempty"`
- EnableXOM *bool `json:",omitempty"`
- XOMExcludePaths []string `json:",omitempty"`
-
Experimental_mte *bool `json:",omitempty"`
VendorPath *string `json:",omitempty"`
@@ -242,7 +251,9 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
- NativeCoverage *bool `json:",omitempty"`
+ NativeLineCoverage *bool `json:",omitempty"`
+ Native_coverage *bool `json:",omitempty"`
+ ClangCoverage *bool `json:",omitempty"`
CoveragePaths []string `json:",omitempty"`
CoverageExcludePaths []string `json:",omitempty"`
@@ -316,6 +327,8 @@
EnforceProductPartitionInterface *bool `json:",omitempty"`
InstallExtraFlattenedApexes *bool `json:",omitempty"`
+
+ BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -370,7 +383,7 @@
}
}
-func variableMutator(mctx BottomUpMutatorContext) {
+func VariableMutator(mctx BottomUpMutatorContext) {
var module Module
var ok bool
if module, ok = mctx.Module().(Module); !ok {
@@ -385,11 +398,9 @@
}
variableValues := reflect.ValueOf(a.variableProperties).Elem().FieldByName("Product_variables")
- zeroValues := reflect.ValueOf(zeroProductVariables).FieldByName("Product_variables")
for i := 0; i < variableValues.NumField(); i++ {
variableValue := variableValues.Field(i)
- zeroValue := zeroValues.Field(i)
name := variableValues.Type().Field(i).Name
property := "product_variables." + proptools.PropertyNameForField(name)
@@ -407,10 +418,9 @@
}
// Check if any properties were set for the module
- if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) {
+ if variableValue.IsZero() {
continue
}
-
a.setVariableProperties(mctx, property, variableValue, val.Interface())
}
}
@@ -528,6 +538,20 @@
return ret.Interface()
}
+func initProductVariableModule(m Module) {
+ base := m.base()
+
+ // Allow tests to override the default product variables
+ if base.variableProperties == nil {
+ base.variableProperties = defaultProductVariables
+ }
+ // Filter the product variables properties to the ones that exist on this module
+ base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
+ if base.variableProperties != nil {
+ m.AddProperties(base.variableProperties)
+ }
+}
+
// createVariableProperties takes the list of property structs for a module and returns a property struct that
// contains the product variable properties that exist in the property structs, or nil if there are none. It
// caches the result.
diff --git a/android/variable_test.go b/android/variable_test.go
index 451d43d..9cafedd 100644
--- a/android/variable_test.go
+++ b/android/variable_test.go
@@ -148,7 +148,7 @@
clonedProps := proptools.CloneProperties(reflect.ValueOf(props)).Interface()
m.AddProperties(clonedProps)
- // Set a default variableProperties, this will be used as the input to the property struct filter
+ // Set a default soongConfigVariableProperties, this will be used as the input to the property struct filter
// for this test module.
m.variableProperties = testProductVariableProperties
InitAndroidModule(m)
@@ -159,19 +159,19 @@
func TestProductVariables(t *testing.T) {
ctx := NewTestContext()
// A module type that has a srcs property but not a cflags property.
- ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(struct {
+ ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct {
Srcs []string
}{}))
// A module type that has a cflags property but not a srcs property.
- ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(struct {
+ ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct {
Cflags []string
}{}))
// A module type that does not have any properties that match product_variables.
- ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(struct {
+ ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct {
Foo []string
}{}))
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("variable", variableMutator).Parallel()
+ ctx.BottomUp("variable", VariableMutator).Parallel()
})
// Test that a module can use one product variable even if it doesn't have all the properties
@@ -209,6 +209,115 @@
FailIfErrored(t, errs)
}
+var testProductVariableDefaultsProperties = struct {
+ Product_variables struct {
+ Eng struct {
+ Foo []string
+ Bar []string
+ }
+ }
+}{}
+
+type productVariablesDefaultsTestProperties struct {
+ Foo []string
+}
+
+type productVariablesDefaultsTestProperties2 struct {
+ Foo []string
+ Bar []string
+}
+
+type productVariablesDefaultsTestModule struct {
+ ModuleBase
+ DefaultableModuleBase
+ properties productVariablesDefaultsTestProperties
+}
+
+func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ ctx.Build(pctx, BuildParams{
+ Rule: Touch,
+ Output: PathForModuleOut(ctx, "out"),
+ })
+}
+
+func productVariablesDefaultsTestModuleFactory() Module {
+ module := &productVariablesDefaultsTestModule{}
+ module.AddProperties(&module.properties)
+ module.variableProperties = testProductVariableDefaultsProperties
+ InitAndroidModule(module)
+ InitDefaultableModule(module)
+ return module
+}
+
+type productVariablesDefaultsTestDefaults struct {
+ ModuleBase
+ DefaultsModuleBase
+}
+
+func productVariablesDefaultsTestDefaultsFactory() Module {
+ defaults := &productVariablesDefaultsTestDefaults{}
+ defaults.AddProperties(&productVariablesDefaultsTestProperties{})
+ defaults.AddProperties(&productVariablesDefaultsTestProperties2{})
+ defaults.variableProperties = testProductVariableDefaultsProperties
+ InitDefaultsModule(defaults)
+ return defaults
+}
+
+// Test a defaults module that supports more product variable properties than the target module.
+func TestProductVariablesDefaults(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults",
+ product_variables: {
+ eng: {
+ foo: ["product_variable_defaults"],
+ bar: ["product_variable_defaults"],
+ },
+ },
+ foo: ["defaults"],
+ bar: ["defaults"],
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults"],
+ foo: ["module"],
+ product_variables: {
+ eng: {
+ foo: ["product_variable_module"],
+ },
+ },
+ }
+ `
+
+ config := TestConfig(buildDir, nil, bp, nil)
+ config.TestProductVariables.Eng = boolPtr(true)
+
+ ctx := NewTestContext()
+
+ ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory)
+ ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory)
+
+ ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+ ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("variable", VariableMutator).Parallel()
+ })
+
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ foo := ctx.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule)
+
+ want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"}
+ if g, w := foo.properties.Foo, want; !reflect.DeepEqual(g, w) {
+ t.Errorf("expected foo %q, got %q", w, g)
+ }
+}
+
func BenchmarkSliceToTypeArray(b *testing.B) {
for _, n := range []int{1, 2, 4, 8, 100} {
var propStructs []interface{}
diff --git a/android/visibility.go b/android/visibility.go
index a597687..3f04123 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -186,8 +186,8 @@
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
// The map from qualifiedModuleName to visibilityRule.
-func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
- return ctx.Config().Once(visibilityRuleMap, func() interface{} {
+func moduleToVisibilityRuleMap(config Config) *sync.Map {
+ return config.Once(visibilityRuleMap, func() interface{} {
return &sync.Map{}
}).(*sync.Map)
}
@@ -304,7 +304,7 @@
if visibility := m.visibility(); visibility != nil {
rule := parseRules(ctx, currentPkg, m.visibility())
if rule != nil {
- moduleToVisibilityRuleMap(ctx).Store(qualifiedModuleId, rule)
+ moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
}
}
}
@@ -312,6 +312,7 @@
func parseRules(ctx BaseModuleContext, currentPkg string, visibility []string) compositeRule {
rules := make(compositeRule, 0, len(visibility))
hasPrivateRule := false
+ hasPublicRule := false
hasNonPrivateRule := false
for _, v := range visibility {
ok, pkg, name := splitRule(v, currentPkg)
@@ -328,6 +329,7 @@
isPrivateRule = true
case "public":
r = publicRule{}
+ hasPublicRule = true
}
} else {
switch name {
@@ -355,6 +357,11 @@
return compositeRule{privateRule{}}
}
+ if hasPublicRule {
+ // Public overrides all other rules so just return it.
+ return compositeRule{publicRule{}}
+ }
+
return rules
}
@@ -415,21 +422,21 @@
return
}
- rule := effectiveVisibilityRules(ctx, depQualified)
+ rule := effectiveVisibilityRules(ctx.Config(), depQualified)
if rule != nil && !rule.matches(qualified) {
ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
}
})
}
-func effectiveVisibilityRules(ctx BaseModuleContext, qualified qualifiedModuleName) compositeRule {
- moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
+ moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
value, ok := moduleToVisibilityRule.Load(qualified)
var rule compositeRule
if ok {
rule = value.(compositeRule)
} else {
- rule = packageDefaultVisibility(ctx, qualified)
+ rule = packageDefaultVisibility(config, qualified)
}
return rule
}
@@ -441,8 +448,8 @@
return qualified
}
-func packageDefaultVisibility(ctx BaseModuleContext, moduleId qualifiedModuleName) compositeRule {
- moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
+ moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
packageQualifiedId := moduleId.getContainingPackageId()
for {
value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
@@ -469,7 +476,7 @@
dir := ctx.OtherModuleDir(module)
qualified := qualifiedModuleName{dir, moduleName}
- rule := effectiveVisibilityRules(ctx, qualified)
+ rule := effectiveVisibilityRules(ctx.Config(), qualified)
return rule.Strings()
}
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 6006072..8dd6a8f 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1,15 +1,17 @@
package android
import (
+ "reflect"
"testing"
"github.com/google/blueprint"
)
var visibilityTests = []struct {
- name string
- fs map[string][]byte
- expectedErrors []string
+ name string
+ fs map[string][]byte
+ expectedErrors []string
+ effectiveVisibility map[qualifiedModuleName][]string
}{
{
name: "invalid visibility: empty list",
@@ -493,6 +495,9 @@
deps: ["libexample"],
}`),
},
+ effectiveVisibility: map[qualifiedModuleName][]string{
+ qualifiedModuleName{pkg: "top", name: "libexample"}: {"//visibility:public"},
+ },
},
{
name: "//visibility:public mixed with other from different defaults 1",
@@ -903,13 +908,27 @@
func TestVisibility(t *testing.T) {
for _, test := range visibilityTests {
t.Run(test.name, func(t *testing.T) {
- _, errs := testVisibility(buildDir, test.fs)
+ ctx, errs := testVisibility(buildDir, test.fs)
CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
+
+ if test.effectiveVisibility != nil {
+ checkEffectiveVisibility(t, ctx, test.effectiveVisibility)
+ }
})
}
}
+func checkEffectiveVisibility(t *testing.T, ctx *TestContext, effectiveVisibility map[qualifiedModuleName][]string) {
+ for moduleName, expectedRules := range effectiveVisibility {
+ rule := effectiveVisibilityRules(ctx.config, moduleName)
+ stringRules := rule.Strings()
+ if !reflect.DeepEqual(expectedRules, stringRules) {
+ t.Errorf("effective rules mismatch: expected %q, found %q", expectedRules, stringRules)
+ }
+ }
+}
+
func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []error) {
// Create a new config per test as visibility information is stored in the config.
diff --git a/android/vts_config.go b/android/vts_config.go
index 86f6e72..9a1df7c 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -17,6 +17,7 @@
import (
"fmt"
"io"
+ "strings"
)
func init() {
@@ -26,6 +27,8 @@
type vtsConfigProperties struct {
// Override the default (AndroidTest.xml) test manifest file name.
Test_config *string
+ // Additional test suites to add the test to.
+ Test_suites []string `android:"arch_variant"`
}
type VtsConfig struct {
@@ -50,7 +53,8 @@
fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
*me.properties.Test_config)
}
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := vts")
+ fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n",
+ strings.Join(me.properties.Test_suites, " "))
},
}
return androidMkData
diff --git a/apex/androidmk.go b/apex/androidmk.go
index ad7d2f1..0abec0d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -42,7 +42,11 @@
}}
}
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
+ // apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
+ // An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
+ // In many cases, the two names are the same, but could be different in general.
+
moduleNames := []string{}
apexType := a.properties.ApexType
// To avoid creating duplicate build rules, run this function only when primaryApexType is true
@@ -52,13 +56,48 @@
return moduleNames
}
+ // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
+ // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
+ // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
+ // for the overriding VNDK APEXes.
+ symbolFilesNotNeeded := a.vndkApex && len(a.overridableProperties.Overrides) > 0
+ if symbolFilesNotNeeded && apexType != flattenedApex {
+ return moduleNames
+ }
+
+ var postInstallCommands []string
+ for _, fi := range a.filesInfo {
+ if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
+ // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
+ linkTarget := filepath.Join("/system", fi.Path())
+ linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.Path())
+ mkdirCmd := "mkdir -p " + filepath.Dir(linkPath)
+ linkCmd := "ln -sfn " + linkTarget + " " + linkPath
+ postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd)
+ }
+ }
+
for _, fi := range a.filesInfo {
if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
continue
}
- if !android.InList(fi.moduleName, moduleNames) {
- moduleNames = append(moduleNames, fi.moduleName)
+ linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform()
+
+ var moduleName string
+ if linkToSystemLib {
+ moduleName = fi.moduleName
+ } else {
+ moduleName = fi.moduleName + "." + apexBundleName + a.suffix
+ }
+
+ if !android.InList(moduleName, moduleNames) {
+ moduleNames = append(moduleNames, moduleName)
+ }
+
+ if linkToSystemLib {
+ // No need to copy the file since it's linked to the system file
+ continue
}
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
@@ -67,14 +106,14 @@
} else {
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
}
- fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
+ fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName)
// /apex/<apex_name>/{lib|framework|...}
pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
if apexType == flattenedApex {
// /system/apex/<name>/{lib|framework|...}
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
- apexName, fi.installDir))
- if a.primaryApexType {
+ apexBundleName, fi.installDir))
+ if a.primaryApexType && !symbolFilesNotNeeded {
fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
}
if len(fi.symlinks) > 0 {
@@ -86,6 +125,11 @@
}
} else {
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated)
+
+ // For non-flattend APEXes, the merged notice file is attached to the APEX itself.
+ // We don't need to have notice file for the individual modules in it. Otherwise,
+ // we will have duplicated notice entries.
+ fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
}
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
@@ -132,6 +176,7 @@
fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
} else if fi.class == app {
+ fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", fi.certificate.AndroidMkString())
// soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk Therefore
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
// we will have foo.apk.apk
@@ -151,22 +196,33 @@
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
} else {
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
- if a.primaryApexType && fi.builtFile == a.manifestPbOut {
- // Make apex_manifest.pb module for this APEX to override all other
- // modules in the APEXes being overridden by this APEX
- var patterns []string
- for _, o := range a.overridableProperties.Overrides {
- patterns = append(patterns, "%."+o+a.suffix)
- }
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
+ if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
+ if a.primaryApexType {
+ // Make apex_manifest.pb module for this APEX to override all other
+ // modules in the APEXes being overridden by this APEX
+ var patterns []string
+ for _, o := range a.overridableProperties.Overrides {
+ patterns = append(patterns, "%."+o+a.suffix)
+ }
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
- if len(a.compatSymlinks) > 0 {
- // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(a.compatSymlinks, " && "))
+ if len(a.compatSymlinks) > 0 {
+ // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
+ postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
+ }
+ }
+ if len(postInstallCommands) > 0 {
+ fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
}
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
}
+
+ // m <module_name> will build <module_name>.<apex_name> as well.
+ if fi.moduleName != moduleName && a.primaryApexType {
+ fmt.Fprintln(w, ".PHONY: "+fi.moduleName)
+ fmt.Fprintln(w, fi.moduleName+": "+moduleName)
+ }
}
return moduleNames
}
@@ -199,7 +255,7 @@
apexType := a.properties.ApexType
if a.installable() {
apexName := proptools.StringDefault(a.properties.Apex_name, name)
- moduleNames = a.androidMkForFiles(w, apexName, moduleDir)
+ moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir)
}
if apexType == flattenedApex {
@@ -240,6 +296,11 @@
if len(postInstallCommands) > 0 {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
}
+
+ if a.mergedNotices.Merged.Valid() {
+ fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())
+ }
+
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
if apexType == imageApex {
diff --git a/apex/apex.go b/apex/apex.go
index 33b1be3..79fdb71 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -45,18 +45,21 @@
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
+
+ // determines if the dependent will be part of the APEX payload
+ payload bool
}
var (
- sharedLibTag = dependencyTag{name: "sharedLib"}
- executableTag = dependencyTag{name: "executable"}
- javaLibTag = dependencyTag{name: "javaLib"}
- prebuiltTag = dependencyTag{name: "prebuilt"}
- testTag = dependencyTag{name: "test"}
+ sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
+ executableTag = dependencyTag{name: "executable", payload: true}
+ javaLibTag = dependencyTag{name: "javaLib", payload: true}
+ prebuiltTag = dependencyTag{name: "prebuilt", payload: true}
+ testTag = dependencyTag{name: "test", payload: true}
keyTag = dependencyTag{name: "key"}
certificateTag = dependencyTag{name: "certificate"}
usesTag = dependencyTag{name: "uses"}
- androidAppTag = dependencyTag{name: "androidApp"}
+ androidAppTag = dependencyTag{name: "androidApp", payload: true}
apexAvailWl = makeApexAvailableWhitelist()
)
@@ -70,107 +73,322 @@
//
// Module separator
//
- m["com.android.adbd"] = []string{"adbd", "libcrypto"}
+ m["com.android.adbd"] = []string{
+ "adbd",
+ "bcm_object",
+ "fmtlib",
+ "libadbconnection_server",
+ "libadbd",
+ "libadbd_auth",
+ "libadbd_core",
+ "libadbd_services",
+ "libasyncio",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libbuildversion",
+ "libc++",
+ "libcap",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "libcutils_headers",
+ "libdiagnose_usb",
+ "liblog_headers",
+ "libmdnssd",
+ "libminijail",
+ "libminijail_gen_constants",
+ "libminijail_gen_constants_obj",
+ "libminijail_gen_syscall",
+ "libminijail_gen_syscall_obj",
+ "libminijail_generated",
+ "libpackagelistparser",
+ "libpcre2",
+ "libprocessgroup_headers",
+ "libqemu_pipe",
+ "libselinux",
+ "libsystem_headers",
+ "libutils_headers",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.appsearch"] = []string{
+ "icing-java-proto-lite",
+ "libprotobuf-java-lite",
+ }
//
// Module separator
//
m["com.android.art"] = []string{
+ "art_cmdlineparser_headers",
+ "art_disassembler_headers",
+ "art_libartbase_headers",
+ "bcm_object",
+ "bionic_libc_platform_headers",
+ "core-repackaged-icu4j",
+ "cpp-define-generator-asm-support",
+ "cpp-define-generator-definitions",
+ "crtbegin_dynamic",
+ "crtbegin_dynamic1",
+ "crtbegin_so1",
+ "crtbrand",
+ "conscrypt.module.intra.core.api.stubs",
+ "dex2oat_headers",
+ "dt_fd_forward_export",
+ "fmtlib",
+ "icu4c_extra_headers",
"jacocoagent",
+ "javavm_headers",
+ "jni_platform_headers",
+ "libPlatformProperties",
+ "libadbconnection_client",
"libadbconnection_server",
+ "libandroidicuinit",
+ "libart_runtime_headers_ndk",
"libartd-disassembler",
+ "libasync_safe",
"libbacktrace",
"libbase",
+ "libbase_headers",
"libc++",
+ "libc++_static",
+ "libc++abi",
+ "libc++demangle",
+ "libc_headers",
"libcrypto",
+ "libdexfile_all_headers",
+ "libdexfile_external_headers",
"libdexfile_support",
+ "libdmabufinfo",
"libexpat",
+ "libfdlibm",
+ "libgtest_prod",
+ "libicui18n_headers",
"libicuuc",
+ "libicuuc_headers",
+ "libicuuc_stubdata",
+ "libjdwp_headers",
+ "liblog_headers",
+ "liblz4",
"liblzma",
"libmeminfo",
+ "libnativebridge-headers",
+ "libnativehelper_header_only",
+ "libnativeloader-headers",
+ "libnpt_headers",
+ "libopenjdkjvmti_headers",
+ "libperfetto_client_experimental",
"libprocinfo",
+ "libprotobuf-cpp-lite",
+ "libunwind_llvm",
"libunwindstack",
+ "libv8",
+ "libv8base",
+ "libv8gen",
+ "libv8platform",
+ "libv8sampler",
+ "libv8src",
"libvixl",
"libvixld",
"libz",
"libziparchive",
- "prebuilt_libclang_rt",
+ "perfetto_trace_protos",
}
//
// Module separator
//
m["com.android.bluetooth.updatable"] = []string{
"android.hardware.audio.common@5.0",
- "android.hardware.bluetooth@1.0",
- "android.hardware.bluetooth@1.1",
"android.hardware.bluetooth.a2dp@1.0",
"android.hardware.bluetooth.audio@2.0",
+ "android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.media@1.0",
"android.hidl.safe_union@1.0",
+ "android.hidl.token@1.0",
+ "android.hidl.token@1.0-utils",
+ "avrcp-target-service",
+ "avrcp_headers",
+ "bcm_object",
+ "bluetooth-protos-lite",
+ "bluetooth.mapsapi",
+ "com.android.vcard",
+ "fmtlib",
+ "guava",
+ "internal_include_headers",
+ "lib-bt-packets",
+ "lib-bt-packets-avrcp",
+ "lib-bt-packets-base",
+ "libFraunhoferAAC",
+ "libaudio-a2dp-hw-utils",
+ "libaudio-hearing-aid-hw-utils",
+ "libbacktrace_headers",
"libbase",
- "libbinderthreadstate",
+ "libbase_headers",
+ "libbinder_headers",
"libbluetooth",
+ "libbluetooth-types",
+ "libbluetooth-types-header",
+ "libbluetooth_gd",
+ "libbluetooth_headers",
"libbluetooth_jni",
+ "libbt-audio-hal-interface",
+ "libbt-bta",
+ "libbt-common",
+ "libbt-hci",
+ "libbt-platform-protos-lite",
+ "libbt-protos-lite",
+ "libbt-sbc-decoder",
+ "libbt-sbc-encoder",
+ "libbt-stack",
+ "libbt-utils",
+ "libbtcore",
+ "libbtdevice",
+ "libbte",
+ "libbtif",
"libc++",
"libchrome",
"libcrypto",
"libcutils",
+ "libcutils_headers",
"libevent",
"libfmq",
+ "libg722codec",
+ "libgtest_prod",
+ "libgui_headers",
"libhidlbase",
+ "libhidlbase-impl-internal",
+ "libhidltransport-impl-internal",
+ "libhwbinder-impl-internal",
+ "libjsoncpp",
+ "liblog_headers",
+ "libmedia_headers",
+ "libmodpb64",
+ "libosi",
"libprocessgroup",
+ "libprocessgroup_headers",
"libprotobuf-cpp-lite",
+ "libprotobuf-java-lite",
+ "libprotobuf-java-micro",
+ "libstagefright_foundation_headers",
+ "libstagefright_headers",
"libstatslog",
+ "libstatssocket",
+ "libsystem_headers",
"libtinyxml2",
- "libutils",
+ "libudrv-uipc",
+ "libutils_headers",
"libz",
+ "media_plugin_headers",
+ "sap-api-java-static",
+ "services.net",
}
//
// Module separator
//
- m["com.android.conscrypt"] = []string{"boringssl_self_test", "libc++", "libcrypto", "libssl"}
+ m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
//
// Module separator
//
- m["com.android.cronet"] = []string{"org.chromium.net.cronet", "prebuilt_libcronet.80.0.3986.0"}
+ m["com.android.conscrypt"] = []string{
+ "bcm_object",
+ "boringssl_self_test",
+ "libc++",
+ "libcrypto",
+ "libnativehelper_header_only",
+ "libssl",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.extservices"] = []string{
+ "flatbuffer_headers",
+ "liblua",
+ "libtextclassifier",
+ "libtextclassifier_hash_static",
+ "libtflite_static",
+ "libutf",
+ "libz_current",
+ "tensorflow_headers",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.cronet"] = []string{
+ "cronet_impl_common_java",
+ "cronet_impl_native_java",
+ "cronet_impl_platform_java",
+ "libcronet.80.0.3986.0",
+ "org.chromium.net.cronet",
+ "prebuilt_libcronet.80.0.3986.0",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.neuralnetworks"] = []string{
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
+ "android.hardware.neuralnetworks@1.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory.token@1.0",
+ "android.hidl.memory@1.0",
+ "android.hidl.safe_union@1.0",
+ "bcm_object",
+ "fmtlib",
+ "gemmlowp_headers",
+ "libarect",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libbuildversion",
+ "libc++",
+ "libcrypto",
+ "libcrypto_static",
+ "libcutils",
+ "libcutils_headers",
+ "libeigen",
+ "libfmq",
+ "libhidlbase",
+ "libhidlbase-impl-internal",
+ "libhidlmemory",
+ "libhidltransport-impl-internal",
+ "libhwbinder-impl-internal",
+ "libjsoncpp",
+ "liblog_headers",
+ "libmath",
+ "libneuralnetworks_common",
+ "libneuralnetworks_headers",
+ "libprocessgroup",
+ "libprocessgroup_headers",
+ "libprocpartition",
+ "libsync",
+ "libsystem_headers",
+ "libtextclassifier_hash",
+ "libtextclassifier_hash_headers",
+ "libtextclassifier_hash_static",
+ "libtflite_kernel_utils",
+ "libutils_headers",
+ "philox_random",
+ "philox_random_headers",
+ "tensorflow_headers",
+ }
//
// Module separator
//
m["com.android.media"] = []string{
- "android.hardware.cas@1.0",
- "android.hardware.cas.native@1.0",
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
- "android.hidl.memory.token@1.0",
- "android.hidl.token@1.0",
- "android.hidl.token@1.0-utils",
- "libaacextractor",
- "libamrextractor",
- "libbase",
- "libbinderthreadstate",
- "libc++",
- "libcrypto",
- "libcutils",
- "libflacextractor",
- "libhidlbase",
- "libhidlmemory",
- "libmidiextractor",
- "libmkvextractor",
- "libmp3extractor",
- "libmp4extractor",
- "libmpeg2extractor",
- "liboggextractor",
- "libprocessgroup",
- "libutils",
- "libwavextractor",
- "updatable-media",
- }
- //
- // Module separator
- //
- m["com.android.media.swcodec"] = []string{
"android.frameworks.bufferhub@1.0",
+ "android.hardware.cas.native@1.0",
+ "android.hardware.cas@1.0",
+ "android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
- "android.hardware.configstore-utils",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.bufferqueue@1.0",
@@ -181,23 +399,196 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.media.omx@1.0",
"android.hardware.media@1.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory.token@1.0",
+ "android.hidl.memory@1.0",
+ "android.hidl.token@1.0",
+ "android.hidl.token@1.0-utils",
+ "bcm_object",
+ "bionic_libc_platform_headers",
+ "fmtlib",
+ "gl_headers",
+ "libEGL",
+ "libEGL_blobCache",
+ "libEGL_getProcAddress",
+ "libFLAC",
+ "libFLAC-config",
+ "libFLAC-headers",
+ "libGLESv2",
+ "libaacextractor",
+ "libamrextractor",
+ "libarect",
+ "libasync_safe",
+ "libaudio_system_headers",
+ "libaudioclient",
+ "libaudioclient_headers",
+ "libaudiofoundation",
+ "libaudiofoundation_headers",
+ "libaudiomanager",
+ "libaudiopolicy",
+ "libaudioutils",
+ "libaudioutils_fixedfft",
+ "libbacktrace",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libbinder_headers",
+ "libbluetooth-types-header",
+ "libbufferhub",
+ "libbufferhub_headers",
+ "libbufferhubqueue",
+ "libc++",
+ "libc_headers",
+ "libc_malloc_debug_backtrace",
+ "libcamera_client",
+ "libcamera_metadata",
+ "libcrypto",
+ "libcutils",
+ "libcutils_headers",
+ "libdexfile_external_headers",
+ "libdexfile_support",
+ "libdvr_headers",
+ "libexpat",
+ "libfifo",
+ "libflacextractor",
+ "libgrallocusage",
+ "libgraphicsenv",
+ "libgui",
+ "libgui_headers",
+ "libhardware_headers",
+ "libhidlbase",
+ "libhidlbase-impl-internal",
+ "libhidlmemory",
+ "libhidltransport-impl-internal",
+ "libhwbinder-impl-internal",
+ "libinput",
+ "libjsoncpp",
+ "liblog_headers",
+ "liblzma",
+ "libmath",
+ "libmedia",
+ "libmedia_codeclist",
+ "libmedia_headers",
+ "libmedia_helper",
+ "libmedia_helper_headers",
+ "libmedia_midiiowrapper",
+ "libmedia_omx",
+ "libmediautils",
+ "libmidiextractor",
+ "libmkvextractor",
+ "libmp3extractor",
+ "libmp4extractor",
+ "libmpeg2extractor",
+ "libnativebase_headers",
+ "libnativebridge-headers",
+ "libnativebridge_lazy",
+ "libnativeloader-headers",
+ "libnativeloader_lazy",
+ "libnativewindow_headers",
+ "libnblog",
+ "liboggextractor",
+ "libpackagelistparser",
+ "libpcre2",
+ "libpdx",
+ "libpdx_default_transport",
+ "libpdx_headers",
+ "libpdx_uds",
+ "libprocessgroup",
+ "libprocessgroup_headers",
+ "libprocinfo",
+ "libselinux",
+ "libsonivox",
+ "libspeexresampler",
+ "libspeexresampler",
+ "libstagefright_esds",
+ "libstagefright_flacdec",
+ "libstagefright_flacdec",
+ "libstagefright_foundation",
+ "libstagefright_foundation_headers",
+ "libstagefright_foundation_without_imemory",
+ "libstagefright_headers",
+ "libstagefright_id3",
+ "libstagefright_metadatautils",
+ "libstagefright_mpeg2extractor",
+ "libstagefright_mpeg2support",
+ "libsync",
+ "libsystem_headers",
+ "libui",
+ "libui_headers",
+ "libunwindstack",
+ "libutils_headers",
+ "libvibrator",
+ "libvorbisidec",
+ "libwavextractor",
+ "libwebm",
+ "media_ndk_headers",
+ "media_plugin_headers",
+ "updatable-media",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.media.swcodec"] = []string{
+ "android.frameworks.bufferhub@1.0",
+ "android.hardware.common-ndk_platform",
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hardware.media.bufferpool@2.0",
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
- "android.hidl.memory@1.0",
+ "android.hardware.media@1.0",
+ "android.hardware.media@1.0",
"android.hidl.memory.token@1.0",
+ "android.hidl.memory@1.0",
"android.hidl.safe_union@1.0",
"android.hidl.token@1.0",
"android.hidl.token@1.0-utils",
+ "fmtlib",
+ "libEGL",
+ "libFLAC",
+ "libFLAC-config",
+ "libFLAC-headers",
+ "libFraunhoferAAC",
+ "libarect",
+ "libasync_safe",
+ "libaudio_system_headers",
+ "libaudioutils",
+ "libaudioutils",
+ "libaudioutils_fixedfft",
+ "libavcdec",
+ "libavcenc",
+ "libavservices_minijail",
"libavservices_minijail",
"libbacktrace",
+ "libbacktrace_headers",
"libbase",
- "libbinderthreadstate",
+ "libbase_headers",
+ "libbinder_headers",
+ "libbluetooth-types-header",
+ "libbufferhub_headers",
"libc++",
+ "libc_scudo",
"libcap",
"libcodec2",
+ "libcodec2_headers",
"libcodec2_hidl@1.0",
+ "libcodec2_hidl@1.1",
+ "libcodec2_internal",
"libcodec2_soft_aacdec",
"libcodec2_soft_aacenc",
"libcodec2_soft_amrnbdec",
@@ -230,73 +621,373 @@
"libcodec2_soft_vp9dec",
"libcodec2_soft_vp9enc",
"libcodec2_vndk",
- "libc_scudo",
"libcutils",
+ "libcutils_headers",
"libdexfile_support",
- "libEGL",
+ "libdvr_headers",
"libfmq",
+ "libfmq",
+ "libgav1",
+ "libgralloctypes",
+ "libgrallocusage",
"libgraphicsenv",
+ "libgsm",
+ "libgui_bufferqueue_static",
+ "libgui_headers",
"libhardware",
+ "libhardware_headers",
+ "libhevcdec",
+ "libhevcenc",
"libhidlbase",
+ "libhidlbase-impl-internal",
"libhidlmemory",
+ "libhidltransport-impl-internal",
+ "libhwbinder-impl-internal",
"libion",
+ "libjpeg",
+ "libjsoncpp",
+ "liblog_headers",
"liblzma",
+ "libmath",
"libmedia_codecserviceregistrant",
+ "libmedia_headers",
"libminijail",
+ "libminijail_gen_constants",
+ "libminijail_gen_constants_obj",
+ "libminijail_gen_syscall",
+ "libminijail_gen_syscall_obj",
+ "libminijail_generated",
+ "libmpeg2dec",
+ "libnativebase_headers",
"libnativebridge_lazy",
"libnativeloader_lazy",
+ "libnativewindow_headers",
"libopus",
+ "libpdx_headers",
"libprocessgroup",
+ "libprocessgroup_headers",
"libscudo_wrapper",
"libsfplugin_ccodec_utils",
"libstagefright_amrnb_common",
+ "libstagefright_amrnbdec",
+ "libstagefright_amrnbenc",
+ "libstagefright_amrwbdec",
+ "libstagefright_amrwbenc",
"libstagefright_bufferpool@2.0.1",
"libstagefright_bufferqueue_helper",
"libstagefright_enc_common",
"libstagefright_flacdec",
"libstagefright_foundation",
+ "libstagefright_foundation_headers",
+ "libstagefright_headers",
+ "libstagefright_m4vh263dec",
+ "libstagefright_m4vh263enc",
+ "libstagefright_mp3dec",
"libsync",
+ "libsystem_headers",
"libui",
+ "libui_headers",
"libunwindstack",
- "libutils",
+ "libutils_headers",
"libvorbisidec",
"libvpx",
+ "libyuv",
+ "libyuv_static",
+ "media_ndk_headers",
+ "media_plugin_headers",
"mediaswcodec",
- "prebuilt_libclang_rt",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.mediaprovider"] = []string{
+ "MediaProvider",
+ "MediaProviderGoogle",
+ "fmtlib_ndk",
+ "guava",
+ "libbase_ndk",
+ "libfuse",
+ "libfuse_jni",
+ "libnativehelper_header_only",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.permission"] = []string{
+ "androidx.annotation_annotation",
+ "androidx.annotation_annotation-nodeps",
+ "androidx.lifecycle_lifecycle-common",
+ "androidx.lifecycle_lifecycle-common-java8",
+ "androidx.lifecycle_lifecycle-common-java8-nodeps",
+ "androidx.lifecycle_lifecycle-common-nodeps",
+ "kotlin-annotations",
+ "kotlin-stdlib",
+ "kotlin-stdlib-jdk7",
+ "kotlin-stdlib-jdk8",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-android-nodeps",
+ "kotlinx-coroutines-core",
+ "kotlinx-coroutines-core-nodeps",
+ "libprotobuf-java-lite",
+ "permissioncontroller-statsd",
}
//
// Module separator
//
m["com.android.runtime"] = []string{
+ "bionic_libc_platform_headers",
+ "fmtlib",
+ "libarm-optimized-routines-math",
+ "libasync_safe",
+ "libasync_safe_headers",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libc++",
+ "libc_aeabi",
+ "libc_bionic",
+ "libc_bionic_ndk",
+ "libc_bootstrap",
+ "libc_common",
+ "libc_common_shared",
+ "libc_common_static",
+ "libc_dns",
+ "libc_dynamic_dispatch",
+ "libc_fortify",
+ "libc_freebsd",
+ "libc_freebsd_large_stack",
+ "libc_gdtoa",
+ "libc_headers",
+ "libc_init_dynamic",
+ "libc_init_static",
+ "libc_jemalloc_wrapper",
+ "libc_netbsd",
+ "libc_nomalloc",
+ "libc_nopthread",
+ "libc_openbsd",
+ "libc_openbsd_large_stack",
+ "libc_openbsd_ndk",
+ "libc_pthread",
+ "libc_static_dispatch",
+ "libc_syscalls",
+ "libc_tzcode",
+ "libc_unwind_static",
+ "libcutils",
+ "libcutils_headers",
+ "libdebuggerd",
+ "libdebuggerd_common_headers",
+ "libdebuggerd_handler_core",
+ "libdebuggerd_handler_fallback",
+ "libdexfile_external_headers",
+ "libdexfile_support",
+ "libdexfile_support_static",
+ "libgtest_prod",
+ "libjemalloc5",
+ "liblinker_main",
+ "liblinker_malloc",
+ "liblog_headers",
+ "liblz4",
+ "liblzma",
+ "libprocessgroup_headers",
+ "libprocinfo",
+ "libpropertyinfoparser",
+ "libscudo",
+ "libstdc++",
+ "libsystem_headers",
+ "libsystemproperties",
+ "libtombstoned_client_static",
+ "libunwindstack",
+ "libutils_headers",
+ "libz",
+ "libziparchive",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.resolv"] = []string{
+ "bcm_object",
+ "dnsresolver_aidl_interface-unstable-ndk_platform",
+ "fmtlib",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libc++",
+ "libcrypto",
+ "libcutils",
+ "libcutils_headers",
+ "libgtest_prod",
+ "libjsoncpp",
+ "liblog_headers",
+ "libnativehelper_header_only",
+ "libnetd_client_headers",
+ "libnetd_resolv",
+ "libnetdutils",
+ "libprocessgroup",
+ "libprocessgroup_headers",
+ "libprotobuf-cpp-lite",
+ "libssl",
+ "libstatslog_resolv",
+ "libstatspush_compat",
+ "libstatssocket",
+ "libstatssocket_headers",
+ "libsystem_headers",
+ "libsysutils",
+ "libutils_headers",
+ "netd_event_listener_interface-ndk_platform",
+ "server_configurable_flags",
+ "stats_proto",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.tethering"] = []string{
"libbase",
"libc++",
- "libdexfile_support",
- "liblzma",
- "libunwindstack",
- "prebuilt_libclang_rt",
+ "libnativehelper_compat_libc++",
+ "android.hardware.tetheroffload.config@1.0",
+ "fmtlib",
+ "libbacktrace_headers",
+ "libbase_headers",
+ "libcgrouprc",
+ "libcgrouprc_format",
+ "libcutils",
+ "libcutils_headers",
+ "libhidlbase",
+ "libhidlbase-impl-internal",
+ "libhidltransport-impl-internal",
+ "libhwbinder-impl-internal",
+ "libjsoncpp",
+ "liblog_headers",
+ "libprocessgroup",
+ "libprocessgroup_headers",
+ "libsystem_headers",
+ "libtetherutilsjni",
+ "libutils_headers",
+ "libvndksupport",
+ "tethering-aidl-interfaces-java",
}
//
// Module separator
//
- m["com.android.resolv"] = []string{"libcrypto", "libnetd_resolv", "libssl"}
- //
- // Module separator
- //
- m["com.android.tethering"] = []string{"libbase", "libc++", "libnativehelper_compat_libc++"}
- //
- // Module separator
- //
- m["com.android.vndk"] = []string{
- "libbacktrace",
- "libbinderthreadstate",
- "libblas",
- "libcompiler_rt",
- "libgui",
- "libunwind",
+ m["com.android.wifi"] = []string{
+ "PlatformProperties",
+ "android.hardware.wifi-V1.0-java",
+ "android.hardware.wifi-V1.1-java",
+ "android.hardware.wifi-V1.2-java",
+ "android.hardware.wifi-V1.3-java",
+ "android.hardware.wifi-V1.4-java",
+ "android.hardware.wifi.hostapd-V1.0-java",
+ "android.hardware.wifi.hostapd-V1.1-java",
+ "android.hardware.wifi.hostapd-V1.2-java",
+ "android.hardware.wifi.supplicant-V1.0-java",
+ "android.hardware.wifi.supplicant-V1.1-java",
+ "android.hardware.wifi.supplicant-V1.2-java",
+ "android.hardware.wifi.supplicant-V1.3-java",
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ "android.hidl.manager-V1.1-java",
+ "android.hidl.manager-V1.2-java",
+ "androidx.annotation_annotation",
+ "androidx.annotation_annotation-nodeps",
+ "bouncycastle-unbundled",
+ "dnsresolver_aidl_interface-V2-java",
+ "error_prone_annotations",
+ "ipmemorystore-aidl-interfaces-V3-java",
+ "ipmemorystore-aidl-interfaces-java",
+ "ksoap2",
+ "libbacktrace_headers",
+ "libbase",
+ "libbase_headers",
+ "libc++",
+ "libcutils",
+ "libcutils_headers",
+ "liblog_headers",
+ "libnanohttpd",
+ "libprocessgroup",
+ "libprocessgroup_headers",
+ "libprotobuf-java-lite",
+ "libprotobuf-java-nano",
+ "libsystem_headers",
+ "libutils_headers",
+ "libwifi-jni",
+ "net-utils-services-common",
+ "netd_aidl_interface-V2-java",
+ "netd_aidl_interface-unstable-java",
+ "netd_event_listener_interface-java",
+ "netlink-client",
+ "networkstack-aidl-interfaces-unstable-java",
+ "networkstack-client",
+ "services.net",
+ "wifi-lite-protos",
+ "wifi-nano-protos",
+ "wifi-service-pre-jarjar",
+ "wifi-service-resources",
+ "prebuilt_androidx.annotation_annotation-nodeps",
}
//
// Module separator
//
+ m["com.android.sdkext"] = []string{
+ "fmtlib_ndk",
+ "libbase_ndk",
+ "libprotobuf-cpp-lite-ndk",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.os.statsd"] = []string{
+ "libbacktrace_headers",
+ "libbase_headers",
+ "libc++",
+ "libcutils",
+ "libcutils_headers",
+ "liblog_headers",
+ "libprocessgroup_headers",
+ "libstatssocket",
+ "libsystem_headers",
+ "libutils_headers",
+ }
+ //
+ // Module separator
+ //
+ m["//any"] = []string{
+ "crtbegin_dynamic",
+ "crtbegin_dynamic1",
+ "crtbegin_so",
+ "crtbegin_so1",
+ "crtbegin_static",
+ "crtbrand",
+ "crtend_android",
+ "crtend_so",
+ "libatomic",
+ "libc++_static",
+ "libc++abi",
+ "libc++demangle",
+ "libc_headers",
+ "libclang_rt",
+ "libgcc_stripped",
+ "libprofile-clang-extras",
+ "libprofile-clang-extras_ndk",
+ "libprofile-extras",
+ "libprofile-extras_ndk",
+ "libunwind_llvm",
+ "ndk_crtbegin_dynamic.27",
+ "ndk_crtbegin_so.16",
+ "ndk_crtbegin_so.19",
+ "ndk_crtbegin_so.21",
+ "ndk_crtbegin_so.24",
+ "ndk_crtbegin_so.27",
+ "ndk_crtend_android.27",
+ "ndk_crtend_so.16",
+ "ndk_crtend_so.19",
+ "ndk_crtend_so.21",
+ "ndk_crtend_so.24",
+ "ndk_crtend_so.27",
+ "ndk_libandroid_support",
+ "ndk_libc++_static",
+ "ndk_libc++abi",
+ "ndk_libunwind",
+ }
return m
}
@@ -324,7 +1015,7 @@
}
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("apex_deps", apexDepsMutator)
+ ctx.TopDown("apex_deps", apexDepsMutator)
ctx.BottomUp("apex", apexMutator).Parallel()
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
@@ -332,36 +1023,36 @@
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
-func apexDepsMutator(mctx android.BottomUpMutatorContext) {
- if a, ok := mctx.Module().(*apexBundle); ok {
- apexBundleName := mctx.ModuleName()
- mctx.WalkDeps(func(child, parent android.Module) bool {
- depName := mctx.OtherModuleName(child)
- // If the parent is apexBundle, this child is directly depended.
- _, directDep := parent.(*apexBundle)
- if a.installable() && !a.testApex {
- // TODO(b/123892969): Workaround for not having any way to annotate test-apexs
- // non-installable apex's cannot be installed and so should not prevent libraries from being
- // installed to the system.
- android.UpdateApexDependency(apexBundleName, depName, directDep)
- }
-
- if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
- (directDep || am.DepIsInSameApex(mctx, child)) {
- am.BuildForApex(apexBundleName)
- return true
- } else {
- return false
- }
- })
+func apexDepsMutator(mctx android.TopDownMutatorContext) {
+ var apexBundles []android.ApexInfo
+ var directDep bool
+ if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
+ apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
+ directDep = true
+ } else if am, ok := mctx.Module().(android.ApexModule); ok {
+ apexBundles = am.ApexVariations()
+ directDep = false
}
+
+ if len(apexBundles) == 0 {
+ return
+ }
+
+ mctx.VisitDirectDeps(func(child android.Module) {
+ depName := mctx.OtherModuleName(child)
+ if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
+ (directDep || am.DepIsInSameApex(mctx, child)) {
+ android.UpdateApexDependency(apexBundles, depName, directDep)
+ am.BuildForApexes(apexBundles)
+ }
+ })
}
// Create apex variations if a module is included in APEX(s).
func apexMutator(mctx android.BottomUpMutatorContext) {
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
am.CreateApexVariations(mctx)
- } else if _, ok := mctx.Module().(*apexBundle); ok {
+ } else if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
// apex bundle itself is mutated so that it and its modules have same
// apex variant.
apexBundleName := mctx.ModuleName()
@@ -584,6 +1275,11 @@
Legacy_android10_support *bool
IsCoverageVariant bool `blueprint:"mutated"`
+
+ // Whether this APEX is considered updatable or not. When set to true, this will enforce additional
+ // rules for making sure that the APEX is truely updatable. This will also disable the size optimizations
+ // like symlinking to the system libs. Default is false.
+ Updatable *bool
}
type apexTargetBundleProperties struct {
@@ -709,7 +1405,8 @@
targetRequiredModuleNames []string
hostRequiredModuleNames []string
- jacocoReportClassesFile android.Path // only for javalibs and apps
+ jacocoReportClassesFile android.Path // only for javalibs and apps
+ certificate java.Certificate // only for apps
}
func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile {
@@ -733,6 +1430,36 @@
return af.builtFile != nil && af.builtFile.String() != ""
}
+// Path() returns path of this apex file relative to the APEX root
+func (af *apexFile) Path() string {
+ return filepath.Join(af.installDir, af.builtFile.Base())
+}
+
+// SymlinkPaths() returns paths of the symlinks (if any) relative to the APEX root
+func (af *apexFile) SymlinkPaths() []string {
+ var ret []string
+ for _, symlink := range af.symlinks {
+ ret = append(ret, filepath.Join(af.installDir, symlink))
+ }
+ return ret
+}
+
+func (af *apexFile) AvailableToPlatform() bool {
+ if af.module == nil {
+ return false
+ }
+ if am, ok := af.module.(android.ApexModule); ok {
+ return am.AvailableFor(android.AvailableToPlatform)
+ }
+ return false
+}
+
+type depInfo struct {
+ to string
+ from []string
+ isExternal bool
+}
+
type apexBundle struct {
android.ModuleBase
android.DefaultableModuleBase
@@ -766,10 +1493,8 @@
// list of module names that should be installed along with this APEX
requiredDeps []string
- // list of module names that this APEX is depending on (to be shown via *-deps-info target)
- externalDeps []string
// list of module names that this APEX is including (to be shown via *-deps-info target)
- internalDeps []string
+ depInfos map[string]depInfo
testApex bool
vndkApex bool
@@ -790,6 +1515,13 @@
suffix string
installedFilesFile android.WritablePath
+
+ // Whether to create symlink to the system file instead of having a file
+ // inside the apex or not
+ linkToSystemLib bool
+
+ // Struct holding the merged notice file paths in different formats
+ mergedNotices android.NoticeOutputs
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -1056,7 +1788,7 @@
}
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
- return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
+ return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
}
func (a *apexBundle) PreventInstall() {
@@ -1162,11 +1894,18 @@
return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
}
+func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
+ dirInApex := filepath.Join("etc", config.SubDir())
+ fileToCopy := config.CompatConfig()
+ return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config)
+}
+
func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
android.Module
Privileged() bool
OutputFile() android.Path
JacocoReportClassesFile() android.Path
+ Certificate() java.Certificate
}, pkgName string) apexFile {
appDir := "app"
if aapp.Privileged() {
@@ -1176,6 +1915,7 @@
fileToCopy := aapp.OutputFile()
af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
+ af.certificate = aapp.Certificate()
return af
}
@@ -1188,6 +1928,78 @@
return true
}
+// Visit dependencies that contributes to the payload of this APEX
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
+ do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
+ ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+ am, ok := child.(android.ApexModule)
+ if !ok || !am.CanHaveApexVariants() {
+ return false
+ }
+
+ // Check for the direct dependencies that contribute to the payload
+ if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
+ if dt.payload {
+ do(ctx, parent, am, false /* externalDep */)
+ return true
+ }
+ return false
+ }
+
+ // Check for the indirect dependencies if it is considered as part of the APEX
+ if am.DepIsInSameApex(ctx, am) {
+ do(ctx, parent, am, false /* externalDep */)
+ return true
+ }
+
+ do(ctx, parent, am, true /* externalDep */)
+
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
+ })
+}
+
+// Ensures that the dependencies are marked as available for this APEX
+func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
+ // Let's be practical. Availability for test, host, and the VNDK apex isn't important
+ if ctx.Host() || a.testApex || a.vndkApex {
+ return
+ }
+
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ apexName := ctx.ModuleName()
+ if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, to) {
+ return
+ }
+ ctx.ModuleErrorf("requires %q that is not available for the APEX.", to.Name())
+ })
+}
+
+// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
+func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
+ a.depInfos = make(map[string]depInfo)
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ if from.Name() == to.Name() {
+ // This can happen for cc.reuseObjTag. We are not interested in tracking this.
+ return
+ }
+
+ if info, exists := a.depInfos[to.Name()]; exists {
+ if !android.InList(from.Name(), info.from) {
+ info.from = append(info.from, from.Name())
+ }
+ info.isExternal = info.isExternal && externalDep
+ a.depInfos[to.Name()] = info
+ } else {
+ a.depInfos[to.Name()] = depInfo{
+ to: to.Name(),
+ from: []string{from.Name()},
+ isExternal: externalDep,
+ }
+ }
+ })
+}
+
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
switch a.properties.ApexType {
@@ -1223,6 +2035,10 @@
return
}
+ a.checkApexAvailability(ctx)
+
+ a.collectDepsInfo(ctx)
+
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
// native lib dependencies
@@ -1254,20 +2070,19 @@
})
var filesInfo []apexFile
+ // TODO(jiyong) do this using walkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
depName := ctx.OtherModuleName(child)
if _, isDirectDep := parent.(*apexBundle); isDirectDep {
- if depTag != keyTag && depTag != certificateTag {
- a.internalDeps = append(a.internalDeps, depName)
- }
switch depTag {
case sharedLibTag:
- if cc, ok := child.(*cc.Module); ok {
- if cc.HasStubsVariants() {
- provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+ if c, ok := child.(*cc.Module); ok {
+ // bootstrap bionic libs are treated as provided by system
+ if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+ provideNativeLibs = append(provideNativeLibs, c.OutputFile().Path().Base())
}
- filesInfo = append(filesInfo, apexFileForNativeLibrary(ctx, cc, handleSpecialLibs))
+ filesInfo = append(filesInfo, apexFileForNativeLibrary(ctx, c, handleSpecialLibs))
return true // track transitive dependencies
} else {
ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
@@ -1301,13 +2116,6 @@
return false
}
filesInfo = append(filesInfo, af)
-
- pf, _ := sdkLib.OutputFiles(".xml")
- if len(pf) != 1 {
- ctx.PropertyErrorf("java_libs", "%q failed to generate permission XML", depName)
- return false
- }
- filesInfo = append(filesInfo, newApexFile(ctx, pf[0], pf[0].Base(), "etc/permissions", etc, nil))
return true // track transitive dependencies
} else {
ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -1327,8 +2135,10 @@
case prebuiltTag:
if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ } else if prebuilt, ok := child.(java.PlatformCompatConfigIntf); ok {
+ filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, prebuilt, depName))
} else {
- ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+ ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc and not a platform_compat_config module", depName)
}
case testTag:
if ccTest, ok := child.(*cc.Module); ok {
@@ -1394,7 +2204,6 @@
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) {
a.requiredDeps = append(a.requiredDeps, cc.Name())
}
- a.externalDeps = append(a.externalDeps, depName)
requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
// Don't track further
return false
@@ -1402,8 +2211,6 @@
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
af.transitiveDep = true
filesInfo = append(filesInfo, af)
- a.internalDeps = append(a.internalDeps, depName)
- a.internalDeps = append(a.internalDeps, cc.AllStaticDeps()...)
return true // track transitive dependencies
}
} else if cc.IsTestPerSrcDepTag(depTag) {
@@ -1414,15 +2221,17 @@
// of the original test module (`depName`, shared by all `test_per_src`
// variations of that module).
af.moduleName = filepath.Base(af.builtFile.String())
- af.transitiveDep = true
+ // these are not considered transitive dep
+ af.transitiveDep = false
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
}
} else if java.IsJniDepTag(depTag) {
- a.externalDeps = append(a.externalDeps, depName)
return true
- } else if java.IsStaticLibDepTag(depTag) {
- a.internalDeps = append(a.internalDeps, depName)
+ } else if java.IsXmlPermissionsFileDepTag(depTag) {
+ if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
+ filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ }
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
}
@@ -1452,15 +2261,22 @@
// remove duplicates in filesInfo
removeDup := func(filesInfo []apexFile) []apexFile {
- encountered := make(map[string]bool)
- result := []apexFile{}
+ encountered := make(map[string]apexFile)
for _, f := range filesInfo {
dest := filepath.Join(f.installDir, f.builtFile.Base())
- if !encountered[dest] {
- encountered[dest] = true
- result = append(result, f)
+ if e, ok := encountered[dest]; !ok {
+ encountered[dest] = f
+ } else {
+ // If a module is directly included and also transitively depended on
+ // consider it as directly included.
+ e.transitiveDep = e.transitiveDep && f.transitiveDep
+ encountered[dest] = e
}
}
+ var result []apexFile
+ for _, v := range encountered {
+ result = append(result, v)
+ }
return result
}
filesInfo = removeDup(filesInfo)
@@ -1470,29 +2286,6 @@
return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
})
- // check apex_available requirements
- if !ctx.Host() && !a.testApex {
- for _, fi := range filesInfo {
- if am, ok := fi.module.(android.ApexModule); ok {
- // vndk {enabled:true} implies visibility to the vndk apex
- if ccm, ok := fi.module.(*cc.Module); ok && ccm.IsVndk() && a.vndkApex {
- continue
- }
-
- if !am.AvailableFor(ctx.ModuleName()) && !whitelistedApexAvailable(ctx.ModuleName(), a.vndkApex, fi.module) {
- ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
- // don't stop so that we can report other violations in the same run
- }
- }
- }
- }
-
- // prepend the name of this APEX to the module names. These names will be the names of
- // modules that will be defined if the APEX is flattened.
- for i := range filesInfo {
- filesInfo[i].moduleName = filesInfo[i].moduleName + "." + a.Name() + a.suffix
- }
-
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
@@ -1512,6 +2305,20 @@
return
}
}
+ // Optimization. If we are building bundled APEX, for the files that are gathered due to the
+ // transitive dependencies, don't place them inside the APEX, but place a symlink pointing
+ // the same library in the system partition, thus effectively sharing the same libraries
+ // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
+ // in the APEX.
+ a.linkToSystemLib = !ctx.Config().UnbundledBuild() &&
+ a.installable() &&
+ !proptools.Bool(a.properties.Use_vendor)
+
+ // We don't need the optimization for updatable APEXes, as it might give false signal
+ // to the system health when the APEXes are still bundled (b/149805758)
+ if proptools.Bool(a.properties.Updatable) && a.properties.ApexType == imageApex {
+ a.linkToSystemLib = false
+ }
// prepare apex_manifest.json
a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
@@ -1528,22 +2335,31 @@
a.buildApexDependencyInfo(ctx)
}
-func whitelistedApexAvailable(apex string, is_vndk bool, module android.Module) bool {
+func whitelistedApexAvailable(apex string, module android.Module) bool {
key := apex
key = strings.Replace(key, "test_", "", 1)
key = strings.Replace(key, "com.android.art.debug", "com.android.art", 1)
key = strings.Replace(key, "com.android.art.release", "com.android.art", 1)
moduleName := module.Name()
- if strings.Contains(moduleName, "prebuilt_libclang_rt") {
- // This module has variants that depend on the product being built.
- moduleName = "prebuilt_libclang_rt"
+ // Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
+ // system. Trim the prefix for the check since they are confusing
+ moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
+ if strings.HasPrefix(moduleName, "libclang_rt.") {
+ // This module has many arch variants that depend on the product being built.
+ // We don't want to list them all
+ moduleName = "libclang_rt"
}
if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
return true
}
+ key = "//any"
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
return false
}
@@ -1569,12 +2385,16 @@
return bundle
}
+// apex_test is an APEX for testing. The difference from the ordinary apex module type is that
+// certain compatibility checks such as apex_available are not done for apex_test.
func testApexBundleFactory() android.Module {
bundle := newApexBundle()
bundle.testApex = true
return bundle
}
+// apex packages other modules into an APEX file which is a packaging format for system-level
+// components like binaries, shared libraries, etc.
func BundleFactory() android.Module {
return newApexBundle()
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 84bb2b5..7361fc6 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -91,116 +91,14 @@
config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
}
+func withUnbundledBuild(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+}
+
func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
android.ClearApexDependency()
bp = bp + `
- toolchain_library {
- name: "libcompiler_rt-extras",
- src: "",
- vendor_available: true,
- recovery_available: true,
- }
-
- toolchain_library {
- name: "libatomic",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- toolchain_library {
- name: "libgcc",
- src: "",
- vendor_available: true,
- recovery_available: true,
- }
-
- toolchain_library {
- name: "libgcc_stripped",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-aarch64-android",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-arm-android",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-x86_64-android",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-i686-android",
- src: "",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- cc_object {
- name: "crtbegin_so",
- stl: "none",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- cc_object {
- name: "crtend_so",
- stl: "none",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- }
-
- cc_object {
- name: "crtbegin_static",
- stl: "none",
- }
-
- cc_object {
- name: "crtend_android",
- stl: "none",
- }
-
- llndk_library {
- name: "libc",
- symbol_file: "",
- native_bridge_supported: true,
- }
-
- llndk_library {
- name: "libm",
- symbol_file: "",
- native_bridge_supported: true,
- }
-
- llndk_library {
- name: "libdl",
- symbol_file: "",
- native_bridge_supported: true,
- }
-
filegroup {
name: "myapex-file_contexts",
srcs: [
@@ -209,6 +107,8 @@
}
`
+ bp = bp + cc.GatherRequiredDepsForTest(android.Android)
+
bp = bp + java.GatherRequiredDepsForTest()
fs := map[string][]byte{
@@ -219,6 +119,7 @@
"apex_manifest.json": nil,
"AndroidManifest.xml": nil,
"system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex.updatable-file_contexts": nil,
"system/sepolicy/apex/myapex2-file_contexts": nil,
"system/sepolicy/apex/otherapex-file_contexts": nil,
"system/sepolicy/apex/commonapex-file_contexts": nil,
@@ -254,6 +155,8 @@
"dummy.txt": nil,
}
+ cc.GatherRequiredFilesForTest(fs)
+
for _, handler := range handlers {
// The fs now needs to be populated before creating the config, call handlers twice
// for now, once to get any fs changes, and later after the config was created to
@@ -287,12 +190,15 @@
ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
ctx.RegisterModuleType("override_apex", overrideApexFactory)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+
cc.RegisterRequiredBuildComponentsForTest(ctx)
- ctx.RegisterModuleType("cc_binary", cc.BinaryFactory)
ctx.RegisterModuleType("cc_test", cc.TestFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
ctx.RegisterModuleType("prebuilt_etc", android.PrebuiltEtcFactory)
+ ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
ctx.RegisterModuleType("sh_binary", android.ShBinaryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
java.RegisterJavaBuildComponents(ctx)
@@ -300,9 +206,7 @@
java.RegisterAppBuildComponents(ctx)
ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
- ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
- ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
ctx.Register(config)
@@ -448,7 +352,6 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- compile_dex: true,
static_libs: ["myotherjar"],
libs: ["mysharedjar"],
// TODO: remove //apex_available:platform
@@ -463,7 +366,11 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- compile_dex: true,
+ // TODO: remove //apex_available:platform
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
}
java_library {
@@ -471,7 +378,6 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- compile_dex: true,
}
`)
@@ -517,7 +423,7 @@
found_foo_link_64 := false
found_foo := false
for _, cmd := range strings.Split(copyCmds, " && ") {
- if strings.HasPrefix(cmd, "ln -s foo64") {
+ if strings.HasPrefix(cmd, "ln -sfn foo64") {
if strings.HasSuffix(cmd, "bin/foo") {
found_foo = true
} else if strings.HasSuffix(cmd, "bin/foo_link_64") {
@@ -539,10 +445,11 @@
ensureListContains(t, noticeInputs, "custom_notice")
depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n")
- ensureListContains(t, depsInfo, "internal myjar")
- ensureListContains(t, depsInfo, "internal mylib")
- ensureListContains(t, depsInfo, "internal mylib2")
- ensureListContains(t, depsInfo, "internal myotherjar")
+ ensureListContains(t, depsInfo, "myjar <- myapex")
+ ensureListContains(t, depsInfo, "mylib <- myapex")
+ ensureListContains(t, depsInfo, "mylib2 <- mylib")
+ ensureListContains(t, depsInfo, "myotherjar <- myjar")
+ ensureListContains(t, depsInfo, "mysharedjar (external) <- myjar")
}
func TestDefaults(t *testing.T) {
@@ -584,7 +491,6 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- compile_dex: true,
apex_available: [ "myapex" ],
}
@@ -596,7 +502,7 @@
apex_available: [ "myapex" ],
}
`)
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"etc/myetc",
"javalib/myjar.jar",
"lib64/mylib.so",
@@ -755,13 +661,13 @@
ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
// Ensure that stubs libs are built without -include flags
- mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylib2Cflags, "-include ")
// Ensure that genstub is invoked with --apex
ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_3").Rule("genStubSrc").Args["flags"])
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"lib64/mylib.so",
"lib64/mylib3.so",
"lib64/mylib4.so",
@@ -786,6 +692,7 @@
name: "mylib",
srcs: ["mylib.cpp"],
shared_libs: ["libfoo#10"],
+ static_libs: ["libbaz"],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex2" ],
@@ -809,6 +716,14 @@
stl: "none",
}
+ cc_library_static {
+ name: "libbaz",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex2" ],
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule")
@@ -836,10 +751,10 @@
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
depsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("myapex2-deps-info.txt").Args["content"], "\\n")
- ensureListContains(t, depsInfo, "internal mylib")
- ensureListContains(t, depsInfo, "external libfoo")
- ensureListNotContains(t, depsInfo, "internal libfoo")
- ensureListNotContains(t, depsInfo, "external mylib")
+
+ ensureListContains(t, depsInfo, "mylib <- myapex2")
+ ensureListContains(t, depsInfo, "libbaz <- mylib")
+ ensureListContains(t, depsInfo, "libfoo (external) <- mylib")
}
func TestApexWithRuntimeLibsDependency(t *testing.T) {
@@ -881,6 +796,7 @@
stubs: {
versions: ["10", "20", "30"],
},
+ apex_available: [ "myapex" ],
}
cc_library {
@@ -996,47 +912,6 @@
}
cc_library {
- name: "libc",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["27", "28", "29"],
- },
- }
-
- cc_library {
- name: "libm",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["27", "28", "29"],
- },
- apex_available: [
- "//apex_available:platform",
- "myapex"
- ],
- }
-
- cc_library {
- name: "libdl",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["27", "28", "29"],
- },
- apex_available: [
- "//apex_available:platform",
- "myapex"
- ],
- }
-
- cc_library {
name: "libBootstrap",
srcs: ["mylib.cpp"],
stl: "none",
@@ -1568,6 +1443,7 @@
export_include_dirs: ["my_include"],
system_shared_libs: [],
stl: "none",
+ apex_available: [ "myapex" ],
}
cc_library {
@@ -1598,46 +1474,72 @@
ensureContains(t, cFlags, "-Imy_include")
}
-func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName string, files []string) {
+type fileInApex struct {
+ path string // path in apex
+ src string // src path
+ isLink bool
+}
+
+func getFiles(t *testing.T, ctx *android.TestContext, moduleName, variant string) []fileInApex {
t.Helper()
- apexRule := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Rule("apexRule")
+ apexRule := ctx.ModuleForTests(moduleName, variant).Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
imageApexDir := "/image.apex/"
- var failed bool
- var surplus []string
- filesMatched := make(map[string]bool)
- addContent := func(content string) {
- for _, expected := range files {
- if matched, _ := path.Match(expected, content); matched {
- filesMatched[expected] = true
- return
- }
- }
- surplus = append(surplus, content)
- }
+ var ret []fileInApex
for _, cmd := range strings.Split(copyCmds, "&&") {
cmd = strings.TrimSpace(cmd)
if cmd == "" {
continue
}
terms := strings.Split(cmd, " ")
+ var dst, src string
+ var isLink bool
switch terms[0] {
case "mkdir":
case "cp":
- if len(terms) != 3 {
+ if len(terms) != 3 && len(terms) != 4 {
t.Fatal("copyCmds contains invalid cp command", cmd)
}
- dst := terms[2]
+ dst = terms[len(terms)-1]
+ src = terms[len(terms)-2]
+ isLink = false
+ case "ln":
+ if len(terms) != 3 && len(terms) != 4 {
+ // ln LINK TARGET or ln -s LINK TARGET
+ t.Fatal("copyCmds contains invalid ln command", cmd)
+ }
+ dst = terms[len(terms)-1]
+ src = terms[len(terms)-2]
+ isLink = true
+ default:
+ t.Fatalf("copyCmds should contain mkdir/cp commands only: %q", cmd)
+ }
+ if dst != "" {
index := strings.Index(dst, imageApexDir)
if index == -1 {
t.Fatal("copyCmds should copy a file to image.apex/", cmd)
}
dstFile := dst[index+len(imageApexDir):]
- addContent(dstFile)
- default:
- t.Fatalf("copyCmds should contain mkdir/cp commands only: %q", cmd)
+ ret = append(ret, fileInApex{path: dstFile, src: src, isLink: isLink})
}
}
+ return ret
+}
+
+func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, variant string, files []string) {
+ t.Helper()
+ var failed bool
+ var surplus []string
+ filesMatched := make(map[string]bool)
+ for _, file := range getFiles(t, ctx, moduleName, variant) {
+ for _, expected := range files {
+ if matched, _ := path.Match(expected, file.path); matched {
+ filesMatched[expected] = true
+ return
+ }
+ }
+ surplus = append(surplus, file.path)
+ }
if len(surplus) > 0 {
sort.Strings(surplus)
@@ -1700,7 +1602,7 @@
}
`+vndkLibrariesTxtFiles("current"))
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
"lib/libvndksp.so",
"lib64/libvndk.so",
@@ -1760,7 +1662,7 @@
"libvndk.arm.so": nil,
}))
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
"lib/libvndk.arm.so",
"lib64/libvndk.so",
@@ -1851,7 +1753,7 @@
"libvndk27_x86_64.so": nil,
}))
- ensureExactContents(t, ctx, "myapex_v27", []string{
+ ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{
"lib/libvndk27_arm.so",
"lib64/libvndk27_arm64.so",
"etc/*",
@@ -1924,7 +1826,7 @@
}`+vndkLibrariesTxtFiles("28", "current"))
assertApexName := func(expected, moduleName string) {
- bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Module().(*apexBundle)
+ bundle := ctx.ModuleForTests(moduleName, "android_common_image").Module().(*apexBundle)
actual := proptools.String(bundle.properties.Apex_name)
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Got '%v', expected '%v'", actual, expected)
@@ -1972,7 +1874,7 @@
},
}))
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
"lib64/libvndk.so",
"etc/*",
@@ -2068,7 +1970,7 @@
}),
)
- ensureExactContents(t, ctx, "myapex_v27", []string{
+ ensureExactContents(t, ctx, "myapex_v27", "android_common_image", []string{
"lib/libvndk27binder32.so",
"etc/*",
})
@@ -2179,11 +2081,12 @@
}
func TestApexName(t *testing.T) {
- ctx, _ := testApex(t, `
+ ctx, config := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
apex_name: "com.android.myapex",
+ native_shared_libs: ["mylib"],
}
apex_key {
@@ -2191,6 +2094,17 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
+ }
`)
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
@@ -2198,6 +2112,16 @@
ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
apexRule := module.Rule("apexRule")
ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+ ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
}
func TestNonTestApex(t *testing.T) {
@@ -2301,11 +2225,6 @@
// Ensure that the platform variant ends with _shared
ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared")
-
- if android.InAnyApex("mylib_common_test") {
- t.Log("Found mylib_common_test in some apex!")
- t.Fail()
- }
}
func TestApexWithTarget(t *testing.T) {
@@ -2927,7 +2846,6 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
- compile_dex: true,
enabled: false,
}
`)
@@ -2973,6 +2891,7 @@
srcs: ["mylib.cpp"],
stl: "none",
system_shared_libs: [],
+ apex_available: [ "myapex" ],
}
`)
@@ -2984,7 +2903,7 @@
ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
// JNI libraries are embedded inside APK
- appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Rule("zip")
+ appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni lib")
libjniOutput := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
ensureListContains(t, appZipRule.Implicits.Strings(), libjniOutput.String())
// ... uncompressed
@@ -3228,10 +3147,15 @@
}`)
// check that libfoo and libbar are created only for myapex, but not for the platform
- ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
- ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
- ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
- ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
+ // TODO(jiyong) the checks for the platform variant are removed because we now create
+ // the platform variant regardless of the apex_availability. Instead, we will make sure that
+ // the platform variants are not used from other platform modules. When that is done,
+ // these checks will be replaced by expecting a specific error message that will be
+ // emitted when the platform variant is used.
+ // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
+ // ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+ // ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
+ // ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
ctx, _ = testApex(t, `
apex {
@@ -3280,11 +3204,16 @@
}`)
// shared variant of libfoo is only available to myapex
- ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
- ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
- // but the static variant is available to both myapex and the platform
- ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static")
+ // TODO(jiyong) the checks for the platform variant are removed because we now create
+ // the platform variant regardless of the apex_availability. Instead, we will make sure that
+ // the platform variants are not used from other platform modules. When that is done,
+ // these checks will be replaced by expecting a specific error message that will be
+ // emitted when the platform variant is used.
+ // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
+ // ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+ // // but the static variant is available to both myapex and the platform
+ // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static_myapex")
+ // ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_static")
}
func TestOverrideApex(t *testing.T) {
@@ -3366,6 +3295,7 @@
apex {
name: "myapex",
key: "myapex.key",
+ native_shared_libs: ["mylib"],
legacy_android10_support: true,
}
@@ -3374,12 +3304,32 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
- `)
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ stl: "libc++",
+ system_shared_libs: [],
+ apex_available: [ "myapex" ],
+ }
+ `, withUnbundledBuild)
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
args := module.Rule("apexRule").Args
ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
ensureNotContains(t, args["opt_flags"], "--no_hashtree")
+
+ // The copies of the libraries in the apex should have one more dependency than
+ // the ones outside the apex, namely the unwinder. Ideally we should check
+ // the dependency names directly here but for some reason the names are blank in
+ // this test.
+ for _, lib := range []string{"libc++", "mylib"} {
+ apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
+ nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
+ if len(apexImplicits) != len(nonApexImplicits)+1 {
+ t.Errorf("%q missing unwinder dep", lib)
+ }
+ }
}
func TestJavaSDKLibrary(t *testing.T) {
@@ -3412,13 +3362,47 @@
}))
// java_sdk_library installs both impl jar and permission XML
- ensureExactContents(t, ctx, "myapex", []string{
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"javalib/foo.jar",
"etc/permissions/foo.xml",
})
// Permission XML should point to the activated path of impl jar of java_sdk_library
- xml := ctx.ModuleForTests("foo", "android_common_myapex").Output("foo.xml")
- ensureContains(t, xml.Args["content"], `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
+ sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
+ ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`)
+}
+
+func TestCompatConfig(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ prebuilts: ["myjar-platform-compat-config"],
+ java_libs: ["myjar"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ platform_compat_config {
+ name: "myjar-platform-compat-config",
+ src: ":myjar",
+ }
+
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+ `)
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "etc/compatconfig/myjar-platform-compat-config.xml",
+ "javalib/myjar.jar",
+ })
}
func TestRejectNonInstallableJavaLibrary(t *testing.T) {
@@ -3440,6 +3424,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "none",
system_modules: "none",
+ compile_dex: false,
}
`)
}
@@ -3482,6 +3467,130 @@
ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES += e f\n")
}
+func TestSymlinksFromApexToSystem(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ java_libs: ["myjar"],
+ }
+
+ apex {
+ name: "myapex.updatable",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ java_libs: ["myjar"],
+ updatable: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["myotherlib"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "myapex.updatable",
+ "//apex_available:platform",
+ ],
+ }
+
+ cc_library {
+ name: "myotherlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "myapex.updatable",
+ "//apex_available:platform",
+ ],
+ }
+
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ libs: ["myotherjar"],
+ apex_available: [
+ "myapex",
+ "myapex.updatable",
+ "//apex_available:platform",
+ ],
+ }
+
+ java_library {
+ name: "myotherjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [
+ "myapex",
+ "myapex.updatable",
+ "//apex_available:platform",
+ ],
+ }
+ `
+
+ ensureRealfileExists := func(t *testing.T, files []fileInApex, file string) {
+ for _, f := range files {
+ if f.path == file {
+ if f.isLink {
+ t.Errorf("%q is not a real file", file)
+ }
+ return
+ }
+ }
+ t.Errorf("%q is not found", file)
+ }
+
+ ensureSymlinkExists := func(t *testing.T, files []fileInApex, file string) {
+ for _, f := range files {
+ if f.path == file {
+ if !f.isLink {
+ t.Errorf("%q is not a symlink", file)
+ }
+ return
+ }
+ }
+ t.Errorf("%q is not found", file)
+ }
+
+ // For unbundled build, symlink shouldn't exist regardless of whether an APEX
+ // is updatable or not
+ ctx, _ := testApex(t, bp, withUnbundledBuild)
+ files := getFiles(t, ctx, "myapex", "android_common_myapex_image")
+ ensureRealfileExists(t, files, "javalib/myjar.jar")
+ ensureRealfileExists(t, files, "lib64/mylib.so")
+ ensureRealfileExists(t, files, "lib64/myotherlib.so")
+
+ files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+ ensureRealfileExists(t, files, "javalib/myjar.jar")
+ ensureRealfileExists(t, files, "lib64/mylib.so")
+ ensureRealfileExists(t, files, "lib64/myotherlib.so")
+
+ // For bundled build, symlink to the system for the non-updatable APEXes only
+ ctx, _ = testApex(t, bp)
+ files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
+ ensureRealfileExists(t, files, "javalib/myjar.jar")
+ ensureRealfileExists(t, files, "lib64/mylib.so")
+ ensureSymlinkExists(t, files, "lib64/myotherlib.so") // this is symlink
+
+ files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+ ensureRealfileExists(t, files, "javalib/myjar.jar")
+ ensureRealfileExists(t, files, "lib64/mylib.so")
+ ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 9122188..5e0baf4 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -160,7 +160,7 @@
`echo -e "New unexpected files were added to ${apex_module_name}." ` +
` "To fix the build run following command:" && ` +
`echo "system/apex/tools/update_whitelist.sh ${whitelisted_files_file} ${image_content_file}" && ` +
- `exit 1)`,
+ `exit 1); touch ${out}`,
Description: "Diff ${image_content_file} and ${whitelisted_files_file}",
}, "image_content_file", "whitelisted_files_file", "apex_module_name")
)
@@ -211,7 +211,7 @@
})
}
-func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext, apexFileName string) android.OptionalPath {
+func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
noticeFiles := []android.Path{}
for _, f := range a.filesInfo {
if f.module != nil {
@@ -227,10 +227,10 @@
}
if len(noticeFiles) == 0 {
- return android.OptionalPath{}
+ return android.NoticeOutputs{}
}
- return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)).HtmlGzOutput
+ return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles))
}
func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
@@ -239,7 +239,7 @@
rule.Command().
Implicit(builtApex).
Text("(cd " + imageDir.String() + " ; ").
- Text("find . -type f -printf \"%s %p\\n\") ").
+ Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") ").
Text(" | sort -nr > ").
Output(output)
rule.Build(pctx, ctx, "installed-files."+a.Name(), "Installed files")
@@ -258,34 +258,40 @@
apexType := a.properties.ApexType
suffix := apexType.suffix()
+ var implicitInputs []android.Path
unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned")
- filesToCopy := []android.Path{}
- for _, f := range a.filesInfo {
- filesToCopy = append(filesToCopy, f.builtFile)
+ // TODO(jiyong): construct the copy rules using RuleBuilder
+ var copyCommands []string
+ for _, fi := range a.filesInfo {
+ destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.Path()).String()
+ copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(destPath))
+ if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
+ // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
+ pathOnDevice := filepath.Join("/system", fi.Path())
+ copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
+ } else {
+ copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+ implicitInputs = append(implicitInputs, fi.builtFile)
+ }
+ // create additional symlinks pointing the file inside the APEX
+ for _, symlinkPath := range fi.SymlinkPaths() {
+ symlinkDest := android.PathForModuleOut(ctx, "image"+suffix, symlinkPath).String()
+ copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+ }
}
- copyCommands := []string{}
- emitCommands := []string{}
- imageContentFile := android.PathForModuleOut(ctx, a.Name()+"-content.txt")
+ // TODO(jiyong): use RuleBuilder
+ var emitCommands []string
+ imageContentFile := android.PathForModuleOut(ctx, "content.txt")
emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String())
if proptools.Bool(a.properties.Legacy_android10_support) {
emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
}
- for i, src := range filesToCopy {
- dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
- emitCommands = append(emitCommands, "echo './"+dest+"' >> "+imageContentFile.String())
- dest_path := filepath.Join(android.PathForModuleOut(ctx, "image"+suffix).String(), dest)
- copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
- copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
- for _, sym := range a.filesInfo[i].symlinks {
- symlinkDest := filepath.Join(filepath.Dir(dest_path), sym)
- copyCommands = append(copyCommands, "ln -s "+filepath.Base(dest)+" "+symlinkDest)
- }
+ for _, fi := range a.filesInfo {
+ emitCommands = append(emitCommands, "echo './"+fi.Path()+"' >> "+imageContentFile.String())
}
emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
-
- implicitInputs := append(android.Paths(nil), filesToCopy...)
implicitInputs = append(implicitInputs, a.manifestPbOut)
if a.properties.Whitelisted_files != nil {
@@ -376,21 +382,23 @@
}
targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
- if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
- ctx.Config().UnbundledBuild() &&
- !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
- ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
- apiFingerprint := java.ApiFingerprintPath(ctx)
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", apiFingerprint.String())
- implicitInputs = append(implicitInputs, apiFingerprint)
+ minSdkVersion := ctx.Config().DefaultAppTargetSdk()
+ if java.UseApiFingerprint(ctx, targetSdkVersion) {
+ targetSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
+ }
+ if java.UseApiFingerprint(ctx, minSdkVersion) {
+ minSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
}
optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
+ optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
- noticeFile := a.buildNoticeFile(ctx, a.Name()+suffix)
- if noticeFile.Valid() {
+ a.mergedNotices = a.buildNoticeFiles(ctx, a.Name()+suffix)
+ if a.mergedNotices.HtmlGzOutput.Valid() {
// If there's a NOTICE file, embed it as an asset file in the APEX.
- implicitInputs = append(implicitInputs, noticeFile.Path())
- optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String()))
+ implicitInputs = append(implicitInputs, a.mergedNotices.HtmlGzOutput.Path())
+ optFlags = append(optFlags, "--assets_dir "+filepath.Dir(a.mergedNotices.HtmlGzOutput.String()))
}
if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && ctx.ModuleDir() != "system/apex/shim/build" && a.testOnlyShouldSkipHashtreeGeneration() {
@@ -500,13 +508,13 @@
// instead of `android.PathForOutput`) to return the correct path to the flattened
// APEX (as its contents is installed by Make, not Soong).
factx := flattenedApexContext{ctx}
- apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
- a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName)
+ apexBundleName := a.Name()
+ a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName)
if a.installable() && a.GetOverriddenBy() == "" {
- installPath := android.PathForModuleInstall(ctx, "apex", apexName)
+ installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName)
devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
- addFlattenedFileContextsInfos(ctx, apexName+":"+devicePath+":"+a.fileContexts.String())
+ addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String())
}
a.buildFilesInfo(ctx)
}
@@ -530,7 +538,7 @@
if a.installable() {
// For flattened APEX, do nothing but make sure that APEX manifest and apex_pubkey are also copied along
// with other ordinary files.
- a.filesInfo = append(a.filesInfo, newApexFile(ctx, a.manifestPbOut, "apex_manifest.pb."+a.Name()+a.suffix, ".", etc, nil))
+ a.filesInfo = append(a.filesInfo, newApexFile(ctx, a.manifestPbOut, "apex_manifest.pb", ".", etc, nil))
// rename to apex_pubkey
copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -539,12 +547,12 @@
Input: a.public_key_file,
Output: copiedPubkey,
})
- a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey."+a.Name()+a.suffix, ".", etc, nil))
+ a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil))
if a.properties.ApexType == flattenedApex {
- apexName := proptools.StringDefault(a.properties.Apex_name, a.Name())
+ apexBundleName := a.Name()
for _, fi := range a.filesInfo {
- dir := filepath.Join("apex", apexName, fi.installDir)
+ dir := filepath.Join("apex", apexBundleName, fi.installDir)
target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
for _, sym := range fi.symlinks {
ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
@@ -588,19 +596,14 @@
return
}
- internalDeps := a.internalDeps
- externalDeps := a.externalDeps
-
- internalDeps = android.SortedUniqueStrings(internalDeps)
- externalDeps = android.SortedUniqueStrings(externalDeps)
- externalDeps = android.RemoveListFromList(externalDeps, internalDeps)
-
var content strings.Builder
- for _, name := range internalDeps {
- fmt.Fprintf(&content, "internal %s\\n", name)
- }
- for _, name := range externalDeps {
- fmt.Fprintf(&content, "external %s\\n", name)
+ for _, key := range android.SortedStringKeys(a.depInfos) {
+ info := a.depInfos[key]
+ toName := info.to
+ if info.isExternal {
+ toName = toName + " (external)"
+ }
+ fmt.Fprintf(&content, "%s <- %s\\n", toName, strings.Join(android.SortedUniqueStrings(info.from), ", "))
}
depsInfoFile := android.PathForOutput(ctx, a.Name()+"-deps-info.txt")
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
new file mode 100644
index 0000000..a9e26ad
--- /dev/null
+++ b/apex/vndk_test.go
@@ -0,0 +1,112 @@
+package apex
+
+import (
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+func TestVndkApexUsesVendorVariant(t *testing.T) {
+ bp := `
+ apex_vndk {
+ name: "myapex",
+ key: "mykey",
+ }
+ apex_key {
+ name: "mykey",
+ }
+ cc_library {
+ name: "libfoo",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ ` + vndkLibrariesTxtFiles("current")
+
+ ensureFileSrc := func(t *testing.T, files []fileInApex, path, src string) {
+ t.Helper()
+ for _, f := range files {
+ if f.path == path {
+ ensureContains(t, f.src, src)
+ return
+ }
+ }
+ t.Fail()
+ }
+
+ t.Run("VNDK lib doesn't have an apex variant", func(t *testing.T) {
+ ctx, _ := testApex(t, bp)
+
+ // libfoo doesn't have apex variants
+ for _, variant := range ctx.ModuleVariantsForTests("libfoo") {
+ ensureNotContains(t, variant, "_myapex")
+ }
+
+ // VNDK APEX doesn't create apex variant
+ files := getFiles(t, ctx, "myapex", "android_common_image")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+ })
+
+ t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
+ ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
+ // Now product variant is available
+ config.TestProductVariables.ProductVndkVersion = proptools.StringPtr("current")
+ })
+
+ files := getFiles(t, ctx, "myapex", "android_common_image")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+ })
+
+ t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
+ ctx, _ := testApex(t, bp+`
+ cc_library {
+ name: "libprofile-extras",
+ vendor_available: true,
+ recovery_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ cc_library {
+ name: "libprofile-clang-extras",
+ vendor_available: true,
+ recovery_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ cc_library {
+ name: "libprofile-extras_ndk",
+ vendor_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ cc_library {
+ name: "libprofile-clang-extras_ndk",
+ vendor_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
+ })
+
+ files := getFiles(t, ctx, "myapex", "android_common_image")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+
+ files = getFiles(t, ctx, "myapex", "android_common_cov_image")
+ ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared_cov/libfoo.so")
+ })
+}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 024fcbc..59d1502 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -33,7 +33,7 @@
var (
pctx = android.NewPackageContext("android/soong/bpf")
- ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.SUPPORTS_GOMA,
+ ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
@@ -66,6 +66,8 @@
// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
"-isystem bionic/libc/kernel/uapi/asm-arm64",
"-isystem bionic/libc/kernel/android/uapi",
+ // TODO(b/149785767): only give access to specific file with AID_* constants
+ "-I system/core/libcutils/include",
"-I system/bpf/progs/include",
"-I " + ctx.ModuleDir(),
}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 4633aa6..0516279 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -120,6 +120,10 @@
Name: "removeEmptyLibDependencies",
Fix: removeEmptyLibDependencies,
},
+ {
+ Name: "removeHidlInterfaceTypes",
+ Fix: removeHidlInterfaceTypes,
+ },
}
func NewFixRequest() FixRequest {
@@ -698,6 +702,18 @@
return nil
}
+// Removes hidl_interface 'types' which are no longer needed
+func removeHidlInterfaceTypes(f *Fixer) error {
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !(ok && mod.Type == "hidl_interface") {
+ continue
+ }
+ removeProperty(mod, "types")
+ }
+ 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) {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 032282f..38cefdd 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -887,3 +887,34 @@
})
}
}
+
+func TestRemoveHidlInterfaceTypes(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "remove types",
+ in: `
+ hidl_interface {
+ name: "foo@1.0",
+ types: ["ParcelFooBar"],
+ }
+ `,
+ out: `
+ hidl_interface {
+ name: "foo@1.0",
+
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, func(fixer *Fixer) error {
+ return removeHidlInterfaceTypes(fixer)
+ })
+ })
+ }
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 02b346d..008030f 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -6,12 +6,15 @@
# The following environment variables affect the result:
# BUILD_NUMBER build number, used to generate unique ID (will use UUID if not set)
# DIST_DIR where the resulting all.kzip will be placed
+# KYTHE_KZIP_ENCODING proto or json (proto is default)
# OUT_DIR output directory (out if not specified})
# TARGET_BUILD_VARIANT variant, e.g., `userdebug`
# TARGET_PRODUCT target device name, e.g., 'aosp_blueline'
# XREF_CORPUS source code repository URI, e.g., 'android.googlesource.com/platform/superproject'
: ${BUILD_NUMBER:=$(uuidgen)}
+: ${KYTHE_KZIP_ENCODING:=proto}
+export KYTHE_KZIP_ENCODING
# The extraction might fail for some source files, so run with -k and then check that
# sufficiently many files were generated.
@@ -20,13 +23,14 @@
build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
#Build extraction file for Go files in build/soong directory.
declare -r abspath_out=$(realpath "${out}")
-(cd build/soong;
- ../../prebuilts/build-tools/linux-x86/bin/go_extractor \
- --goroot="${PWD}/../../prebuilts/go/linux-x86" \
- --rules=vnames.go.json \
- --canonicalize_package_corpus \
- --output "${abspath_out}/soong/all.go.kzip" \
- ./... )
+declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor)
+declare -r go_root=$(realpath prebuilts/go/linux-x86)
+for dir in blueprint soong; do
+ (cd "build/$dir";
+ "$go_extractor" --goroot="$go_root" --rules=vnames.go.json --canonicalize_package_corpus \
+ --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
+ )
+done
declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ff88091..a78e455 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -27,6 +27,7 @@
nativeBridgeSuffix = ".native_bridge"
productSuffix = ".product"
vendorSuffix = ".vendor"
+ ramdiskSuffix = ".ramdisk"
recoverySuffix = ".recovery"
)
@@ -40,6 +41,7 @@
UseVndk() bool
VndkVersion() string
static() bool
+ InRamdisk() bool
InRecovery() bool
}
@@ -217,6 +219,9 @@
fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
fmt.Fprintln(w, "LOCAL_VNDK_DEPEND_ON_CORE_VARIANT := true")
}
+ if library.checkSameCoreVariant {
+ fmt.Fprintln(w, "LOCAL_CHECK_SAME_VNDK_VARIANTS := true")
+ }
})
if library.shared() && !library.buildStubs() {
@@ -230,7 +235,7 @@
})
}
if len(library.Properties.Stubs.Versions) > 0 &&
- android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRecovery() && !ctx.UseVndk() &&
+ android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
!ctx.static() {
if !library.buildStubs() {
ret.SubName = ".bootstrap"
@@ -410,7 +415,7 @@
func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
ret.Class = "SHARED_LIBRARIES"
- ret.SubName = c.NameSuffix()
+ ret.SubName = c.androidMkSuffix
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
c.libraryDecorator.androidMkWriteExportedFlags(w)
@@ -421,6 +426,63 @@
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ if c.tocFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+ }
+ })
+}
+
+func (c *vendorSnapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ // Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current
+ // and the version of the prebuilt is same as BOARD_VNDK_VERSION.
+ if c.shared() {
+ ret.Class = "SHARED_LIBRARIES"
+ } else if c.static() {
+ ret.Class = "STATIC_LIBRARIES"
+ } else if c.header() {
+ ret.Class = "HEADER_LIBRARIES"
+ }
+
+ if c.androidMkVendorSuffix {
+ ret.SubName = vendorSuffix
+ } else {
+ ret.SubName = ""
+ }
+
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ c.libraryDecorator.androidMkWriteExportedFlags(w)
+
+ if c.shared() || c.static() {
+ path, file := filepath.Split(c.path.ToMakePath().String())
+ stem, suffix, ext := android.SplitFileExt(file)
+ fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
+ fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ if c.shared() {
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
+ }
+ if c.tocFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+ }
+ }
+
+ if !c.shared() { // static or header
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ }
+ })
+}
+
+func (c *vendorSnapshotBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ret.Class = "EXECUTABLES"
+
+ if c.androidMkVendorSuffix {
+ ret.SubName = vendorSuffix
+ } else {
+ ret.SubName = ""
+ }
+
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(c.Properties.Symlinks, " "))
})
}
diff --git a/cc/binary.go b/cc/binary.go
index 617d4dd..661264e 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -56,8 +56,12 @@
}
func init() {
- android.RegisterModuleType("cc_binary", BinaryFactory)
- android.RegisterModuleType("cc_binary_host", binaryHostFactory)
+ RegisterBinaryBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterBinaryBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_binary", BinaryFactory)
+ ctx.RegisterModuleType("cc_binary_host", binaryHostFactory)
}
// cc_binary produces a binary that is runnable on a device.
@@ -196,6 +200,11 @@
module.compiler = NewBaseCompiler()
module.linker = binary
module.installer = binary
+
+ // Allow module to be added as member of an sdk/module_exports.
+ module.sdkMemberTypes = []android.SdkMemberType{
+ ccBinarySdkMemberType,
+ }
return module, binary
}
@@ -260,7 +269,7 @@
} else {
switch ctx.Os() {
case android.Android:
- if ctx.bootstrap() && !ctx.inRecovery() {
+ if ctx.bootstrap() && !ctx.inRecovery() && !ctx.inRamdisk() {
flags.DynamicLinker = "/system/bin/bootstrap/linker"
} else {
flags.DynamicLinker = "/system/bin/linker"
@@ -454,7 +463,7 @@
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRecovery() {
+ if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
new file mode 100644
index 0000000..53bc065
--- /dev/null
+++ b/cc/binary_sdk_member.go
@@ -0,0 +1,143 @@
+// Copyright 2020 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 (
+ "path/filepath"
+
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+func init() {
+ android.RegisterSdkMemberType(ccBinarySdkMemberType)
+}
+
+var ccBinarySdkMemberType = &binarySdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "native_binaries",
+ },
+}
+
+type binarySdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ targets := mctx.MultiTargets()
+ for _, lib := range names {
+ for _, target := range targets {
+ name, version := StubsLibNameAndVersion(lib)
+ if version == "" {
+ version = LatestStubsVersionFor(mctx.Config(), name)
+ }
+ mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "version", Variation: version},
+ }...), dependencyTag, name)
+ }
+ }
+}
+
+func (mt *binarySdkMemberType) IsInstance(module android.Module) bool {
+ // Check the module to see if it can be used with this module type.
+ if m, ok := module.(*Module); ok {
+ for _, allowableMemberType := range m.sdkMemberTypes {
+ if allowableMemberType == mt {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ info := mt.organizeVariants(member)
+ buildSharedNativeBinarySnapshot(info, builder, member)
+}
+
+// Organize the variants by architecture.
+func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
+ memberName := member.Name()
+ info := &nativeBinaryInfo{
+ name: memberName,
+ memberType: mt,
+ }
+
+ for _, variant := range member.Variants() {
+ ccModule := variant.(*Module)
+
+ info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
+ name: memberName,
+ archType: ccModule.Target().Arch.ArchType.String(),
+ outputFile: ccModule.OutputFile().Path(),
+ })
+ }
+
+ // Initialize the unexported properties that will not be set during the
+ // extraction process.
+ info.commonProperties.name = memberName
+
+ // Extract common properties from the arch specific properties.
+ extractCommonProperties(&info.commonProperties, info.archVariantProperties)
+
+ return info
+}
+
+func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+ pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
+ pbm.AddProperty("compile_multilib", "both")
+ archProperties := pbm.AddPropertySet("arch")
+ for _, av := range info.archVariantProperties {
+ archTypeProperties := archProperties.AddPropertySet(av.archType)
+ archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
+
+ builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
+ }
+}
+
+const (
+ nativeBinaryDir = "bin"
+)
+
+// path to the native binary. Relative to <sdk_root>/<api_dir>
+func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
+ return filepath.Join(lib.archType,
+ nativeBinaryDir, lib.outputFile.Base())
+}
+
+// nativeBinaryInfoProperties represents properties of a native binary
+//
+// The exported (capitalized) fields will be examined and may be changed during common value extraction.
+// The unexported fields will be left untouched.
+type nativeBinaryInfoProperties struct {
+ // The name of the library, is not exported as this must not be changed during optimization.
+ name string
+
+ // archType is not exported as if set (to a non default value) it is always arch specific.
+ // This is "" for common properties.
+ archType string
+
+ // outputFile is not exported as it is always arch specific.
+ outputFile android.Path
+}
+
+// nativeBinaryInfo represents a collection of arch-specific modules having the same name
+type nativeBinaryInfo struct {
+ name string
+ memberType *binarySdkMemberType
+ archVariantProperties []nativeBinaryInfoProperties
+ commonProperties nativeBinaryInfoProperties
+}
diff --git a/cc/builder.go b/cc/builder.go
index 1ec323f..136263b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -46,7 +46,7 @@
var (
pctx = android.NewPackageContext("android/soong/cc")
- cc = pctx.AndroidRemoteStaticRule("cc", android.SUPPORTS_BOTH,
+ cc = pctx.AndroidRemoteStaticRule("cc", android.RemoteRuleSupports{Goma: true, RBE: true},
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
@@ -55,9 +55,9 @@
},
"ccCmd", "cFlags")
- ccNoDeps = pctx.AndroidRemoteStaticRule("ccNoDeps", android.SUPPORTS_GOMA,
+ ccNoDeps = pctx.AndroidStaticRule("ccNoDeps",
blueprint.RuleParams{
- Command: "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -o $out $in",
+ Command: "$relPwd $ccCmd -c $cFlags -o $out $in",
CommandDeps: []string{"$ccCmd"},
},
"ccCmd", "cFlags")
@@ -178,7 +178,7 @@
windres = pctx.AndroidStaticRule("windres",
blueprint.RuleParams{
- Command: "$windresCmd $flags -I$$(dirname $in) -i $in -o $out",
+ Command: "$windresCmd $flags -I$$(dirname $in) -i $in -o $out --preprocessor \"${config.ClangBin}/clang -E -xc-header -DRC_INVOKED\"",
CommandDeps: []string{"$windresCmd"},
},
"windresCmd", "flags")
@@ -238,9 +238,13 @@
_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
_ = pctx.VariableFunc("kytheCorpus",
func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
+ _ = pctx.VariableFunc("kytheCuEncoding",
+ func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
kytheExtract = pctx.StaticRule("kythe",
blueprint.RuleParams{
- Command: "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out KYTHE_VNAMES=$kytheVnames $cxxExtractor $cFlags $in ",
+ Command: `rm -f $out && ` +
+ `KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out KYTHE_VNAMES=$kytheVnames KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+ `$cxxExtractor $cFlags $in `,
CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
diff --git a/cc/cc.go b/cc/cc.go
index d1b97b4..5af8459 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -49,6 +49,8 @@
ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel()
+ ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel()
+ ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel()
})
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -93,6 +95,8 @@
HeaderLibs []string
RuntimeLibs []string
+ StaticUnwinderIfLegacy bool
+
ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
ObjFiles []string
@@ -223,11 +227,15 @@
// file
Logtags []string
+ // Make this module available when building for ramdisk
+ Ramdisk_available *bool
+
// Make this module available when building for recovery
Recovery_available *bool
// Set by imageMutator
CoreVariantNeeded bool `blueprint:"mutated"`
+ RamdiskVariantNeeded bool `blueprint:"mutated"`
RecoveryVariantNeeded bool `blueprint:"mutated"`
ExtraVariants []string `blueprint:"mutated"`
@@ -238,6 +246,10 @@
// Even if DeviceConfig().VndkUseCoreVariant() is set, this module must use vendor variant.
// see soong/cc/config/vndk.go
MustUseVendorVariant bool `blueprint:"mutated"`
+
+ // Used by vendor snapshot to record dependencies from snapshot modules.
+ SnapshotSharedLibs []string `blueprint:"mutated"`
+ SnapshotRuntimeLibs []string `blueprint:"mutated"`
}
type VendorProperties struct {
@@ -290,6 +302,7 @@
isVndkExt() bool
inProduct() bool
inVendor() bool
+ inRamdisk() bool
inRecovery() bool
shouldCreateSourceAbiDump() bool
selectedStl() string
@@ -374,6 +387,7 @@
lateSharedDepTag = DependencyTag{Name: "late shared", Library: true, Shared: true}
staticExportDepTag = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
lateStaticDepTag = DependencyTag{Name: "late static", Library: true}
+ staticUnwinderDepTag = DependencyTag{Name: "static unwinder", Library: true}
wholeStaticDepTag = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
headerDepTag = DependencyTag{Name: "header", Library: true}
headerExportDepTag = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
@@ -398,13 +412,6 @@
return ok && ccDepTag.Shared
}
-func IsStaticDepTag(depTag blueprint.DependencyTag) bool {
- ccDepTag, ok := depTag.(DependencyTag)
- return ok && (ccDepTag == staticExportDepTag ||
- ccDepTag == lateStaticDepTag ||
- ccDepTag == wholeStaticDepTag)
-}
-
func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(DependencyTag)
return ok && ccDepTag == runtimeDepTag
@@ -446,9 +453,6 @@
vndkdep *vndkdep
lto *lto
pgo *pgo
- xom *xom
-
- androidMkSharedLibDeps []string
outputFile android.OptionalPath
@@ -470,9 +474,6 @@
makeLinkType string
// Kythe (source file indexer) paths for this compilation module
kytheFiles android.Paths
-
- // name of the modules that are direct or indirect static deps of this module
- allStaticDeps []string
}
func (c *Module) Toc() android.OptionalPath {
@@ -735,9 +736,6 @@
if c.pgo != nil {
c.AddProperties(c.pgo.props()...)
}
- if c.xom != nil {
- c.AddProperties(c.xom.props()...)
- }
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
@@ -878,10 +876,18 @@
return c.Properties.ImageVariationPrefix == VendorVariationPrefix
}
+func (c *Module) InRamdisk() bool {
+ return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk()
+}
+
func (c *Module) InRecovery() bool {
return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
}
+func (c *Module) OnlyInRamdisk() bool {
+ return c.ModuleBase.InstallInRamdisk()
+}
+
func (c *Module) OnlyInRecovery() bool {
return c.ModuleBase.InstallInRecovery()
}
@@ -917,6 +923,19 @@
return c.linker != nil && c.linker.nativeCoverage()
}
+func (c *Module) isSnapshotPrebuilt() bool {
+ if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ return true
+ }
+ if _, ok := c.linker.(*vendorSnapshotLibraryDecorator); ok {
+ return true
+ }
+ if _, ok := c.linker.(*vendorSnapshotBinaryDecorator); ok {
+ return true
+ }
+ return false
+}
+
func (c *Module) ExportedIncludeDirs() android.Paths {
if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
return flagsProducer.exportedDirs()
@@ -1018,7 +1037,7 @@
}
func (ctx *moduleContextImpl) useSdk() bool {
- if ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() {
+ if ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() {
return String(ctx.mod.Properties.Sdk_version) != ""
}
return false
@@ -1090,6 +1109,10 @@
return ctx.mod.inVendor()
}
+func (ctx *moduleContextImpl) inRamdisk() bool {
+ return ctx.mod.InRamdisk()
+}
+
func (ctx *moduleContextImpl) inRecovery() bool {
return ctx.mod.InRecovery()
}
@@ -1113,7 +1136,7 @@
// Host modules do not need ABI dumps.
return false
}
- if ctx.isStubs() {
+ if ctx.isStubs() || ctx.isNDKStubLibrary() {
// Stubs do not need ABI dumps.
return false
}
@@ -1182,7 +1205,6 @@
module.vndkdep = &vndkdep{}
module.lto = <o{}
module.pgo = &pgo{}
- module.xom = &xom{}
return module
}
@@ -1249,8 +1271,11 @@
allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
staticDepFiles := []android.Path{}
for _, dep := range staticDeps {
- allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
- staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
+ // The OutputFile may not be valid for a variant not present, and the AllowMissingDependencies flag is set.
+ if dep.OutputFile().Valid() {
+ allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
+ staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
+ }
}
sharedDepFiles := []android.Path{}
for _, sharedDep := range sharedDeps {
@@ -1268,15 +1293,6 @@
return results
}
-func gatherTransitiveStaticDeps(staticDeps []LinkableInterface) []string {
- var ret []string
- for _, dep := range staticDeps {
- ret = append(ret, dep.Module().Name())
- ret = append(ret, dep.AllStaticDeps()...)
- }
- return android.FirstUniqueStrings(ret)
-}
-
func (c *Module) IsTestPerSrcAllTestsVariation() bool {
test, ok := c.linker.(testPerSrc)
return ok && test.isAllTestsVariation()
@@ -1335,6 +1351,8 @@
// .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
// such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
c.Properties.SubName += vendorSuffix
+ } else if c.InRamdisk() && !c.OnlyInRamdisk() {
+ c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix
}
@@ -1381,9 +1399,6 @@
if c.pgo != nil {
flags = c.pgo.flags(ctx, flags)
}
- if c.xom != nil {
- flags = c.xom.flags(ctx, flags)
- }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -1444,7 +1459,7 @@
// (unless it is explicitly referenced via .bootstrap suffix or the
// module is marked with 'bootstrap: true').
if c.HasStubsVariants() &&
- android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) &&
+ android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) && !c.InRamdisk() &&
!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
c.IsStubs() {
c.Properties.HideFromMake = false // unhide
@@ -1602,6 +1617,10 @@
}
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
+ if !c.Enabled() {
+ return
+ }
+
ctx := &depsContext{
BottomUpMutatorContext: actx,
moduleContextImpl: moduleContextImpl{
@@ -1617,7 +1636,7 @@
if ctx.Os() == android.Android {
version := ctx.sdkVersion()
- // rewriteNdkLibs takes a list of names of shared libraries and scans it for three types
+ // rewriteLibs takes a list of names of shared libraries and scans it for three types
// of names:
//
// 1. Name of an NDK library that refers to a prebuilt module.
@@ -1633,7 +1652,26 @@
// nonvariantLibs
vendorPublicLibraries := vendorPublicLibraries(actx.Config())
- rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
+ vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config())
+
+ rewriteVendorLibs := func(lib string) string {
+ if isLlndkLibrary(lib, ctx.Config()) {
+ return lib + llndkLibrarySuffix
+ }
+
+ // only modules with BOARD_VNDK_VERSION uses snapshot.
+ if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
+ return lib
+ }
+
+ if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok {
+ return snapshot
+ }
+
+ return lib
+ }
+
+ rewriteLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
variantLibs = []string{}
nonvariantLibs = []string{}
for _, entry := range list {
@@ -1645,8 +1683,8 @@
} else {
variantLibs = append(variantLibs, name+ndkLibrarySuffix)
}
- } else if ctx.useVndk() && isLlndkLibrary(name, ctx.Config()) {
- nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
+ } else if ctx.useVndk() {
+ nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry))
} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
vendorPublicLib := name + vendorPublicLibrarySuffix
if actx.OtherModuleExists(vendorPublicLib) {
@@ -1665,9 +1703,14 @@
return nonvariantLibs, variantLibs
}
- deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs)
- deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
- deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders)
+ deps.SharedLibs, variantNdkLibs = rewriteLibs(deps.SharedLibs)
+ deps.LateSharedLibs, variantLateNdkLibs = rewriteLibs(deps.LateSharedLibs)
+ deps.ReexportSharedLibHeaders, _ = rewriteLibs(deps.ReexportSharedLibHeaders)
+ if ctx.useVndk() {
+ for idx, lib := range deps.RuntimeLibs {
+ deps.RuntimeLibs[idx] = rewriteVendorLibs(lib)
+ }
+ }
}
buildStubs := false
@@ -1679,11 +1722,28 @@
}
}
+ rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string {
+ // only modules with BOARD_VNDK_VERSION uses snapshot.
+ if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
+ return lib
+ }
+
+ if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok {
+ return snapshot
+ }
+
+ return lib
+ }
+
+ vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config())
for _, lib := range deps.HeaderLibs {
depTag := headerDepTag
if inList(lib, deps.ReexportHeaderLibHeaders) {
depTag = headerExportDepTag
}
+
+ lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs)
+
if buildStubs {
actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
depTag, lib)
@@ -1699,12 +1759,16 @@
}
syspropImplLibraries := syspropImplLibraries(actx.Config())
+ vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config())
for _, lib := range deps.WholeStaticLibs {
depTag := wholeStaticDepTag
if impl, ok := syspropImplLibraries[lib]; ok {
lib = impl
}
+
+ lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)
+
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, depTag, lib)
@@ -1720,19 +1784,29 @@
lib = impl
}
+ lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)
+
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, depTag, lib)
}
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "static"},
- }, lateStaticDepTag, deps.LateStaticLibs...)
+ if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, staticUnwinderDepTag, staticUnwinder(actx))
+ }
+
+ for _, lib := range deps.LateStaticLibs {
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs))
+ }
addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
var variations []blueprint.Variation
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
- versionVariantAvail := !ctx.useVndk() && !c.InRecovery()
+ versionVariantAvail := !ctx.useVndk() && !c.InRecovery() && !c.InRamdisk()
if version != "" && versionVariantAvail {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
@@ -1758,6 +1832,9 @@
for _, lib := range deps.SharedLibs {
depTag := SharedDepTag
+ if c.static() {
+ depTag = SharedFromStaticDepTag
+ }
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
@@ -1863,6 +1940,10 @@
// Platform code can link to anything
return
}
+ if from.InRamdisk() {
+ // Ramdisk code is not NDK
+ return
+ }
if from.InRecovery() {
// Recovery code is not NDK
return
@@ -2089,6 +2170,14 @@
}
}
+ if depTag == staticUnwinderDepTag {
+ if c.ApexProperties.Info.LegacyAndroid10Support {
+ depTag = StaticDepTag
+ } else {
+ return
+ }
+ }
+
// Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
// Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
// won't be matched to SharedDepTag and lateSharedDepTag.
@@ -2123,8 +2212,8 @@
// If not building for APEX, use stubs only when it is from
// an APEX (and not from platform)
useThisDep = (depInPlatform != depIsStubs)
- if c.InRecovery() || c.bootstrap() {
- // However, for recovery or bootstrap modules,
+ if c.InRamdisk() || c.InRecovery() || c.bootstrap() {
+ // However, for ramdisk, recovery or bootstrap modules,
// always link to non-stub variant
useThisDep = !depIsStubs
}
@@ -2171,7 +2260,7 @@
depFile := android.OptionalPath{}
switch depTag {
- case ndkStubDepTag, SharedDepTag, sharedExportDepTag:
+ case ndkStubDepTag, SharedDepTag, SharedFromStaticDepTag, sharedExportDepTag:
ptr = &depPaths.SharedLibs
depPtr = &depPaths.SharedLibsDeps
depFile = ccDep.Toc()
@@ -2267,15 +2356,34 @@
*depPtr = append(*depPtr, dep.Path())
}
- makeLibName := func(depName string) string {
+ vendorSuffixModules := vendorSuffixModules(ctx.Config())
+
+ baseLibName := func(depName string) string {
libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
libName = strings.TrimPrefix(libName, "prebuilt_")
+ return libName
+ }
+
+ makeLibName := func(depName string) string {
+ libName := baseLibName(depName)
isLLndk := isLlndkLibrary(libName, ctx.Config())
isVendorPublicLib := inList(libName, *vendorPublicLibraries)
bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
- if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRecovery() {
+ if c, ok := ccDep.(*Module); ok {
+ // Use base module name for snapshots when exporting to Makefile.
+ if c.isSnapshotPrebuilt() && !c.IsVndk() {
+ baseName := c.BaseModuleName()
+ if vendorSuffixModules[baseName] {
+ return baseName + ".vendor"
+ } else {
+ return baseName
+ }
+ }
+ }
+
+ if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() {
// The vendor module is a no-vendor-variant VNDK library. Depend on the
// core module instead.
return libName
@@ -2285,6 +2393,8 @@
return libName + c.getNameSuffixWithVndkVersion(ctx)
} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
return libName + vendorPublicLibrarySuffix
+ } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
+ return libName + ramdiskSuffix
} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
return libName + recoverySuffix
} else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
@@ -2312,6 +2422,8 @@
// they merely serve as Make dependencies and do not affect this lib itself.
c.Properties.AndroidMkSharedLibs = append(
c.Properties.AndroidMkSharedLibs, makeLibName(depName))
+ // Record baseLibName for snapshots.
+ c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName))
case ndkStubDepTag, ndkLateStubDepTag:
c.Properties.AndroidMkSharedLibs = append(
c.Properties.AndroidMkSharedLibs,
@@ -2322,6 +2434,8 @@
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
c.Properties.AndroidMkRuntimeLibs, makeLibName(depName))
+ // Record baseLibName for snapshots.
+ c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
case wholeStaticDepTag:
c.Properties.AndroidMkWholeStaticLibs = append(
c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName))
@@ -2347,8 +2461,6 @@
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
}
- c.allStaticDeps = gatherTransitiveStaticDeps(directStaticDeps)
-
return depPaths
}
@@ -2369,6 +2481,10 @@
return c.installer.inSanitizerDir()
}
+func (c *Module) InstallInRamdisk() bool {
+ return c.InRamdisk()
+}
+
func (c *Module) InstallInRecovery() bool {
return c.InRecovery()
}
@@ -2441,6 +2557,8 @@
return "native:product"
}
return "native:vendor"
+ } else if c.InRamdisk() {
+ return "native:ramdisk"
} else if c.InRecovery() {
return "native:recovery"
} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
@@ -2502,10 +2620,6 @@
return false
}
-func (c *Module) AllStaticDeps() []string {
- return c.allStaticDeps
-}
-
func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
if c.linker != nil {
if library, ok := c.linker.(*libraryDecorator); ok {
@@ -2516,9 +2630,17 @@
func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok {
- if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.Shared {
- // dynamic dep to a stubs lib crosses APEX boundary
- return false
+ if cc, ok := dep.(*Module); ok {
+ if cc.HasStubsVariants() && depTag.Shared && depTag.Library {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ if depTag.FromStatic {
+ // shared_lib dependency from a static lib is considered as crossing
+ // the APEX boundary because the dependency doesn't actually is
+ // linked; the dependency is used only during the compilation phase.
+ return false
+ }
}
}
return true
@@ -2570,7 +2692,6 @@
&VndkProperties{},
<OProperties{},
&PgoProperties{},
- &XomProperties{},
&android.ProtoProperties{},
)
@@ -2647,6 +2768,7 @@
}
var coreVariantNeeded bool = false
+ var ramdiskVariantNeeded bool = false
var recoveryVariantNeeded bool = false
var vendorVariants []string
@@ -2687,10 +2809,16 @@
platformVndkVersion,
productVndkVersion,
)
- } else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ } else if m.isSnapshotPrebuilt() {
// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
// PRODUCT_EXTRA_VNDK_VERSIONS.
- vendorVariants = append(vendorVariants, lib.version())
+ if snapshot, ok := m.linker.(interface {
+ version() string
+ }); ok {
+ vendorVariants = append(vendorVariants, snapshot.version())
+ } else {
+ mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ }
} else if m.HasVendorVariant() && !vendorSpecific {
// This will be available in /system, /vendor and /product
// or a /system directory that is available to vendor and product.
@@ -2729,6 +2857,15 @@
productVariants = []string{}
}
+ if Bool(m.Properties.Ramdisk_available) {
+ ramdiskVariantNeeded = true
+ }
+
+ if m.ModuleBase.InstallInRamdisk() {
+ ramdiskVariantNeeded = true
+ coreVariantNeeded = false
+ }
+
if Bool(m.Properties.Recovery_available) {
recoveryVariantNeeded = true
}
@@ -2746,6 +2883,7 @@
m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant)
}
+ m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
m.Properties.CoreVariantNeeded = coreVariantNeeded
}
@@ -2754,6 +2892,10 @@
return c.Properties.CoreVariantNeeded
}
+func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return c.Properties.RamdiskVariantNeeded
+}
+
func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return c.Properties.RecoveryVariantNeeded
}
@@ -2764,13 +2906,23 @@
func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
m := module.(*Module)
- if variant == android.RecoveryVariation {
+ if variant == android.RamdiskVariation {
+ m.MakeAsPlatform()
+ } else if variant == android.RecoveryVariation {
m.MakeAsPlatform()
squashRecoverySrcs(m)
} else if strings.HasPrefix(variant, VendorVariationPrefix) {
m.Properties.ImageVariationPrefix = VendorVariationPrefix
m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
squashVendorSrcs(m)
+
+ // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
+ // Hide other vendor variants to avoid collision.
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
+ m.Properties.HideFromMake = true
+ m.SkipInstall()
+ }
} else if strings.HasPrefix(variant, ProductVariationPrefix) {
m.Properties.ImageVariationPrefix = ProductVariationPrefix
m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4d02f4f..30ba733 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -258,8 +258,8 @@
}
}
-func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, moduleName, snapshotFilename, subDir, variant string) {
- vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+func checkSnapshot(t *testing.T, ctx *android.TestContext, singletonName, moduleName, snapshotFilename, subDir, variant string) {
+ snapshotSingleton := ctx.SingletonForTests(singletonName)
mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
if !ok {
@@ -273,9 +273,9 @@
}
snapshotPath := filepath.Join(subDir, snapshotFilename)
- out := vndkSnapshot.Output(snapshotPath)
+ out := snapshotSingleton.Output(snapshotPath)
if out.Input.String() != outputFiles[0].String() {
- t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), outputFiles[0])
+ t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
}
}
@@ -398,16 +398,16 @@
variant := "android_vendor.VER_arm64_armv8-a_shared"
variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared"
- checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
- checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
- checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
- checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
+ checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLibPath, variant)
+ checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
+ checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
+ checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
- checkVndkSnapshot(t, ctx, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
- checkVndkSnapshot(t, ctx, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
- checkVndkSnapshot(t, ctx, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
- checkVndkSnapshot(t, ctx, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
+ checkSnapshot(t, ctx, "vndk-snapshot", "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
+ checkSnapshot(t, ctx, "vndk-snapshot", "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
+ checkSnapshot(t, ctx, "vndk-snapshot", "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
+ checkSnapshot(t, ctx, "vndk-snapshot", "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
"LLNDK: libc.so",
@@ -799,6 +799,88 @@
`)
}
+func TestVendorSnapshot(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvendor_available",
+ vendor_available: true,
+ nocrt: true,
+ }
+
+ cc_library_headers {
+ name: "libvendor_headers",
+ vendor_available: true,
+ nocrt: true,
+ }
+
+ cc_binary {
+ name: "vendor_bin",
+ vendor: true,
+ nocrt: true,
+ }
+
+ cc_binary {
+ name: "vendor_available_bin",
+ vendor_available: true,
+ nocrt: true,
+ }
+`
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := testCcWithConfig(t, config)
+
+ // Check Vendor snapshot output.
+
+ snapshotDir := "vendor-snapshot"
+ snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ []string{"arm", "armv7-a-neon"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ // For shared libraries, only non-VNDK vendor_available modules are captured
+ sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.so", sharedDir, sharedVariant)
+ checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+
+ // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
+ staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
+ staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+ checkSnapshot(t, ctx, "vendor-snapshot", "libvndk", "libvndk.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+
+ // For binary libraries, all vendor:true and vendor_available modules are captured.
+ if archType == "arm64" {
+ binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+ binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+ checkSnapshot(t, ctx, "vendor-snapshot", "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
+ checkSnapshot(t, ctx, "vendor-snapshot", "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
+ }
+ }
+}
+
func TestDoubleLoadableDepError(t *testing.T) {
// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
@@ -2303,13 +2385,13 @@
// Check the shared version of lib2.
variant := "android_arm64_armv8-a_shared"
module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
- checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
+ checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
// Check the static version of lib2.
variant = "android_arm64_armv8-a_static"
module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
// libc++_static is linked additionally.
- checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic", "libgcc_stripped"}, module)
+ checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
}
var compilerFlagsTestCases = []struct {
@@ -2592,20 +2674,20 @@
cc_binary {
name: "mybin",
srcs: ["foo.c"],
- static_libs: ["libB"],
+ static_libs: ["libfooB"],
static_executable: true,
stl: "none",
}
cc_library {
- name: "libB",
+ name: "libfooB",
srcs: ["foo.c"],
- shared_libs: ["libC"],
+ shared_libs: ["libfooC"],
stl: "none",
}
cc_library {
- name: "libC",
+ name: "libfooC",
srcs: ["foo.c"],
stl: "none",
stubs: {
@@ -2615,7 +2697,7 @@
mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a").Module().(*Module)
actual := mybin.depsInLinkOrder
- expected := getOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libB", "libC"})
+ expected := getOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libfooB", "libfooC"})
if !reflect.DeepEqual(actual, expected) {
t.Errorf("staticDeps orderings were not propagated correctly"+
@@ -2751,3 +2833,42 @@
t.Errorf("libboth ar rule wanted %q, got %q", w, g)
}
}
+
+func TestProductVariableDefaults(t *testing.T) {
+ bp := `
+ cc_defaults {
+ name: "libfoo_defaults",
+ srcs: ["foo.c"],
+ cppflags: ["-DFOO"],
+ product_variables: {
+ debuggable: {
+ cppflags: ["-DBAR"],
+ },
+ },
+ }
+
+ cc_library {
+ name: "libfoo",
+ defaults: ["libfoo_defaults"],
+ }
+ `
+
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.Debuggable = BoolPtr(true)
+
+ ctx := CreateTestContext()
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("variable", android.VariableMutator).Parallel()
+ })
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module)
+ if !android.InList("-DBAR", libfoo.flags.Local.CppFlags) {
+ t.Errorf("expected -DBAR in cppflags, got %q", libfoo.flags.Local.CppFlags)
+ }
+}
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index 4e23a7b..225405c 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -17,7 +17,6 @@
import (
"encoding/json"
"fmt"
- "os"
"path"
"sort"
"strings"
@@ -106,7 +105,7 @@
moduleDeps.Modules = moduleInfos
- ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName).String()
+ ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName)
err := createJsonFile(moduleDeps, ccfpath)
if err != nil {
ctx.Errorf(err.Error())
@@ -236,17 +235,14 @@
return m
}
-func createJsonFile(moduleDeps ccDeps, ccfpath string) error {
- file, err := os.Create(ccfpath)
- if err != nil {
- return fmt.Errorf("Failed to create file: %s, relative: %v", ccdepsJsonFileName, err)
- }
- defer file.Close()
- moduleDeps.Modules = sortMap(moduleDeps.Modules)
+func createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error {
buf, err := json.MarshalIndent(moduleDeps, "", "\t")
if err != nil {
- return fmt.Errorf("Write file failed: %s, relative: %v", ccdepsJsonFileName, err)
+ return fmt.Errorf("JSON marshal of cc deps failed: %s", err)
}
- fmt.Fprintf(file, string(buf))
+ err = android.WriteFileToOutputDir(ccfpath, buf, 0666)
+ if err != nil {
+ return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err)
+ }
return nil
}
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
index b61f2a8..855ff25 100644
--- a/cc/cflag_artifacts.go
+++ b/cc/cflag_artifacts.go
@@ -41,12 +41,7 @@
// filter.
func allowedDir(subdir string) bool {
subdir += "/"
- for _, prefix := range TrackedCFlagsDir {
- if strings.HasPrefix(subdir, prefix) {
- return true
- }
- }
- return false
+ return android.HasAnyPrefix(subdir, TrackedCFlagsDir)
}
func (s *cflagArtifactsText) genFlagFilename(flag string) string {
diff --git a/cc/compiler.go b/cc/compiler.go
index 1ced451..c1a8d96 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -241,12 +241,7 @@
// Return true if the module is in the WarningAllowedProjects.
func warningsAreAllowed(subdir string) bool {
subdir += "/"
- for _, prefix := range config.WarningAllowedProjects {
- if strings.HasPrefix(subdir, prefix) {
- return true
- }
- }
- return false
+ return android.HasAnyPrefix(subdir, config.WarningAllowedProjects)
}
func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) {
@@ -515,7 +510,7 @@
// Exclude directories from manual binder interface whitelisting.
//TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
- if android.PrefixInList(ctx.ModuleDir(), allowedManualInterfacePaths) {
+ if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) {
flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
}
@@ -604,16 +599,12 @@
func isThirdParty(path string) bool {
thirdPartyDirPrefixes := []string{"external/", "vendor/", "hardware/"}
- for _, prefix := range thirdPartyDirPrefixes {
- if strings.HasPrefix(path, prefix) {
- for _, prefix := range thirdPartyDirPrefixExceptions {
- if prefix.MatchString(path) {
- return false
- }
+ if android.HasAnyPrefix(path, thirdPartyDirPrefixes) {
+ for _, prefix := range thirdPartyDirPrefixExceptions {
+ if prefix.MatchString(path) {
+ return false
}
- break
}
}
-
return true
}
diff --git a/cc/config/OWNERS b/cc/config/OWNERS
new file mode 100644
index 0000000..b2f54e5
--- /dev/null
+++ b/cc/config/OWNERS
@@ -0,0 +1 @@
+per-file vndk.go = smoreland@google.com, victoryang@google.com
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 8618d09..d849906 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -169,6 +169,10 @@
"-Wno-reorder-init-list",
// http://b/145211066
"-Wno-implicit-int-float-conversion",
+ // New warnings to be fixed after clang-r377782.
+ "-Wno-int-in-bool-context", // http://b/148287349
+ "-Wno-sizeof-array-div", // http://b/148815709
+ "-Wno-tautological-overlap-compare", // http://b/148815696
}, " "))
// Extra cflags for external third-party projects to disable warnings that
diff --git a/cc/config/global.go b/cc/config/global.go
index bae5555..d01dd84 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -88,6 +88,7 @@
"-Wl,--no-undefined-version",
"-Wl,--exclude-libs,libgcc.a",
"-Wl,--exclude-libs,libgcc_stripped.a",
+ "-Wl,--exclude-libs,libunwind_llvm.a",
}
deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
@@ -126,8 +127,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r370808"
- ClangDefaultShortVersion = "10.0.1"
+ ClangDefaultVersion = "clang-r377782b"
+ ClangDefaultShortVersion = "10.0.4"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
@@ -165,6 +166,11 @@
flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
flags = append(flags, "-ftrivial-auto-var-init=pattern")
+ } else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
+ flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
+ } else {
+ // Default to pattern initialization.
+ flags = append(flags, "-ftrivial-auto-var-init=pattern")
}
return strings.Join(flags, " ")
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 9feb5a3..54f693e 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -18,152 +18,31 @@
// For these libraries, the vendor variants must be installed even if the device
// has VndkUseCoreVariant set.
var VndkMustUseVendorVariantList = []string{
- "android.frameworks.sensorservice@1.0",
- "android.hardware.atrace@1.0",
- "android.hardware.audio.common@5.0",
- "android.hardware.audio.effect@2.0",
- "android.hardware.audio.effect@4.0",
- "android.hardware.audio.effect@5.0",
- "android.hardware.audio@2.0",
- "android.hardware.audio@4.0",
- "android.hardware.audio@5.0",
- "android.hardware.automotive.evs@1.0",
- "android.hardware.automotive.vehicle@2.0",
- "android.hardware.bluetooth.audio@2.0",
- "android.hardware.boot@1.0",
- "android.hardware.broadcastradio@1.0",
- "android.hardware.broadcastradio@1.1",
- "android.hardware.broadcastradio@2.0",
- "android.hardware.camera.device@1.0",
- "android.hardware.camera.device@3.2",
- "android.hardware.camera.device@3.3",
- "android.hardware.camera.device@3.4",
- "android.hardware.camera.provider@2.4",
- "android.hardware.cas.native@1.0",
- "android.hardware.cas@1.0",
- "android.hardware.configstore@1.0",
- "android.hardware.configstore@1.1",
- "android.hardware.contexthub@1.0",
- "android.hardware.drm@1.0",
- "android.hardware.drm@1.1",
- "android.hardware.fastboot@1.0",
- "android.hardware.gatekeeper@1.0",
- "android.hardware.gnss@1.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
- "android.hardware.health@1.0",
- "android.hardware.health@2.0",
- "android.hardware.ir@1.0",
- "android.hardware.keymaster@3.0",
- "android.hardware.keymaster@4.0",
- "android.hardware.light@2.0",
- "android.hardware.media.bufferpool@1.0",
- "android.hardware.media.omx@1.0",
- "android.hardware.memtrack@1.0",
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
- "android.hardware.neuralnetworks@1.3",
- "android.hardware.nfc@1.0",
- "android.hardware.nfc@1.1",
+ "android.hardware.light-ndk_platform",
+ "android.hardware.identity-ndk_platform",
"android.hardware.nfc@1.2",
- "android.hardware.oemlock@1.0",
- "android.hardware.power.stats@1.0",
- "android.hardware.power@1.0",
- "android.hardware.power@1.1",
- "android.hardware.radio@1.4",
- "android.hardware.secure_element@1.0",
- "android.hardware.sensors@1.0",
- "android.hardware.soundtrigger@2.0",
- "android.hardware.soundtrigger@2.0-core",
- "android.hardware.soundtrigger@2.1",
- "android.hardware.tetheroffload.config@1.0",
- "android.hardware.tetheroffload.control@1.0",
- "android.hardware.thermal@1.0",
- "android.hardware.tv.cec@1.0",
- "android.hardware.tv.input@1.0",
+ "android.hardware.power-ndk_platform",
"android.hardware.vibrator-ndk_platform",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.weaver@1.0",
- "android.hardware.wifi.hostapd@1.0",
- "android.hardware.wifi.offload@1.0",
- "android.hardware.wifi.supplicant@1.0",
- "android.hardware.wifi.supplicant@1.1",
- "android.hardware.wifi@1.0",
- "android.hardware.wifi@1.1",
- "android.hardware.wifi@1.2",
- "android.hardwareundtrigger@2.0",
- "android.hardwareundtrigger@2.0-core",
- "android.hardwareundtrigger@2.1",
- "android.hidl.allocator@1.0",
- "android.hidl.token@1.0",
- "android.hidl.token@1.0-utils",
- "android.system.net.netd@1.0",
- "android.system.wifi.keystore@1.0",
- "libaudioroute",
- "libaudioutils",
"libbinder",
- "libcamera_metadata",
"libcrypto",
- "libdiskconfig",
- "libdumpstateutil",
"libexpat",
- "libfmq",
"libgatekeeper",
"libgui",
"libhidlcache",
"libkeymaster_messages",
"libkeymaster_portable",
- "libmedia_helper",
"libmedia_omx",
- "libmemtrack",
- "libnetutils",
- "libprotobuf-cpp-full",
- "libprotobuf-cpp-lite",
"libpuresoftkeymasterdevice",
- "libradio_metadata",
"libselinux",
"libsoftkeymasterdevice",
"libsqlite",
"libssl",
- "libstagefright_amrnb_common",
+ "libstagefright_bufferpool@2.0",
"libstagefright_bufferqueue_helper",
- "libstagefright_enc_common",
- "libstagefright_flacdec",
"libstagefright_foundation",
"libstagefright_omx",
"libstagefright_omx_utils",
- "libstagefright_soft_aacdec",
- "libstagefright_soft_aacenc",
- "libstagefright_soft_amrdec",
- "libstagefright_soft_amrnbenc",
- "libstagefright_soft_amrwbenc",
- "libstagefright_soft_avcdec",
- "libstagefright_soft_avcenc",
- "libstagefright_soft_flacdec",
- "libstagefright_soft_flacenc",
- "libstagefright_soft_g711dec",
- "libstagefright_soft_gsmdec",
- "libstagefright_soft_hevcdec",
- "libstagefright_soft_mp3dec",
- "libstagefright_soft_mpeg2dec",
- "libstagefright_soft_mpeg4dec",
- "libstagefright_soft_mpeg4enc",
- "libstagefright_soft_opusdec",
- "libstagefright_soft_rawdec",
- "libstagefright_soft_vorbisdec",
- "libstagefright_soft_vpxdec",
- "libstagefright_soft_vpxenc",
"libstagefright_xmlparser",
- "libsysutils",
- "libtinyxml2",
"libui",
- "libvorbisidec",
"libxml2",
- "libyuv",
- "libziparchive",
}
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 63b9d48..25225b5 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -100,7 +100,7 @@
pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
return xcrunSdk(ctx, "--show-sdk-path")
})
- pctx.StaticVariable("macMinVersion", "10.8")
+ pctx.StaticVariable("macMinVersion", "10.10")
pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
return xcrun(ctx, "--find", "ar")
})
diff --git a/cc/coverage.go b/cc/coverage.go
index b6451ee..b94b628 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -43,7 +43,7 @@
return []interface{}{&cov.Properties}
}
-func getProfileLibraryName(ctx ModuleContextIntf) string {
+func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
// This function should only ever be called for a cc.Module, so the
// following statement should always succeed.
if ctx.useSdk() {
@@ -53,28 +53,47 @@
}
}
+func getClangProfileLibraryName(ctx ModuleContextIntf) string {
+ if ctx.useSdk() {
+ return "libprofile-clang-extras_ndk"
+ } else {
+ return "libprofile-clang-extras"
+ }
+}
+
func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
if cov.Properties.NeedCoverageVariant {
ctx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, coverageDepTag, getProfileLibraryName(ctx))
+ }, coverageDepTag, getGcovProfileLibraryName(ctx))
+ ctx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, coverageDepTag, getClangProfileLibraryName(ctx))
}
return deps
}
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- if !ctx.DeviceConfig().NativeCoverageEnabled() {
+ gcovCoverage := ctx.DeviceConfig().NativeCoverageEnabled()
+ clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
+
+ if !gcovCoverage && !clangCoverage {
return flags, deps
}
if cov.Properties.CoverageEnabled {
flags.Coverage = true
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
cov.linkCoverage = true
- // Override -Wframe-larger-than and non-default optimization
- // flags that the module may use.
- flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
+ if gcovCoverage {
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
+
+ // Override -Wframe-larger-than and non-default optimization
+ // flags that the module may use.
+ flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
+ } else if clangCoverage {
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-fprofile-instr-generate", "-fcoverage-mapping")
+ }
}
// Even if we don't have coverage enabled, if any of our object files were compiled
@@ -112,12 +131,19 @@
}
if cov.linkCoverage {
- flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
+ if gcovCoverage {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
- coverage := ctx.GetDirectDepWithTag(getProfileLibraryName(ctx), coverageDepTag).(*Module)
- deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+ coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), coverageDepTag).(*Module)
+ deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
+ } else if clangCoverage {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate")
+
+ coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), coverageDepTag).(*Module)
+ deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+ }
}
return flags, deps
@@ -125,7 +151,7 @@
func (cov *coverage) begin(ctx BaseModuleContext) {
// Coverage is disabled globally
- if !ctx.DeviceConfig().NativeCoverageEnabled() {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
return
}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 8b84be8..ee24300 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -355,10 +355,10 @@
return
}
- // Discard vendor-NDK-linked + recovery modules, they're duplicates of
+ // Discard vendor-NDK-linked + ramdisk + recovery modules, they're duplicates of
// fuzz targets we're going to package anyway.
if !ccModule.Enabled() || ccModule.Properties.PreventInstall ||
- ccModule.UseVndk() || ccModule.InRecovery() {
+ ccModule.UseVndk() || ccModule.InRamdisk() || ccModule.InRecovery() {
return
}
diff --git a/cc/gen.go b/cc/gen.go
index 17ab45f..b0aadc6 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -162,17 +162,19 @@
})
}
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
+ headers := android.WritablePaths{headerFile, publicHeaderFile}
+
ctx.Build(pctx, android.BuildParams{
- Rule: sysprop,
- Description: "sysprop " + syspropFile.Rel(),
- Output: cppFile,
- ImplicitOutput: headerFile,
- Input: syspropFile,
+ Rule: sysprop,
+ Description: "sysprop " + syspropFile.Rel(),
+ Output: cppFile,
+ ImplicitOutputs: headers,
+ Input: syspropFile,
Args: map[string]string{
"headerOutDir": filepath.Dir(headerFile.String()),
"publicOutDir": filepath.Dir(publicHeaderFile.String()),
@@ -181,7 +183,7 @@
},
})
- return cppFile, headerFile
+ return cppFile, headers.Paths()
}
func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
@@ -259,9 +261,9 @@
srcFiles[i] = rcFile
deps = append(deps, headerFile)
case ".sysprop":
- cppFile, headerFile := genSysprop(ctx, srcFile)
+ cppFile, headerFiles := genSysprop(ctx, srcFile)
srcFiles[i] = cppFile
- deps = append(deps, headerFile)
+ deps = append(deps, headerFiles...)
}
}
diff --git a/cc/genrule.go b/cc/genrule.go
index 548d5f2..155e410 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -25,6 +25,7 @@
type GenruleExtraProperties struct {
Vendor_available *bool
+ Ramdisk_available *bool
Recovery_available *bool
}
@@ -62,6 +63,10 @@
return Bool(g.Vendor_available) || !(ctx.SocSpecific() || ctx.DeviceSpecific())
}
+func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return Bool(g.Ramdisk_available)
+}
+
func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return Bool(g.Recovery_available)
}
diff --git a/cc/library.go b/cc/library.go
index ae95bc5..bca9a96 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -281,11 +281,9 @@
}
func (f *flagExporter) reexportFlags(flags ...string) {
- for _, flag := range flags {
- if strings.HasPrefix(flag, "-I") || strings.HasPrefix(flag, "-isystem") {
- panic(fmt.Errorf("Exporting invalid flag %q: "+
- "use reexportDirs or reexportSystemDirs to export directories", flag))
- }
+ if android.PrefixInList(flags, "-I") || android.PrefixInList(flags, "-isystem") {
+ panic(fmt.Errorf("Exporting invalid flag %q: "+
+ "use reexportDirs or reexportSystemDirs to export directories", flag))
}
f.flags = append(f.flags, flags...)
}
@@ -385,7 +383,8 @@
// If useCoreVariant is true, the vendor variant of a VNDK library is
// not installed.
- useCoreVariant bool
+ useCoreVariant bool
+ checkSameCoreVariant bool
// Decorated interafaces
*baseCompiler
@@ -756,6 +755,13 @@
deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Recovery.Exclude_shared_libs)
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
}
+ if ctx.inRamdisk() {
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Ramdisk.Exclude_static_libs)
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Ramdisk.Exclude_shared_libs)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Ramdisk.Exclude_static_libs)
+ deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_shared_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_static_libs)
+ }
return deps
}
@@ -1039,7 +1045,7 @@
isVendor := ctx.useVndk()
isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
- if !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
+ if !ctx.inRamdisk() && !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
dir = android.PathForModuleGen(ctx, "sysprop/public", "include")
}
}
@@ -1096,8 +1102,25 @@
if ctx.isVndkSp() {
library.baseInstaller.subDir = "vndk-sp"
} else if ctx.isVndk() {
- if ctx.DeviceConfig().VndkUseCoreVariant() && !ctx.mustUseVendorVariant() {
- library.useCoreVariant = true
+ mayUseCoreVariant := true
+
+ if ctx.mustUseVendorVariant() {
+ mayUseCoreVariant = false
+ }
+
+ if ctx.isVndkExt() {
+ mayUseCoreVariant = false
+ }
+
+ if ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
+ mayUseCoreVariant = false
+ }
+
+ if mayUseCoreVariant {
+ library.checkSameCoreVariant = true
+ if ctx.DeviceConfig().VndkUseCoreVariant() {
+ library.useCoreVariant = true
+ }
}
library.baseInstaller.subDir = "vndk"
}
@@ -1114,7 +1137,7 @@
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRecovery() {
+ if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRamdisk() && !ctx.inRecovery() {
if ctx.Device() {
library.installSymlinkToRuntimeApex(ctx, file)
}
@@ -1129,7 +1152,7 @@
}
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
- !ctx.useVndk() && !ctx.inRecovery() && ctx.Device() &&
+ !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() &&
!library.buildStubs() {
installPath := getNdkSysrootBase(ctx).Join(
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index fd5a4da..165901d 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -241,39 +241,43 @@
func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- // a function for emitting include dirs
- addExportedDirsForNativeLibs := func(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
- includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
- if len(includeDirs) == 0 {
- return
- }
- var propertyName string
- if !systemInclude {
- propertyName = "export_include_dirs"
- } else {
- propertyName = "export_system_include_dirs"
- }
- properties.AddProperty(propertyName, includeDirs)
- }
-
pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
- addExportedDirsForNativeLibs(info.commonProperties, pbm, false /*systemInclude*/)
- addExportedDirsForNativeLibs(info.commonProperties, pbm, true /*systemInclude*/)
+ addPossiblyArchSpecificProperties(info.commonProperties, pbm)
archProperties := pbm.AddPropertySet("arch")
for _, av := range info.archVariantProperties {
archTypeProperties := archProperties.AddPropertySet(av.archType)
+ // Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
- // export_* properties are added inside the arch: {<arch>: {...}} block
- addExportedDirsForNativeLibs(av, archTypeProperties, false /*systemInclude*/)
- addExportedDirsForNativeLibs(av, archTypeProperties, true /*systemInclude*/)
+ addPossiblyArchSpecificProperties(av, archTypeProperties)
}
pbm.AddProperty("stl", "none")
pbm.AddProperty("system_shared_libs", []string{})
}
+// Add properties that may, or may not, be arch specific.
+func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+ addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
+ addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
+}
+
+// a function for emitting include dirs
+func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
+ includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
+ if len(includeDirs) == 0 {
+ return
+ }
+ var propertyName string
+ if !systemInclude {
+ propertyName = "export_include_dirs"
+ } else {
+ propertyName = "export_system_include_dirs"
+ }
+ properties.AddProperty(propertyName, includeDirs)
+}
+
const (
nativeIncludeDir = "include"
nativeGeneratedIncludeDir = "include_gen"
diff --git a/cc/linkable.go b/cc/linkable.go
index 106092b..e4f034c 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -38,6 +38,9 @@
Shared() bool
Toc() android.OptionalPath
+ InRamdisk() bool
+ OnlyInRamdisk() bool
+
InRecovery() bool
OnlyInRecovery() bool
@@ -51,8 +54,6 @@
ToolchainLibrary() bool
NdkPrebuiltStl() bool
StubDecorator() bool
-
- AllStaticDeps() []string
}
type DependencyTag struct {
@@ -64,12 +65,17 @@
ReexportFlags bool
ExplicitlyVersioned bool
+
+ FromStatic bool
}
var (
SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true}
StaticDepTag = DependencyTag{Name: "static", Library: true}
+ // Same as SharedDepTag, but from a static lib
+ SharedFromStaticDepTag = DependencyTag{Name: "shared from static", Library: true, Shared: true, FromStatic: true}
+
CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
CrtEndDepTag = DependencyTag{Name: "crtend"}
)
diff --git a/cc/linker.go b/cc/linker.go
index 07d41ec..af4cbf3 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -145,6 +145,19 @@
// of the C/C++ module.
Exclude_header_libs []string
}
+ Ramdisk struct {
+ // list of static libs that only should be used to build the recovery
+ // variant of the C/C++ module.
+ Static_libs []string
+
+ // list of shared libs that should not be used to build
+ // the ramdisk variant of the C/C++ module.
+ Exclude_shared_libs []string
+
+ // list of static libs that should not be used to build
+ // the ramdisk variant of the C/C++ module.
+ Exclude_static_libs []string
+ }
}
// make android::build:GetBuildNumber() available containing the build ID.
@@ -155,6 +168,9 @@
// local file name to pass to the linker as --version_script
Version_script *string `android:"path,arch_variant"`
+
+ // list of static libs that should not be used to build this module
+ Exclude_static_libs []string
}
func NewBaseLinker(sanitize *sanitize) *baseLinker {
@@ -200,6 +216,8 @@
deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs)
+
if Bool(linker.Properties.Use_version_lib) {
deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion")
}
@@ -228,12 +246,20 @@
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
}
+ if ctx.inRamdisk() {
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
+ deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Recovery.Exclude_shared_libs)
+ deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Recovery.Static_libs...)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+ }
+
if ctx.toolchain().Bionic() {
- // libclang_rt.builtins, libgcc and libatomic have to be last on the command line
+ // libclang_rt.builtins and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
- deps.LateStaticLibs = append(deps.LateStaticLibs, "libgcc_stripped")
}
systemSharedLibs := linker.Properties.System_shared_libs
@@ -346,6 +372,8 @@
flags.Global.LdFlags = append(flags.Global.LdFlags,
"-Wl,--pack-dyn-relocs=android+relr",
"-Wl,--use-android-relr-tags")
+ } else if CheckSdkVersionAtLeast(ctx, 23) {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android")
}
}
} else {
diff --git a/cc/pgo.go b/cc/pgo.go
index 0072355..d5c4b87 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -41,9 +41,9 @@
var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
-const profileSamplingFlag = "-gline-tables-only"
+const profileSamplingFlag = "-gmlt -fdebug-info-for-profiling"
const profileUseInstrumentFormat = "-fprofile-use=%s"
-const profileUseSamplingFormat = "-fprofile-sample-use=%s"
+const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
func getPgoProfileProjects(config android.DeviceConfig) []string {
return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
@@ -177,6 +177,10 @@
// if profileFile gets updated
flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
+
+ if props.isSampling() {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
+ }
}
return flags
}
@@ -252,6 +256,12 @@
}
}
+ // PGO profile use is not feasible for a Clang coverage build because
+ // -fprofile-use and -fprofile-instr-generate are incompatible.
+ if ctx.DeviceConfig().ClangCoverageEnabled() {
+ return
+ }
+
if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c4aeb96..5663aa7 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -350,9 +350,15 @@
s.Diag.Cfi = nil
}
+ // Also disable CFI if building against snapshot.
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" {
+ s.Cfi = nil
+ }
+
// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
- // Keep libc instrumented so that recovery can run hwasan-instrumented code if necessary.
- if ctx.inRecovery() && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
+ // Keep libc instrumented so that ramdisk / recovery can run hwasan-instrumented code if necessary.
+ if (ctx.inRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
s.Hwaddress = nil
}
@@ -739,13 +745,16 @@
return false
}
- if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
+ d, ok := child.(*Module)
+ if !ok || !d.static() {
+ return false
+ }
+ if d.sanitize != nil {
if enableMinimalRuntime(d.sanitize) {
// If a static dependency is built with the minimal runtime,
// make sure we include the ubsan minimal runtime.
c.sanitize.Properties.MinimalRuntimeDep = true
- } else if Bool(d.sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
- len(d.sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0 {
+ } else if enableUbsanRuntime(d.sanitize) {
// If a static dependency runs with full ubsan diagnostics,
// make sure we include the ubsan runtime.
c.sanitize.Properties.UbsanRuntimeDep = true
@@ -758,9 +767,18 @@
}
return true
- } else {
- return false
}
+
+ if p, ok := d.linker.(*vendorSnapshotLibraryDecorator); ok {
+ if Bool(p.properties.Sanitize_minimal_dep) {
+ c.sanitize.Properties.MinimalRuntimeDep = true
+ }
+ if Bool(p.properties.Sanitize_ubsan_dep) {
+ c.sanitize.Properties.UbsanRuntimeDep = true
+ }
+ }
+
+ return false
})
}
}
@@ -901,12 +919,31 @@
// Note that by adding dependency with {static|shared}DepTag, the lib is
// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
if c.staticBinary() {
+ deps := append(extraStaticDeps, runtimeLibrary)
+ // If we're using snapshots and in vendor, redirect to snapshot whenever possible
+ if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
+ snapshots := vendorSnapshotStaticLibs(mctx.Config())
+ for idx, dep := range deps {
+ if lib, ok := snapshots.get(dep, mctx.Arch().ArchType); ok {
+ deps[idx] = lib
+ }
+ }
+ }
+
// static executable gets static runtime libs
mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
{Mutator: "link", Variation: "static"},
c.ImageVariation(),
- }...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...)
+ }...), StaticDepTag, deps...)
} else if !c.static() && !c.header() {
+ // If we're using snapshots and in vendor, redirect to snapshot whenever possible
+ if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
+ snapshots := vendorSnapshotSharedLibs(mctx.Config())
+ if lib, ok := snapshots.get(runtimeLibrary, mctx.Arch().ArchType); ok {
+ runtimeLibrary = lib
+ }
+ }
+
// dynamic executable and shared libs get shared runtime libs
mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
@@ -1052,6 +1089,11 @@
return false
}
+func enableUbsanRuntime(sanitize *sanitize) bool {
+ return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
+ len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0
+}
+
func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
cfiStaticLibs := cfiStaticLibs(ctx.Config())
sort.Strings(*cfiStaticLibs)
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
new file mode 100644
index 0000000..8f48f86
--- /dev/null
+++ b/cc/snapshot_utils.go
@@ -0,0 +1,131 @@
+// Copyright 2020 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.
+package cc
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
+)
+
+type snapshotLibraryInterface interface {
+ exportedFlagsProducer
+ libraryInterface
+}
+
+var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
+var _ snapshotLibraryInterface = (*libraryDecorator)(nil)
+
+type snapshotMap struct {
+ snapshots map[string]string
+}
+
+func newSnapshotMap() *snapshotMap {
+ return &snapshotMap{
+ snapshots: make(map[string]string),
+ }
+}
+
+func snapshotMapKey(name string, arch android.ArchType) string {
+ return name + ":" + arch.String()
+}
+
+// Adds a snapshot name for given module name and architecture.
+// e.g. add("libbase", X86, "libbase.vndk.29.x86")
+func (s *snapshotMap) add(name string, arch android.ArchType, snapshot string) {
+ s.snapshots[snapshotMapKey(name, arch)] = snapshot
+}
+
+// Returns snapshot name for given module name and architecture, if found.
+// e.g. get("libcutils", X86) => "libcutils.vndk.29.x86", true
+func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, found bool) {
+ snapshot, found = s.snapshots[snapshotMapKey(name, arch)]
+ return snapshot, found
+}
+
+func exportedHeaders(ctx android.SingletonContext, l exportedFlagsProducer) android.Paths {
+ var ret android.Paths
+
+ // Headers in the source tree should be globbed. On the contrast, generated headers
+ // can't be globbed, and they should be manually collected.
+ // So, we first filter out intermediate directories (which contains generated headers)
+ // from exported directories, and then glob headers under remaining directories.
+ for _, path := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
+ dir := path.String()
+ // Skip if dir is for generated headers
+ if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
+ continue
+ }
+ exts := headerExts
+ // Glob all files under this special directory, because of C++ headers.
+ if strings.HasPrefix(dir, "external/libcxx/include") {
+ exts = []string{""}
+ }
+ for _, ext := range exts {
+ glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
+ if err != nil {
+ ctx.Errorf("%#v\n", err)
+ return nil
+ }
+ for _, header := range glob {
+ if strings.HasSuffix(header, "/") {
+ continue
+ }
+ ret = append(ret, android.PathForSource(ctx, header))
+ }
+ }
+ }
+
+ // Collect generated headers
+ for _, header := range append(l.exportedGeneratedHeaders(), l.exportedDeps()...) {
+ // TODO(b/148123511): remove exportedDeps after cleaning up genrule
+ if strings.HasSuffix(header.Base(), "-phony") {
+ continue
+ }
+ ret = append(ret, header)
+ }
+
+ return ret
+}
+
+func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: path,
+ Output: outPath,
+ Description: "Cp " + out,
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+ return outPath
+}
+
+func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: outPath,
+ Description: "WriteFile " + out,
+ Args: map[string]string{
+ "content": content,
+ },
+ })
+ return outPath
+}
diff --git a/cc/stl.go b/cc/stl.go
index 5ccd44a..eda8a4f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -151,6 +151,14 @@
return version < 21
}
+func staticUnwinder(ctx android.BaseModuleContext) string {
+ if ctx.Arch().ArchType == android.Arm {
+ return "libunwind_llvm"
+ } else {
+ return "libgcc_stripped"
+ }
+}
+
func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
switch stl.Properties.SelectedStl {
case "libstdc++":
@@ -171,15 +179,17 @@
deps.StaticLibs = append(deps.StaticLibs, "libc++demangle")
}
if ctx.toolchain().Bionic() {
- if ctx.Arch().ArchType == android.Arm {
- deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm")
- }
if ctx.staticBinary() {
- deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
+ deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx))
+ } else {
+ deps.StaticUnwinderIfLegacy = true
}
}
case "":
// None or error.
+ if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" {
+ deps.StaticUnwinderIfLegacy = true
+ }
case "ndk_system":
// TODO: Make a system STL prebuilt for the NDK.
// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
@@ -196,6 +206,8 @@
}
if ctx.Arch().ArchType == android.Arm {
deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
+ } else {
+ deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped")
}
default:
panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
diff --git a/cc/testing.go b/cc/testing.go
index bc31077..7b0305f 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -23,11 +23,14 @@
android.RegisterPrebuiltMutators(ctx)
RegisterCCBuildComponents(ctx)
+ RegisterBinaryBuildComponents(ctx)
RegisterLibraryBuildComponents(ctx)
ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
ctx.RegisterModuleType("cc_object", ObjectFactory)
+ ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
+ ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
}
func GatherRequiredDepsForTest(os android.OsType) string {
@@ -36,6 +39,7 @@
name: "libatomic",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
src: "",
}
@@ -50,6 +54,7 @@
name: "libclang_rt.builtins-arm-android",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
src: "",
}
@@ -57,6 +62,7 @@
name: "libclang_rt.builtins-aarch64-android",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
src: "",
}
@@ -64,6 +70,7 @@
name: "libclang_rt.builtins-i686-android",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
src: "",
}
@@ -71,6 +78,7 @@
name: "libclang_rt.builtins-x86_64-android",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
src: "",
}
@@ -114,6 +122,7 @@
name: "libclang_rt.ubsan_standalone-aarch64-android",
vendor_available: true,
recovery_available: true,
+ system_shared_libs: [],
srcs: [""],
}
@@ -135,8 +144,12 @@
name: "libc",
no_libcrt: true,
nocrt: true,
+ stl: "none",
system_shared_libs: [],
recovery_available: true,
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
}
llndk_library {
name: "libc",
@@ -146,8 +159,16 @@
name: "libm",
no_libcrt: true,
nocrt: true,
+ stl: "none",
system_shared_libs: [],
recovery_available: true,
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "myapex"
+ ],
}
llndk_library {
name: "libm",
@@ -157,8 +178,16 @@
name: "libdl",
no_libcrt: true,
nocrt: true,
+ stl: "none",
system_shared_libs: [],
recovery_available: true,
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "myapex"
+ ],
}
llndk_library {
name: "libdl",
@@ -197,6 +226,10 @@
enabled: true,
support_system_process: true,
},
+ apex_available: [
+ "//apex_available:platform",
+ "myapex"
+ ],
}
cc_library {
name: "libc++demangle",
@@ -222,6 +255,7 @@
name: "crtbegin_so",
recovery_available: true,
vendor_available: true,
+ native_bridge_supported: true,
stl: "none",
}
@@ -229,18 +263,23 @@
name: "crtbegin_dynamic",
recovery_available: true,
vendor_available: true,
+ native_bridge_supported: true,
+ stl: "none",
}
cc_object {
name: "crtbegin_static",
recovery_available: true,
vendor_available: true,
+ native_bridge_supported: true,
+ stl: "none",
}
cc_object {
name: "crtend_so",
recovery_available: true,
vendor_available: true,
+ native_bridge_supported: true,
stl: "none",
}
@@ -248,12 +287,57 @@
name: "crtend_android",
recovery_available: true,
vendor_available: true,
+ native_bridge_supported: true,
+ stl: "none",
}
cc_library {
name: "libprotobuf-cpp-lite",
}
- `
+
+ cc_library {
+ name: "ndk_libunwind",
+ sdk_version: "current",
+ stl: "none",
+ system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "libc.ndk.current",
+ sdk_version: "current",
+ stl: "none",
+ system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "libm.ndk.current",
+ sdk_version: "current",
+ stl: "none",
+ system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "libdl.ndk.current",
+ sdk_version: "current",
+ stl: "none",
+ system_shared_libs: [],
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtbegin_so.27",
+ sdk_version: "27",
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtend_so.27",
+ sdk_version: "27",
+ }
+
+ ndk_prebuilt_shared_stl {
+ name: "ndk_libc++_shared",
+ }
+ `
+
if os == android.Fuchsia {
ret += `
cc_library {
@@ -269,6 +353,18 @@
return ret
}
+func GatherRequiredFilesForTest(fs map[string][]byte) {
+ fs["prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtbegin_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtend_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtbegin_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtend_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtbegin_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtend_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtbegin_so.o"] = nil
+ fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtend_so.o"] = nil
+}
+
func TestConfig(buildDir string, os android.OsType, env map[string]string,
bp string, fs map[string][]byte) android.Config {
@@ -289,6 +385,8 @@
"liba.so": nil,
}
+ GatherRequiredFilesForTest(mockFS)
+
for k, v := range fs {
mockFS[k] = v
}
@@ -305,8 +403,6 @@
func CreateTestContext() *android.TestContext {
ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("cc_binary", BinaryFactory)
- ctx.RegisterModuleType("cc_binary_host", binaryHostFactory)
ctx.RegisterModuleType("cc_fuzz", FuzzFactory)
ctx.RegisterModuleType("cc_test", TestFactory)
ctx.RegisterModuleType("llndk_headers", llndkHeadersFactory)
@@ -318,6 +414,7 @@
RegisterRequiredBuildComponentsForTest(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+ ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
return ctx
}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
new file mode 100644
index 0000000..aed7918
--- /dev/null
+++ b/cc/vendor_snapshot.go
@@ -0,0 +1,842 @@
+// Copyright 2020 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.
+package cc
+
+import (
+ "encoding/json"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+const (
+ vendorSnapshotHeaderSuffix = ".vendor_header."
+ vendorSnapshotSharedSuffix = ".vendor_shared."
+ vendorSnapshotStaticSuffix = ".vendor_static."
+ vendorSnapshotBinarySuffix = ".vendor_binary."
+)
+
+var (
+ vendorSnapshotsLock sync.Mutex
+ vendorSuffixModulesKey = android.NewOnceKey("vendorSuffixModules")
+ vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
+ vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
+ vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
+ vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries")
+)
+
+// vendor snapshot maps hold names of vendor snapshot modules per arch
+func vendorSuffixModules(config android.Config) map[string]bool {
+ return config.Once(vendorSuffixModulesKey, func() interface{} {
+ return make(map[string]bool)
+ }).(map[string]bool)
+}
+
+func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotBinaries(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotBinariesKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+type vendorSnapshotLibraryProperties struct {
+ // snapshot version.
+ Version string
+
+ // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
+ Target_arch string
+
+ // Prebuilt file for each arch.
+ Src *string `android:"arch_variant"`
+
+ // list of flags that will be used for any module that links against this module.
+ Export_flags []string `android:"arch_variant"`
+
+ // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
+ // etc).
+ Check_elf_files *bool
+
+ // Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
+ Sanitize_ubsan_dep *bool `android:"arch_variant"`
+
+ // Whether this prebuilt needs to depend on sanitize minimal runtime or not.
+ Sanitize_minimal_dep *bool `android:"arch_variant"`
+}
+
+type vendorSnapshotLibraryDecorator struct {
+ *libraryDecorator
+ properties vendorSnapshotLibraryProperties
+ androidMkVendorSuffix bool
+}
+
+func (p *vendorSnapshotLibraryDecorator) Name(name string) string {
+ return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotLibraryDecorator) NameSuffix() string {
+ versionSuffix := p.version()
+ if p.arch() != "" {
+ versionSuffix += "." + p.arch()
+ }
+
+ var linkageSuffix string
+ if p.buildShared() {
+ linkageSuffix = vendorSnapshotSharedSuffix
+ } else if p.buildStatic() {
+ linkageSuffix = vendorSnapshotStaticSuffix
+ } else {
+ linkageSuffix = vendorSnapshotHeaderSuffix
+ }
+
+ return linkageSuffix + versionSuffix
+}
+
+func (p *vendorSnapshotLibraryDecorator) version() string {
+ return p.properties.Version
+}
+
+func (p *vendorSnapshotLibraryDecorator) arch() string {
+ return p.properties.Target_arch
+}
+
+func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
+ return p.libraryDecorator.linkerFlags(ctx, flags)
+}
+
+func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+ arches := config.Arches()
+ if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+ return false
+ }
+ if !p.header() && p.properties.Src == nil {
+ return false
+ }
+ return true
+}
+
+func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
+ flags Flags, deps PathDeps, objs Objects) android.Path {
+ m := ctx.Module().(*Module)
+ p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+ if p.header() {
+ return p.libraryDecorator.link(ctx, flags, deps, objs)
+ }
+
+ if !p.matchesWithDevice(ctx.DeviceConfig()) {
+ return nil
+ }
+
+ p.libraryDecorator.exportIncludes(ctx)
+ p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+
+ in := android.PathForModuleSrc(ctx, *p.properties.Src)
+ p.unstrippedOutputFile = in
+
+ if p.shared() {
+ libName := in.Base()
+ builderFlags := flagsToBuilderFlags(flags)
+
+ // Optimize out relinking against shared libraries whose interface hasn't changed by
+ // depending on a table of contents file instead of the library itself.
+ tocFile := android.PathForModuleOut(ctx, libName+".toc")
+ p.tocFile = android.OptionalPathForPath(tocFile)
+ TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+ }
+
+ return in
+}
+
+func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
+ return false
+}
+
+func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
+ if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
+ p.baseInstaller.install(ctx, file)
+ }
+}
+
+type vendorSnapshotInterface interface {
+ version() string
+}
+
+func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) {
+ if p.version() != ctx.DeviceConfig().VndkVersion() {
+ ctx.Module().Disable()
+ return
+ }
+}
+
+func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
+ module, library := NewLibrary(android.DeviceSupported)
+
+ module.stl = nil
+ module.sanitize = nil
+ library.StripProperties.Strip.None = BoolPtr(true)
+
+ prebuilt := &vendorSnapshotLibraryDecorator{
+ libraryDecorator: library,
+ }
+
+ prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
+ prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if prebuilt.baseLinker.Properties.System_shared_libs == nil {
+ prebuilt.baseLinker.Properties.System_shared_libs = []string{}
+ }
+
+ module.compiler = nil
+ module.linker = prebuilt
+ module.installer = prebuilt
+
+ module.AddProperties(
+ &prebuilt.properties,
+ )
+
+ return module, prebuilt
+}
+
+func VendorSnapshotSharedFactory() android.Module {
+ module, prebuilt := vendorSnapshotLibrary()
+ prebuilt.libraryDecorator.BuildOnlyShared()
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, prebuilt)
+ })
+ return module.Init()
+}
+
+func VendorSnapshotStaticFactory() android.Module {
+ module, prebuilt := vendorSnapshotLibrary()
+ prebuilt.libraryDecorator.BuildOnlyStatic()
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, prebuilt)
+ })
+ return module.Init()
+}
+
+func VendorSnapshotHeaderFactory() android.Module {
+ module, prebuilt := vendorSnapshotLibrary()
+ prebuilt.libraryDecorator.HeaderOnly()
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, prebuilt)
+ })
+ return module.Init()
+}
+
+type vendorSnapshotBinaryProperties struct {
+ // snapshot version.
+ Version string
+
+ // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
+ Target_arch string
+
+ // Prebuilt file for each arch.
+ Src *string `android:"arch_variant"`
+}
+
+type vendorSnapshotBinaryDecorator struct {
+ *binaryDecorator
+ properties vendorSnapshotBinaryProperties
+ androidMkVendorSuffix bool
+}
+
+func (p *vendorSnapshotBinaryDecorator) Name(name string) string {
+ return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotBinaryDecorator) NameSuffix() string {
+ versionSuffix := p.version()
+ if p.arch() != "" {
+ versionSuffix += "." + p.arch()
+ }
+ return vendorSnapshotBinarySuffix + versionSuffix
+}
+
+func (p *vendorSnapshotBinaryDecorator) version() string {
+ return p.properties.Version
+}
+
+func (p *vendorSnapshotBinaryDecorator) arch() string {
+ return p.properties.Target_arch
+}
+
+func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+ if config.DeviceArch() != p.arch() {
+ return false
+ }
+ if p.properties.Src == nil {
+ return false
+ }
+ return true
+}
+
+func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext,
+ flags Flags, deps PathDeps, objs Objects) android.Path {
+ if !p.matchesWithDevice(ctx.DeviceConfig()) {
+ return nil
+ }
+
+ in := android.PathForModuleSrc(ctx, *p.properties.Src)
+ builderFlags := flagsToBuilderFlags(flags)
+ p.unstrippedOutputFile = in
+ binName := in.Base()
+ if p.needsStrip(ctx) {
+ stripped := android.PathForModuleOut(ctx, "stripped", binName)
+ p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ in = stripped
+ }
+
+ m := ctx.Module().(*Module)
+ p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+ // use cpExecutable to make it executable
+ outputFile := android.PathForModuleOut(ctx, binName)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpExecutable,
+ Description: "prebuilt",
+ Output: outputFile,
+ Input: in,
+ })
+
+ return outputFile
+}
+
+func VendorSnapshotBinaryFactory() android.Module {
+ module, binary := NewBinary(android.DeviceSupported)
+ binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
+ binary.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if binary.baseLinker.Properties.System_shared_libs == nil {
+ binary.baseLinker.Properties.System_shared_libs = []string{}
+ }
+
+ prebuilt := &vendorSnapshotBinaryDecorator{
+ binaryDecorator: binary,
+ }
+
+ module.compiler = nil
+ module.sanitize = nil
+ module.stl = nil
+ module.linker = prebuilt
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, prebuilt)
+ })
+
+ module.AddProperties(&prebuilt.properties)
+ return module.Init()
+}
+
+func init() {
+ android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+ android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
+ android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+ android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
+ android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+}
+
+func VendorSnapshotSingleton() android.Singleton {
+ return &vendorSnapshotSingleton{}
+}
+
+type vendorSnapshotSingleton struct {
+ vendorSnapshotZipFile android.OptionalPath
+}
+
+var (
+ // Modules under following directories are ignored. They are OEM's and vendor's
+ // proprietary modules(device/, vendor/, and hardware/).
+ // TODO(b/65377115): Clean up these with more maintainable way
+ vendorProprietaryDirs = []string{
+ "device",
+ "vendor",
+ "hardware",
+ }
+
+ // Modules under following directories are included as they are in AOSP,
+ // although hardware/ is normally for vendor's own.
+ // TODO(b/65377115): Clean up these with more maintainable way
+ aospDirsUnderProprietary = []string{
+ "hardware/interfaces",
+ "hardware/libhardware",
+ "hardware/libhardware_legacy",
+ "hardware/ril",
+ }
+)
+
+// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
+// device/, vendor/, etc.
+func isVendorProprietaryPath(dir string) bool {
+ for _, p := range vendorProprietaryDirs {
+ if strings.HasPrefix(dir, p) {
+ // filter out AOSP defined directories, e.g. hardware/interfaces/
+ aosp := false
+ for _, p := range aospDirsUnderProprietary {
+ if strings.HasPrefix(dir, p) {
+ aosp = true
+ break
+ }
+ }
+ if !aosp {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Determine if a module is going to be included in vendor snapshot or not.
+//
+// Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in
+// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
+// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
+// image and newer system image altogether.
+func isVendorSnapshotModule(ctx android.SingletonContext, m *Module) bool {
+ if !m.Enabled() {
+ return false
+ }
+ // skip proprietary modules, but include all VNDK (static)
+ if isVendorProprietaryPath(ctx.ModuleDir(m)) && !m.IsVndk() {
+ return false
+ }
+ if m.Target().Os.Class != android.Device {
+ return false
+ }
+ if m.Target().NativeBridge == android.NativeBridgeEnabled {
+ return false
+ }
+ // the module must be installed in /vendor
+ if !m.installable() || m.isSnapshotPrebuilt() || !m.inVendor() {
+ return false
+ }
+ // exclude test modules
+ if _, ok := m.linker.(interface{ gtest() bool }); ok {
+ return false
+ }
+ // TODO(b/65377115): add full support for sanitizer
+ if m.sanitize != nil && !m.sanitize.isUnsanitizedVariant() {
+ return false
+ }
+
+ // Libraries
+ if l, ok := m.linker.(snapshotLibraryInterface); ok {
+ if l.static() {
+ return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+ }
+ if l.shared() {
+ return !m.IsVndk()
+ }
+ return true
+ }
+
+ // Binaries
+ _, ok := m.linker.(*binaryDecorator)
+ if !ok {
+ if _, ok := m.linker.(*prebuiltBinaryLinker); !ok {
+ return false
+ }
+ }
+ return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+}
+
+func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
+ if ctx.DeviceConfig().VndkVersion() != "current" {
+ return
+ }
+
+ var snapshotOutputs android.Paths
+
+ /*
+ Vendor snapshot zipped artifacts directory structure:
+ {SNAPSHOT_ARCH}/
+ arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
+ shared/
+ (.so shared libraries)
+ static/
+ (.a static libraries)
+ header/
+ (header only libraries)
+ binary/
+ (executable binaries)
+ arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
+ shared/
+ (.so shared libraries)
+ static/
+ (.a static libraries)
+ header/
+ (header only libraries)
+ binary/
+ (executable binaries)
+ NOTICE_FILES/
+ (notice files, e.g. libbase.txt)
+ configs/
+ (config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
+ include/
+ (header files of same directory structure with source tree)
+ */
+
+ snapshotDir := "vendor-snapshot"
+ snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
+
+ includeDir := filepath.Join(snapshotArchDir, "include")
+ configsDir := filepath.Join(snapshotArchDir, "configs")
+ noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+
+ installedNotices := make(map[string]bool)
+ installedConfigs := make(map[string]bool)
+
+ var headers android.Paths
+
+ type vendorSnapshotLibraryInterface interface {
+ exportedFlagsProducer
+ libraryInterface
+ }
+
+ var _ vendorSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
+ var _ vendorSnapshotLibraryInterface = (*libraryDecorator)(nil)
+
+ installSnapshot := func(m *Module) android.Paths {
+ targetArch := "arch-" + m.Target().Arch.ArchType.String()
+ if m.Target().Arch.ArchVariant != "" {
+ targetArch += "-" + m.Target().Arch.ArchVariant
+ }
+
+ var ret android.Paths
+
+ prop := struct {
+ ModuleName string `json:",omitempty"`
+ RelativeInstallPath string `json:",omitempty"`
+
+ // library flags
+ ExportedDirs []string `json:",omitempty"`
+ ExportedSystemDirs []string `json:",omitempty"`
+ ExportedFlags []string `json:",omitempty"`
+ SanitizeMinimalDep bool `json:",omitempty"`
+ SanitizeUbsanDep bool `json:",omitempty"`
+
+ // binary flags
+ Symlinks []string `json:",omitempty"`
+
+ // dependencies
+ SharedLibs []string `json:",omitempty"`
+ RuntimeLibs []string `json:",omitempty"`
+ Required []string `json:",omitempty"`
+
+ // extra config files
+ InitRc []string `json:",omitempty"`
+ VintfFragments []string `json:",omitempty"`
+ }{}
+
+ // Common properties among snapshots.
+ prop.ModuleName = ctx.ModuleName(m)
+ prop.RelativeInstallPath = m.RelativeInstallPath()
+ prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
+ prop.Required = m.RequiredModuleNames()
+ for _, path := range m.InitRc() {
+ prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
+ }
+ for _, path := range m.VintfFragments() {
+ prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
+ }
+
+ // install config files. ignores any duplicates.
+ for _, path := range append(m.InitRc(), m.VintfFragments()...) {
+ out := filepath.Join(configsDir, path.Base())
+ if !installedConfigs[out] {
+ installedConfigs[out] = true
+ ret = append(ret, copyFile(ctx, path, out))
+ }
+ }
+
+ var propOut string
+
+ if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
+ // library flags
+ prop.ExportedFlags = l.exportedFlags()
+ for _, dir := range l.exportedDirs() {
+ prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
+ }
+ for _, dir := range l.exportedSystemDirs() {
+ prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
+ }
+ // shared libs dependencies aren't meaningful on static or header libs
+ if l.shared() {
+ prop.SharedLibs = m.Properties.SnapshotSharedLibs
+ }
+ if l.static() && m.sanitize != nil {
+ prop.SanitizeMinimalDep = m.sanitize.Properties.MinimalRuntimeDep || enableMinimalRuntime(m.sanitize)
+ prop.SanitizeUbsanDep = m.sanitize.Properties.UbsanRuntimeDep || enableUbsanRuntime(m.sanitize)
+ }
+
+ var libType string
+ if l.static() {
+ libType = "static"
+ } else if l.shared() {
+ libType = "shared"
+ } else {
+ libType = "header"
+ }
+
+ var stem string
+
+ // install .a or .so
+ if libType != "header" {
+ libPath := m.outputFile.Path()
+ stem = libPath.Base()
+ snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
+ ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+ } else {
+ stem = ctx.ModuleName(m)
+ }
+
+ propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
+ } else {
+ // binary flags
+ prop.Symlinks = m.Symlinks()
+ prop.SharedLibs = m.Properties.SnapshotSharedLibs
+
+ // install bin
+ binPath := m.outputFile.Path()
+ snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
+ ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+ propOut = snapshotBinOut + ".json"
+ }
+
+ j, err := json.Marshal(prop)
+ if err != nil {
+ ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
+ return nil
+ }
+ ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+
+ return ret
+ }
+
+ ctx.VisitAllModules(func(module android.Module) {
+ m, ok := module.(*Module)
+ if !ok || !isVendorSnapshotModule(ctx, m) {
+ return
+ }
+
+ snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+ if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
+ headers = append(headers, exportedHeaders(ctx, l)...)
+ }
+
+ if m.NoticeFile().Valid() {
+ noticeName := ctx.ModuleName(m) + ".txt"
+ noticeOut := filepath.Join(noticeDir, noticeName)
+ // skip already copied notice file
+ if !installedNotices[noticeOut] {
+ installedNotices[noticeOut] = true
+ snapshotOutputs = append(snapshotOutputs, copyFile(
+ ctx, m.NoticeFile().Path(), noticeOut))
+ }
+ }
+ })
+
+ // install all headers after removing duplicates
+ for _, header := range android.FirstUniquePaths(headers) {
+ snapshotOutputs = append(snapshotOutputs, copyFile(
+ ctx, header, filepath.Join(includeDir, header.String())))
+ }
+
+ // All artifacts are ready. Sort them to normalize ninja and then zip.
+ sort.Slice(snapshotOutputs, func(i, j int) bool {
+ return snapshotOutputs[i].String() < snapshotOutputs[j].String()
+ })
+
+ zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip")
+ zipRule := android.NewRuleBuilder()
+
+ // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
+ snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list")
+ zipRule.Command().
+ Text("tr").
+ FlagWithArg("-d ", "\\'").
+ FlagWithRspFileInputList("< ", snapshotOutputs).
+ FlagWithOutput("> ", snapshotOutputList)
+
+ zipRule.Temporary(snapshotOutputList)
+
+ zipRule.Command().
+ BuiltTool(ctx, "soong_zip").
+ FlagWithOutput("-o ", zipPath).
+ FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
+ FlagWithInput("-l ", snapshotOutputList)
+
+ zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String())
+ zipRule.DeleteTemporaryFiles()
+ c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath)
+}
+
+func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String())
+}
+
+type snapshotInterface interface {
+ matchesWithDevice(config android.DeviceConfig) bool
+}
+
+var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
+var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
+var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
+
+// gathers all snapshot modules for vendor, and disable unnecessary snapshots
+// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
+func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ // don't need snapshot if current
+ if vndkVersion == "current" || vndkVersion == "" {
+ return
+ }
+
+ module, ok := ctx.Module().(*Module)
+ if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
+ return
+ }
+
+ snapshot, ok := module.linker.(snapshotInterface)
+ if !ok {
+ return
+ }
+
+ if !snapshot.matchesWithDevice(ctx.DeviceConfig()) {
+ // Disable unnecessary snapshot module, but do not disable
+ // vndk_prebuilt_shared because they might be packed into vndk APEX
+ if !module.IsVndk() {
+ module.Disable()
+ }
+ return
+ }
+
+ var snapshotMap *snapshotMap
+
+ if lib, ok := module.linker.(libraryInterface); ok {
+ if lib.static() {
+ snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+ } else if lib.shared() {
+ snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+ } else {
+ // header
+ snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+ }
+ } else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
+ snapshotMap = vendorSnapshotBinaries(ctx.Config())
+ } else {
+ return
+ }
+
+ vendorSnapshotsLock.Lock()
+ defer vendorSnapshotsLock.Unlock()
+ snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
+}
+
+// Disables source modules which have snapshots
+func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+ if !ctx.Device() {
+ return
+ }
+
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ // don't need snapshot if current
+ if vndkVersion == "current" || vndkVersion == "" {
+ return
+ }
+
+ module, ok := ctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ // vendor suffix should be added to snapshots if the source module isn't vendor: true.
+ if !module.SocSpecific() {
+ // But we can't just check SocSpecific() since we already passed the image mutator.
+ // Check ramdisk and recovery to see if we are real "vendor: true" module.
+ ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+ recovery_available := module.InRecovery() && !module.OnlyInRecovery()
+
+ if !ramdisk_available && !recovery_available {
+ vendorSnapshotsLock.Lock()
+ defer vendorSnapshotsLock.Unlock()
+
+ vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+ }
+ }
+
+ if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
+ // only non-snapshot modules with BOARD_VNDK_VERSION
+ return
+ }
+
+ var snapshotMap *snapshotMap
+
+ if lib, ok := module.linker.(libraryInterface); ok {
+ if lib.static() {
+ snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+ } else if lib.shared() {
+ snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+ } else {
+ // header
+ snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+ }
+ } else if _, ok := module.linker.(*binaryDecorator); ok {
+ snapshotMap = vendorSnapshotBinaries(ctx.Config())
+ } else if _, ok := module.linker.(*prebuiltBinaryLinker); ok {
+ snapshotMap = vendorSnapshotBinaries(ctx.Config())
+ } else {
+ return
+ }
+
+ if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
+ // Corresponding snapshot doesn't exist
+ return
+ }
+
+ // Disables source modules if corresponding snapshot exists.
+ if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
+ // But do not disable because the shared variant depends on the static variant.
+ module.SkipInstall()
+ module.Properties.HideFromMake = true
+ } else {
+ module.Disable()
+ }
+}
diff --git a/cc/vndk.go b/cc/vndk.go
index 872a473..4578a7d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -229,8 +229,6 @@
vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibraries")
vndkMustUseVendorVariantListKey = android.NewOnceKey("vndkMustUseVendorVariantListKey")
vndkLibrariesLock sync.Mutex
-
- headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
)
func vndkCoreLibraries(config android.Config) map[string]string {
@@ -351,7 +349,7 @@
if lib, ok := m.linker.(libraryInterface); ok {
useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
- return lib.shared() && m.UseVndk() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
+ return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
}
return false
}
@@ -548,29 +546,10 @@
snapshotDir := "vndk-snapshot"
snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
- targetArchDirMap := make(map[android.ArchType]string)
- for _, target := range ctx.Config().Targets[android.Android] {
- dir := snapshotArchDir
- if ctx.DeviceConfig().BinderBitness() == "32" {
- dir = filepath.Join(dir, "binder32")
- }
- arch := "arch-" + target.Arch.ArchType.String()
- if target.Arch.ArchVariant != "" {
- arch += "-" + target.Arch.ArchVariant
- }
- dir = filepath.Join(dir, arch)
- targetArchDirMap[target.Arch.ArchType] = dir
- }
configsDir := filepath.Join(snapshotArchDir, "configs")
noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
includeDir := filepath.Join(snapshotArchDir, "include")
- // set of include paths exported by VNDK libraries
- exportedIncludes := make(map[string]bool)
-
- // generated header files among exported headers.
- var generatedHeaders android.Paths
-
// set of notice files copied.
noticeBuilt := make(map[string]bool)
@@ -581,67 +560,20 @@
// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
moduleNames := make(map[string]string)
- installSnapshotFileFromPath := func(path android.Path, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: path,
- Output: outPath,
- Description: "vndk snapshot " + out,
- Args: map[string]string{
- "cpFlags": "-f -L",
- },
- })
- return outPath
- }
+ var headers android.Paths
- installSnapshotFileFromContent := func(content, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Output: outPath,
- Description: "vndk snapshot " + out,
- Args: map[string]string{
- "content": content,
- },
- })
- return outPath
- }
-
- type vndkSnapshotLibraryInterface interface {
- exportedFlagsProducer
- libraryInterface
- }
-
- var _ vndkSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
- var _ vndkSnapshotLibraryInterface = (*libraryDecorator)(nil)
-
- installVndkSnapshotLib := func(m *Module, l vndkSnapshotLibraryInterface, vndkType string) (android.Paths, bool) {
- targetArchDir, ok := targetArchDirMap[m.Target().Arch.ArchType]
- if !ok {
- return nil, false
- }
-
+ installVndkSnapshotLib := func(m *Module, l snapshotLibraryInterface, vndkType string) (android.Paths, bool) {
var ret android.Paths
- libPath := m.outputFile.Path()
- stem := libPath.Base()
- snapshotLibOut := filepath.Join(targetArchDir, "shared", vndkType, stem)
- ret = append(ret, installSnapshotFileFromPath(libPath, snapshotLibOut))
-
- moduleNames[stem] = ctx.ModuleName(m)
- modulePaths[stem] = ctx.ModuleDir(m)
-
- if m.NoticeFile().Valid() {
- noticeName := stem + ".txt"
- // skip already copied notice file
- if _, ok := noticeBuilt[noticeName]; !ok {
- noticeBuilt[noticeName] = true
- ret = append(ret, installSnapshotFileFromPath(
- m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
- }
+ targetArch := "arch-" + m.Target().Arch.ArchType.String()
+ if m.Target().Arch.ArchVariant != "" {
+ targetArch += "-" + m.Target().Arch.ArchVariant
}
+ libPath := m.outputFile.Path()
+ snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
+ ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+
if ctx.Config().VndkSnapshotBuildArtifacts() {
prop := struct {
ExportedDirs []string `json:",omitempty"`
@@ -661,19 +593,19 @@
ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
return nil, false
}
- ret = append(ret, installSnapshotFileFromContent(string(j), propOut))
+ ret = append(ret, writeStringToFile(ctx, string(j), propOut))
}
return ret, true
}
- isVndkSnapshotLibrary := func(m *Module) (i vndkSnapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+ isVndkSnapshotLibrary := func(m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
if m.Target().NativeBridge == android.NativeBridgeEnabled {
return nil, "", false
}
- if !m.UseVndk() || !m.IsForPlatform() || !m.installable() || !m.inVendor() {
+ if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
return nil, "", false
}
- l, ok := m.linker.(vndkSnapshotLibraryInterface)
+ l, ok := m.linker.(snapshotLibraryInterface)
if !ok || !l.shared() {
return nil, "", false
}
@@ -699,75 +631,38 @@
return
}
+ // install .so files for appropriate modules.
+ // Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
libs, ok := installVndkSnapshotLib(m, l, vndkType)
if !ok {
return
}
-
snapshotOutputs = append(snapshotOutputs, libs...)
- // We glob headers from include directories inside source tree. So we first gather
- // all include directories inside our source tree. On the contrast, we manually
- // collect generated headers from dependencies as they can't globbed.
- generatedHeaders = append(generatedHeaders, l.exportedGeneratedHeaders()...)
- for _, dir := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
- exportedIncludes[dir.String()] = true
+ // These are for generating module_names.txt and module_paths.txt
+ stem := m.outputFile.Path().Base()
+ moduleNames[stem] = ctx.ModuleName(m)
+ modulePaths[stem] = ctx.ModuleDir(m)
+
+ if m.NoticeFile().Valid() {
+ noticeName := stem + ".txt"
+ // skip already copied notice file
+ if _, ok := noticeBuilt[noticeName]; !ok {
+ noticeBuilt[noticeName] = true
+ snapshotOutputs = append(snapshotOutputs, copyFile(
+ ctx, m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
+ }
+ }
+
+ if ctx.Config().VndkSnapshotBuildArtifacts() {
+ headers = append(headers, exportedHeaders(ctx, l)...)
}
})
- if ctx.Config().VndkSnapshotBuildArtifacts() {
- globbedHeaders := make(map[string]bool)
-
- for _, dir := range android.SortedStringKeys(exportedIncludes) {
- // Skip if dir is for generated headers
- if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
- continue
- }
- exts := headerExts
- // Glob all files under this special directory, because of C++ headers.
- if strings.HasPrefix(dir, "external/libcxx/include") {
- exts = []string{""}
- }
- for _, ext := range exts {
- glob, err := ctx.GlobWithDeps(dir+"/**/*"+ext, nil)
- if err != nil {
- ctx.Errorf("%#v\n", err)
- return
- }
- for _, header := range glob {
- if strings.HasSuffix(header, "/") {
- continue
- }
- globbedHeaders[header] = true
- }
- }
- }
-
- for _, header := range android.SortedStringKeys(globbedHeaders) {
- snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
- android.PathForSource(ctx, header), filepath.Join(includeDir, header)))
- }
-
- isHeader := func(path string) bool {
- for _, ext := range headerExts {
- if strings.HasSuffix(path, ext) {
- return true
- }
- }
- return false
- }
-
- // For generated headers, manually install one by one, rather than glob
- for _, path := range android.PathsToDirectorySortedPaths(android.FirstUniquePaths(generatedHeaders)) {
- header := path.String()
-
- if !isHeader(header) {
- continue
- }
-
- snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
- path, filepath.Join(includeDir, header)))
- }
+ // install all headers after removing duplicates
+ for _, header := range android.FirstUniquePaths(headers) {
+ snapshotOutputs = append(snapshotOutputs, copyFile(
+ ctx, header, filepath.Join(includeDir, header.String())))
}
// install *.libraries.txt except vndkcorevariant.libraries.txt
@@ -776,7 +671,8 @@
if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
return
}
- snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(m.OutputFile(), filepath.Join(configsDir, m.Name())))
+ snapshotOutputs = append(snapshotOutputs, copyFile(
+ ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
})
/*
@@ -796,7 +692,7 @@
txtBuilder.WriteString(" ")
txtBuilder.WriteString(m[k])
}
- return installSnapshotFileFromContent(txtBuilder.String(), path)
+ return writeStringToFile(ctx, txtBuilder.String(), path)
}
/*
@@ -827,14 +723,13 @@
zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
zipRule := android.NewRuleBuilder()
- // If output files are too many, soong_zip command can exceed ARG_MAX.
- // So first dump file lists into a single list file, and then feed it to Soong
+ // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
zipRule.Command().
- Text("( xargs").
- FlagWithRspFileInputList("-n1 echo < ", snapshotOutputs).
- FlagWithOutput("| tr -d \\' > ", snapshotOutputList).
- Text(")")
+ Text("tr").
+ FlagWithArg("-d ", "\\'").
+ FlagWithRspFileInputList("< ", snapshotOutputs).
+ FlagWithOutput("> ", snapshotOutputList)
zipRule.Temporary(snapshotOutputList)
@@ -845,6 +740,7 @@
FlagWithInput("-l ", snapshotOutputList)
zipRule.Build(pctx, ctx, zipPath.String(), "vndk snapshot "+zipPath.String())
+ zipRule.DeleteTemporaryFiles()
c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index c941c46..53b5181 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -31,7 +31,8 @@
//
// vndk_prebuilt_shared {
// name: "libfoo",
-// version: "27.1.0",
+// version: "27",
+// target_arch: "arm64",
// vendor_available: true,
// vndk: {
// enabled: true,
@@ -61,10 +62,6 @@
// Prebuilt files for each arch.
Srcs []string `android:"arch_variant"`
- // list of directories relative to the Blueprints file that will be added to the include
- // path (using -isystem) for any module that links against this module.
- Export_system_include_dirs []string `android:"arch_variant"`
-
// list of flags that will be used for any module that links against this module.
Export_flags []string `android:"arch_variant"`
@@ -75,7 +72,8 @@
type vndkPrebuiltLibraryDecorator struct {
*libraryDecorator
- properties vndkPrebuiltProperties
+ properties vndkPrebuiltProperties
+ androidMkSuffix string
}
func (p *vndkPrebuiltLibraryDecorator) Name(name string) string {
@@ -137,11 +135,33 @@
if len(p.properties.Srcs) > 0 && p.shared() {
p.libraryDecorator.exportIncludes(ctx)
- p.libraryDecorator.reexportSystemDirs(
- android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
// current VNDK prebuilts are only shared libs.
- return p.singleSourcePath(ctx)
+
+ in := p.singleSourcePath(ctx)
+ builderFlags := flagsToBuilderFlags(flags)
+ p.unstrippedOutputFile = in
+ libName := in.Base()
+ if p.needsStrip(ctx) {
+ stripped := android.PathForModuleOut(ctx, "stripped", libName)
+ p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ in = stripped
+ }
+
+ // Optimize out relinking against shared libraries whose interface hasn't changed by
+ // depending on a table of contents file instead of the library itself.
+ tocFile := android.PathForModuleOut(ctx, libName+".toc")
+ p.tocFile = android.OptionalPathForPath(tocFile)
+ TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+
+ p.androidMkSuffix = p.NameSuffix()
+
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ if vndkVersion == p.version() {
+ p.androidMkSuffix = ""
+ }
+
+ return in
}
ctx.Module().SkipInstall()
@@ -220,7 +240,8 @@
//
// vndk_prebuilt_shared {
// name: "libfoo",
-// version: "27.1.0",
+// version: "27",
+// target_arch: "arm64",
// vendor_available: true,
// vndk: {
// enabled: true,
diff --git a/cc/xom.go b/cc/xom.go
deleted file mode 100644
index ce817aa..0000000
--- a/cc/xom.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2018 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 (
- "android/soong/android"
-)
-
-type XomProperties struct {
- Xom *bool
-}
-
-type xom struct {
- Properties XomProperties
-}
-
-func (xom *xom) props() []interface{} {
- return []interface{}{&xom.Properties}
-}
-
-func (xom *xom) begin(ctx BaseModuleContext) {}
-
-func (xom *xom) deps(ctx BaseModuleContext, deps Deps) Deps {
- return deps
-}
-
-func (xom *xom) flags(ctx ModuleContext, flags Flags) Flags {
- disableXom := false
-
- if !ctx.Config().EnableXOM() || ctx.Config().XOMDisabledForPath(ctx.ModuleDir()) {
- disableXom = true
- }
-
- if xom.Properties.Xom != nil && !*xom.Properties.Xom {
- return flags
- }
-
- // If any static dependencies have XOM disabled, we should disable XOM in this module,
- // the assumption being if it's been explicitly disabled then there's probably incompatible
- // code in the library which may get pulled in.
- if !disableXom {
- ctx.VisitDirectDeps(func(m android.Module) {
- cc, ok := m.(*Module)
- if !ok || cc.xom == nil || !cc.static() {
- return
- }
- if cc.xom.Properties.Xom != nil && !*cc.xom.Properties.Xom {
- disableXom = true
- return
- }
- })
- }
-
- // Enable execute-only if none of the dependencies disable it,
- // also if it's explicitly set true (allows overriding dependencies disabling it).
- if !disableXom || (xom.Properties.Xom != nil && *xom.Properties.Xom) {
- // XOM is only supported on AArch64 when using lld.
- if ctx.Arch().ArchType == android.Arm64 && ctx.useClangLld(ctx) {
- flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,--execute-only",
- "-Wl,-z,separate-code",
- )
- }
- }
-
- return flags
-}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a9be612..a95aca9 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -667,8 +667,10 @@
return nil
}
var err error
- fiz.reader, err = zip.OpenReader(fiz.Name())
- return err
+ if fiz.reader, err = zip.OpenReader(fiz.Name()); err != nil {
+ return fmt.Errorf("%s: %s", fiz.Name(), err.Error())
+ }
+ return nil
}
func main() {
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 7057b33..65a34fd 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -36,6 +36,7 @@
outputRoot string
keepOutDir bool
depfileOut string
+ inputHash string
)
func init() {
@@ -51,6 +52,8 @@
flag.StringVar(&depfileOut, "depfile-out", "",
"file path of the depfile to generate. This value will replace '__SBOX_DEPFILE__' in the command and will be treated as an output but won't be added to __SBOX_OUT_FILES__")
+ flag.StringVar(&inputHash, "input-hash", "",
+ "This option is ignored. Typical usage is to supply a hash of the list of input names so that the module will be rebuilt if the list (and thus the hash) changes.")
}
func usageViolation(violation string) {
@@ -59,7 +62,7 @@
}
fmt.Fprintf(os.Stderr,
- "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
+ "Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] [--input-hash hash] <outputFile> [<outputFile>...]\n"+
"\n"+
"Deletes <outputRoot>,"+
"runs <commandToRun>,"+
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 974c644..db61fba 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -174,6 +174,10 @@
stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
stat.AddOutput(status.NewCriticalPath(log))
+ buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
+ buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
+ config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
+
defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics"))
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index c5f24e2..b8f7ea6 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -4,6 +4,7 @@
srcs: [
"config.go",
"dexpreopt.go",
+ "testing.go",
],
testSrcs: [
"dexpreopt_test.go",
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 2a929c5..98850e5 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -16,22 +16,23 @@
import (
"encoding/json"
+ "fmt"
"strings"
+ "github.com/google/blueprint"
+
"android/soong/android"
)
// GlobalConfig stores the configuration for dex preopting. The fields are set
-// from product variables via dex_preopt_config.mk, except for SoongConfig
-// which come from CreateGlobalSoongConfig.
+// from product variables via dex_preopt_config.mk.
type GlobalConfig struct {
DisablePreopt bool // disable preopt for all modules
DisablePreoptModules []string // modules with preopt disabled by product-specific config
OnlyPreoptBootImageAndSystemServer bool // only preopt jars in the boot image or system server
- GenerateApexImage bool // generate an extra boot image only containing jars from the runtime apex
- UseApexImage bool // use the apex image by default
+ UseArtImage bool // use the art image (use other boot class path dex files without image)
HasSystemOther bool // store odex files that match PatternsOnSystemOther on the system_other partition
PatternsOnSystemOther []string // patterns (using '%' to denote a prefix match) to put odex on the system_other partition
@@ -82,8 +83,6 @@
BootFlags string // extra flags to pass to dex2oat for the boot image
Dex2oatImageXmx string // max heap size for dex2oat for the boot image
Dex2oatImageXms string // initial heap size for dex2oat for the boot image
-
- SoongConfig GlobalSoongConfig // settings read from dexpreopt_soong.config
}
// GlobalSoongConfig contains the global config that is generated from Soong,
@@ -179,14 +178,11 @@
return constructPath(ctx, path).(android.WritablePath)
}
-// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig
-// struct, except the SoongConfig field which is set from the provided
-// soongConfig argument. LoadGlobalConfig 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, data []byte, soongConfig GlobalSoongConfig) (GlobalConfig, error) {
+// ParseGlobalConfig parses the given data assumed to be read from the global
+// dexpreopt.config file into a GlobalConfig struct.
+func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, error) {
type GlobalJSONConfig struct {
- GlobalConfig
+ *GlobalConfig
// Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be
// used to construct the real value manually below.
@@ -204,19 +200,70 @@
config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects))
config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles)
- // Set this here to force the caller to provide a value for this struct (from
- // either CreateGlobalSoongConfig or LoadGlobalSoongConfig).
- config.GlobalConfig.SoongConfig = soongConfig
-
return config.GlobalConfig, nil
}
-// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which
-// receives a ModuleConfig struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called from oMake to
-// read the module dexpreopt.config written by Make.
-func LoadModuleConfig(ctx android.PathContext, data []byte) (ModuleConfig, error) {
+type globalConfigAndRaw struct {
+ global *GlobalConfig
+ data []byte
+}
+
+// GetGlobalConfig returns the global dexpreopt.config that's created in the
+// make config phase. 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 GetGlobalConfig(ctx android.PathContext) *GlobalConfig {
+ return getGlobalConfigRaw(ctx).global
+}
+
+// GetGlobalConfigRawData is the same as GetGlobalConfig, except that it returns
+// the literal content of dexpreopt.config.
+func GetGlobalConfigRawData(ctx android.PathContext) []byte {
+ return getGlobalConfigRaw(ctx).data
+}
+
+var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig")
+var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
+
+func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
+ return ctx.Config().Once(globalConfigOnceKey, func() interface{} {
+ if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
+ panic(err)
+ } else if data != nil {
+ globalConfig, err := ParseGlobalConfig(ctx, data)
+ if err != nil {
+ panic(err)
+ }
+ return globalConfigAndRaw{globalConfig, data}
+ }
+
+ // No global config filename set, see if there is a test config set
+ return ctx.Config().Once(testGlobalConfigOnceKey, func() interface{} {
+ // Nope, return a config with preopting disabled
+ return globalConfigAndRaw{&GlobalConfig{
+ DisablePreopt: true,
+ DisableGenerateProfile: true,
+ }, nil}
+ })
+ }).(globalConfigAndRaw)
+}
+
+// SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig
+// will return. It must be called before the first call to GetGlobalConfig for
+// the config.
+func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) {
+ config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
+}
+
+// ParseModuleConfig parses a per-module dexpreopt.config file into a
+// ModuleConfig struct. It is not used in Soong, which receives a ModuleConfig
+// struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called
+// from Make to read the module dexpreopt.config written in the Make config
+// stage.
+func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) {
type ModuleJSONConfig struct {
- ModuleConfig
+ *ModuleConfig
// Copies of entries in ModuleConfig that are not constructable without extra parameters. They will be
// used to construct the real value manually below.
@@ -253,21 +300,63 @@
return config.ModuleConfig, nil
}
-// CreateGlobalSoongConfig creates a GlobalSoongConfig from the current context.
-// Should not be used in dexpreopt_gen.
-func CreateGlobalSoongConfig(ctx android.PathContext) GlobalSoongConfig {
- // Default to debug version to help find bugs.
+// dex2oatModuleName returns the name of the module to use for the dex2oat host
+// tool. It should be a binary module with public visibility that is compiled
+// and installed for host.
+func dex2oatModuleName(config android.Config) string {
+ // Default to the debug variant of dex2oat to help find bugs.
// Set USE_DEX2OAT_DEBUG to false for only building non-debug versions.
- var dex2oatBinary string
- if ctx.Config().Getenv("USE_DEX2OAT_DEBUG") == "false" {
- dex2oatBinary = "dex2oat"
+ if config.Getenv("USE_DEX2OAT_DEBUG") == "false" {
+ return "dex2oat"
} else {
- dex2oatBinary = "dex2oatd"
+ return "dex2oatd"
+ }
+}
+
+var dex2oatDepTag = struct {
+ blueprint.BaseDependencyTag
+}{}
+
+// RegisterToolDeps adds the necessary dependencies to binary modules for tools
+// that are required later when Get(Cached)GlobalSoongConfig is called. It
+// should be called from a mutator that's registered with
+// android.RegistrationContext.FinalDepsMutators.
+func RegisterToolDeps(ctx android.BottomUpMutatorContext) {
+ dex2oatBin := dex2oatModuleName(ctx.Config())
+ v := ctx.Config().BuildOSTarget.Variations()
+ ctx.AddFarVariationDependencies(v, dex2oatDepTag, dex2oatBin)
+}
+
+func dex2oatPathFromDep(ctx android.ModuleContext) android.Path {
+ dex2oatBin := dex2oatModuleName(ctx.Config())
+
+ dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag)
+ if dex2oatModule == nil {
+ // If this happens there's probably a missing call to AddToolDeps in DepsMutator.
+ panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
}
- return GlobalSoongConfig{
+ dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath()
+ if !dex2oatPath.Valid() {
+ panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule))
+ }
+
+ return dex2oatPath.Path()
+}
+
+// createGlobalSoongConfig creates a GlobalSoongConfig from the current context.
+// Should not be used in dexpreopt_gen.
+func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig {
+ if ctx.Config().TestProductVariables != nil {
+ // If we're called in a test there'll be a confusing error from the path
+ // functions below that gets reported without a stack trace, so let's panic
+ // properly with a more helpful message.
+ panic("This should not be called from tests. Please call GlobalSoongConfigForTests somewhere in the test setup.")
+ }
+
+ return &GlobalSoongConfig{
Profman: ctx.Config().HostToolPath(ctx, "profman"),
- Dex2oat: ctx.Config().HostToolPath(ctx, dex2oatBinary),
+ Dex2oat: dex2oatPathFromDep(ctx),
Aapt: ctx.Config().HostToolPath(ctx, "aapt"),
SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"),
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
@@ -276,6 +365,47 @@
}
}
+// The main reason for this Once cache for GlobalSoongConfig is to make the
+// dex2oat path available to singletons. In ordinary modules we get it through a
+// dex2oatDepTag dependency, but in singletons there's no simple way to do the
+// same thing and ensure the right variant is selected, hence this cache to make
+// the resolved path available to singletons. This means we depend on there
+// being at least one ordinary module with a dex2oatDepTag dependency.
+//
+// TODO(b/147613152): Implement a way to deal with dependencies from singletons,
+// and then possibly remove this cache altogether (but the use in
+// GlobalSoongConfigForTests also needs to be rethought).
+var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig")
+
+// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called,
+// and later returns the same cached instance.
+func GetGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig {
+ globalSoong := ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} {
+ return createGlobalSoongConfig(ctx)
+ }).(*GlobalSoongConfig)
+
+ // Always resolve the tool path from the dependency, to ensure that every
+ // module has the dependency added properly.
+ myDex2oat := dex2oatPathFromDep(ctx)
+ if myDex2oat != globalSoong.Dex2oat {
+ panic(fmt.Sprintf("Inconsistent dex2oat path in cached config: expected %s, got %s", globalSoong.Dex2oat, myDex2oat))
+ }
+
+ return globalSoong
+}
+
+// GetCachedGlobalSoongConfig returns a cached GlobalSoongConfig created by an
+// earlier GetGlobalSoongConfig call. This function works with any context
+// compatible with a basic PathContext, since it doesn't try to create a
+// GlobalSoongConfig with the proper paths (which requires a full
+// ModuleContext). If there has been no prior call to GetGlobalSoongConfig, nil
+// is returned.
+func GetCachedGlobalSoongConfig(ctx android.PathContext) *GlobalSoongConfig {
+ return ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} {
+ return (*GlobalSoongConfig)(nil)
+ }).(*GlobalSoongConfig)
+}
+
type globalJsonSoongConfig struct {
Profman string
Dex2oat string
@@ -286,17 +416,18 @@
ConstructContext string
}
-// LoadGlobalSoongConfig reads the dexpreopt_soong.config file into a
-// GlobalSoongConfig struct. It is only used in dexpreopt_gen.
-func LoadGlobalSoongConfig(ctx android.PathContext, data []byte) (GlobalSoongConfig, error) {
+// ParseGlobalSoongConfig parses the given data assumed to be read from the
+// global dexpreopt_soong.config file into a GlobalSoongConfig struct. It is
+// only used in dexpreopt_gen.
+func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (*GlobalSoongConfig, error) {
var jc globalJsonSoongConfig
err := json.Unmarshal(data, &jc)
if err != nil {
- return GlobalSoongConfig{}, err
+ return &GlobalSoongConfig{}, err
}
- config := GlobalSoongConfig{
+ config := &GlobalSoongConfig{
Profman: constructPath(ctx, jc.Profman),
Dex2oat: constructPath(ctx, jc.Dex2oat),
Aapt: constructPath(ctx, jc.Aapt),
@@ -310,7 +441,17 @@
}
func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- config := CreateGlobalSoongConfig(ctx)
+ if GetGlobalConfig(ctx).DisablePreopt {
+ return
+ }
+
+ config := GetCachedGlobalSoongConfig(ctx)
+ if config == nil {
+ // No module has enabled dexpreopting, so we assume there will be no calls
+ // to dexpreopt_gen.
+ return
+ }
+
jc := globalJsonSoongConfig{
Profman: config.Profman.String(),
Dex2oat: config.Dex2oat.String(),
@@ -337,7 +478,14 @@
}
func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
- config := CreateGlobalSoongConfig(ctx)
+ if GetGlobalConfig(ctx).DisablePreopt {
+ return
+ }
+
+ config := GetCachedGlobalSoongConfig(ctx)
+ if config == nil {
+ return
+ }
ctx.Strict("DEX2OAT", config.Dex2oat.String())
ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{
@@ -351,8 +499,8 @@
}, " "))
}
-func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
- return GlobalConfig{
+func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
+ return &GlobalConfig{
DisablePreopt: false,
DisablePreoptModules: nil,
OnlyPreoptBootImageAndSystemServer: false,
@@ -390,7 +538,14 @@
BootFlags: "",
Dex2oatImageXmx: "",
Dex2oatImageXms: "",
- SoongConfig: GlobalSoongConfig{
+ }
+}
+
+func GlobalSoongConfigForTests(config android.Config) *GlobalSoongConfig {
+ // Install the test GlobalSoongConfig in the Once cache so that later calls to
+ // Get(Cached)GlobalSoongConfig returns it without trying to create a real one.
+ return config.Once(globalSoongConfigOnceKey, func() interface{} {
+ return &GlobalSoongConfig{
Profman: android.PathForTesting("profman"),
Dex2oat: android.PathForTesting("dex2oat"),
Aapt: android.PathForTesting("aapt"),
@@ -398,6 +553,6 @@
Zip2zip: android.PathForTesting("zip2zip"),
ManifestCheck: android.PathForTesting("manifest_check"),
ConstructContext: android.PathForTesting("construct_context.sh"),
- },
- }
+ }
+ }).(*GlobalSoongConfig)
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index ac5b691..6cb9873 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -41,16 +41,25 @@
"android/soong/android"
+ "github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
)
const SystemPartition = "/system/"
const SystemOtherPartition = "/system_other/"
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var SystemServerDepTag = dependencyTag{name: "system-server-dep"}
+var SystemServerForcedDepTag = dependencyTag{name: "system-server-forced-dep"}
+
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
-func GenerateDexpreoptRule(ctx android.PathContext,
- global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) {
+func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig,
+ global *GlobalConfig, module *ModuleConfig) (rule *android.RuleBuilder, err error) {
defer func() {
if r := recover(); r != nil {
@@ -72,13 +81,13 @@
var profile android.WritablePath
if generateProfile {
- profile = profileCommand(ctx, global, module, rule)
+ profile = profileCommand(ctx, globalSoong, global, module, rule)
}
if generateBootProfile {
- bootProfileCommand(ctx, global, module, rule)
+ bootProfileCommand(ctx, globalSoong, global, module, rule)
}
- if !dexpreoptDisabled(global, module) {
+ if !dexpreoptDisabled(ctx, global, module) {
// Don't preopt individual boot jars, they will be preopted together.
if !contains(global.BootJars, module.Name) {
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
@@ -87,7 +96,7 @@
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
- dexpreoptCommand(ctx, global, module, rule, archIdx, profile, appImage, generateDM)
+ dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
}
}
}
@@ -95,14 +104,21 @@
return rule, nil
}
-func dexpreoptDisabled(global GlobalConfig, module ModuleConfig) bool {
+func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) bool {
if contains(global.DisablePreoptModules, module.Name) {
return true
}
// Don't preopt system server jars that are updatable.
for _, p := range global.UpdatableSystemServerJars {
- if _, jar := SplitApexJarPair(p); jar == module.Name {
+ if _, jar := android.SplitApexJarPair(p); jar == module.Name {
+ return true
+ }
+ }
+
+ // Don't preopt system server jars that are not Soong modules.
+ if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
+ if _, ok := ctx.(android.ModuleContext); !ok {
return true
}
}
@@ -119,8 +135,8 @@
return false
}
-func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig,
- rule *android.RuleBuilder) android.WritablePath {
+func profileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+ module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
profilePath := module.BuildPath.InSameDir(ctx, "profile.prof")
profileInstalledPath := module.DexLocation + ".prof"
@@ -131,7 +147,7 @@
cmd := rule.Command().
Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(global.SoongConfig.Profman)
+ Tool(globalSoong.Profman)
if module.ProfileIsTextListing {
// The profile is a test listing of classes (used for framework jars).
@@ -158,8 +174,8 @@
return profilePath
}
-func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig,
- rule *android.RuleBuilder) android.WritablePath {
+func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+ module *ModuleConfig, rule *android.RuleBuilder) android.WritablePath {
profilePath := module.BuildPath.InSameDir(ctx, "profile.bprof")
profileInstalledPath := module.DexLocation + ".bprof"
@@ -170,7 +186,7 @@
cmd := rule.Command().
Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(global.SoongConfig.Profman)
+ Tool(globalSoong.Profman)
// The profile is a test listing of methods.
// We need to generate the actual binary profile.
@@ -190,8 +206,9 @@
return profilePath
}
-func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
- archIdx int, profile android.WritablePath, appImage bool, generateDM bool) {
+func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
+ module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
+ appImage bool, generateDM bool) {
arch := module.Archs[archIdx]
@@ -236,7 +253,8 @@
var conditionalClassLoaderContextHost29 android.Paths
var conditionalClassLoaderContextTarget29 []string
- var classLoaderContextHostString string
+ var classLoaderContextHostString, classLoaderContextDeviceString string
+ var classLoaderDeps android.Paths
if module.EnforceUsesLibraries {
usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
@@ -282,6 +300,30 @@
filepath.Join("/system/framework", hidlBase+".jar"))
classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":")
+ } else if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
+ // We expect that all dexpreopted system server jars are Soong modules.
+ mctx, isModule := ctx.(android.ModuleContext)
+ if !isModule {
+ panic("Cannot dexpreopt system server jar that is not a soong module.")
+ }
+
+ // System server jars should be dexpreopted together: class loader context of each jar
+ // should include preceding jars (which can be found as dependencies of the current jar
+ // with a special tag).
+ var jarsOnHost android.Paths
+ var jarsOnDevice []string
+ mctx.VisitDirectDepsWithTag(SystemServerDepTag, func(dep android.Module) {
+ depName := mctx.OtherModuleName(dep)
+ if jar, ok := dep.(interface{ DexJar() android.Path }); ok {
+ jarsOnHost = append(jarsOnHost, jar.DexJar())
+ jarsOnDevice = append(jarsOnDevice, "/system/framework/"+depName+".jar")
+ } else {
+ mctx.ModuleErrorf("module \"%s\" is not a jar", depName)
+ }
+ })
+ classLoaderContextHostString = strings.Join(jarsOnHost.Strings(), ":")
+ classLoaderContextDeviceString = strings.Join(jarsOnDevice, ":")
+ classLoaderDeps = jarsOnHost
} else {
// Pass special class loader context to skip the classpath and collision check.
// This will get removed once LOCAL_USES_LIBRARIES is enforced.
@@ -293,20 +335,25 @@
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
rule.Command().FlagWithOutput("rm -f ", odexPath)
// Set values in the environment of the rule. These may be modified by construct_context.sh.
- rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", classLoaderContextHostString)
- rule.Command().Text(`stored_class_loader_context_arg=""`)
+ if classLoaderContextHostString == `\&` {
+ rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`)
+ rule.Command().Text(`stored_class_loader_context_arg=""`)
+ } else {
+ rule.Command().Text("class_loader_context_arg=--class-loader-context=PCL[" + classLoaderContextHostString + "]")
+ rule.Command().Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + classLoaderContextDeviceString + "]")
+ }
if module.EnforceUsesLibraries {
if module.ManifestPath != nil {
rule.Command().Text(`target_sdk_version="$(`).
- Tool(global.SoongConfig.ManifestCheck).
+ Tool(globalSoong.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.SoongConfig.Aapt).
+ Tool(globalSoong.Aapt).
Flag("dump badging").
Input(module.DexPath).
Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
@@ -327,7 +374,7 @@
Implicits(conditionalClassLoaderContextHost29)
rule.Command().Textf(`conditional_target_libs_29="%s"`,
strings.Join(conditionalClassLoaderContextTarget29, " "))
- rule.Command().Text("source").Tool(global.SoongConfig.ConstructContext).Input(module.DexPath)
+ rule.Command().Text("source").Tool(globalSoong.ConstructContext).Input(module.DexPath)
}
// Devices that do not have a product partition use a symlink from /product to /system/product.
@@ -340,7 +387,7 @@
cmd := rule.Command().
Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(global.SoongConfig.Dex2oat).
+ Tool(globalSoong.Dex2oat).
Flag("--avoid-storing-invocation").
FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms).
@@ -348,7 +395,7 @@
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
Flag("${class_loader_context_arg}").
- Flag("${stored_class_loader_context_arg}").
+ Flag("${stored_class_loader_context_arg}").Implicits(classLoaderDeps).
FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
FlagWithInput("--dex-file=", module.DexPath).
FlagWithArg("--dex-location=", dexLocationArg).
@@ -379,7 +426,7 @@
cmd.FlagWithArg("--copy-dex-files=", "false")
}
- if !anyHavePrefix(preoptFlags, "--compiler-filter=") {
+ if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
var compilerFilter string
if contains(global.SystemServerJars, module.Name) {
// Jars of system server, use the product option if it is set, speed otherwise.
@@ -409,7 +456,7 @@
dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm")
tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex")
rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath)
- rule.Command().Tool(global.SoongConfig.SoongZip).
+ rule.Command().Tool(globalSoong.SoongZip).
FlagWithArg("-L", "9").
FlagWithOutput("-o", dmPath).
Flag("-j").
@@ -474,14 +521,14 @@
rule.Install(vdexPath, vdexInstallPath)
}
-func shouldGenerateDM(module ModuleConfig, global GlobalConfig) bool {
+func shouldGenerateDM(module *ModuleConfig, global *GlobalConfig) bool {
// Generating DM files only makes sense for verify, avoid doing for non verify compiler filter APKs.
// No reason to use a dm file if the dex is already uncompressed.
return global.GenerateDMFiles && !module.UncompressedDex &&
contains(module.PreoptFlags, "--compiler-filter=verify")
}
-func OdexOnSystemOtherByName(name string, dexLocation string, global GlobalConfig) bool {
+func OdexOnSystemOtherByName(name string, dexLocation string, global *GlobalConfig) bool {
if !global.HasSystemOther {
return false
}
@@ -503,7 +550,7 @@
return false
}
-func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+func odexOnSystemOther(module *ModuleConfig, global *GlobalConfig) bool {
return OdexOnSystemOtherByName(module.Name, module.DexLocation, global)
}
@@ -516,7 +563,7 @@
return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
}
-func pathForLibrary(module ModuleConfig, lib string) android.Path {
+func pathForLibrary(module *ModuleConfig, lib string) android.Path {
path, ok := module.LibraryPaths[lib]
if !ok {
panic(fmt.Errorf("unknown library path for %q", lib))
@@ -537,19 +584,29 @@
}
// Expected format for apexJarValue = <apex name>:<jar name>
-func SplitApexJarPair(apexJarValue string) (string, string) {
- var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
- if apexJarPair == nil || len(apexJarPair) != 2 {
- panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
- apexJarValue))
- }
- return apexJarPair[0], apexJarPair[1]
+func GetJarLocationFromApexJarPair(apexJarValue string) string {
+ apex, jar := android.SplitApexJarPair(apexJarValue)
+ return filepath.Join("/apex", apex, "javalib", jar+".jar")
}
-// Expected format for apexJarValue = <apex name>:<jar name>
-func GetJarLocationFromApexJarPair(apexJarValue string) string {
- apex, jar := SplitApexJarPair(apexJarValue)
- return filepath.Join("/apex", apex, "javalib", jar+".jar")
+func GetJarsFromApexJarPairs(apexJarPairs []string) []string {
+ modules := make([]string, len(apexJarPairs))
+ for i, p := range apexJarPairs {
+ _, jar := android.SplitApexJarPair(p)
+ modules[i] = jar
+ }
+ return modules
+}
+
+var nonUpdatableSystemServerJarsKey = android.NewOnceKey("nonUpdatableSystemServerJars")
+
+// TODO: eliminate the superficial global config parameter by moving global config definition
+// from java subpackage to dexpreopt.
+func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
+ return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} {
+ return android.RemoveListFromList(global.SystemServerJars,
+ GetJarsFromApexJarPairs(global.UpdatableSystemServerJars))
+ }).([]string)
}
func contains(l []string, s string) bool {
@@ -561,32 +618,4 @@
return false
}
-// remove all elements in a from b, returning a new slice
-func filterOut(a []string, b []string) []string {
- var ret []string
- for _, x := range b {
- if !contains(a, x) {
- ret = append(ret, x)
- }
- }
- return ret
-}
-
-func replace(l []string, from, to string) {
- for i := range l {
- if l[i] == from {
- l[i] = to
- }
- }
-}
-
var copyOf = android.CopyOf
-
-func anyHavePrefix(l []string, prefix string) bool {
- for _, x := range l {
- if strings.HasPrefix(x, prefix) {
- return true
- }
- }
- return false
-}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index e2818bb..e89f045 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -80,13 +80,13 @@
globalSoongConfigData, err := ioutil.ReadFile(*globalSoongConfigPath)
if err != nil {
- fmt.Fprintf(os.Stderr, "error reading global config %q: %s\n", *globalSoongConfigPath, err)
+ fmt.Fprintf(os.Stderr, "error reading global Soong config %q: %s\n", *globalSoongConfigPath, err)
os.Exit(2)
}
- globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, globalSoongConfigData)
+ globalSoongConfig, err := dexpreopt.ParseGlobalSoongConfig(ctx, globalSoongConfigData)
if err != nil {
- fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalSoongConfigPath, err)
+ fmt.Fprintf(os.Stderr, "error parsing global Soong config %q: %s\n", *globalSoongConfigPath, err)
os.Exit(2)
}
@@ -96,9 +96,9 @@
os.Exit(2)
}
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, globalConfigData, globalSoongConfig)
+ globalConfig, err := dexpreopt.ParseGlobalConfig(ctx, globalConfigData)
if err != nil {
- fmt.Fprintf(os.Stderr, "error parse global config %q: %s\n", *globalConfigPath, err)
+ fmt.Fprintf(os.Stderr, "error parsing global config %q: %s\n", *globalConfigPath, err)
os.Exit(2)
}
@@ -108,9 +108,9 @@
os.Exit(2)
}
- moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, moduleConfigData)
+ moduleConfig, err := dexpreopt.ParseModuleConfig(ctx, moduleConfigData)
if err != nil {
- fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err)
+ fmt.Fprintf(os.Stderr, "error parsing module config %q: %s\n", *moduleConfigPath, err)
os.Exit(2)
}
@@ -130,12 +130,12 @@
}
}()
- writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath)
+ writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
}
-func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig,
- dexpreoptScriptPath string) {
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module)
+func writeScripts(ctx android.PathContext, globalSoong *dexpreopt.GlobalSoongConfig,
+ global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
if err != nil {
panic(err)
}
@@ -150,7 +150,7 @@
dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String()))
dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
}
- dexpreoptRule.Command().Tool(global.SoongConfig.SoongZip).
+ dexpreoptRule.Command().Tool(globalSoong.SoongZip).
FlagWithArg("-o ", "$2").
FlagWithArg("-C ", installDir.String()).
FlagWithArg("-D ", installDir.String())
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index a128dc0..d239993 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -20,20 +20,20 @@
"testing"
)
-func testSystemModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testSystemModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
return testModuleConfig(ctx, name, "system")
}
-func testSystemProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testSystemProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
return testModuleConfig(ctx, name, "system/product")
}
-func testProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+func testProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
return testModuleConfig(ctx, name, "product")
}
-func testModuleConfig(ctx android.PathContext, name, partition string) ModuleConfig {
- return ModuleConfig{
+func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleConfig {
+ return &ModuleConfig{
Name: name,
DexLocation: fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
BuildPath: android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
@@ -61,10 +61,13 @@
}
func TestDexPreopt(t *testing.T) {
- ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
- global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.PathContextForTesting(config)
+ globalSoong := GlobalSoongConfigForTests(config)
+ global := GlobalConfigForTests(ctx)
+ module := testSystemModuleConfig(ctx, "test")
- rule, err := GenerateDexpreoptRule(ctx, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
if err != nil {
t.Fatal(err)
}
@@ -80,7 +83,9 @@
}
func TestDexPreoptSystemOther(t *testing.T) {
- ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.PathContextForTesting(config)
+ globalSoong := GlobalSoongConfigForTests(config)
global := GlobalConfigForTests(ctx)
systemModule := testSystemModuleConfig(ctx, "Stest")
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -89,7 +94,7 @@
global.HasSystemOther = true
type moduleTest struct {
- module ModuleConfig
+ module *ModuleConfig
expectedPartition string
}
tests := []struct {
@@ -118,7 +123,7 @@
for _, test := range tests {
global.PatternsOnSystemOther = test.patterns
for _, mt := range test.moduleTests {
- rule, err := GenerateDexpreoptRule(ctx, global, mt.module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
if err != nil {
t.Fatal(err)
}
@@ -138,12 +143,15 @@
}
func TestDexPreoptProfile(t *testing.T) {
- ctx := android.PathContextForTesting(android.TestConfig("out", nil, "", nil))
- global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.PathContextForTesting(config)
+ globalSoong := GlobalSoongConfigForTests(config)
+ global := GlobalConfigForTests(ctx)
+ module := testSystemModuleConfig(ctx, "test")
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
- rule, err := GenerateDexpreoptRule(ctx, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
if err != nil {
t.Fatal(err)
}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
new file mode 100644
index 0000000..b572eb3
--- /dev/null
+++ b/dexpreopt/testing.go
@@ -0,0 +1,47 @@
+// Copyright 2020 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 dexpreopt
+
+import (
+ "android/soong/android"
+)
+
+type dummyToolBinary struct {
+ android.ModuleBase
+}
+
+func (m *dummyToolBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func (m *dummyToolBinary) HostToolPath() android.OptionalPath {
+ return android.OptionalPathForPath(android.PathForTesting("dex2oat"))
+}
+
+func dummyToolBinaryFactory() android.Module {
+ module := &dummyToolBinary{}
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ return module
+}
+
+func RegisterToolModulesForTest(ctx *android.TestContext) {
+ ctx.RegisterModuleType("dummy_tool_binary", dummyToolBinaryFactory)
+}
+
+func BpToolModulesForTest() string {
+ return `
+ dummy_tool_binary {
+ name: "dex2oatd",
+ }
+ `
+}
diff --git a/docs/perf.md b/docs/perf.md
index c3a2647..538adff 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -8,7 +8,7 @@
viewed. Just open `$OUT_DIR/build.trace.gz` in Chrome's <chrome://tracing>, or
with [catapult's trace viewer][catapult trace_viewer]. The last few traces are
stored in `build.trace.#.gz` (larger numbers are older). The associated logs
-are stored in `soong.#.log`.
+are stored in `soong.#.log` and `verbose.#.log.gz`.

@@ -31,29 +31,29 @@
In most cases, we've found that the fast-path is slow because all of the
`$(shell)` commands need to be re-executed to determine if their output changed.
-The `$OUT_DIR/soong.log` contains statistics from the regen check:
+The `$OUT_DIR/verbose.log.gz` contains statistics from the regen check:
```
-.../kati.go:127: *kati*: regen check time: 1.699207
-.../kati.go:127: *kati*: glob time (regen): 0.377193 / 33609
-.../kati.go:127: *kati*: shell time (regen): 1.313529 / 184
-.../kati.go:127: *kati*: 0.217 find device vendor -type f -name \*.pk8 -o -name verifiedboot\* -o -name \*.x509.pem -o -name oem\*.prop | sort
-.../kati.go:127: *kati*: 0.105 cd packages/apps/Dialer ; find -L . -type d -name "res"
-.../kati.go:127: *kati*: 0.035 find device vendor -maxdepth 4 -name '*_aux_variant_config.mk' -o -name '*_aux_os_config.mk' | sort
-.../kati.go:127: *kati*: 0.029 cd frameworks/base ; find -L core/java graphics/java location/java media/java media/mca/effect/java media/mca/filterfw/java media/mca/filterpacks/java drm/java opengl/java sax/java telecomm/java telephony/java wifi/java lowpan/java keystore/java rs/java ../opt/telephony/src/java/android/telephony ../opt/telephony/src/java/android/telephony/gsm ../opt/net/voip/src/java/android/net/rtp ../opt/net/voip/src/java/android/net/sip -name "*.html" -and -not -name ".*"
-.../kati.go:127: *kati*: 0.025 test -d device && find -L device -maxdepth 4 -path '*/marlin/BoardConfig.mk'
-.../kati.go:127: *kati*: 0.023 find packages/apps/Settings/tests/robotests -type f -name '*Test.java' | sed -e 's!.*\(com/google.*Test\)\.java!\1!' -e 's!.*\(com/android.*Test\)\.java!\1!' | sed 's!/!\.!g' | cat
-.../kati.go:127: *kati*: 0.022 test -d vendor && find -L vendor -maxdepth 4 -path '*/marlin/BoardConfig.mk'
-.../kati.go:127: *kati*: 0.017 cd cts/tests/tests/shortcutmanager/packages/launchermanifest ; find -L ../src -name "*.java" -and -not -name ".*"
-.../kati.go:127: *kati*: 0.016 cd cts/tests/tests/shortcutmanager/packages/launchermanifest ; find -L ../../common/src -name "*.java" -and -not -name ".*"
-.../kati.go:127: *kati*: 0.015 cd libcore && (find luni/src/test/java -name "*.java" 2> /dev/null) | grep -v -f java_tests_blacklist
-.../kati.go:127: *kati*: stat time (regen): 0.250384 / 4405
+verbose: *kati*: regen check time: 0.754030
+verbose: *kati*: glob time (regen): 0.545859 / 43840
+verbose: *kati*: shell time (regen): 0.278095 / 66 (59 unique)
+verbose: *kati*: 0.012 / 1 mkdir -p out/target/product/generic && echo Android/aosp_arm/generic:R/AOSP.MASTER/$(date -d @$(cat out/build_date.txt) +%m%d%H%M):eng/test-keys >out/target/product/generic/build_fingerprint.txt && grep " " out/target/product/generic/build_fingerprint.txt
+verbose: *kati*: 0.010 / 1 echo 'com.android.launcher3.config.FlagOverrideSampleTest com.android.launcher3.logging.FileLogTest com.android.launcher3.model.AddWorkspaceItemsTaskTest com.android.launcher3.model.CacheDataUpdatedTaskTest com.android.launcher3.model.DbDowngradeHelperTest com.android.launcher3.model.GridBackupTableTest com.android.launcher3.model.GridSizeMigrationTaskTest com.android.launcher3.model.PackageInstallStateChangedTaskTest com.android.launcher3.popup.PopupPopulatorTest com.android.launcher3.util.GridOccupancyTest com.android.launcher3.util.IntSetTest' | tr ' ' '\n' | cat
+verbose: *kati*: 0.010 / 1 cd cts/tests/framework/base/windowmanager ; find -L * -name "Components.java" -and -not -name ".*"
+verbose: *kati*: 0.010 / 1 git -C test/framework/build log -s -n 1 --format="%cd" --date=format:"%Y%m%d_%H%M%S" 2>/dev/null
+verbose: *kati*: 0.009 / 2 cd development/samples/ShortcutDemo/publisher ; find -L ../common/src -name "*.java" -and -not -name ".*"
+verbose: *kati*: 0.009 / 2 cd development/samples/ShortcutDemo/launcher ; find -L ../common/src -name "*.java" -and -not -name ".*"
+verbose: *kati*: 0.009 / 1 if ! cmp -s out/target/product/generic/obj/CONFIG/kati_packaging/dist.mk.tmp out/target/product/generic/obj/CONFIG/kati_packaging/dist.mk; then mv out/target/product/generic/obj/CONFIG/kati_packaging/dist.mk.tmp out/target/product/generic/obj/CONFIG/kati_packaging/dist.mk; else rm out/target/product/generic/obj/CONFIG/kati_packaging/dist.mk.tmp; fi
+verbose: *kati*: 0.008 / 1 mkdir -p out/target/product/generic && echo R/AOSP.MASTER/$(cat out/build_number.txt):eng/test-keys >out/target/product/generic/build_thumbprint.txt && grep " " out/target/product/generic/build_thumbprint.txt
+verbose: *kati*: 0.007 / 1 echo 'com.android.customization.model.clock.BaseClockManagerTest com.android.customization.model.clock.ClockManagerTest com.android.customization.model.grid.GridOptionsManagerTest com.android.customization.model.theme.ThemeManagerTest' | tr ' ' '\n' | cat
+verbose: *kati*: 0.007 / 1 uname -sm
+verbose: *kati*: stat time (regen): 0.361907 / 1241
```
-In this case, the total time spent checking was 1.69 seconds, even though the
+In this case, the total time spent checking was 0.75 seconds, even though the
other "(regen)" numbers add up to more than that (some parts are parallelized
-where possible). The biggest contributor is the `$(shell)` times -- 184
-executions took a total of 1.31 seconds. The top 10 longest shell functions are
+where possible). Often times, the biggest contributor is the `$(shell)` times
+-- in this case, 66 calls took 0.27s. The top 10 longest shell functions are
printed.
All the longest commands in this case are all variants of a call to `find`, but
@@ -96,7 +96,8 @@
$(sort $(shell find device vendor -type -f -a -name \*.pk8 -o -name verifiedboot\* -o -name \*.x509.pem -o -name oem\*.prop))
```
-Kati is learning about the implicit `-a` in [this change](https://github.com/google/kati/pull/132)
+Kati has now learned about the implicit `-a`, so this particular change is no
+longer necessary, but the basic concept holds.
#### Kati regens too often
@@ -113,6 +114,46 @@
is available when ckati is run with `--regen_debug`, but that can be a lot of
data to understand.
+#### Debugging the slow path
+
+Kati will now dump out information about which Makefiles took the most time to
+execute. This is also in the `verbose.log.gz` file:
+
+```
+verbose: *kati*: included makefiles: 73.640833 / 232810 (1066 unique)
+verbose: *kati*: 18.389 / 1 out/soong/Android-aosp_arm.mk
+verbose: *kati*: 13.137 / 20144 build/make/core/soong_cc_prebuilt.mk
+verbose: *kati*: 11.743 / 27666 build/make/core/base_rules.mk
+verbose: *kati*: 2.289 / 1 art/Android.mk
+verbose: *kati*: 2.054 / 1 art/build/Android.cpplint.mk
+verbose: *kati*: 1.955 / 28269 build/make/core/clear_vars.mk
+verbose: *kati*: 1.795 / 283 build/make/core/package.mk
+verbose: *kati*: 1.790 / 283 build/make/core/package_internal.mk
+verbose: *kati*: 1.757 / 17382 build/make/core/link_type.mk
+verbose: *kati*: 1.078 / 297 build/make/core/aapt2.mk
+```
+
+This shows that soong_cc_prebuilt.mk was included 20144 times, for a total time
+spent of 13.137 secounds. While Android-aosp_arm.mk was only included once, and
+took 18.389 seconds. In this case, Android-aosp_arm.mk is the only file that
+includes soong_cc_prebuilt.mk, so we can safely assume that 13 of the 18 seconds
+in Android-aosp_arm.mk was actually spent within soong_cc_prebuilt.mk (or
+something that it included, like base_rules.mk).
+
+By default this only includes the top 10 entries, but you can ask for the stats
+for any makefile to be printed with `$(KATI_profile_makefile)`:
+
+```
+$(KATI_profile_makefile build/make/core/product.mk)
+```
+
+With these primitives, it's possible to get the timing information for small
+chunks, or even single lines, of a makefile. Just move the lines you want to
+measure into a new makefile, and replace their use with an `include` of the
+new makefile. It's possible to analyze where the time is being spent by doing
+a binary search using this method, but you do need to be careful not to split
+conditionals across two files (the ifeq/else/endif must all be in the same file).
+
### Ninja
#### Understanding why something rebuilt
@@ -164,15 +205,14 @@
### Common
-#### mm
+### <= Android 10 (Q): mm
Soong always loads the entire module graph, so as modules convert from Make to
Soong, `mm` is becoming closer to `mma`. This produces more correct builds, but
does slow down builds, as we need to verify/produce/load a larger build graph.
-We're exploring a few options to speed up build startup, one being [an
-experimental set of ninja patches][ninja parse optimization],
-though that's not the current path we're working towards.
+As of Android Q, loading large build graphs is fast, and in Android R, `mm` is
+now an alias of `mma`.
### Android 8.1 (Oreo MR1)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 57ca9bc..fe877fe 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -26,14 +26,23 @@
"android/soong/android"
"android/soong/shared"
+ "crypto/sha256"
"path/filepath"
)
func init() {
- android.RegisterModuleType("genrule_defaults", defaultsFactory)
+ registerGenruleBuildComponents(android.InitRegistrationContext)
+}
- android.RegisterModuleType("gensrcs", GenSrcsFactory)
- android.RegisterModuleType("genrule", GenRuleFactory)
+func registerGenruleBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
+
+ ctx.RegisterModuleType("gensrcs", GenSrcsFactory)
+ ctx.RegisterModuleType("genrule", GenRuleFactory)
+
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
+ })
}
var (
@@ -166,7 +175,7 @@
return g.outputDeps
}
-func (g *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
+func toolDepsMutator(ctx android.BottomUpMutatorContext) {
if g, ok := ctx.Module().(*Module); ok {
for _, tool := range g.properties.Tools {
tag := hostToolDependencyTag{label: tool}
@@ -301,6 +310,7 @@
addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
}
+ referencedIn := false
referencedDepfile := false
rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
@@ -325,6 +335,7 @@
}
return locationLabels[firstLabel][0], false, nil
case "in":
+ referencedIn = true
return "${in}", true, nil
case "out":
return "__SBOX_OUT_FILES__", false, nil
@@ -390,8 +401,16 @@
// Escape the command for the shell
rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
g.rawCommands = append(g.rawCommands, rawCommand)
- sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
- task.genDir, sandboxPath, task.genDir, rawCommand, depfilePlaceholder)
+
+ sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s",
+ task.genDir, sandboxPath, task.genDir)
+
+ if !referencedIn {
+ sandboxCommand = sandboxCommand + hashSrcFiles(srcFiles)
+ }
+
+ sandboxCommand = sandboxCommand + fmt.Sprintf(" -c %s %s $allouts",
+ rawCommand, depfilePlaceholder)
ruleParams := blueprint.RuleParams{
Command: sandboxCommand,
@@ -455,6 +474,14 @@
}
+func hashSrcFiles(srcFiles android.Paths) string {
+ h := sha256.New()
+ for _, src := range srcFiles {
+ h.Write([]byte(src.String()))
+ }
+ return fmt.Sprintf(" --input-hash %x", h.Sum(nil))
+}
+
func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
desc := "generate"
if len(task.out) == 0 {
@@ -542,6 +569,7 @@
func (x noopImageInterface) ImageMutatorBegin(android.BaseModuleContext) {}
func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool { return false }
+func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index ea49e08..4b36600 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -55,10 +55,10 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- ctx.RegisterModuleType("genrule", GenRuleFactory)
- ctx.RegisterModuleType("gensrcs", GenSrcsFactory)
- ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
ctx.RegisterModuleType("tool", toolFactory)
+
+ registerGenruleBuildComponents(ctx)
+
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.Register(config)
@@ -502,6 +502,93 @@
}
}
+func TestGenruleHashInputs(t *testing.T) {
+
+ // The basic idea here is to verify that the sbox command (which is
+ // in the Command field of the generate rule) contains a hash of the
+ // inputs, but only if $(in) is not referenced in the genrule cmd
+ // property.
+
+ // By including a hash of the inputs, we cause the rule to re-run if
+ // the list of inputs changes (because the sbox command changes).
+
+ // However, if the genrule cmd property already contains $(in), then
+ // the dependency is already expressed, so we don't need to include the
+ // hash in that case.
+
+ bp := `
+ genrule {
+ name: "hash0",
+ srcs: ["in1.txt", "in2.txt"],
+ out: ["out"],
+ cmd: "echo foo > $(out)",
+ }
+ genrule {
+ name: "hash1",
+ srcs: ["*.txt"],
+ out: ["out"],
+ cmd: "echo bar > $(out)",
+ }
+ genrule {
+ name: "hash2",
+ srcs: ["*.txt"],
+ out: ["out"],
+ cmd: "echo $(in) > $(out)",
+ }
+ `
+ testcases := []struct {
+ name string
+ expectedHash string
+ }{
+ {
+ name: "hash0",
+ // sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
+ expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
+ },
+ {
+ name: "hash1",
+ // sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
+ expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
+ },
+ {
+ name: "hash2",
+ // $(in) is present, option should not appear
+ expectedHash: "",
+ },
+ }
+
+ config := testConfig(bp, nil)
+ ctx := testContext(config)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if errs == nil {
+ _, errs = ctx.PrepareBuildActions(config)
+ }
+ if errs != nil {
+ t.Fatal(errs)
+ }
+
+ for _, test := range testcases {
+ t.Run(test.name, func(t *testing.T) {
+ gen := ctx.ModuleForTests(test.name, "")
+ command := gen.Rule("generator").RuleParams.Command
+
+ if len(test.expectedHash) > 0 {
+ // We add spaces before and after to make sure that
+ // this option doesn't abutt another sbox option.
+ expectedInputHashOption := " --input-hash " + test.expectedHash + " "
+
+ if !strings.Contains(command, expectedInputHashOption) {
+ t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
+ }
+ } else {
+ if strings.Contains(command, "--input-hash") {
+ t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
+ }
+ }
+ })
+ }
+}
+
func TestGenSrcs(t *testing.T) {
testcases := []struct {
name string
diff --git a/java/aapt2.go b/java/aapt2.go
index cfe0dea..04e4de5 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -147,10 +147,16 @@
RspfileContent: "$in",
})
+var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} ${out} ${in}`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
+ })
+
func aapt2Link(ctx android.ModuleContext,
packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath,
flags []string, deps android.Paths,
- compiledRes, compiledOverlay android.Paths, splitPackages android.WritablePaths) {
+ compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
genDir := android.PathForModuleGen(ctx, "aapt2", "R")
@@ -186,12 +192,25 @@
}
implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
+ linkOutput := packageRes
+
+ // AAPT2 ignores assets in overlays. Merge them after linking.
+ if len(assetPackages) > 0 {
+ linkOutput = android.PathForModuleOut(ctx, "aapt2", "package-res.apk")
+ inputZips := append(android.Paths{linkOutput}, assetPackages...)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Inputs: inputZips,
+ Output: packageRes,
+ Description: "merge assets from dependencies",
+ })
+ }
ctx.Build(pctx, android.BuildParams{
Rule: aapt2LinkRule,
Description: "aapt2 link",
Implicits: deps,
- Output: packageRes,
+ Output: linkOutput,
ImplicitOutputs: implicitOutputs,
Args: map[string]string{
"flags": strings.Join(flags, " "),
diff --git a/java/aar.go b/java/aar.go
index ae064e5..6e3b9e6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -15,11 +15,12 @@
package java
import (
- "android/soong/android"
"fmt"
"path/filepath"
"strings"
+ "android/soong/android"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -31,6 +32,7 @@
ExportedRRODirs() []rroDir
ExportedStaticPackages() android.Paths
ExportedManifests() android.Paths
+ ExportedAssets() android.OptionalPath
}
func init() {
@@ -92,12 +94,14 @@
extraAaptPackagesFile android.Path
mergedManifestFile android.Path
noticeFile android.OptionalPath
+ assetPackage android.OptionalPath
isLibrary bool
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
sdkLibraries []string
hasNoCode bool
+ LoggingParent string
splitNames []string
splits []split
@@ -123,19 +127,16 @@
return a.transitiveManifestPaths
}
+func (a *aapt) ExportedAssets() android.OptionalPath {
+ return a.assetPackage
+}
+
func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
- hasVersionCode := false
- hasVersionName := false
- for _, f := range a.aaptProperties.Aaptflags {
- if strings.HasPrefix(f, "--version-code") {
- hasVersionCode = true
- } else if strings.HasPrefix(f, "--version-name") {
- hasVersionName = true
- }
- }
+ hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code")
+ hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name")
// Flags specified in Android.bp
linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
@@ -176,7 +177,10 @@
linkDeps = append(linkDeps, assetFiles...)
// SDK version flags
- minSdkVersion := sdkVersionOrDefault(ctx, sdkContext.minSdkVersion())
+ minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion)
linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion)
@@ -215,9 +219,15 @@
}
}
+var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
+ blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`,
+ CommandDeps: []string{"${config.Zip2ZipCmd}"},
+ })
+
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext)
// App manifest file
@@ -225,7 +235,8 @@
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
- a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
+ a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
+ a.LoggingParent)
// Add additional manifest files to transitive manifests.
additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
@@ -317,7 +328,20 @@
}
aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
- linkFlags, linkDeps, compiledRes, compiledOverlay, splitPackages)
+ linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages)
+
+ // Extract assets from the resource package output so that they can be used later in aapt2link
+ // for modules that depend on this one.
+ if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+ assets := android.PathForModuleOut(ctx, "assets.zip")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractAssetsRule,
+ Input: packageRes,
+ Output: assets,
+ Description: "extract assets from built resource file",
+ })
+ a.assetPackage = android.OptionalPathForPath(assets)
+ }
a.aaptSrcJar = srcJar
a.exportPackage = packageRes
@@ -331,7 +355,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, sdkLibraries []string) {
+ staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) {
var sharedLibs android.Paths
@@ -369,6 +393,9 @@
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
+ if aarDep.ExportedAssets().Valid() {
+ assets = append(assets, aarDep.ExportedAssets().Path())
+ }
outer:
for _, d := range aarDep.ExportedRRODirs() {
@@ -398,7 +425,7 @@
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
- return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
+ return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
}
type AndroidLibrary struct {
@@ -523,22 +550,22 @@
exportedStaticPackages android.Paths
}
-func (a *AARImport) sdkVersion() string {
- return String(a.properties.Sdk_version)
+func (a *AARImport) sdkVersion() sdkSpec {
+ return sdkSpecFrom(String(a.properties.Sdk_version))
}
func (a *AARImport) systemModules() string {
return ""
}
-func (a *AARImport) minSdkVersion() string {
+func (a *AARImport) minSdkVersion() sdkSpec {
if a.properties.Min_sdk_version != nil {
- return *a.properties.Min_sdk_version
+ return sdkSpecFrom(*a.properties.Min_sdk_version)
}
return a.sdkVersion()
}
-func (a *AARImport) targetSdkVersion() string {
+func (a *AARImport) targetSdkVersion() sdkSpec {
return a.sdkVersion()
}
@@ -568,6 +595,11 @@
return android.Paths{a.manifest}
}
+// TODO(jungjw): Decide whether we want to implement this.
+func (a *AARImport) ExportedAssets() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
func (a *AARImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -656,7 +688,7 @@
linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
linkDeps = append(linkDeps, a.manifest)
- transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext(a))
_ = staticLibManifests
@@ -669,7 +701,7 @@
overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
- linkFlags, linkDeps, nil, overlayRes, nil)
+ linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
}
var _ Dependency = (*AARImport)(nil)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 021883e..9a71be2 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -53,13 +53,13 @@
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
- isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool) android.Path {
+ isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
var args []string
if isLibrary {
args = append(args, "--library")
} else {
- minSdkVersion, err := sdkVersionToNumber(ctx, sdkContext.minSdkVersion())
+ minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersion(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
@@ -91,18 +91,32 @@
args = append(args, "--has-no-code")
}
+ if loggingParent != "" {
+ args = append(args, "--logging-parent", loggingParent)
+ }
var deps android.Paths
- targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion())
- if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
- ctx.Config().UnbundledBuild() &&
- !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
- ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
- apiFingerprint := ApiFingerprintPath(ctx)
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", apiFingerprint.String())
- deps = append(deps, apiFingerprint)
+ targetSdkVersion, err := sdkContext.targetSdkVersion().effectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
+ }
+ if UseApiFingerprint(ctx, targetSdkVersion) {
+ targetSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ deps = append(deps, ApiFingerprintPath(ctx))
+ }
+
+ minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+ if UseApiFingerprint(ctx, minSdkVersion) {
+ minSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ deps = append(deps, ApiFingerprintPath(ctx))
}
fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
ctx.Build(pctx, android.BuildParams{
Rule: manifestFixerRule,
Description: "fix manifest",
@@ -110,7 +124,7 @@
Implicits: deps,
Output: fixedManifest,
Args: map[string]string{
- "minSdkVersion": sdkVersionOrDefault(ctx, sdkContext.minSdkVersion()),
+ "minSdkVersion": minSdkVersion,
"targetSdkVersion": targetSdkVersion,
"args": strings.Join(args, " "),
},
diff --git a/java/androidmk.go b/java/androidmk.go
index 04bf15c..d76e29b 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -93,7 +93,7 @@
if len(library.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled)
}
- entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion())
+ entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion().raw)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
@@ -174,7 +174,7 @@
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw)
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
},
},
@@ -223,7 +223,7 @@
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw)
},
},
}}
@@ -341,7 +341,7 @@
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", app.Privileged())
- entries.SetPath("LOCAL_CERTIFICATE", app.certificate.Pem)
+ entries.SetString("LOCAL_CERTIFICATE", app.certificate.AndroidMkString())
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...)
for _, jniLib := range app.installJniLibs {
@@ -663,11 +663,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", a.Privileged())
- if a.certificate != nil {
- entries.SetPath("LOCAL_CERTIFICATE", a.certificate.Pem)
- } else {
- entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED")
- }
+ entries.SetString("LOCAL_CERTIFICATE", a.certificate.AndroidMkString())
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", a.properties.Overrides...)
if len(a.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
@@ -695,3 +691,17 @@
}
entries.AddStrings("LOCAL_COMPATIBILITY_SUPPORT_FILES", testFiles...)
}
+
+func (r *RuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(r.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
+ entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
+ },
+ },
+ }}
+}
diff --git a/java/app.go b/java/app.go
index 7828a80..71bad68 100755
--- a/java/app.go
+++ b/java/app.go
@@ -47,6 +47,7 @@
ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory)
ctx.RegisterModuleType("android_app_import", AndroidAppImportFactory)
ctx.RegisterModuleType("android_test_import", AndroidTestImportFactory)
+ ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory)
}
// AndroidManifest.xml merging
@@ -110,6 +111,9 @@
// the package name of this app. The package name in the manifest file is used if one was not given.
Package_name *string
+
+ // the logging parent of this app.
+ Logging_parent *string
}
type AndroidApp struct {
@@ -141,6 +145,10 @@
noticeOutputs android.NoticeOutputs
}
+func (a *AndroidApp) IsInstallable() bool {
+ return Bool(a.properties.Installable)
+}
+
func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
return nil
}
@@ -153,16 +161,31 @@
return a.outputFile
}
+func (a *AndroidApp) Certificate() Certificate {
+ return a.certificate
+}
+
var _ AndroidLibraryDependency = (*AndroidApp)(nil)
type Certificate struct {
- Pem, Key android.Path
+ Pem, Key android.Path
+ presigned bool
+}
+
+var presignedCertificate = Certificate{presigned: true}
+
+func (c Certificate) AndroidMkString() string {
+ if c.presigned {
+ return "PRESIGNED"
+ } else {
+ return c.Pem.String()
+ }
}
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
- if String(a.appProperties.Stl) == "c++_shared" && a.sdkVersion() == "" {
+ if String(a.appProperties.Stl) == "c++_shared" && !a.sdkVersion().specified() {
ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
}
@@ -211,7 +234,7 @@
// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
- minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
+ minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
}
@@ -253,13 +276,7 @@
aaptLinkFlags := []string{}
// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
- hasProduct := false
- for _, f := range a.aaptProperties.Aaptflags {
- if strings.HasPrefix(f, "--product") {
- hasProduct = true
- break
- }
- }
+ hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product")
if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
}
@@ -289,7 +306,7 @@
a.aapt.splitNames = a.appProperties.Package_splits
a.aapt.sdkLibraries = a.exportedSdkLibs
-
+ a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
// apps manifests are handled by aapt, don't let Module see them
@@ -322,7 +339,6 @@
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()
@@ -404,12 +420,15 @@
if certPropValue != "" {
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
mainCert = Certificate{
- defaultDir.Join(ctx, certPropValue+".x509.pem"),
- defaultDir.Join(ctx, certPropValue+".pk8"),
+ Pem: defaultDir.Join(ctx, certPropValue+".x509.pem"),
+ Key: defaultDir.Join(ctx, certPropValue+".pk8"),
}
} else {
pem, key := ctx.Config().DefaultAppCertificate(ctx)
- mainCert = Certificate{pem, key}
+ mainCert = Certificate{
+ Pem: pem,
+ Key: key,
+ }
}
certificates = append([]Certificate{mainCert}, certificates...)
}
@@ -564,6 +583,13 @@
return String(a.overridableAppProperties.Certificate)
}
+func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ if IsJniDepTag(ctx.OtherModuleDependencyTag(dep)) {
+ return true
+ }
+ return a.Library.DepIsInSameApex(ctx, dep)
+}
+
// For OutputFileProducer interface
func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
switch tag {
@@ -644,22 +670,40 @@
}
a.generateAndroidBuildActions(ctx)
- a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
+ testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config)
- if a.overridableAppProperties.Package_name != nil {
- fixedConfig := android.PathForModuleOut(ctx, "test_config_fixer", "AndroidTest.xml")
- rule := android.NewRuleBuilder()
- rule.Command().BuiltTool(ctx, "test_config_fixer").
- FlagWithInput("--manifest ", a.manifestPath).
- FlagWithArg("--package-name ", *a.overridableAppProperties.Package_name).
- Input(a.testConfig).
- Output(fixedConfig)
- rule.Build(pctx, ctx, "fix_test_config", "fix test config")
- a.testConfig = fixedConfig
- }
+ a.testConfig = a.FixTestConfig(ctx, testConfig)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
+func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
+ if testConfig == nil {
+ return nil
+ }
+
+ fixedConfig := android.PathForModuleOut(ctx, "test_config_fixer", "AndroidTest.xml")
+ rule := android.NewRuleBuilder()
+ command := rule.Command().BuiltTool(ctx, "test_config_fixer").Input(testConfig).Output(fixedConfig)
+ fixNeeded := false
+
+ if ctx.ModuleName() != a.installApkName {
+ fixNeeded = true
+ command.FlagWithArg("--test-file-name ", a.installApkName+".apk")
+ }
+
+ if a.overridableAppProperties.Package_name != nil {
+ fixNeeded = true
+ command.FlagWithInput("--manifest ", a.manifestPath).
+ FlagWithArg("--package-name ", *a.overridableAppProperties.Package_name)
+ }
+
+ if fixNeeded {
+ rule.Build(pctx, ctx, "fix_test_config", "fix test config")
+ return fixedConfig
+ }
+ return testConfig
+}
+
func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) {
a.AndroidApp.DepsMutator(ctx)
}
@@ -779,8 +823,8 @@
func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cert := String(c.properties.Certificate)
c.Certificate = Certificate{
- android.PathForModuleSrc(ctx, cert+".x509.pem"),
- android.PathForModuleSrc(ctx, cert+".pk8"),
+ Pem: android.PathForModuleSrc(ctx, cert+".x509.pem"),
+ Key: android.PathForModuleSrc(ctx, cert+".pk8"),
}
}
@@ -837,7 +881,7 @@
archVariants interface{}
outputFile android.Path
- certificate *Certificate
+ certificate Certificate
dexpreopter
@@ -878,6 +922,10 @@
Filename *string
}
+func (a *AndroidAppImport) IsInstallable() bool {
+ return true
+}
+
// Updates properties with variant-specific values.
func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
config := ctx.Config()
@@ -1020,7 +1068,6 @@
}
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
- a.dexpreopter.isInstallable = true
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
@@ -1045,7 +1092,7 @@
if len(certificates) != 1 {
ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
}
- a.certificate = &certificates[0]
+ a.certificate = certificates[0]
signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
SignAppPackage(ctx, signed, dexOutput, certificates)
a.outputFile = signed
@@ -1053,6 +1100,7 @@
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
TransformZipAlign(ctx, alignedApk, dexOutput)
a.outputFile = alignedApk
+ a.certificate = presignedCertificate
}
// TODO: Optionally compress the output apk.
@@ -1079,6 +1127,10 @@
return nil
}
+func (a *AndroidAppImport) Certificate() Certificate {
+ return a.certificate
+}
+
var dpiVariantGroupType reflect.Type
var archVariantGroupType reflect.Type
@@ -1194,6 +1246,99 @@
return module
}
+type RuntimeResourceOverlay struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ aapt
+
+ properties RuntimeResourceOverlayProperties
+
+ certificate Certificate
+
+ outputFile android.Path
+ installDir android.InstallPath
+}
+
+type RuntimeResourceOverlayProperties struct {
+ // the name of a certificate in the default certificate directory or an android_app_certificate
+ // module name in the form ":module".
+ Certificate *string
+
+ // optional theme name. If specified, the overlay package will be applied
+ // only when the ro.boot.vendor.overlay.theme system property is set to the same value.
+ Theme *string
+
+ // if not blank, set to the version of the sdk to compile against.
+ // Defaults to compiling against the current platform.
+ Sdk_version *string
+
+ // if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
+ // Defaults to sdk_version if not set.
+ Min_sdk_version *string
+}
+
+func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
+ sdkDep := decodeSdkDep(ctx, sdkContext(r))
+ if sdkDep.hasFrameworkLibs() {
+ r.aapt.deps(ctx, sdkDep)
+ }
+
+ cert := android.SrcIsModule(String(r.properties.Certificate))
+ if cert != "" {
+ ctx.AddDependency(ctx.Module(), certificateTag, cert)
+ }
+}
+
+func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Compile and link resources
+ r.aapt.hasNoCode = true
+ // Do not remove resources without default values nor dedupe resource configurations with the same value
+ r.aapt.buildActions(ctx, r, "--no-resource-deduping", "--no-resource-removal")
+
+ // Sign the built package
+ _, certificates := collectAppDeps(ctx, false)
+ certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
+ signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
+ SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
+ r.certificate = certificates[0]
+
+ r.outputFile = signed
+ r.installDir = android.PathForModuleInstall(ctx, "overlay", String(r.properties.Theme))
+ ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
+}
+
+func (r *RuntimeResourceOverlay) sdkVersion() sdkSpec {
+ return sdkSpecFrom(String(r.properties.Sdk_version))
+}
+
+func (r *RuntimeResourceOverlay) systemModules() string {
+ return ""
+}
+
+func (r *RuntimeResourceOverlay) minSdkVersion() sdkSpec {
+ if r.properties.Min_sdk_version != nil {
+ return sdkSpecFrom(*r.properties.Min_sdk_version)
+ }
+ return r.sdkVersion()
+}
+
+func (r *RuntimeResourceOverlay) targetSdkVersion() sdkSpec {
+ return r.sdkVersion()
+}
+
+// runtime_resource_overlay generates a resource-only apk file that can overlay application and
+// system resources at run time.
+func RuntimeResourceOverlayFactory() android.Module {
+ module := &RuntimeResourceOverlay{}
+ module.AddProperties(
+ &module.properties,
+ &module.aaptProperties)
+
+ InitJavaModule(module, android.DeviceSupported)
+
+ 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
diff --git a/java/app_test.go b/java/app_test.go
index 862af77..dfd8571 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -323,6 +323,107 @@
}
}
+func TestLibraryAssets(t *testing.T) {
+ bp := `
+ android_app {
+ name: "foo",
+ sdk_version: "current",
+ static_libs: ["lib1", "lib2", "lib3"],
+ }
+
+ android_library {
+ name: "lib1",
+ sdk_version: "current",
+ asset_dirs: ["assets_a"],
+ }
+
+ android_library {
+ name: "lib2",
+ sdk_version: "current",
+ }
+
+ android_library {
+ name: "lib3",
+ sdk_version: "current",
+ static_libs: ["lib4"],
+ }
+
+ android_library {
+ name: "lib4",
+ sdk_version: "current",
+ asset_dirs: ["assets_b"],
+ }
+ `
+
+ testCases := []struct {
+ name string
+ assetFlag string
+ assetPackages []string
+ }{
+ {
+ name: "foo",
+ // lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
+ assetPackages: []string{
+ buildDir + "/.intermediates/foo/android_common/aapt2/package-res.apk",
+ buildDir + "/.intermediates/lib1/android_common/assets.zip",
+ buildDir + "/.intermediates/lib3/android_common/assets.zip",
+ },
+ },
+ {
+ name: "lib1",
+ assetFlag: "-A assets_a",
+ },
+ {
+ name: "lib2",
+ },
+ {
+ name: "lib3",
+ assetPackages: []string{
+ buildDir + "/.intermediates/lib3/android_common/aapt2/package-res.apk",
+ buildDir + "/.intermediates/lib4/android_common/assets.zip",
+ },
+ },
+ {
+ name: "lib4",
+ assetFlag: "-A assets_b",
+ },
+ }
+ ctx := testApp(t, bp)
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ m := ctx.ModuleForTests(test.name, "android_common")
+
+ // Check asset flag in aapt2 link flags
+ var aapt2link android.TestingBuildParams
+ if len(test.assetPackages) > 0 {
+ aapt2link = m.Output("aapt2/package-res.apk")
+ } else {
+ aapt2link = m.Output("package-res.apk")
+ }
+ aapt2Flags := aapt2link.Args["flags"]
+ if test.assetFlag != "" {
+ if !strings.Contains(aapt2Flags, test.assetFlag) {
+ t.Errorf("Can't find asset flag %q in aapt2 link flags %q", test.assetFlag, aapt2Flags)
+ }
+ } else {
+ if strings.Contains(aapt2Flags, " -A ") {
+ t.Errorf("aapt2 link flags %q contain unexpected asset flag", aapt2Flags)
+ }
+ }
+
+ // Check asset merge rule.
+ if len(test.assetPackages) > 0 {
+ mergeAssets := m.Output("package-res.apk")
+ if !reflect.DeepEqual(test.assetPackages, mergeAssets.Inputs.Strings()) {
+ t.Errorf("Unexpected mergeAssets inputs: %v, expected: %v",
+ mergeAssets.Inputs.Strings(), test.assetPackages)
+ }
+ }
+ })
+ }
+}
+
func TestAndroidResources(t *testing.T) {
testCases := []struct {
name string
@@ -1080,6 +1181,7 @@
name: "bar",
base: "foo",
certificate: ":new_certificate",
+ logging_parent: "bah",
}
android_app_certificate {
@@ -1095,37 +1197,41 @@
`)
expectedVariants := []struct {
- moduleName string
- variantName string
- apkName string
- apkPath string
- signFlag string
- overrides []string
- aaptFlag string
+ moduleName string
+ variantName string
+ apkName string
+ apkPath string
+ signFlag string
+ overrides []string
+ aaptFlag string
+ logging_parent 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{"qux"},
- aaptFlag: "",
+ 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{"qux"},
+ aaptFlag: "",
+ logging_parent: "",
},
{
- 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{"qux", "foo"},
- aaptFlag: "",
+ 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{"qux", "foo"},
+ aaptFlag: "",
+ logging_parent: "bah",
},
{
- 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{"qux", "foo"},
- aaptFlag: "--rename-manifest-package org.dandroid.bp",
+ 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{"qux", "foo"},
+ aaptFlag: "--rename-manifest-package org.dandroid.bp",
+ logging_parent: "",
},
}
for _, expected := range expectedVariants {
@@ -1159,6 +1265,13 @@
expected.overrides, mod.appProperties.Overrides)
}
+ // Test Overridable property: Logging_parent
+ logging_parent := mod.aapt.LoggingParent
+ if expected.logging_parent != logging_parent {
+ t.Errorf("Incorrect overrides property value for logging parent, expected: %q, got: %q",
+ expected.logging_parent, logging_parent)
+ }
+
// Check the package renaming flag, if exists.
res := variant.Output("package-res.apk")
aapt2Flags := res.Args["flags"]
@@ -1305,6 +1418,87 @@
}
}
+func TestAndroidTest_FixTestConfig(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ package_name: "com.android.foo",
+ sdk_version: "current",
+ }
+
+ android_test {
+ name: "foo_test",
+ srcs: ["b.java"],
+ instrumentation_for: "foo",
+ }
+
+ android_test {
+ name: "bar_test",
+ srcs: ["b.java"],
+ package_name: "com.android.bar.test",
+ instrumentation_for: "foo",
+ }
+
+ override_android_test {
+ name: "baz_test",
+ base: "foo_test",
+ package_name: "com.android.baz.test",
+ }
+ `)
+
+ testCases := []struct {
+ moduleName string
+ variantName string
+ expectedFlags []string
+ }{
+ {
+ moduleName: "foo_test",
+ variantName: "android_common",
+ },
+ {
+ moduleName: "bar_test",
+ variantName: "android_common",
+ expectedFlags: []string{
+ "--manifest " + buildDir + "/.intermediates/bar_test/android_common/manifest_fixer/AndroidManifest.xml",
+ "--package-name com.android.bar.test",
+ },
+ },
+ {
+ moduleName: "foo_test",
+ variantName: "android_common_baz_test",
+ expectedFlags: []string{
+ "--manifest " + buildDir +
+ "/.intermediates/foo_test/android_common_baz_test/manifest_fixer/AndroidManifest.xml",
+ "--package-name com.android.baz.test",
+ "--test-file-name baz_test.apk",
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ variant := ctx.ModuleForTests(test.moduleName, test.variantName)
+ params := variant.MaybeOutput("test_config_fixer/AndroidTest.xml")
+
+ if len(test.expectedFlags) > 0 {
+ if params.Rule == nil {
+ t.Errorf("test_config_fixer was expected to run, but didn't")
+ } else {
+ for _, flag := range test.expectedFlags {
+ if !strings.Contains(params.RuleParams.Command, flag) {
+ t.Errorf("Flag %q was not found in command: %q", flag, params.RuleParams.Command)
+ }
+ }
+ }
+ } else {
+ if params.Rule != nil {
+ t.Errorf("test_config_fixer was not expected to run, but did: %q", params.RuleParams.Command)
+ }
+ }
+
+ }
+}
+
func TestAndroidAppImport(t *testing.T) {
ctx, _ := testJava(t, `
android_app_import {
@@ -1665,42 +1859,6 @@
func TestStl(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
- name: "ndk_libunwind",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
- }
-
- cc_library {
- name: "libc.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
- }
-
- cc_library {
- name: "libm.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
- }
-
- cc_library {
- name: "libdl.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
- }
-
- cc_object {
- name: "ndk_crtbegin_so.27",
- }
-
- cc_object {
- name: "ndk_crtend_so.27",
- }
-
- cc_library {
name: "libjni",
sdk_version: "current",
stl: "c++_shared",
@@ -1720,10 +1878,6 @@
compile_multilib: "both",
sdk_version: "current",
}
-
- ndk_prebuilt_shared_stl {
- name: "ndk_libc++_shared",
- }
`)
testCases := []struct {
@@ -2126,3 +2280,59 @@
}
}
}
+
+func TestRuntimeResourceOverlay(t *testing.T) {
+ ctx, config := testJava(t, `
+ runtime_resource_overlay {
+ name: "foo",
+ certificate: "platform",
+ product_specific: true,
+ aaptflags: ["--keep-raw-values"],
+ }
+
+ runtime_resource_overlay {
+ name: "foo_themed",
+ certificate: "platform",
+ product_specific: true,
+ theme: "faza",
+ }
+ `)
+
+ m := ctx.ModuleForTests("foo", "android_common")
+
+ // Check AAPT2 link flags.
+ aapt2Flags := m.Output("package-res.apk").Args["flags"]
+ expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
+ absentFlags := android.RemoveListFromList(expectedFlags, strings.Split(aapt2Flags, " "))
+ if len(absentFlags) > 0 {
+ t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
+ }
+
+ // Check cert signing flag.
+ signedApk := m.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["certificates"]
+ expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+ path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_CERTIFICATE"]
+ expectedPath := []string{"build/make/target/product/security/platform.x509.pem"}
+ if !reflect.DeepEqual(path, expectedPath) {
+ t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath)
+ }
+
+ // Check device location.
+ path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ expectedPath = []string{"/tmp/target/product/test_device/product/overlay"}
+ if !reflect.DeepEqual(path, expectedPath) {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
+ }
+
+ // A themed module has a different device location
+ m = ctx.ModuleForTests("foo_themed", "android_common")
+ path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ expectedPath = []string{"/tmp/target/product/test_device/product/overlay/faza"}
+ if !reflect.DeepEqual(path, expectedPath) {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath)
+ }
+}
diff --git a/java/builder.go b/java/builder.go
index 417a7fa..f9b5367 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -38,7 +38,7 @@
// this, all java rules write into separate directories and then are combined into a .jar file
// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
// .srcjar files are unzipped into a temporary directory when compiled with javac.
- javac = pctx.AndroidRemoteStaticRule("javac", android.SUPPORTS_GOMA,
+ javac = pctx.AndroidRemoteStaticRule("javac", android.RemoteRuleSupports{Goma: true, RBE: true, RBEFlag: android.RBE_JAVAC},
blueprint.RuleParams{
Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
@@ -64,6 +64,8 @@
_ = pctx.VariableFunc("kytheCorpus",
func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
+ _ = pctx.VariableFunc("kytheCuEncoding",
+ func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
// Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about
// "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
@@ -76,6 +78,7 @@
`KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` +
`KYTHE_CORPUS=${kytheCorpus} ` +
`KYTHE_VNAMES=${kytheVnames} ` +
+ `KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
`-jar ${config.JavaKytheExtractorJar} ` +
diff --git a/java/config/config.go b/java/config/config.go
index 9738454..7f446e5 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -45,7 +45,9 @@
"core-icu4j",
"core-oj",
"core-libart",
+ // TODO: Could this be all updatable bootclasspath jars?
"updatable-media",
+ "framework-sdkextensions",
"ike",
}
)
@@ -146,6 +148,20 @@
return ""
})
+ pctx.VariableFunc("R8Wrapper", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("R8_WRAPPER"); override != "" {
+ return override + " "
+ }
+ return ""
+ })
+
+ pctx.VariableFunc("D8Wrapper", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("D8_WRAPPER"); override != "" {
+ return override + " "
+ }
+ return ""
+ })
+
pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
pctx.HostBinToolVariable("ManifestCheckCmd", "manifest_check")
diff --git a/java/dex.go b/java/dex.go
index cd6d90d..6afdb6d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -22,10 +22,10 @@
"android/soong/android"
)
-var d8 = pctx.AndroidStaticRule("d8",
+var d8 = pctx.AndroidRemoteStaticRule("d8", android.RemoteRuleSupports{RBE: true, RBEFlag: android.RBE_D8},
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
+ `${config.D8Wrapper}${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
`${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
@@ -36,11 +36,11 @@
},
"outDir", "d8Flags", "zipFlags")
-var r8 = pctx.AndroidStaticRule("r8",
+var r8 = pctx.AndroidRemoteStaticRule("r8", android.RemoteRuleSupports{RBE: true, RBEFlag: android.RBE_R8},
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
`rm -f "$outDict" && ` +
- `${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
+ `${config.R8Wrapper}${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
`--force-proguard-compatibility ` +
`--no-data-resources ` +
`-printmapping $outDict ` +
@@ -73,12 +73,12 @@
"--verbose")
}
- minSdkVersion, err := sdkVersionToNumberAsString(ctx, j.minSdkVersion())
+ minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err)
}
- flags = append(flags, "--min-api "+minSdkVersion)
+ flags = append(flags, "--min-api "+minSdkVersion.asNumberString())
return flags
}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index da68660..4313964 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -19,6 +19,11 @@
"android/soong/dexpreopt"
)
+type dexpreopterInterface interface {
+ IsInstallable() bool // Structs that embed dexpreopter must implement this.
+ dexpreoptDisabled(ctx android.BaseModuleContext) bool
+}
+
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
@@ -26,7 +31,6 @@
uncompressedDex bool
isSDKLibrary bool
isTest bool
- isInstallable bool
isPresignedPrebuilt bool
manifestFile android.Path
@@ -58,8 +62,8 @@
}
}
-func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool {
- global := dexpreoptGlobalConfig(ctx)
+func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
+ global := dexpreopt.GetGlobalConfig(ctx)
if global.DisablePreopt {
return true
@@ -81,7 +85,11 @@
return true
}
- if !d.isInstallable {
+ if !ctx.Module().(dexpreopterInterface).IsInstallable() {
+ return true
+ }
+
+ if ctx.Host() {
return true
}
@@ -95,19 +103,33 @@
return false
}
+func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
+ if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
+ return
+ }
+ dexpreopt.RegisterToolDeps(ctx)
+}
+
func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreoptGlobalConfig(ctx))
+ return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
}
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
- if d.dexpreoptDisabled(ctx) {
+ // TODO(b/148690468): The check on d.installPath is to bail out in cases where
+ // the dexpreopter struct hasn't been fully initialized before we're called,
+ // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
+ // disabled, even if installable is true.
+ if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." {
return dexJarFile
}
- global := dexpreoptGlobalConfig(ctx)
+ globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
bootImage := defaultBootImageConfig(ctx)
- if global.UseApexImage {
- bootImage = frameworkJZBootImageConfig(ctx)
+ dexFiles := bootImage.dexPathsDeps.Paths()
+ dexLocations := bootImage.dexLocationsDeps
+ if global.UseArtImage {
+ bootImage = artBootImageConfig(ctx)
}
var archs []android.ArchType
@@ -154,7 +176,7 @@
}
}
- dexpreoptConfig := dexpreopt.ModuleConfig{
+ dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: ctx.ModuleName(),
DexLocation: dexLocation,
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
@@ -178,8 +200,8 @@
DexPreoptImagesDeps: imagesDeps,
DexPreoptImageLocations: bootImage.imageLocations,
- PreoptBootClassPathDexFiles: bootImage.dexPathsDeps.Paths(),
- PreoptBootClassPathDexLocations: bootImage.dexLocationsDeps,
+ PreoptBootClassPathDexFiles: dexFiles,
+ PreoptBootClassPathDexLocations: dexLocations,
PreoptExtractedApk: false,
@@ -189,7 +211,7 @@
PresignedPrebuilt: d.isPresignedPrebuilt,
}
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, dexpreoptConfig)
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
return dexJarFile
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 66840b5..655a476 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -88,6 +88,9 @@
images map[android.ArchType]android.OutputPath // first image file
imagesDeps map[android.ArchType]android.OutputPaths // all files
+ // Only for extensions, paths to the primary boot images (grouped by target).
+ primaryImages map[android.ArchType]android.OutputPath
+
// File path to a zip archive with all image files (or nil, if not needed).
zip android.WritablePath
}
@@ -162,7 +165,7 @@
}
func skipDexpreoptBootJars(ctx android.PathContext) bool {
- if dexpreoptGlobalConfig(ctx).DisablePreopt {
+ if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
return true
}
@@ -190,7 +193,11 @@
if skipDexpreoptBootJars(ctx) {
return nil
}
- return artBootImageConfig(ctx).imagesDeps
+
+ // Include dexpreopt files for the primary boot image.
+ files := artBootImageConfig(ctx).imagesDeps
+
+ return files
}
// dexpreoptBoot singleton rules
@@ -198,11 +205,15 @@
if skipDexpreoptBootJars(ctx) {
return
}
+ if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil {
+ // No module has enabled dexpreopting, so we assume there will be no boot image to make.
+ return
+ }
d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
- global := dexpreoptGlobalConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
// and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
@@ -218,11 +229,6 @@
d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx))
// Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx)))
- if global.GenerateApexImage {
- // Create boot images for the JIT-zygote experiment.
- d.otherImages = append(d.otherImages, buildBootImage(ctx, artJZBootImageConfig(ctx)))
- d.otherImages = append(d.otherImages, buildBootImage(ctx, frameworkJZBootImageConfig(ctx)))
- }
dumpOatRules(ctx, d.defaultBootImage)
}
@@ -293,7 +299,8 @@
func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage,
arch android.ArchType, profile android.Path, missingDeps []string) android.WritablePaths {
- global := dexpreoptGlobalConfig(ctx)
+ globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
@@ -328,7 +335,7 @@
invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
- cmd.Tool(global.SoongConfig.Dex2oat).
+ cmd.Tool(globalSoong.Dex2oat).
Flag("--avoid-storing-invocation").
FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms).
@@ -344,7 +351,7 @@
}
if image.extension {
- artImage := artBootImageConfig(ctx).images[arch]
+ artImage := image.primaryImages[arch]
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
@@ -431,7 +438,8 @@
Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
- global := dexpreoptGlobalConfig(ctx)
+ globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
return nil
@@ -462,7 +470,7 @@
rule.Command().
Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(global.SoongConfig.Profman).
+ Tool(globalSoong.Profman).
FlagWithInput("--create-profile-from=", bootImageProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
FlagForEachArg("--dex-location=", image.dexLocationsDeps).
@@ -485,7 +493,8 @@
var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
- global := dexpreoptGlobalConfig(ctx)
+ globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
return nil
@@ -511,7 +520,7 @@
rule.Command().
Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(global.SoongConfig.Profman).
+ Tool(globalSoong.Profman).
Flag("--generate-boot-profile").
FlagWithInput("--create-profile-from=", bootFrameworkProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
@@ -573,7 +582,7 @@
}
func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
- data := dexpreoptGlobalConfigRaw(ctx).data
+ data := dexpreopt.GetGlobalConfigRawData(ctx)
ctx.Build(pctx, android.BuildParams{
Rule: android.WriteFile,
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 4ce30f6..c3b2133 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -49,7 +49,7 @@
pathCtx := android.PathContextForTesting(config)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"}
- setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
+ dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext()
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 31bec93..28f56d2 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,6 +15,7 @@
package java
import (
+ "fmt"
"path/filepath"
"strings"
@@ -22,67 +23,36 @@
"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 data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
- panic(err)
- } else if data != nil {
- soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx)
- globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, data, soongConfig)
- if err != nil {
- panic(err)
- }
- 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 globalConfigAndRaw{dexpreopt.GlobalConfig{
- DisablePreopt: true,
- DisableGenerateProfile: true,
- }, nil}
- })
- }).(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 globalConfigAndRaw{globalConfig, nil} })
-}
-
-var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
-var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
-
// systemServerClasspath returns the on-device locations of the modules in the system server classpath. It is computed
// once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
// ctx.Config().
-func systemServerClasspath(ctx android.PathContext) []string {
+func systemServerClasspath(ctx android.MakeVarsContext) []string {
return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
- global := dexpreoptGlobalConfig(ctx)
-
+ global := dexpreopt.GetGlobalConfig(ctx)
var systemServerClasspathLocations []string
- for _, m := range global.SystemServerJars {
+ var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
+ // 1) The jars that are dexpreopted.
+ for _, m := range dexpreoptJars {
systemServerClasspathLocations = append(systemServerClasspathLocations,
filepath.Join("/system/framework", m+".jar"))
}
+ // 2) The jars that are from an updatable apex.
for _, m := range global.UpdatableSystemServerJars {
systemServerClasspathLocations = append(systemServerClasspathLocations,
dexpreopt.GetJarLocationFromApexJarPair(m))
}
+ // 3) The jars from make (which are not updatable, not preopted).
+ for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) {
+ if !android.InList(m, dexpreoptJars) {
+ systemServerClasspathLocations = append(systemServerClasspathLocations,
+ filepath.Join("/system/framework", m+".jar"))
+ }
+ }
+ if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
+ panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
+ len(systemServerClasspathLocations),
+ len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
+ }
return systemServerClasspathLocations
})
}
@@ -112,28 +82,17 @@
return moduleName
}
-func getJarsFromApexJarPairs(apexJarPairs []string) []string {
- modules := make([]string, len(apexJarPairs))
- for i, p := range apexJarPairs {
- _, jar := dexpreopt.SplitApexJarPair(p)
- modules[i] = jar
- }
- return modules
-}
-
var (
- bootImageConfigKey = android.NewOnceKey("bootImageConfig")
- artBootImageName = "art"
- frameworkBootImageName = "boot"
- artJZBootImageName = "jitzygote-art"
- frameworkJZBootImageName = "jitzygote-boot"
+ bootImageConfigKey = android.NewOnceKey("bootImageConfig")
+ artBootImageName = "art"
+ frameworkBootImageName = "boot"
)
// Construct the global boot image configs.
func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigKey, func() interface{} {
- global := dexpreoptGlobalConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
targets := dexpreoptTargets(ctx)
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
@@ -143,7 +102,7 @@
artModules = append(artModules, "jacocoagent")
}
frameworkModules := android.RemoveListFromList(global.BootJars,
- concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars)))
+ concat(artModules, dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)))
artSubdir := "apex/com.android.art/javalib"
frameworkSubdir := "system/framework"
@@ -180,33 +139,9 @@
dexLocationsDeps: append(artLocations, frameworkLocations...),
}
- // ART config for JIT-zygote boot image.
- artJZCfg := bootImageConfig{
- extension: false,
- name: artJZBootImageName,
- stem: "apex",
- installSubdir: artSubdir,
- modules: artModules,
- dexLocations: artLocations,
- dexLocationsDeps: artLocations,
- }
-
- // Framework config for JIT-zygote boot image extension.
- frameworkJZCfg := bootImageConfig{
- extension: true,
- name: frameworkJZBootImageName,
- stem: "apex",
- installSubdir: frameworkSubdir,
- modules: frameworkModules,
- dexLocations: frameworkLocations,
- dexLocationsDeps: append(artLocations, frameworkLocations...),
- }
-
configs := map[string]*bootImageConfig{
- artBootImageName: &artCfg,
- frameworkBootImageName: &frameworkCfg,
- artJZBootImageName: &artJZCfg,
- frameworkJZBootImageName: &frameworkJZCfg,
+ artBootImageName: &artCfg,
+ frameworkBootImageName: &frameworkCfg,
}
// common to all configs
@@ -246,12 +181,9 @@
// specific to the framework config
frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
+ frameworkCfg.primaryImages = artCfg.images
frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
- // specific to the jitzygote-framework config
- frameworkJZCfg.dexPathsDeps = append(artJZCfg.dexPathsDeps, frameworkJZCfg.dexPathsDeps...)
- frameworkJZCfg.imageLocations = append(artJZCfg.imageLocations, frameworkJZCfg.imageLocations...)
-
return configs
}).(map[string]*bootImageConfig)
}
@@ -264,17 +196,9 @@
return *genBootImageConfigs(ctx)[frameworkBootImageName]
}
-func artJZBootImageConfig(ctx android.PathContext) bootImageConfig {
- return *genBootImageConfigs(ctx)[artJZBootImageName]
-}
-
-func frameworkJZBootImageConfig(ctx android.PathContext) bootImageConfig {
- return *genBootImageConfigs(ctx)[frameworkJZBootImageName]
-}
-
func defaultBootclasspath(ctx android.PathContext) []string {
return ctx.Config().OnceStringSlice(defaultBootclasspathKey, func() []string {
- global := dexpreoptGlobalConfig(ctx)
+ global := dexpreopt.GetGlobalConfig(ctx)
image := defaultBootImageConfig(ctx)
updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
diff --git a/java/droiddoc.go b/java/droiddoc.go
index f62f5f9..fd4b90d 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -223,6 +223,9 @@
// if set to true, generate docs through Dokka instead of Doclava.
Dokka_enabled *bool
+
+ // Compat config XML. Generates compat change documentation if set.
+ Compat_config *string `android:"path"`
}
type DroidstubsProperties struct {
@@ -424,19 +427,19 @@
var _ android.OutputFileProducer = (*Javadoc)(nil)
-func (j *Javadoc) sdkVersion() string {
- return String(j.properties.Sdk_version)
+func (j *Javadoc) sdkVersion() sdkSpec {
+ return sdkSpecFrom(String(j.properties.Sdk_version))
}
func (j *Javadoc) systemModules() string {
return proptools.String(j.properties.System_modules)
}
-func (j *Javadoc) minSdkVersion() string {
+func (j *Javadoc) minSdkVersion() sdkSpec {
return j.sdkVersion()
}
-func (j *Javadoc) targetSdkVersion() string {
+func (j *Javadoc) targetSdkVersion() sdkSpec {
return j.sdkVersion()
}
@@ -531,6 +534,9 @@
ctx.AddMissingDependencies(sdkDep.java9Classpath)
} else if sdkDep.useFiles {
deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
+ deps.aidlPreprocess = sdkDep.aidl
+ } else {
+ deps.aidlPreprocess = sdkDep.aidl
}
ctx.VisitDirectDeps(func(module android.Module) {
@@ -541,10 +547,10 @@
case bootClasspathTag:
if dep, ok := module.(Dependency); ok {
deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
- } else if sm, ok := module.(*SystemModules); ok {
+ } else if sm, ok := module.(SystemModulesProvider); ok {
// A system modules dependency has been added to the bootclasspath
// so add its libs to the bootclasspath.
- deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+ deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
} else {
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
}
@@ -572,11 +578,9 @@
if deps.systemModules != nil {
panic("Found two system module dependencies")
}
- sm := module.(*SystemModules)
- if sm.outputDir == nil && len(sm.outputDeps) == 0 {
- panic("Missing directory for system module dependency")
- }
- deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+ sm := module.(SystemModulesProvider)
+ outputDir, outputDeps := sm.OutputDirAndDeps()
+ deps.systemModules = &systemModules{outputDir, outputDeps}
}
})
// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -599,11 +603,8 @@
continue
}
packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".")
- for _, pkg := range filterPackages {
- if strings.HasPrefix(packageName, pkg) {
- filtered = append(filtered, src)
- break
- }
+ if android.HasAnyPrefix(packageName, filterPackages) {
+ filtered = append(filtered, src)
}
}
return filtered
@@ -1037,6 +1038,11 @@
cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+ if d.properties.Compat_config != nil {
+ compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config))
+ cmd.FlagWithInput("-compatconfig ", compatConfig)
+ }
+
var desc string
if Bool(d.properties.Dokka_enabled) {
desc = "dokka"
@@ -1456,6 +1462,8 @@
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
+ // Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
+ rule.HighMem()
cmd := rule.Command().BuiltTool(ctx, "metalava").
Flag(config.JavacVmFlags).
FlagWithArg("-encoding ", "UTF-8").
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index ad84cde..7850193 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -293,10 +293,9 @@
outputPath := hiddenAPISingletonPaths(ctx).metadata
rule.Command().
- Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py")).
- Inputs(metadataCSV).
- Text(">").
- Output(outputPath)
+ BuiltTool(ctx, "merge_csv").
+ FlagWithOutput("--output=", outputPath).
+ Inputs(metadataCSV)
rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
diff --git a/java/java.go b/java/java.go
index 4c6a5a5..462dba8 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,12 +23,14 @@
"path/filepath"
"strconv"
"strings"
+ "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java/config"
"android/soong/tradefed"
)
@@ -37,14 +39,7 @@
RegisterJavaBuildComponents(android.InitRegistrationContext)
// Register sdk member types.
- android.RegisterSdkMemberType(&headerLibrarySdkMemberType{
- librarySdkMemberType{
- android.SdkMemberTypeBase{
- PropertyName: "java_header_libs",
- SupportsSdk: true,
- },
- },
- })
+ android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
android.RegisterSdkMemberType(&implLibrarySdkMemberType{
librarySdkMemberType{
@@ -59,6 +54,8 @@
PropertyName: "java_tests",
},
})
+
+ android.PostDepsMutators(RegisterPostDepsMutators)
}
func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
@@ -79,15 +76,57 @@
ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
ctx.RegisterModuleType("dex_import", DexImportFactory)
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
+ })
+
ctx.RegisterSingletonType("logtags", LogtagsSingleton)
ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
}
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("ordered_system_server_jars", systemServerJarsDepsMutator)
+}
+
+var (
+ dexpreoptedSystemServerJarsKey = android.NewOnceKey("dexpreoptedSystemServerJars")
+ dexpreoptedSystemServerJarsLock sync.Mutex
+)
+
+func DexpreoptedSystemServerJars(config android.Config) *[]string {
+ return config.Once(dexpreoptedSystemServerJarsKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+// A PostDepsMutator pass that enforces total order on non-updatable system server jars. A total
+// order is neededed because such jars must be dexpreopted together (each jar on the list must have
+// all preceding jars in its class loader context). The total order must be compatible with the
+// partial order imposed by genuine dependencies between system server jars (which is not always
+// respected by the PRODUCT_SYSTEM_SERVER_JARS variable).
+//
+// An earlier mutator pass creates genuine dependencies, and this pass traverses the jars in that
+// order (which is partial and non-deterministic). This pass adds additional dependencies between
+// jars, making the order total and deterministic. It also constructs a global ordered list.
+func systemServerJarsDepsMutator(ctx android.BottomUpMutatorContext) {
+ jars := dexpreopt.NonUpdatableSystemServerJars(ctx, dexpreopt.GetGlobalConfig(ctx))
+ name := ctx.ModuleName()
+ if android.InList(name, jars) {
+ dexpreoptedSystemServerJarsLock.Lock()
+ defer dexpreoptedSystemServerJarsLock.Unlock()
+ jars := DexpreoptedSystemServerJars(ctx.Config())
+ for _, dep := range *jars {
+ ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerDepTag, dep)
+ }
+ *jars = append(*jars, name)
+ }
+}
+
func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
if j.SocSpecific() || j.DeviceSpecific() ||
(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
if sc, ok := ctx.Module().(sdkContext); ok {
- if sc.sdkVersion() == "" {
+ if !sc.sdkVersion().specified() {
ctx.PropertyErrorf("sdk_version",
"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
}
@@ -98,12 +137,11 @@
func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
if sc, ok := ctx.Module().(sdkContext); ok {
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
- if usePlatformAPI != (sc.sdkVersion() == "") {
- if usePlatformAPI {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
- } else {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
- }
+ sdkVersionSpecified := sc.sdkVersion().specified()
+ if usePlatformAPI && sdkVersionSpecified {
+ ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+ } else if !usePlatformAPI && !sdkVersionSpecified {
+ ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
}
}
@@ -451,8 +489,8 @@
}
type SdkLibraryDependency interface {
- SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths
- SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths
+ SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+ SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
}
type xref interface {
@@ -553,24 +591,24 @@
ctx.Config().UnbundledBuild())
}
-func (j *Module) sdkVersion() string {
- return String(j.deviceProperties.Sdk_version)
+func (j *Module) sdkVersion() sdkSpec {
+ return sdkSpecFrom(String(j.deviceProperties.Sdk_version))
}
func (j *Module) systemModules() string {
return proptools.String(j.deviceProperties.System_modules)
}
-func (j *Module) minSdkVersion() string {
+func (j *Module) minSdkVersion() sdkSpec {
if j.deviceProperties.Min_sdk_version != nil {
- return *j.deviceProperties.Min_sdk_version
+ return sdkSpecFrom(*j.deviceProperties.Min_sdk_version)
}
return j.sdkVersion()
}
-func (j *Module) targetSdkVersion() string {
+func (j *Module) targetSdkVersion() sdkSpec {
if j.deviceProperties.Target_sdk_version != nil {
- return *j.deviceProperties.Target_sdk_version
+ return sdkSpecFrom(*j.deviceProperties.Target_sdk_version)
}
return j.sdkVersion()
}
@@ -667,6 +705,11 @@
} else if j.shouldInstrumentStatic(ctx) {
ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
}
+
+ // services depend on com.android.location.provider, but dependency in not registered in a Blueprint file
+ if ctx.ModuleName() == "services" {
+ ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerForcedDepTag, "com.android.location.provider")
+ }
}
func hasSrcExt(srcs []string, ext string) bool {
@@ -758,9 +801,13 @@
type linkType int
const (
+ // TODO(jiyong) rename these for better readability. Make the allowed
+ // and disallowed link types explicit
javaCore linkType = iota
javaSdk
javaSystem
+ javaModule
+ javaSystemServer
javaPlatform
)
@@ -776,26 +823,33 @@
name == "stub-annotations" || name == "private-stub-annotations-jar" ||
name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
return javaCore, true
- case ver == "core_current":
+ case ver.kind == sdkCore:
return javaCore, false
case name == "android_system_stubs_current":
return javaSystem, true
- case strings.HasPrefix(ver, "system_"):
+ case ver.kind == sdkSystem:
return javaSystem, false
case name == "android_test_stubs_current":
return javaSystem, true
- case strings.HasPrefix(ver, "test_"):
+ case ver.kind == sdkTest:
return javaPlatform, false
case name == "android_stubs_current":
return javaSdk, true
- case ver == "current":
+ case ver.kind == sdkPublic:
return javaSdk, false
- case ver == "" || ver == "none" || ver == "core_platform":
+ case name == "android_module_lib_stubs_current":
+ return javaModule, true
+ case ver.kind == sdkModule:
+ return javaModule, false
+ case name == "services-stubs":
+ return javaSystemServer, true
+ case ver.kind == sdkSystemServer:
+ return javaSystemServer, false
+ case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform:
return javaPlatform, false
+ case !ver.valid():
+ panic(fmt.Errorf("sdk_version is invalid. got %q", ver.raw))
default:
- if _, err := strconv.Atoi(ver); err != nil {
- panic(fmt.Errorf("expected sdk_version to be a number, got %q", ver))
- }
return javaSdk, false
}
}
@@ -826,11 +880,23 @@
}
break
case javaSystem:
- if otherLinkType == javaPlatform {
+ if otherLinkType == javaPlatform || otherLinkType == javaModule || otherLinkType == javaSystemServer {
ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
ctx.OtherModuleName(to))
}
break
+ case javaModule:
+ if otherLinkType == javaPlatform || otherLinkType == javaSystemServer {
+ ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
+ ctx.OtherModuleName(to))
+ }
+ break
+ case javaSystemServer:
+ if otherLinkType == javaPlatform {
+ ctx.ModuleErrorf("compiles against system server API, but dependency %q is compiling against private API."+commonMessage,
+ ctx.OtherModuleName(to))
+ }
+ break
case javaPlatform:
// no restriction on link-type
break
@@ -965,18 +1031,16 @@
case bootClasspathTag:
// If a system modules dependency has been added to the bootclasspath
// then add its libs to the bootclasspath.
- sm := module.(*SystemModules)
- deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+ sm := module.(SystemModulesProvider)
+ deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
}
- sm := module.(*SystemModules)
- if sm.outputDir == nil || len(sm.outputDeps) == 0 {
- panic("Missing directory for system module dependency")
- }
- deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+ sm := module.(SystemModulesProvider)
+ outputDir, outputDeps := sm.OutputDirAndDeps()
+ deps.systemModules = &systemModules{outputDir, outputDeps}
}
}
})
@@ -992,19 +1056,7 @@
}
func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion {
- v := sdkContext.sdkVersion()
- // For PDK builds, use the latest SDK version instead of "current"
- if ctx.Config().IsPdkBuild() &&
- (v == "" || v == "none" || v == "core_platform" || v == "current") {
- sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
- latestSdkVersion := 0
- if len(sdkVersions) > 0 {
- latestSdkVersion = sdkVersions[len(sdkVersions)-1]
- }
- v = strconv.Itoa(latestSdkVersion)
- }
-
- sdk, err := sdkVersionToNumber(ctx, v)
+ sdk, err := sdkContext.sdkVersion().effectiveVersion(ctx)
if err != nil {
ctx.PropertyErrorf("sdk_version", "%s", err)
}
@@ -1483,6 +1535,16 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
+ // Enable dex compilation for the APEX variants, unless it is disabled explicitly
+ if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() {
+ if j.deviceProperties.Compile_dex == nil {
+ j.deviceProperties.Compile_dex = proptools.BoolPtr(true)
+ }
+ if j.deviceProperties.Hostdex == nil {
+ j.deviceProperties.Hostdex = proptools.BoolPtr(true)
+ }
+ }
+
if ctx.Device() && j.hasCode(ctx) &&
(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
// Dex compilation
@@ -1718,8 +1780,10 @@
func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
depTag := ctx.OtherModuleDependencyTag(dep)
- // dependencies other than the static linkage are all considered crossing APEX boundary
- return depTag == staticLibTag
+ // Dependencies other than the static linkage are all considered crossing APEX boundary
+ // Also, a dependency to an sdk member is also considered as such. This is required because
+ // sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
+ return depTag == staticLibTag || j.IsInAnySdk()
}
func (j *Module) Stem() string {
@@ -1730,6 +1794,10 @@
return j.jacocoReportClassesFile
}
+func (j *Module) IsInstallable() bool {
+ return Bool(j.properties.Installable)
+}
+
//
// Java libraries (.jar file)
//
@@ -1741,6 +1809,11 @@
}
func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
+ // Store uncompressed (and aligned) any dex files from jars in APEXes.
+ if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() {
+ return true
+ }
+
// Store uncompressed (and do not strip) dex files from boot class path jars.
if inList(ctx.ModuleName(), ctx.Config().BootJars()) {
return true
@@ -1762,7 +1835,6 @@
j.checkSdkVersion(ctx)
j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
- j.dexpreopter.isInstallable = Bool(j.properties.Installable)
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
j.compile(ctx, nil)
@@ -1843,6 +1915,15 @@
module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
+var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
+ librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_header_libs",
+ SupportsSdk: true,
+ },
+ },
+}
+
type headerLibrarySdkMemberType struct {
librarySdkMemberType
}
@@ -2282,11 +2363,11 @@
exportedSdkLibs []string
}
-func (j *Import) sdkVersion() string {
- return String(j.properties.Sdk_version)
+func (j *Import) sdkVersion() sdkSpec {
+ return sdkSpecFrom(String(j.properties.Sdk_version))
}
-func (j *Import) minSdkVersion() string {
+func (j *Import) minSdkVersion() sdkSpec {
return j.sdkVersion()
}
@@ -2402,6 +2483,14 @@
return nil, nil
}
+func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ // dependencies other than the static linkage are all considered crossing APEX boundary
+ // Also, a dependency to an sdk member is also considered as such. This is required because
+ // sdk members should be mutated into APEXes. Refer to sdk.sdkDepsReplaceMutator.
+ return depTag == staticLibTag || j.IsInAnySdk()
+}
+
// Add compile time check for interface implementation
var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2502,13 +2591,16 @@
return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
}
+func (j *DexImport) IsInstallable() bool {
+ return true
+}
+
func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(j.properties.Jars) != 1 {
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
}
j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
- j.dexpreopter.isInstallable = true
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")
diff --git a/java/java_test.go b/java/java_test.go
index a2788cb..6d972be 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -57,7 +57,15 @@
}
func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
- return TestConfig(buildDir, env, bp, fs)
+ bp += dexpreopt.BpToolModulesForTest()
+
+ config := TestConfig(buildDir, env, bp, fs)
+
+ // Set up the global Once cache used for dexpreopt.GlobalSoongConfig, so that
+ // it doesn't create a real one, which would fail.
+ _ = dexpreopt.GlobalSoongConfigForTests(config)
+
+ return config
}
func testContext() *android.TestContext {
@@ -84,7 +92,8 @@
// Register module types and mutators from cc needed for JNI testing
cc.RegisterRequiredBuildComponentsForTest(ctx)
- ctx.RegisterModuleType("ndk_prebuilt_shared_stl", cc.NdkPrebuiltSharedStlFactory)
+
+ dexpreopt.RegisterToolModulesForTest(ctx)
return ctx
}
@@ -93,7 +102,7 @@
t.Helper()
pathCtx := android.PathContextForTesting(config)
- setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+ dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
ctx.Register(config)
_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -112,7 +121,7 @@
ctx := testContext()
pathCtx := android.PathContextForTesting(config)
- setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+ dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
ctx.Register(config)
_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -479,7 +488,9 @@
java_sdk_library_import {
name: "sdklib",
- jars: ["b.jar"],
+ public: {
+ jars: ["c.jar"],
+ },
}
prebuilt_stubs_sources {
@@ -531,6 +542,54 @@
}
}
+func TestJavaSdkLibraryImport(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "foo.system",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "system_current",
+ }
+
+ java_library {
+ name: "foo.test",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "test_current",
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ system: {
+ jars: ["b.jar"],
+ },
+ test: {
+ jars: ["c.jar"],
+ },
+ }
+ `)
+
+ for _, scope := range []string{"", ".system", ".test"} {
+ fooModule := ctx.ModuleForTests("foo"+scope, "android_common")
+ javac := fooModule.Rule("javac")
+
+ sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+ if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
+ t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
+ }
+ }
+}
+
func TestDefaults(t *testing.T) {
ctx, _ := testJava(t, `
java_defaults {
@@ -922,6 +981,65 @@
}
}
+func TestDroidstubsWithSystemModules(t *testing.T) {
+ ctx, _ := testJava(t, `
+ droidstubs {
+ name: "stubs-source-system-modules",
+ srcs: [
+ "bar-doc/*.java",
+ ],
+ sdk_version: "none",
+ system_modules: "source-system-modules",
+ }
+
+ java_library {
+ name: "source-jar",
+ srcs: [
+ "a.java",
+ ],
+ }
+
+ java_system_modules {
+ name: "source-system-modules",
+ libs: ["source-jar"],
+ }
+
+ droidstubs {
+ name: "stubs-prebuilt-system-modules",
+ srcs: [
+ "bar-doc/*.java",
+ ],
+ sdk_version: "none",
+ system_modules: "prebuilt-system-modules",
+ }
+
+ java_import {
+ name: "prebuilt-jar",
+ jars: ["a.jar"],
+ }
+
+ java_system_modules_import {
+ name: "prebuilt-system-modules",
+ libs: ["prebuilt-jar"],
+ }
+ `)
+
+ checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar")
+
+ checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
+}
+
+func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
+ metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava")
+ var systemJars []string
+ for _, i := range metalavaRule.Implicits {
+ systemJars = append(systemJars, i.Base())
+ }
+ if len(systemJars) != 1 || systemJars[0] != systemJar {
+ t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
+ }
+}
+
func TestJarGenrules(t *testing.T) {
ctx, _ := testJava(t, `
java_library {
@@ -1043,6 +1161,18 @@
libs: ["baz"],
sdk_version: "system_current",
}
+ java_library {
+ name: "baz-test",
+ srcs: ["c.java"],
+ libs: ["foo"],
+ sdk_version: "test_current",
+ }
+ java_library {
+ name: "baz-29",
+ srcs: ["c.java"],
+ libs: ["foo"],
+ sdk_version: "system_29",
+ }
`)
// check the existence of the internal modules
@@ -1050,10 +1180,10 @@
ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix, "android_common")
ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkSystemApiSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkTestApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkTestApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_arm64_armv8-a")
+ ctx.ModuleForTests("foo"+sdkStubsSourceSuffix, "android_common")
+ ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkSystemApiSuffix, "android_common")
+ ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkTestApiSuffix, "android_common")
+ ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
ctx.ModuleForTests("foo.api.public.28", "")
ctx.ModuleForTests("foo.api.system.28", "")
ctx.ModuleForTests("foo.api.test.28", "")
@@ -1075,6 +1205,20 @@
"foo.stubs.jar")
}
+ bazTestJavac := ctx.ModuleForTests("baz-test", "android_common").Rule("javac")
+ // tests if baz-test is actually linked to the test stubs lib
+ if !strings.Contains(bazTestJavac.Args["classpath"], "foo.stubs.test.jar") {
+ t.Errorf("baz-test javac classpath %v does not contain %q", bazTestJavac.Args["classpath"],
+ "foo.stubs.test.jar")
+ }
+
+ baz29Javac := ctx.ModuleForTests("baz-29", "android_common").Rule("javac")
+ // tests if baz-29 is actually linked to the system 29 stubs lib
+ if !strings.Contains(baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") {
+ t.Errorf("baz-29 javac classpath %v does not contain %q", baz29Javac.Args["classpath"],
+ "prebuilts/sdk/29/system/foo.jar")
+ }
+
// test if baz has exported SDK lib names foo and bar to qux
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
@@ -1291,3 +1435,59 @@
}
}
}
+
+func TestJavaLibraryWithSystemModules(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "lib-with-source-system-modules",
+ srcs: [
+ "a.java",
+ ],
+ sdk_version: "none",
+ system_modules: "source-system-modules",
+ }
+
+ java_library {
+ name: "source-jar",
+ srcs: [
+ "a.java",
+ ],
+ }
+
+ java_system_modules {
+ name: "source-system-modules",
+ libs: ["source-jar"],
+ }
+
+ java_library {
+ name: "lib-with-prebuilt-system-modules",
+ srcs: [
+ "a.java",
+ ],
+ sdk_version: "none",
+ system_modules: "prebuilt-system-modules",
+ }
+
+ java_import {
+ name: "prebuilt-jar",
+ jars: ["a.jar"],
+ }
+
+ java_system_modules_import {
+ name: "prebuilt-system-modules",
+ libs: ["prebuilt-jar"],
+ }
+ `)
+
+ checkBootClasspathForSystemModule(t, ctx, "lib-with-source-system-modules", "/source-jar.jar")
+
+ checkBootClasspathForSystemModule(t, ctx, "lib-with-prebuilt-system-modules", "/prebuilt-jar.jar")
+}
+
+func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) {
+ javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac")
+ bootClasspath := javacRule.Args["bootClasspath"]
+ if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) {
+ t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
+ }
+}
diff --git a/java/kotlin.go b/java/kotlin.go
index 5319a4f..cb7da20 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -26,7 +26,7 @@
"github.com/google/blueprint"
)
-var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.SUPPORTS_GOMA,
+var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
@@ -88,7 +88,7 @@
})
}
-var kapt = pctx.AndroidRemoteStaticRule("kapt", android.SUPPORTS_GOMA,
+var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index d5c7579..cb8e684 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -16,11 +16,17 @@
import (
"android/soong/android"
+ "fmt"
)
func init() {
android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
- android.RegisterModuleType("platform_compat_config", platformCompatConfigFactory)
+ android.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
+ android.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
+}
+
+func platformCompatConfigPath(ctx android.PathContext) android.OutputPath {
+ return android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
}
type platformCompatConfigSingleton struct {
@@ -44,11 +50,24 @@
return p.metadataFile
}
-type platformCompatConfigIntf interface {
- compatConfigMetadata() android.OutputPath
+func (p *platformCompatConfig) CompatConfig() android.OutputPath {
+ return p.configFile
}
-var _ platformCompatConfigIntf = (*platformCompatConfig)(nil)
+func (p *platformCompatConfig) SubDir() string {
+ return "compatconfig"
+}
+
+type PlatformCompatConfigIntf interface {
+ android.Module
+
+ compatConfigMetadata() android.OutputPath
+ CompatConfig() android.OutputPath
+ // Sub dir under etc dir.
+ SubDir() string
+}
+
+var _ PlatformCompatConfigIntf = (*platformCompatConfig)(nil)
// compat singleton rules
func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -56,7 +75,7 @@
var compatConfigMetadata android.Paths
ctx.VisitAllModules(func(module android.Module) {
- if c, ok := module.(platformCompatConfigIntf); ok {
+ if c, ok := module.(PlatformCompatConfigIntf); ok {
metadata := c.compatConfigMetadata()
compatConfigMetadata = append(compatConfigMetadata, metadata)
}
@@ -68,7 +87,7 @@
}
rule := android.NewRuleBuilder()
- outputPath := android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
+ outputPath := platformCompatConfigPath(ctx)
rule.Command().
BuiltTool(ctx, "process-compat-config").
@@ -124,9 +143,55 @@
return &platformCompatConfigSingleton{}
}
-func platformCompatConfigFactory() android.Module {
+func PlatformCompatConfigFactory() android.Module {
module := &platformCompatConfig{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
return module
}
+
+//============== merged_compat_config =================
+type globalCompatConfigProperties struct {
+ // name of the file into which the metadata will be copied.
+ Filename *string
+}
+
+type globalCompatConfig struct {
+ android.ModuleBase
+
+ properties globalCompatConfigProperties
+
+ outputFilePath android.OutputPath
+}
+
+func (c *globalCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ filename := String(c.properties.Filename)
+
+ inputPath := platformCompatConfigPath(ctx)
+ c.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+
+ // This ensures that outputFilePath has the correct name for others to
+ // use, as the source file may have a different name.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: c.outputFilePath,
+ Input: inputPath,
+ })
+}
+
+func (h *globalCompatConfig) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return android.Paths{h.outputFilePath}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
+// global_compat_config provides access to the merged compat config xml file generated by the build.
+func globalCompatConfigFactory() android.Module {
+ module := &globalCompatConfig{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+ return module
+}
diff --git a/java/sdk.go b/java/sdk.go
index 66eb284..1e60d67 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -15,14 +15,15 @@
package java
import (
- "android/soong/android"
- "android/soong/java/config"
"fmt"
"path/filepath"
"sort"
"strconv"
"strings"
+ "android/soong/android"
+ "android/soong/java/config"
+
"github.com/google/blueprint/pathtools"
)
@@ -37,83 +38,268 @@
var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
type sdkContext interface {
- // sdkVersion returns the sdk_version property of the current module, or an empty string if it is not set.
- sdkVersion() string
+ // sdkVersion returns sdkSpec that corresponds to the sdk_version property of the current module
+ sdkVersion() sdkSpec
// systemModules returns the system_modules property of the current module, or an empty string if it is not set.
systemModules() string
- // minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set.
- minSdkVersion() string
- // targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set.
- targetSdkVersion() string
+ // minSdkVersion returns sdkSpec that corresponds to the min_sdk_version property of the current module,
+ // or from sdk_version if it is not set.
+ minSdkVersion() sdkSpec
+ // targetSdkVersion returns the sdkSpec that corresponds to the target_sdk_version property of the current module,
+ // or from sdk_version if it is not set.
+ targetSdkVersion() sdkSpec
}
-func sdkVersionOrDefault(ctx android.BaseModuleContext, v string) string {
- switch v {
- case "", "none", "current", "test_current", "system_current", "core_current", "core_platform":
- return ctx.Config().DefaultAppTargetSdk()
+func UseApiFingerprint(ctx android.BaseModuleContext, v string) bool {
+ if v == ctx.Config().PlatformSdkCodename() &&
+ ctx.Config().UnbundledBuild() &&
+ !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
+ ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
+ return true
+ }
+ return false
+}
+
+// sdkKind represents a particular category of an SDK spec like public, system, test, etc.
+type sdkKind int
+
+const (
+ sdkInvalid sdkKind = iota
+ sdkNone
+ sdkCore
+ sdkCorePlatform
+ sdkPublic
+ sdkSystem
+ sdkTest
+ sdkModule
+ sdkSystemServer
+ sdkPrivate
+)
+
+// String returns the string representation of this sdkKind
+func (k sdkKind) String() string {
+ switch k {
+ case sdkPrivate:
+ return "private"
+ case sdkNone:
+ return "none"
+ case sdkPublic:
+ return "public"
+ case sdkSystem:
+ return "system"
+ case sdkTest:
+ return "test"
+ case sdkCore:
+ return "core"
+ case sdkCorePlatform:
+ return "core_platform"
+ case sdkModule:
+ return "module"
+ case sdkSystemServer:
+ return "system_server"
default:
- return v
+ return "invalid"
}
}
-// Returns a sdk version as a number. For modules targeting an unreleased SDK (meaning it does not yet have a number)
-// it returns android.FutureApiLevel (10000).
-func sdkVersionToNumber(ctx android.EarlyModuleContext, v string) (int, error) {
- switch v {
- case "", "none", "current", "test_current", "system_current", "core_current", "core_platform":
- return ctx.Config().DefaultAppTargetSdkInt(), nil
- default:
- n := android.GetNumericSdkVersion(v)
- if i, err := strconv.Atoi(n); err != nil {
- return -1, fmt.Errorf("invalid sdk version %q", n)
- } else {
- return i, nil
+// sdkVersion represents a specific version number of an SDK spec of a particular kind
+type sdkVersion int
+
+const (
+ // special version number for a not-yet-frozen SDK
+ sdkVersionCurrent sdkVersion = sdkVersion(android.FutureApiLevel)
+ // special version number to be used for SDK specs where version number doesn't
+ // make sense, e.g. "none", "", etc.
+ sdkVersionNone sdkVersion = sdkVersion(0)
+)
+
+// isCurrent checks if the sdkVersion refers to the not-yet-published version of an sdkKind
+func (v sdkVersion) isCurrent() bool {
+ return v == sdkVersionCurrent
+}
+
+// isNumbered checks if the sdkVersion refers to the published (a.k.a numbered) version of an sdkKind
+func (v sdkVersion) isNumbered() bool {
+ return !v.isCurrent() && v != sdkVersionNone
+}
+
+// String returns the string representation of this sdkVersion.
+func (v sdkVersion) String() string {
+ if v.isCurrent() {
+ return "current"
+ } else if v.isNumbered() {
+ return strconv.Itoa(int(v))
+ }
+ return "(no version)"
+}
+
+// asNumberString directly converts the numeric value of this sdk version as a string.
+// When isNumbered() is true, this method is the same as String(). However, for sdkVersionCurrent
+// and sdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"),
+// respectively.
+func (v sdkVersion) asNumberString() string {
+ return strconv.Itoa(int(v))
+}
+
+// sdkSpec represents the kind and the version of an SDK for a module to build against
+type sdkSpec struct {
+ kind sdkKind
+ version sdkVersion
+ raw string
+}
+
+// valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the
+// specified SDK actually exists.
+func (s sdkSpec) valid() bool {
+ return s.kind != sdkInvalid
+}
+
+// specified checks if this sdkSpec is well-formed and is not "".
+func (s sdkSpec) specified() bool {
+ return s.valid() && s.kind != sdkPrivate
+}
+
+// prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK
+// that can be used for unbundled builds.
+func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool {
+ // "", "none", and "core_platform" are not available for unbundled build
+ // as we don't/can't have prebuilt stub for the versions
+ return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform
+}
+
+// forPdkBuild converts this sdkSpec into another sdkSpec that is for the PDK builds.
+func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec {
+ // For PDK builds, use the latest SDK version instead of "current" or ""
+ if s.kind == sdkPrivate || s.kind == sdkPublic {
+ kind := s.kind
+ if kind == sdkPrivate {
+ // We don't have prebuilt SDK for private APIs, so use the public SDK
+ // instead. This looks odd, but that's how it has been done.
+ // TODO(b/148271073): investigate the need for this.
+ kind = sdkPublic
}
+ version := sdkVersion(LatestSdkVersionInt(ctx))
+ return sdkSpec{kind, version, s.raw}
}
+ return s
}
-func sdkVersionToNumberAsString(ctx android.EarlyModuleContext, v string) (string, error) {
- n, err := sdkVersionToNumber(ctx, v)
- if err != nil {
- return "", err
+// usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context.
+func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool {
+ if s.version.isCurrent() {
+ // "current" can be built from source and be from prebuilt SDK
+ return ctx.Config().UnbundledBuildUsePrebuiltSdks()
+ } else if s.version.isNumbered() {
+ // sanity check
+ if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest {
+ panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind))
+ return false
+ }
+ // numbered SDKs are always from prebuilt
+ return true
}
- return strconv.Itoa(n), nil
+ // "", "none", "core_platform" fall here
+ return false
+}
+
+// effectiveVersion converts an sdkSpec into the concrete sdkVersion that the module
+// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
+// it returns android.FutureApiLevel(10000).
+func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, error) {
+ if !s.valid() {
+ return s.version, fmt.Errorf("invalid sdk version %q", s.raw)
+ }
+ if ctx.Config().IsPdkBuild() {
+ s = s.forPdkBuild(ctx)
+ }
+ if s.version.isNumbered() {
+ return s.version, nil
+ }
+ return sdkVersion(ctx.Config().DefaultAppTargetSdkInt()), nil
+}
+
+// effectiveVersionString converts an sdkSpec into the concrete version string that the module
+// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
+// it returns the codename (P, Q, R, etc.)
+func (s sdkSpec) effectiveVersionString(ctx android.EarlyModuleContext) (string, error) {
+ ver, err := s.effectiveVersion(ctx)
+ if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdkInt() {
+ return ctx.Config().DefaultAppTargetSdk(), nil
+ }
+ return ver.String(), err
+}
+
+func sdkSpecFrom(str string) sdkSpec {
+ switch str {
+ // special cases first
+ case "":
+ return sdkSpec{sdkPrivate, sdkVersionNone, str}
+ case "none":
+ return sdkSpec{sdkNone, sdkVersionNone, str}
+ case "core_platform":
+ return sdkSpec{sdkCorePlatform, sdkVersionNone, str}
+ default:
+ // the syntax is [kind_]version
+ sep := strings.LastIndex(str, "_")
+
+ var kindString string
+ if sep == 0 {
+ return sdkSpec{sdkInvalid, sdkVersionNone, str}
+ } else if sep == -1 {
+ kindString = ""
+ } else {
+ kindString = str[0:sep]
+ }
+ versionString := str[sep+1 : len(str)]
+
+ var kind sdkKind
+ switch kindString {
+ case "":
+ kind = sdkPublic
+ case "core":
+ kind = sdkCore
+ case "system":
+ kind = sdkSystem
+ case "test":
+ kind = sdkTest
+ case "module":
+ kind = sdkModule
+ case "system_server":
+ kind = sdkSystemServer
+ default:
+ return sdkSpec{sdkInvalid, sdkVersionNone, str}
+ }
+
+ var version sdkVersion
+ if versionString == "current" {
+ version = sdkVersionCurrent
+ } else if i, err := strconv.Atoi(versionString); err == nil {
+ version = sdkVersion(i)
+ } else {
+ return sdkSpec{sdkInvalid, sdkVersionNone, str}
+ }
+
+ return sdkSpec{kind, version, str}
+ }
}
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep {
- v := sdkContext.sdkVersion()
-
- // For PDK builds, use the latest SDK version instead of "current"
- if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
- sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
- latestSdkVersion := 0
- if len(sdkVersions) > 0 {
- latestSdkVersion = sdkVersions[len(sdkVersions)-1]
- }
- v = strconv.Itoa(latestSdkVersion)
- }
-
- numericSdkVersion, err := sdkVersionToNumber(ctx, v)
- if err != nil {
- ctx.PropertyErrorf("sdk_version", "%s", err)
+ sdkVersion := sdkContext.sdkVersion()
+ if !sdkVersion.valid() {
+ ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.raw)
return sdkDep{}
}
- toPrebuilt := func(sdk string) sdkDep {
- var api, v string
- if strings.Contains(sdk, "_") {
- t := strings.Split(sdk, "_")
- api = t[0]
- v = t[1]
- } else {
- api = "public"
- v = sdk
- }
- dir := filepath.Join("prebuilts", "sdk", v, api)
+ if ctx.Config().IsPdkBuild() {
+ sdkVersion = sdkVersion.forPdkBuild(ctx)
+ }
+
+ if sdkVersion.usePrebuilt(ctx) {
+ dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String())
jar := filepath.Join(dir, "android.jar")
// There's no aidl for other SDKs yet.
// TODO(77525052): Add aidl files for other SDKs too.
- public_dir := filepath.Join("prebuilts", "sdk", v, "public")
+ public_dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), "public")
aidl := filepath.Join(public_dir, "framework.aidl")
jarPath := android.ExistentPathForSource(ctx, jar)
aidlPath := android.ExistentPathForSource(ctx, aidl)
@@ -122,17 +308,17 @@
if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
return sdkDep{
invalidVersion: true,
- bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
+ bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.kind, sdkVersion.version.String())},
}
}
if !jarPath.Valid() {
- ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdk, jar)
+ ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, jar)
return sdkDep{}
}
if !aidlPath.Valid() {
- ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdk, aidl)
+ ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, aidl)
return sdkDep{}
}
@@ -143,44 +329,39 @@
}
}
- toModule := func(m, r string, aidl android.Path) sdkDep {
+ toModule := func(modules []string, res string, aidl android.Path) sdkDep {
return sdkDep{
useModule: true,
- bootclasspath: []string{m, config.DefaultLambdaStubsLibrary},
+ bootclasspath: append(modules, config.DefaultLambdaStubsLibrary),
systemModules: "core-current-stubs-system-modules",
- java9Classpath: []string{m},
- frameworkResModule: r,
+ java9Classpath: modules,
+ frameworkResModule: res,
aidl: android.OptionalPathForPath(aidl),
}
}
// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
- if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel {
+ if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() {
allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
if ctx.DeviceSpecific() || ctx.SocSpecific() {
if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
}
}
- if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) {
+ if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) {
ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
- v, allowed_versions)
+ sdkVersion.raw, allowed_versions)
}
}
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
- v != "" && v != "none" && v != "core_platform" {
- return toPrebuilt(v)
- }
-
- switch v {
- case "":
+ switch sdkVersion.kind {
+ case sdkPrivate:
return sdkDep{
useDefaultLibs: true,
frameworkResModule: "framework-res",
}
- case "none":
+ case sdkNone:
systemModules := sdkContext.systemModules()
if systemModules == "" {
ctx.PropertyErrorf("sdk_version",
@@ -197,22 +378,28 @@
systemModules: systemModules,
bootclasspath: []string{systemModules},
}
- case "core_platform":
+ case sdkCorePlatform:
return sdkDep{
useDefaultLibs: true,
frameworkResModule: "framework-res",
noFrameworksLibs: true,
}
- case "current":
- return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
- case "system_current":
- return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
- case "test_current":
- return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
- case "core_current":
- return toModule("core.current.stubs", "", nil)
+ case sdkPublic:
+ return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ case sdkSystem:
+ return toModule([]string{"android_system_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ case sdkTest:
+ return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ case sdkCore:
+ return toModule([]string{"core.current.stubs"}, "", nil)
+ case sdkModule:
+ // TODO(146757305): provide .apk and .aidl that have more APIs for modules
+ return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+ case sdkSystemServer:
+ // TODO(146757305): provide .apk and .aidl that have more APIs for modules
+ return toModule([]string{"android_module_lib_stubs_current", "services-stubs"}, "framework-res", sdkFrameworkAidlPath(ctx))
default:
- return toPrebuilt(v)
+ panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
}
}
@@ -245,6 +432,15 @@
ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
}
+func LatestSdkVersionInt(ctx android.EarlyModuleContext) int {
+ sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
+ latestSdkVersion := 0
+ if len(sdkVersions) > 0 {
+ latestSdkVersion = sdkVersions[len(sdkVersions)-1]
+ }
+ return latestSdkVersion
+}
+
func sdkSingletonFactory() android.Singleton {
return sdkSingleton{}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 9b30e2c..a8edf1d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+
"fmt"
"io"
"path"
@@ -24,6 +25,7 @@
"strings"
"sync"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -31,43 +33,118 @@
sdkStubsLibrarySuffix = ".stubs"
sdkSystemApiSuffix = ".system"
sdkTestApiSuffix = ".test"
- sdkDocsSuffix = ".docs"
+ sdkStubsSourceSuffix = ".stubs.source"
sdkXmlFileSuffix = ".xml"
- permissionsTemplate = `<?xml version="1.0" encoding="utf-8"?>\n` +
+ permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
`<!-- Copyright (C) 2018 The Android Open Source Project\n` +
`\n` +
- ` Licensed under the Apache License, Version 2.0 (the "License");\n` +
+ ` Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
` you may not use this file except in compliance with the License.\n` +
` You may obtain a copy of the License at\n` +
`\n` +
` http://www.apache.org/licenses/LICENSE-2.0\n` +
`\n` +
` Unless required by applicable law or agreed to in writing, software\n` +
- ` distributed under the License is distributed on an "AS IS" BASIS,\n` +
+ ` distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
` See the License for the specific language governing permissions and\n` +
` limitations under the License.\n` +
`-->\n` +
`<permissions>\n` +
- ` <library name="%s" file="%s"/>\n` +
+ ` <library name=\"%s\" file=\"%s\"/>\n` +
`</permissions>\n`
)
+// A tag to associated a dependency with a specific api scope.
+type scopeDependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+ apiScope *apiScope
+}
+
+// Provides information about an api scope, e.g. public, system, test.
+type apiScope struct {
+ // The name of the api scope, e.g. public, system, test
+ name string
+
+ // The tag to use to depend on the stubs library module.
+ stubsTag scopeDependencyTag
+
+ // The tag to use to depend on the stubs
+ apiFileTag scopeDependencyTag
+
+ // The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
+ apiFilePrefix string
+
+ // The scope specific prefix to add to the sdk library module name to construct a scope specific
+ // module name.
+ moduleSuffix string
+
+ // The suffix to add to the make variable that references the location of the api file.
+ apiFileMakeVariableSuffix string
+
+ // SDK version that the stubs library is built against. Note that this is always
+ // *current. Older stubs library built with a numbered SDK version is created from
+ // the prebuilt jar.
+ sdkVersion string
+}
+
+// Initialize a scope, creating and adding appropriate dependency tags
+func initApiScope(scope *apiScope) *apiScope {
+ //apiScope := &scope
+ scope.stubsTag = scopeDependencyTag{
+ name: scope.name + "-stubs",
+ apiScope: scope,
+ }
+ scope.apiFileTag = scopeDependencyTag{
+ name: scope.name + "-api",
+ apiScope: scope,
+ }
+ return scope
+}
+
+func (scope *apiScope) stubsModuleName(baseName string) string {
+ return baseName + sdkStubsLibrarySuffix + scope.moduleSuffix
+}
+
+func (scope *apiScope) docsModuleName(baseName string) string {
+ return baseName + sdkStubsSourceSuffix + scope.moduleSuffix
+}
+
+type apiScopes []*apiScope
+
+func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
+ var list []string
+ for _, scope := range scopes {
+ list = append(list, accessor(scope))
+ }
+ return list
+}
+
var (
- publicApiStubsTag = dependencyTag{name: "public"}
- systemApiStubsTag = dependencyTag{name: "system"}
- testApiStubsTag = dependencyTag{name: "test"}
- publicApiFileTag = dependencyTag{name: "publicApi"}
- systemApiFileTag = dependencyTag{name: "systemApi"}
- testApiFileTag = dependencyTag{name: "testApi"}
-)
-
-type apiScope int
-
-const (
- apiScopePublic apiScope = iota
- apiScopeSystem
- apiScopeTest
+ apiScopePublic = initApiScope(&apiScope{
+ name: "public",
+ sdkVersion: "current",
+ })
+ apiScopeSystem = initApiScope(&apiScope{
+ name: "system",
+ apiFilePrefix: "system-",
+ moduleSuffix: sdkSystemApiSuffix,
+ apiFileMakeVariableSuffix: "_SYSTEM",
+ sdkVersion: "system_current",
+ })
+ apiScopeTest = initApiScope(&apiScope{
+ name: "test",
+ apiFilePrefix: "test-",
+ moduleSuffix: sdkTestApiSuffix,
+ apiFileMakeVariableSuffix: "_TEST",
+ sdkVersion: "test_current",
+ })
+ allApiScopes = apiScopes{
+ apiScopePublic,
+ apiScopeSystem,
+ apiScopeTest,
+ }
)
var (
@@ -142,44 +219,70 @@
//Html_doc *bool
}
+type scopePaths struct {
+ stubsHeaderPath android.Paths
+ stubsImplPath android.Paths
+ apiFilePath android.Path
+}
+
+// Common code between sdk library and sdk library import
+type commonToSdkLibraryAndImport struct {
+ scopePaths map[*apiScope]*scopePaths
+}
+
+func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths {
+ if c.scopePaths == nil {
+ c.scopePaths = make(map[*apiScope]*scopePaths)
+ }
+ paths := c.scopePaths[scope]
+ if paths == nil {
+ paths = &scopePaths{}
+ c.scopePaths[scope] = paths
+ }
+
+ return paths
+}
+
type SdkLibrary struct {
Library
sdkLibraryProperties sdkLibraryProperties
- publicApiStubsPath android.Paths
- systemApiStubsPath android.Paths
- testApiStubsPath android.Paths
-
- publicApiStubsImplPath android.Paths
- systemApiStubsImplPath android.Paths
- testApiStubsImplPath android.Paths
-
- publicApiFilePath android.Path
- systemApiFilePath android.Path
- testApiFilePath android.Path
-
- permissionsFile android.Path
+ commonToSdkLibraryAndImport
}
var _ Dependency = (*SdkLibrary)(nil)
var _ SdkLibraryDependency = (*SdkLibrary)(nil)
-func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
- useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
- // Add dependencies to the stubs library
- if useBuiltStubs {
- ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
- }
- ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
-
+func (module *SdkLibrary) getActiveApiScopes() apiScopes {
if module.sdkLibraryProperties.Has_system_and_test_apis {
- if useBuiltStubs {
- ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
- ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest))
- }
- ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem))
- ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest))
+ return allApiScopes
+ } else {
+ return apiScopes{apiScopePublic}
+ }
+}
+
+var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
+
+func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
+ if dt, ok := depTag.(dependencyTag); ok {
+ return dt == xmlPermissionsFileTag
+ }
+ return false
+}
+
+func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ for _, apiScope := range module.getActiveApiScopes() {
+ // Add dependencies to the stubs library
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
+
+ // And the api file
+ ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.docsName(apiScope))
+ }
+
+ if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
+ // Add dependency to the rule for generating the xml permissions file
+ ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
}
module.Library.deps(ctx)
@@ -191,67 +294,33 @@
module.Library.GenerateAndroidBuildActions(ctx)
}
- module.buildPermissionsFile(ctx)
-
// Record the paths to the header jars of the library (stubs and impl).
- // When this java_sdk_library is dependened from others via "libs" property,
+ // When this java_sdk_library is depended upon from others via "libs" property,
// the recorded paths will be returned depending on the link type of the caller.
ctx.VisitDirectDeps(func(to android.Module) {
otherName := ctx.OtherModuleName(to)
tag := ctx.OtherModuleDependencyTag(to)
if lib, ok := to.(Dependency); ok {
- switch tag {
- case publicApiStubsTag:
- module.publicApiStubsPath = lib.HeaderJars()
- module.publicApiStubsImplPath = lib.ImplementationJars()
- case systemApiStubsTag:
- module.systemApiStubsPath = lib.HeaderJars()
- module.systemApiStubsImplPath = lib.ImplementationJars()
- case testApiStubsTag:
- module.testApiStubsPath = lib.HeaderJars()
- module.testApiStubsImplPath = lib.ImplementationJars()
+ if scopeTag, ok := tag.(scopeDependencyTag); ok {
+ apiScope := scopeTag.apiScope
+ scopePaths := module.getScopePaths(apiScope)
+ scopePaths.stubsHeaderPath = lib.HeaderJars()
+ scopePaths.stubsImplPath = lib.ImplementationJars()
}
}
if doc, ok := to.(ApiFilePath); ok {
- switch tag {
- case publicApiFileTag:
- module.publicApiFilePath = doc.ApiFilePath()
- case systemApiFileTag:
- module.systemApiFilePath = doc.ApiFilePath()
- case testApiFileTag:
- module.testApiFilePath = doc.ApiFilePath()
- default:
+ if scopeTag, ok := tag.(scopeDependencyTag); ok {
+ apiScope := scopeTag.apiScope
+ scopePaths := module.getScopePaths(apiScope)
+ scopePaths.apiFilePath = doc.ApiFilePath()
+ } else {
ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
}
}
})
}
-func (module *SdkLibrary) buildPermissionsFile(ctx android.ModuleContext) {
- xmlContent := fmt.Sprintf(permissionsTemplate, module.BaseModuleName(), module.implPath())
- permissionsFile := android.PathForModuleOut(ctx, module.xmlFileName())
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.WriteFile,
- Output: permissionsFile,
- Description: "Generating " + module.BaseModuleName() + " permissions",
- Args: map[string]string{
- "content": xmlContent,
- },
- })
-
- module.permissionsFile = permissionsFile
-}
-
-func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
- switch tag {
- case ".xml":
- return android.Paths{module.permissionsFile}, nil
- }
- return module.Library.OutputFiles(tag)
-}
-
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
if proptools.Bool(module.sdkLibraryProperties.Api_only) {
return nil
@@ -273,42 +342,23 @@
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 and api files to the dist dir
+ for _, apiScope := range module.getActiveApiScopes() {
+ if scopePaths, ok := module.scopePaths[apiScope]; ok {
+ if len(scopePaths.stubsHeaderPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ scopePaths.stubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, apiScope.name,
+ module.BaseModuleName()+".jar")+")")
+ }
+ if scopePaths.apiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ scopePaths.apiFilePath.String()+
+ ":"+path.Join("apistubs", owner, apiScope.name, "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ }
}
}
},
@@ -317,27 +367,13 @@
}
// Module name of the stubs library
-func (module *SdkLibrary) stubsName(apiScope apiScope) string {
- stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
- switch apiScope {
- case apiScopeSystem:
- stubsName = stubsName + sdkSystemApiSuffix
- case apiScopeTest:
- stubsName = stubsName + sdkTestApiSuffix
- }
- return stubsName
+func (module *SdkLibrary) stubsName(apiScope *apiScope) string {
+ return apiScope.stubsModuleName(module.BaseModuleName())
}
// Module name of the docs
-func (module *SdkLibrary) docsName(apiScope apiScope) string {
- docsName := module.BaseModuleName() + sdkDocsSuffix
- switch apiScope {
- case apiScopeSystem:
- docsName = docsName + sdkSystemApiSuffix
- case apiScopeTest:
- docsName = docsName + sdkTestApiSuffix
- }
- return docsName
+func (module *SdkLibrary) docsName(apiScope *apiScope) string {
+ return apiScope.docsModuleName(module.BaseModuleName())
}
// Module name of the runtime implementation library
@@ -345,54 +381,17 @@
return module.BaseModuleName()
}
-// File path to the runtime implementation library
-func (module *SdkLibrary) implPath() string {
- if apexName := module.ApexName(); apexName != "" {
- // TODO(b/146468504): ApexName() is only a soong module name, not apex name.
- // In most cases, this works fine. But when apex_name is set or override_apex is used
- // this can be wrong.
- return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, module.implName())
- }
- partition := "system"
- if module.SocSpecific() {
- partition = "vendor"
- } else if module.DeviceSpecific() {
- partition = "odm"
- } else if module.ProductSpecific() {
- partition = "product"
- } else if module.SystemExtSpecific() {
- partition = "system_ext"
- }
- return "/" + partition + "/framework/" + module.implName() + ".jar"
-}
-
// Module name of the XML file for the lib
func (module *SdkLibrary) xmlFileName() string {
return module.BaseModuleName() + sdkXmlFileSuffix
}
-// SDK version that the stubs library is built against. Note that this is always
-// *current. Older stubs library built with a numberd SDK version is created from
-// the prebuilt jar.
-func (module *SdkLibrary) sdkVersionForScope(apiScope apiScope) string {
- switch apiScope {
- case apiScopePublic:
- return "current"
- case apiScopeSystem:
- return "system_current"
- case apiScopeTest:
- return "test_current"
- default:
- return "current"
- }
-}
-
// Get the sdk version for use when compiling the stubs library.
-func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) string {
+func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
if sdkDep.hasStandardLibs() {
// If building against a standard sdk then use the sdk version appropriate for the scope.
- return module.sdkVersionForScope(apiScope)
+ return apiScope.sdkVersion
} else {
// Otherwise, use no system module.
return "none"
@@ -402,53 +401,27 @@
// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
// api file for the current source
// TODO: remove this when apicheck is done in soong
-func (module *SdkLibrary) apiTagName(apiScope apiScope) string {
- apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
- switch apiScope {
- case apiScopeSystem:
- apiTagName = apiTagName + "_SYSTEM"
- case apiScopeTest:
- apiTagName = apiTagName + "_TEST"
- }
- return apiTagName
+func (module *SdkLibrary) apiTagName(apiScope *apiScope) string {
+ return strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1) + apiScope.apiFileMakeVariableSuffix
}
-func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
- name := ":" + module.BaseModuleName() + ".api."
- switch apiScope {
- case apiScopePublic:
- name = name + "public"
- case apiScopeSystem:
- name = name + "system"
- case apiScopeTest:
- name = name + "test"
- }
- name = name + ".latest"
- return name
+func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
+ return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
}
-func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
- name := ":" + module.BaseModuleName() + "-removed.api."
- switch apiScope {
- case apiScopePublic:
- name = name + "public"
- case apiScopeSystem:
- name = name + "system"
- case apiScopeTest:
- name = name + "test"
- }
- name = name + ".latest"
- return name
+func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
+ return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
}
// Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) {
props := struct {
Name *string
Srcs []string
Installable *bool
Sdk_version *string
System_modules *string
+ Patch_module *string
Libs []string
Soc_specific *bool
Device_specific *bool
@@ -457,9 +430,6 @@
Compile_dex *bool
Java_version *string
Product_variables struct {
- Unbundled_build struct {
- Enabled *bool
- }
Pdk struct {
Enabled *bool
}
@@ -476,12 +446,9 @@
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion)
props.System_modules = module.Library.Module.deviceProperties.System_modules
+ props.Patch_module = module.Library.Module.properties.Patch_module
props.Installable = proptools.BoolPtr(false)
props.Libs = module.sdkLibraryProperties.Stub_only_libs
- // Unbundled apps will use the prebult one from /prebuilts/sdk
- if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
- props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
- }
props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
@@ -505,7 +472,7 @@
// Creates a droiddoc module that creates stubs source files from the given full source
// files
-func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
props := struct {
Name *string
Srcs []string
@@ -590,16 +557,8 @@
// List of APIs identified from the provided source files are created. They are later
// compared against to the not-yet-released (a.k.a current) list of APIs and to the
// last-released (a.k.a numbered) list of API.
- currentApiFileName := "current.txt"
- removedApiFileName := "removed.txt"
- switch apiScope {
- case apiScopeSystem:
- currentApiFileName = "system-" + currentApiFileName
- removedApiFileName = "system-" + removedApiFileName
- case apiScopeTest:
- currentApiFileName = "test-" + currentApiFileName
- removedApiFileName = "test-" + removedApiFileName
- }
+ currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+ removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
apiDir := module.getApiDir()
currentApiFileName = path.Join(apiDir, currentApiFileName)
removedApiFileName = path.Join(apiDir, removedApiFileName)
@@ -624,89 +583,103 @@
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
- // creates a prebuilt_etc module to actually place the xml file under
- // <partition>/etc/permissions
- etcProps := struct {
+ props := struct {
Name *string
- Src *string
- Sub_dir *string
+ Lib_name *string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
System_ext_specific *bool
- }{}
- etcProps.Name = proptools.StringPtr(module.xmlFileName())
- etcProps.Src = proptools.StringPtr(":" + module.BaseModuleName() + "{.xml}")
- etcProps.Sub_dir = proptools.StringPtr("permissions")
- if module.SocSpecific() {
- etcProps.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- etcProps.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- etcProps.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- etcProps.System_ext_specific = proptools.BoolPtr(true)
+ }{
+ Name: proptools.StringPtr(module.xmlFileName()),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
}
- mctx.CreateModule(android.PrebuiltEtcFactory, &etcProps)
+
+ if module.SocSpecific() {
+ props.Soc_specific = proptools.BoolPtr(true)
+ } else if module.DeviceSpecific() {
+ props.Device_specific = proptools.BoolPtr(true)
+ } else if module.ProductSpecific() {
+ props.Product_specific = proptools.BoolPtr(true)
+ } else if module.SystemExtSpecific() {
+ props.System_ext_specific = proptools.BoolPtr(true)
+ }
+
+ mctx.CreateModule(sdkLibraryXmlFactory, &props)
}
-func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
- var api, v string
- if sdkVersion == "" || sdkVersion == "none" {
- api = "system"
- v = "current"
- } else if strings.Contains(sdkVersion, "_") {
- t := strings.Split(sdkVersion, "_")
- api = t[0]
- v = t[1]
+func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) android.Paths {
+ var ver sdkVersion
+ var kind sdkKind
+ if s.usePrebuilt(ctx) {
+ ver = s.version
+ kind = s.kind
} else {
- api = "public"
- v = sdkVersion
+ // We don't have prebuilt SDK for the specific sdkVersion.
+ // Instead of breaking the build, fallback to use "system_current"
+ ver = sdkVersionCurrent
+ kind = sdkSystem
}
- dir := filepath.Join("prebuilts", "sdk", v, api)
- jar := filepath.Join(dir, module.BaseModuleName()+".jar")
+
+ dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String())
+ jar := filepath.Join(dir, baseName+".jar")
jarPath := android.ExistentPathForSource(ctx, jar)
if !jarPath.Valid() {
if ctx.Config().AllowMissingDependencies() {
return android.Paths{android.PathForSource(ctx, jar)}
} else {
- ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", sdkVersion, jar)
+ ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.raw, jar)
}
return nil
}
return android.Paths{jarPath.Path()}
}
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
- // This module is just a wrapper for the stubs.
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
- return module.PrebuiltJars(ctx, sdkVersion)
+func (module *SdkLibrary) sdkJars(
+ ctx android.BaseModuleContext,
+ sdkVersion sdkSpec,
+ headerJars bool) android.Paths {
+
+ // If a specific numeric version has been requested then use prebuilt versions of the sdk.
+ if sdkVersion.version.isNumbered() {
+ return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
} else {
- if strings.HasPrefix(sdkVersion, "system_") {
- return module.systemApiStubsPath
- } else if sdkVersion == "" {
+ if !sdkVersion.specified() {
+ if headerJars {
+ return module.Library.HeaderJars()
+ } else {
+ return module.Library.ImplementationJars()
+ }
+ }
+ var apiScope *apiScope
+ switch sdkVersion.kind {
+ case sdkSystem:
+ apiScope = apiScopeSystem
+ case sdkTest:
+ apiScope = apiScopeTest
+ case sdkPrivate:
return module.Library.HeaderJars()
+ default:
+ apiScope = apiScopePublic
+ }
+
+ paths := module.getScopePaths(apiScope)
+ if headerJars {
+ return paths.stubsHeaderPath
} else {
- return module.publicApiStubsPath
+ return paths.stubsImplPath
}
}
}
// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
- // This module is just a wrapper for the stubs.
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
- return module.PrebuiltJars(ctx, sdkVersion)
- } else {
- if strings.HasPrefix(sdkVersion, "system_") {
- return module.systemApiStubsImplPath
- } else if sdkVersion == "" {
- return module.Library.ImplementationJars()
- } else {
- return module.publicApiStubsImplPath
- }
- }
+func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+ return module.sdkJars(ctx, sdkVersion, true /*headerJars*/)
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+ return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
}
func (module *SdkLibrary) SetNoDist() {
@@ -742,17 +715,14 @@
module.sdkLibraryProperties.Has_system_and_test_apis = hasSystemAndTestApis
module.sdkLibraryProperties.No_dist = proptools.BoolPtr(!hasSystemAndTestApis)
- scopes := []string{""}
- if hasSystemAndTestApis {
- scopes = append(scopes, "system-", "test-")
- }
-
missing_current_api := false
+ activeScopes := module.getActiveApiScopes()
+
apiDir := module.getApiDir()
- for _, scope := range scopes {
+ for _, scope := range activeScopes {
for _, api := range []string{"current.txt", "removed.txt"} {
- path := path.Join(mctx.ModuleDir(), apiDir, scope+api)
+ path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
p := android.ExistentPathForSource(mctx, path)
if !p.Valid() {
mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
@@ -772,22 +742,14 @@
mctx.ModuleErrorf("One or more current api files are missing. "+
"You can update them by:\n"+
"%s %q %s && m update-api",
- script, filepath.Join(mctx.ModuleDir(), apiDir), strings.Join(scopes, " "))
+ script, filepath.Join(mctx.ModuleDir(), apiDir),
+ strings.Join(activeScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
return
}
- // for public API stubs
- module.createStubsLibrary(mctx, apiScopePublic)
- module.createStubsSources(mctx, apiScopePublic)
-
- if hasSystemAndTestApis {
- // for system API stubs
- module.createStubsLibrary(mctx, apiScopeSystem)
- module.createStubsSources(mctx, apiScopeSystem)
-
- // for test API stubs
- module.createStubsLibrary(mctx, apiScopeTest)
- module.createStubsSources(mctx, apiScopeTest)
+ for _, scope := range activeScopes {
+ module.createStubsLibrary(mctx, scope)
+ module.createStubsSources(mctx, scope)
}
if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
@@ -833,21 +795,29 @@
// SDK library prebuilts
//
-type sdkLibraryImportProperties struct {
+// Properties associated with each api scope.
+type sdkLibraryScopeProperties struct {
Jars []string `android:"path"`
Sdk_version *string
- Installable *bool
-
// List of shared java libs that this module has dependencies to
Libs []string
+}
- // List of files to remove from the jar file(s)
- Exclude_files []string
+type sdkLibraryImportProperties struct {
+ // List of shared java libs, common to all scopes, that this module has
+ // dependencies to
+ Libs []string
- // List of directories to remove from the jar file(s)
- Exclude_dirs []string
+ // Properties associated with the public api scope.
+ Public sdkLibraryScopeProperties
+
+ // Properties associated with the system api scope.
+ System sdkLibraryScopeProperties
+
+ // Properties associated with the test api scope.
+ Test sdkLibraryScopeProperties
}
type sdkLibraryImport struct {
@@ -857,7 +827,7 @@
properties sdkLibraryImportProperties
- stubsPath android.Paths
+ commonToSdkLibraryAndImport
}
var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
@@ -868,7 +838,7 @@
module.AddProperties(&module.properties)
- android.InitPrebuiltModule(module, &module.properties.Jars)
+ android.InitPrebuiltModule(module, &[]string{""})
InitJavaModule(module, android.HostAndDeviceSupported)
android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -884,28 +854,55 @@
}
func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookContext) {
- // Creates a java import for the jar with ".stubs" suffix
- props := struct {
- Name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- }{}
- props.Name = proptools.StringPtr(module.BaseModuleName() + sdkStubsLibrarySuffix)
-
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
+ // If the build is configured to use prebuilts then force this to be preferred.
+ if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ module.prebuilt.ForcePrefer()
}
- mctx.CreateModule(ImportFactory, &props, &module.properties)
+ for apiScope, scopeProperties := range module.scopeProperties() {
+ if len(scopeProperties.Jars) == 0 {
+ continue
+ }
+
+ // Creates a java import for the jar with ".stubs" suffix
+ props := struct {
+ Name *string
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ System_ext_specific *bool
+ Sdk_version *string
+ Libs []string
+ Jars []string
+ Prefer *bool
+ }{}
+
+ props.Name = proptools.StringPtr(apiScope.stubsModuleName(module.BaseModuleName()))
+ props.Sdk_version = scopeProperties.Sdk_version
+ // Prepend any of the libs from the legacy public properties to the libs for each of the
+ // scopes to avoid having to duplicate them in each scope.
+ props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
+ props.Jars = scopeProperties.Jars
+
+ if module.SocSpecific() {
+ props.Soc_specific = proptools.BoolPtr(true)
+ } else if module.DeviceSpecific() {
+ props.Device_specific = proptools.BoolPtr(true)
+ } else if module.ProductSpecific() {
+ props.Product_specific = proptools.BoolPtr(true)
+ } else if module.SystemExtSpecific() {
+ props.System_ext_specific = proptools.BoolPtr(true)
+ }
+
+ // If the build should use prebuilt sdks then set prefer to true on the stubs library.
+ // That will cause the prebuilt version of the stubs to override the source version.
+ if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ props.Prefer = proptools.BoolPtr(true)
+ }
+
+ mctx.CreateModule(ImportFactory, &props)
+ }
javaSdkLibraries := javaSdkLibraries(mctx.Config())
javaSdkLibrariesLock.Lock()
@@ -913,9 +910,23 @@
*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
+func (module *sdkLibraryImport) scopeProperties() map[*apiScope]*sdkLibraryScopeProperties {
+ p := make(map[*apiScope]*sdkLibraryScopeProperties)
+ p[apiScopePublic] = &module.properties.Public
+ p[apiScopeSystem] = &module.properties.System
+ p[apiScopeTest] = &module.properties.Test
+ return p
+}
+
func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Add dependencies to the prebuilt stubs library
- ctx.AddVariationDependencies(nil, publicApiStubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
+ for apiScope, scopeProperties := range module.scopeProperties() {
+ if len(scopeProperties.Jars) == 0 {
+ continue
+ }
+
+ // Add dependencies to the prebuilt stubs library
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, apiScope.stubsModuleName(module.BaseModuleName()))
+ }
}
func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -923,21 +934,155 @@
ctx.VisitDirectDeps(func(to android.Module) {
tag := ctx.OtherModuleDependencyTag(to)
- switch tag {
- case publicApiStubsTag:
- module.stubsPath = to.(Dependency).HeaderJars()
+ if lib, ok := to.(Dependency); ok {
+ if scopeTag, ok := tag.(scopeDependencyTag); ok {
+ apiScope := scopeTag.apiScope
+ scopePaths := module.getScopePaths(apiScope)
+ scopePaths.stubsHeaderPath = lib.HeaderJars()
+ }
}
})
}
-// to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
- // This module is just a wrapper for the prebuilt stubs.
- return module.stubsPath
+func (module *sdkLibraryImport) sdkJars(
+ ctx android.BaseModuleContext,
+ sdkVersion sdkSpec) android.Paths {
+
+ // If a specific numeric version has been requested then use prebuilt versions of the sdk.
+ if sdkVersion.version.isNumbered() {
+ return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
+ }
+
+ var apiScope *apiScope
+ switch sdkVersion.kind {
+ case sdkSystem:
+ apiScope = apiScopeSystem
+ case sdkTest:
+ apiScope = apiScopeTest
+ default:
+ apiScope = apiScopePublic
+ }
+
+ paths := module.getScopePaths(apiScope)
+ return paths.stubsHeaderPath
}
// to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
+func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+ // This module is just a wrapper for the prebuilt stubs.
+ return module.sdkJars(ctx, sdkVersion)
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
// This module is just a wrapper for the stubs.
- return module.stubsPath
+ return module.sdkJars(ctx, sdkVersion)
+}
+
+//
+// java_sdk_library_xml
+//
+type sdkLibraryXml struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+ android.ApexModuleBase
+
+ properties sdkLibraryXmlProperties
+
+ outputFilePath android.OutputPath
+ installDirPath android.InstallPath
+}
+
+type sdkLibraryXmlProperties struct {
+ // canonical name of the lib
+ Lib_name *string
+}
+
+// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
+// Not to be used directly by users. java_sdk_library internally uses this.
+func sdkLibraryXmlFactory() android.Module {
+ module := &sdkLibraryXml{}
+
+ module.AddProperties(&module.properties)
+
+ android.InitApexModule(module)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+ return module
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) SubDir() string {
+ return "permissions"
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) OutputFile() android.OutputPath {
+ return module.outputFilePath
+}
+
+// from android.ApexModule
+func (module *sdkLibraryXml) AvailableFor(what string) bool {
+ return true
+}
+
+func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // do nothing
+}
+
+// File path to the runtime implementation library
+func (module *sdkLibraryXml) implPath() string {
+ implName := proptools.String(module.properties.Lib_name)
+ if apexName := module.ApexName(); apexName != "" {
+ // TODO(b/146468504): ApexName() is only a soong module name, not apex name.
+ // In most cases, this works fine. But when apex_name is set or override_apex is used
+ // this can be wrong.
+ return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
+ }
+ partition := "system"
+ if module.SocSpecific() {
+ partition = "vendor"
+ } else if module.DeviceSpecific() {
+ partition = "odm"
+ } else if module.ProductSpecific() {
+ partition = "product"
+ } else if module.SystemExtSpecific() {
+ partition = "system_ext"
+ }
+ return "/" + partition + "/framework/" + implName + ".jar"
+}
+
+func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ libName := proptools.String(module.properties.Lib_name)
+ xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath())
+
+ module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
+ rule := android.NewRuleBuilder()
+ rule.Command().
+ Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
+ Output(module.outputFilePath)
+
+ rule.Build(pctx, ctx, "java_sdk_xml", "Permission XML")
+
+ module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
+}
+
+func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
+ if !module.IsForPlatform() {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Disabled: true,
+ }}
+ }
+
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(module.outputFilePath),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_TAGS", "optional")
+ entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
+ },
+ },
+ }}
}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 9cabd77..ea6733d 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -211,6 +211,22 @@
java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
aidl: "-pprebuilts/sdk/29/public/framework.aidl",
},
+ {
+ name: "module_current",
+ properties: `sdk_version: "module_current",`,
+ bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
+ system: "core-current-stubs-system-modules",
+ java9classpath: []string{"android_module_lib_stubs_current"},
+ aidl: "-p" + buildDir + "/framework.aidl",
+ },
+ {
+ name: "system_server_current",
+ properties: `sdk_version: "system_server_current",`,
+ bootclasspath: []string{"android_module_lib_stubs_current", "services-stubs", "core-lambda-stubs"},
+ system: "core-current-stubs-system-modules",
+ java9classpath: []string{"android_module_lib_stubs_current", "services-stubs"},
+ aidl: "-p" + buildDir + "/framework.aidl",
+ },
}
for _, testcase := range classpathTestcases {
diff --git a/java/system_modules.go b/java/system_modules.go
index 92297c4..47de6e3 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -31,6 +31,15 @@
RegisterSystemModulesBuildComponents(android.InitRegistrationContext)
pctx.SourcePathVariable("moduleInfoJavaPath", "build/soong/scripts/jars-to-module-info-java.sh")
+
+ // Register sdk member types.
+ android.RegisterSdkMemberType(&systemModulesSdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_system_modules",
+ SupportsSdk: true,
+ TransitiveSdkMembers: true,
+ },
+ })
}
func RegisterSystemModulesBuildComponents(ctx android.RegistrationContext) {
@@ -66,6 +75,10 @@
},
},
"classpath", "outDir", "workDir")
+
+ // Dependency tag that causes the added dependencies to be added as java_header_libs
+ // to the sdk/module_exports/snapshot.
+ systemModulesLibsTag = android.DependencyTagForSdkMemberType(javaHeaderLibsSdkMemberType)
)
func TransformJarsToSystemModules(ctx android.ModuleContext, jars android.Paths) (android.Path, android.Paths) {
@@ -104,9 +117,19 @@
return module
}
+type SystemModulesProvider interface {
+ HeaderJars() android.Paths
+ OutputDirAndDeps() (android.Path, android.Paths)
+}
+
+var _ SystemModulesProvider = (*SystemModules)(nil)
+
+var _ SystemModulesProvider = (*systemModulesImport)(nil)
+
type SystemModules struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.SdkBase
properties SystemModulesProperties
@@ -122,10 +145,21 @@
Libs []string
}
+func (system *SystemModules) HeaderJars() android.Paths {
+ return system.headerJars
+}
+
+func (system *SystemModules) OutputDirAndDeps() (android.Path, android.Paths) {
+ if system.outputDir == nil || len(system.outputDeps) == 0 {
+ panic("Missing directory for system module dependency")
+ }
+ return system.outputDir, system.outputDeps
+}
+
func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var jars android.Paths
- ctx.VisitDirectDepsWithTag(libTag, func(module android.Module) {
+ ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
dep, _ := module.(Dependency)
jars = append(jars, dep.HeaderJars()...)
})
@@ -136,7 +170,7 @@
}
func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
- ctx.AddVariationDependencies(nil, libTag, system.properties.Libs...)
+ ctx.AddVariationDependencies(nil, systemModulesLibsTag, system.properties.Libs...)
}
func (system *SystemModules) AndroidMk() android.AndroidMkData {
@@ -173,6 +207,7 @@
android.InitPrebuiltModule(module, &module.properties.Libs)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+ android.InitSdkAwareModule(module)
return module
}
@@ -188,3 +223,37 @@
func (system *systemModulesImport) Prebuilt() *android.Prebuilt {
return &system.prebuilt
}
+
+type systemModulesSdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (mt *systemModulesSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool {
+ if _, ok := module.(*SystemModules); ok {
+ // A prebuilt system module cannot be added as a member of an sdk because the source and
+ // snapshot instances would conflict.
+ _, ok := module.(*systemModulesImport)
+ return !ok
+ }
+ return false
+}
+
+func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ variants := member.Variants()
+ if len(variants) != 1 {
+ sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+ for _, variant := range variants {
+ sdkModuleContext.ModuleErrorf(" %q", variant)
+ }
+ }
+ variant := variants[0]
+ systemModule := variant.(*SystemModules)
+
+ pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
+ // Add the references to the libraries that form the system module.
+ pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag())
+}
diff --git a/java/testing.go b/java/testing.go
index 08bae44..5b6a39b 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -18,6 +18,7 @@
"fmt"
"android/soong/android"
+ "android/soong/cc"
)
func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config {
@@ -30,6 +31,7 @@
"b.kt": nil,
"a.jar": nil,
"b.jar": nil,
+ "c.jar": nil,
"APP_NOTICE": nil,
"GENRULE_NOTICE": nil,
"LIB_NOTICE": nil,
@@ -48,8 +50,8 @@
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
"framework/aidl/a.aidl": nil,
-
- "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so": nil,
+ "assets_a/a": nil,
+ "assets_b/b": nil,
"prebuilts/sdk/14/public/android.jar": nil,
"prebuilts/sdk/14/public/framework.aidl": nil,
@@ -60,6 +62,7 @@
"prebuilts/sdk/29/public/android.jar": nil,
"prebuilts/sdk/29/public/framework.aidl": nil,
"prebuilts/sdk/29/system/android.jar": nil,
+ "prebuilts/sdk/29/system/foo.jar": nil,
"prebuilts/sdk/current/core/android.jar": nil,
"prebuilts/sdk/current/public/android.jar": nil,
"prebuilts/sdk/current/public/framework.aidl": nil,
@@ -118,6 +121,8 @@
"stubs/sources/foo/Foo.java": nil,
}
+ cc.GatherRequiredFilesForTest(mockFS)
+
for k, v := range fs {
mockFS[k] = v
}
@@ -142,6 +147,8 @@
"android_stubs_current",
"android_system_stubs_current",
"android_test_stubs_current",
+ "android_module_lib_stubs_current",
+ "services-stubs",
"core.current.stubs",
"core.platform.api.stubs",
"kotlin-stdlib",
diff --git a/python/python.go b/python/python.go
index c67c577..8b912be 100644
--- a/python/python.go
+++ b/python/python.go
@@ -340,6 +340,11 @@
// dependencies later.
ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite")
+ if ctx.Device() {
+ ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag,
+ "liblog")
+ }
+
if ctx.Target().Os.Bionic() {
ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag,
"libc", "libdl", "libm")
diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py
new file mode 100644
index 0000000..acda2d7
--- /dev/null
+++ b/python/tests/py-cmd_test.py
@@ -0,0 +1,78 @@
+# Copyright 2020 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.
+
+import os
+import site
+import sys
+
+# This file checks the visible python state against expected values when run
+# using a prebuilt python.
+
+failed = False
+def assert_equal(what, a, b):
+ global failed
+ if a != b:
+ print("Expected %s('%s') == '%s'" % (what, a, b))
+ failed = True
+
+assert_equal("__name__", __name__, "__main__")
+assert_equal("os.path.basename(__file__)", os.path.basename(__file__), "py-cmd_test.py")
+
+if os.getenv('ARGTEST', False):
+ assert_equal("len(sys.argv)", len(sys.argv), 3)
+ assert_equal("sys.argv[1]", sys.argv[1], "arg1")
+ assert_equal("sys.argv[2]", sys.argv[2], "arg2")
+elif os.getenv('ARGTEST2', False):
+ assert_equal("len(sys.argv)", len(sys.argv), 3)
+ assert_equal("sys.argv[1]", sys.argv[1], "--arg1")
+ assert_equal("sys.argv[2]", sys.argv[2], "arg2")
+else:
+ assert_equal("len(sys.argv)", len(sys.argv), 1)
+
+if os.getenv('ARGTEST_ONLY', False):
+ if failed:
+ sys.exit(1)
+ sys.exit(0)
+
+assert_equal("__package__", __package__, None)
+assert_equal("sys.argv[0]", sys.argv[0], 'py-cmd_test.py')
+if sys.version_info[0] == 2:
+ assert_equal("basename(sys.executable)", os.path.basename(sys.executable), 'py2-cmd')
+else:
+ assert_equal("basename(sys.executable)", os.path.basename(sys.executable), 'py3-cmd')
+assert_equal("sys.exec_prefix", sys.exec_prefix, sys.executable)
+assert_equal("sys.prefix", sys.prefix, sys.executable)
+assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
+
+if sys.version_info[0] == 2:
+ assert_equal("len(sys.path)", len(sys.path), 4)
+ assert_equal("sys.path[0]", sys.path[0], os.path.dirname(__file__))
+ assert_equal("sys.path[1]", sys.path[1], "/extra")
+ assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal"))
+ assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib"))
+else:
+ assert_equal("len(sys.path)", len(sys.path), 8)
+ assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
+ assert_equal("sys.path[1]", sys.path[1], "/extra")
+ assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
+ assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), '..'))
+ assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
+ assert_equal("sys.path[5]", sys.path[5], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
+ assert_equal("sys.path[6]", sys.path[6], os.path.join(sys.executable, "internal"))
+ assert_equal("sys.path[7]", sys.path[7], os.path.join(sys.executable, "internal", "stdlib"))
+
+if failed:
+ sys.exit(1)
+
+import testpkg.pycmd_test
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index 21187ed..35941dc 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -23,8 +23,11 @@
exit 1
fi
-if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) || ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ]]; then
- echo "Run 'm par_test par_test3' first"
+if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
+ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ||
+ ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
+ ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
+ echo "Run 'm par_test par_test3 py2-cmd py3-cmd' first"
exit 1
fi
@@ -44,4 +47,15 @@
ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 --arg1 arg2
+cd $(dirname ${BASH_SOURCE[0]})
+
+PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py
+
+ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
+ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+
+ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2
+ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2
+
echo "Passed!"
diff --git a/python/tests/testpkg/__init__.py b/python/tests/testpkg/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/tests/testpkg/__init__.py
diff --git a/python/tests/testpkg/pycmd_test.py b/python/tests/testpkg/pycmd_test.py
new file mode 100644
index 0000000..6b8a263
--- /dev/null
+++ b/python/tests/testpkg/pycmd_test.py
@@ -0,0 +1,33 @@
+# Copyright 2018 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.
+
+import os
+import sys
+
+# This file checks the visible python state against expected values when run
+# via the py*-cmd prebuilts
+
+failed = False
+def assert_equal(what, a, b):
+ global failed
+ if a != b:
+ print("Expected %s('%s') == '%s'" % (what, a, b))
+ failed = True
+
+assert_equal("__name__", __name__, "testpkg.pycmd_test")
+assert_equal("basename(__file__)", os.path.basename(__file__), "pycmd_test.py")
+assert_equal("__package__", __package__, "testpkg")
+
+if failed:
+ sys.exit(1)
diff --git a/rust/config/global.go b/rust/config/global.go
index fb9b14b..690d83e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -54,7 +54,6 @@
"-Wl,--fatal-warnings",
"-Wl,--pack-dyn-relocs=android+relr",
- "-Wl,--use-android-relr-tags",
"-Wl,--no-undefined",
"-Wl,--hash-style=gnu",
}
diff --git a/rust/config/whitelist.go b/rust/config/whitelist.go
index 7dfb002..a339050 100644
--- a/rust/config/whitelist.go
+++ b/rust/config/whitelist.go
@@ -2,6 +2,7 @@
var (
RustAllowedPaths = []string{
+ "external/minijail",
"external/rust",
"external/crosvm",
"external/adhd",
diff --git a/rust/rust.go b/rust/rust.go
index 14513fb..de6512c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -85,6 +85,10 @@
return true
}
+func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
+ return mod.InRamdisk()
+}
+
func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
return mod.InRecovery()
}
@@ -152,6 +156,10 @@
panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
}
+func (mod *Module) OnlyInRamdisk() bool {
+ return false
+}
+
func (mod *Module) OnlyInRecovery() bool {
return false
}
@@ -346,11 +354,6 @@
return nil
}
-func (mod *Module) AllStaticDeps() []string {
- // TODO(jiyong): do this for rust?
- return nil
-}
-
func (mod *Module) Module() android.Module {
return mod
}
@@ -615,21 +618,24 @@
linkFile := ccDep.OutputFile()
linkPath := linkPathFromFilePath(linkFile.Path())
libName := libNameFromFilePath(linkFile.Path())
+ depFlag := "-l" + libName
+
if !linkFile.Valid() {
ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
}
exportDep := false
-
switch depTag {
case cc.StaticDepTag:
+ depFlag = "-lstatic=" + libName
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ depPaths.depFlags = append(depPaths.depFlags, depFlag)
directStaticLibDeps = append(directStaticLibDeps, ccDep)
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
case cc.SharedDepTag:
+ depFlag = "-ldylib=" + libName
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ depPaths.depFlags = append(depPaths.depFlags, depFlag)
directSharedLibDeps = append(directSharedLibDeps, ccDep)
mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
exportDep = true
@@ -642,10 +648,10 @@
// Make sure these dependencies are propagated
if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
lib.linkDirs = append(lib.linkDirs, linkPath)
- lib.depFlags = append(lib.depFlags, "-l"+libName)
+ lib.depFlags = append(lib.depFlags, depFlag)
} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
- procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
+ procMacro.depFlags = append(procMacro.depFlags, depFlag)
}
}
@@ -697,13 +703,15 @@
func linkPathFromFilePath(filepath android.Path) string {
return strings.Split(filepath.String(), filepath.Base())[0]
}
+
func libNameFromFilePath(filepath android.Path) string {
- libName := strings.Split(filepath.Base(), filepath.Ext())[0]
+ libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
if strings.HasPrefix(libName, "lib") {
libName = libName[3:]
}
return libName
}
+
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 3be9ee7..020581d 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -22,6 +22,7 @@
"testing"
"android/soong/android"
+ "android/soong/cc"
)
var (
@@ -61,6 +62,8 @@
"libz.so": nil,
}
+ cc.GatherRequiredFilesForTest(fs)
+
return android.TestArchConfig(buildDir, nil, bp, fs)
}
@@ -114,13 +117,13 @@
// Test that we can extract the lib name from a lib path.
func TestLibNameFromFilePath(t *testing.T) {
- libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+ libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
libBarName := libNameFromFilePath(libBarPath)
libLibName := libNameFromFilePath(libLibPath)
- expectedResult := "bar"
+ expectedResult := "bar.so"
if libBarName != expectedResult {
t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 4aaff9a..e848b50 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -3,7 +3,6 @@
main: "manifest_fixer.py",
srcs: [
"manifest_fixer.py",
- "manifest.py",
],
version: {
py2: {
@@ -13,6 +12,9 @@
enabled: false,
},
},
+ libs: [
+ "manifest_utils",
+ ],
}
python_test_host {
@@ -21,6 +23,24 @@
srcs: [
"manifest_fixer_test.py",
"manifest_fixer.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+ libs: [
+ "manifest_utils",
+ ],
+ test_suites: ["general-tests"],
+}
+
+python_library_host {
+ name: "manifest_utils",
+ srcs: [
"manifest.py",
],
version: {
@@ -31,7 +51,6 @@
enabled: false,
},
},
- test_suites: ["general-tests"],
}
python_binary_host {
@@ -39,7 +58,6 @@
main: "manifest_check.py",
srcs: [
"manifest_check.py",
- "manifest.py",
],
version: {
py2: {
@@ -49,6 +67,9 @@
enabled: false,
},
},
+ libs: [
+ "manifest_utils",
+ ],
}
python_test_host {
@@ -57,7 +78,6 @@
srcs: [
"manifest_check_test.py",
"manifest_check.py",
- "manifest.py",
],
version: {
py2: {
@@ -67,6 +87,9 @@
enabled: false,
},
},
+ libs: [
+ "manifest_utils",
+ ],
test_suites: ["general-tests"],
}
@@ -91,7 +114,6 @@
main: "test_config_fixer.py",
srcs: [
"test_config_fixer.py",
- "manifest.py",
],
version: {
py2: {
@@ -101,6 +123,9 @@
enabled: false,
},
},
+ libs: [
+ "manifest_utils",
+ ],
}
python_test_host {
@@ -109,7 +134,6 @@
srcs: [
"test_config_fixer_test.py",
"test_config_fixer.py",
- "manifest.py",
],
version: {
py2: {
@@ -119,5 +143,8 @@
enabled: false,
},
},
+ libs: [
+ "manifest_utils",
+ ],
test_suites: ["general-tests"],
-}
\ No newline at end of file
+}
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 945bc18..c59732b 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -51,6 +51,9 @@
help='specify additional <uses-library> tag to add. android:requred is set to false')
parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
help='manifest is for a package built against the platform')
+ parser.add_argument('--logging-parent', dest='logging_parent', default='',
+ help=('specify logging parent as an additional <meta-data> tag. '
+ 'This value is ignored if the logging_parent meta-data tag is present.'))
parser.add_argument('--use-embedded-dex', dest='use_embedded_dex', action='store_true',
help=('specify if the app wants to use embedded dex and avoid extracted,'
'locally compiled code. Must not conflict if already declared '
@@ -124,6 +127,52 @@
element.setAttributeNode(target_attr)
+def add_logging_parent(doc, logging_parent_value):
+ """Add logging parent as an additional <meta-data> tag.
+
+ Args:
+ doc: The XML document. May be modified by this function.
+ logging_parent_value: A string representing the logging
+ parent value.
+ Raises:
+ RuntimeError: Invalid manifest
+ """
+ manifest = parse_manifest(doc)
+
+ logging_parent_key = 'android.content.pm.LOGGING_PARENT'
+ 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:
+ application = doc.createElement('application')
+ indent = get_indent(manifest.firstChild, 1)
+ first = manifest.firstChild
+ manifest.insertBefore(doc.createTextNode(indent), first)
+ manifest.insertBefore(application, first)
+
+ indent = get_indent(application.firstChild, 2)
+
+ last = application.lastChild
+ if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+ last = None
+
+ if not find_child_with_attribute(application, 'meta-data', android_ns,
+ 'name', logging_parent_key):
+ ul = doc.createElement('meta-data')
+ ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
+ ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
+ application.insertBefore(doc.createTextNode(indent), last)
+ application.insertBefore(ul, last)
+ last = application.lastChild
+
+ # align the closing tag with the opening tag if it's not
+ # indented
+ if last and last.nodeType != minidom.Node.TEXT_NODE:
+ indent = get_indent(application.previousSibling, 1)
+ application.appendChild(doc.createTextNode(indent))
+
+
def add_uses_libraries(doc, new_uses_libraries, required):
"""Add additional <uses-library> tags
@@ -291,6 +340,9 @@
if args.uses_non_sdk_api:
add_uses_non_sdk_api(doc)
+ if args.logging_parent:
+ add_logging_parent(doc, args.logging_parent)
+
if args.use_embedded_dex:
add_use_embedded_dex(doc)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index ea8095e..d6e7f26 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -226,6 +226,47 @@
self.assertEqual(output, expected)
+class AddLoggingParentTest(unittest.TestCase):
+ """Unit tests for add_logging_parent function."""
+
+ def add_logging_parent_test(self, input_manifest, logging_parent=None):
+ doc = minidom.parseString(input_manifest)
+ if logging_parent:
+ manifest_fixer.add_logging_parent(doc, logging_parent)
+ output = StringIO.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ '%s'
+ '</manifest>\n')
+
+ def uses_logging_parent(self, logging_parent=None):
+ attrs = ''
+ if logging_parent:
+ meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
+ 'android:value="%s"/>\n') % (logging_parent)
+ attrs += ' <application>\n %s </application>\n' % (meta_text)
+
+ return attrs
+
+ def test_no_logging_parent(self):
+ """Tests manifest_fixer with no logging_parent."""
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.uses_logging_parent()
+ output = self.add_logging_parent_test(manifest_input)
+ self.assertEqual(output, expected)
+
+ def test_logging_parent(self):
+ """Tests manifest_fixer with no logging_parent."""
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
+ output = self.add_logging_parent_test(manifest_input, 'FOO')
+ self.assertEqual(output, expected)
+
+
class AddUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
diff --git a/scripts/setup-android-build.sh b/scripts/setup-android-build.sh
new file mode 100755
index 0000000..dbb66c3
--- /dev/null
+++ b/scripts/setup-android-build.sh
@@ -0,0 +1,93 @@
+#! /bin/bash
+#
+# Sets the current directory as Android build output directory for a
+# given target by writing the "prefix script" to it. Commands prefixed
+# by this script are executed in the Android build environment. E.g.,
+# running
+# ./run <command>
+# runs <command> as if we issued
+# cd <source>
+# mount --bind <build dir> out
+# . build/envsetup.sh
+# lunch <config>
+# <command>
+# exit
+#
+# This arrangement eliminates the need to issue envsetup/lunch commands
+# manually, and allows to run multiple builds from the same shell.
+# Thus, if your source tree is in ~/aosp and you are building for
+# 'blueline' and 'cuttlefish', issuing
+# cd /sdx/blueline && \
+# ~/aosp/build/soong/scripts/setup-android-build.sh aosp_blueline-userdebug
+# cd /sdx/cuttlefish && \
+# ~/aosp/build/soong/scripts/setup-android-build.sh aosp_cf_arm64_phone-userdebug
+# sets up build directories in /sdx/blueline and /sdx/cuttlefish respectively.
+# After that, issue
+# /sdx/blueline/run m
+# to build blueline image, and issue
+# /sdx/cuttlefish atest CtsSecurityBulletinHostTestCases
+# to run CTS tests. Notice there is no need to change to a specific directory for that.
+#
+# Argument:
+# * configuration (one of those shown by `lunch` command).
+#
+set -e
+function die() { printf "$@"; exit 1; }
+
+# Find out where the source tree using the fact that we are in its
+# build/ subdirectory.
+[[ "$(uname)" == Linux ]] || die "This setup runs only on Linux\n"
+declare -r mydir="${0%/*}"
+declare -r source="${mydir%/build/soong/scripts}"
+[[ "/${mydir}/" =~ '/build/soong/scripts/' ]] || \
+ die "$0 should be in build/soong/scripts/ subdirectory of the source tree\n"
+[[ ! -e .repo && ! -e .git ]] || \
+ die "Current directory looks like source. You should be in the _target_ directory.\n"
+# Do not override old run script.
+if [[ -x ./run ]]; then
+ # Set variables from config=xxx and source=xxx comments in the existing script.
+ . <(sed -nr 's/^# *source=(.*)/oldsource=\1/p;s/^# *config=(.*)/oldconfig=\1/p' run)
+ die "This directory has been already set up to build Android for %s from %s.\n\
+Remove 'run' file if you want to set it up afresh\n" "$oldconfig" "$oldsource"
+fi
+
+(($#<2)) || die "usage: %s [<config>]\n" $0
+
+if (($#==1)); then
+ # Configuration is provided, emit run script.
+ declare -r config="$1"
+ declare -r target="$PWD"
+ cat >./run <<EOF
+#! /bin/bash
+# source=$source
+# config=$config
+declare -r cmd=\$(printf ' %q' "\$@")
+"$source/prebuilts/build-tools/linux-x86/bin/nsjail"\
+ -Mo -q -e -t 0\
+ -EANDROID_QUIET_BUILD=true \
+ -B / -B "$target:$source/out"\
+ --cwd "$source"\
+ --skip_setsid \
+ --keep_caps\
+ --disable_clone_newcgroup\
+ --disable_clone_newnet\
+ --rlimit_as soft\
+ --rlimit_core soft\
+ --rlimit_cpu soft\
+ --rlimit_fsize soft\
+ --rlimit_nofile soft\
+ --proc_rw\
+ --hostname $(hostname) \
+ --\
+ /bin/bash -i -c ". build/envsetup.sh && lunch "$config" &&\$cmd"
+EOF
+ chmod +x ./run
+else
+ # No configuration, show available ones.
+ printf "Please specify build target. Common values:\n"
+ (cd "$source"
+ . build/envsetup.sh
+ get_build_var COMMON_LUNCH_CHOICES | tr ' ' '\n' | pr -c4 -tT -W"$(tput cols)"
+ )
+ exit 1
+fi
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 7bb4b52..32d5b17 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -37,6 +37,8 @@
help=('AndroidManifest.xml that contains the original package name'))
parser.add_argument('--package-name', default='', dest='package_name',
help=('overwrite package fields in the test config'))
+ parser.add_argument('--test-file-name', default='', dest='test_file_name',
+ help=('overwrite test file name in the test config'))
parser.add_argument('input', help='input test config file')
parser.add_argument('output', help='output test config file')
return parser.parse_args()
@@ -46,7 +48,6 @@
manifest = parse_manifest(manifest_doc)
original_package = manifest.getAttribute('package')
- print('package: ' + original_package)
test_config = parse_test_config(test_config_doc)
tests = get_children_with_tag(test_config, 'test')
@@ -57,6 +58,18 @@
if option.getAttribute('name') == "package" and option.getAttribute('value') == original_package:
option.setAttribute('value', package_name)
+def overwrite_test_file_name(test_config_doc, test_file_name):
+
+ test_config = parse_test_config(test_config_doc)
+ tests = get_children_with_tag(test_config, 'target_preparer')
+
+ for test in tests:
+ if test.getAttribute('class') == "com.android.tradefed.targetprep.TestAppInstallSetup":
+ options = get_children_with_tag(test, 'option')
+ for option in options:
+ if option.getAttribute('name') == "test-file-name":
+ option.setAttribute('value', test_file_name)
+
def main():
"""Program entry point."""
try:
@@ -70,6 +83,9 @@
manifest_doc = minidom.parse(args.manifest)
overwrite_package_name(doc, manifest_doc, args.package_name)
+ if args.test_file_name:
+ overwrite_test_file_name(doc, args.test_file_name)
+
with open(args.output, 'wb') as f:
write_xml(f, doc)
diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py
index b90582e..1272c6b 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -67,5 +67,32 @@
self.assertEqual(expected, output.getvalue())
+class OverwriteTestFileNameTest(unittest.TestCase):
+ """ Unit tests for overwrite_test_file_name function """
+
+ test_config = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<configuration description="Runs some tests.">\n'
+ ' <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">\n'
+ ' <option name="test-file-name" value="%s"/>\n'
+ ' </target_preparer>\n'
+ ' <test class="com.android.tradefed.testtype.AndroidJUnitTest">\n'
+ ' <option name="package" value="com.android.foo"/>\n'
+ ' <option name="runtime-hint" value="20s"/>\n'
+ ' </test>\n'
+ '</configuration>\n')
+
+ def test_all(self):
+ doc = minidom.parseString(self.test_config % ("foo.apk"))
+
+ test_config_fixer.overwrite_test_file_name(doc, "bar.apk")
+ output = StringIO.StringIO()
+ test_config_fixer.write_xml(output, doc)
+
+ # Only the matching package name in a test node should be updated.
+ expected = self.test_config % ("bar.apk")
+ self.assertEqual(expected, output.getvalue())
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/sdk/bp.go b/sdk/bp.go
index 19fb70d..6936daf 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -22,6 +22,7 @@
type bpPropertySet struct {
properties map[string]interface{}
+ tags map[string]android.BpPropertyTag
order []string
}
@@ -29,6 +30,7 @@
func (s *bpPropertySet) init() {
s.properties = make(map[string]interface{})
+ s.tags = make(map[string]android.BpPropertyTag)
}
func (s *bpPropertySet) AddProperty(name string, value interface{}) {
@@ -40,6 +42,11 @@
s.order = append(s.order, name)
}
+func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag android.BpPropertyTag) {
+ s.AddProperty(name, value)
+ s.tags[name] = tag
+}
+
func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
set := &bpPropertySet{}
set.init()
@@ -51,16 +58,34 @@
return s.properties[name]
}
-func (s *bpPropertySet) copy() bpPropertySet {
- propertiesCopy := make(map[string]interface{})
- for p, v := range s.properties {
- propertiesCopy[p] = v
- }
+func (s *bpPropertySet) getTag(name string) interface{} {
+ return s.tags[name]
+}
- return bpPropertySet{
- properties: propertiesCopy,
- order: append([]string(nil), s.order...),
+func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
+ var newOrder []string
+ for _, name := range s.order {
+ value := s.properties[name]
+ tag := s.tags[name]
+ var newValue interface{}
+ var newTag android.BpPropertyTag
+ if propertySet, ok := value.(*bpPropertySet); ok {
+ newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
+ } else {
+ newValue, newTag = transformer.transformProperty(name, value, tag)
+ }
+
+ if newValue == nil {
+ // Delete the property from the map and exclude it from the new order.
+ delete(s.properties, name)
+ } else {
+ // Update the property in the map and add the name to the new order list.
+ s.properties[name] = newValue
+ s.tags[name] = newTag
+ newOrder = append(newOrder, name)
+ }
}
+ s.order = newOrder
}
func (s *bpPropertySet) setProperty(name string, value interface{}) {
@@ -68,6 +93,7 @@
s.AddProperty(name, value)
} else {
s.properties[name] = value
+ s.tags[name] = nil
}
}
@@ -95,19 +121,113 @@
}
type bpModule struct {
- bpPropertySet
+ *bpPropertySet
moduleType string
}
var _ android.BpModule = (*bpModule)(nil)
-func (m *bpModule) copy() *bpModule {
- return &bpModule{
- bpPropertySet: m.bpPropertySet.copy(),
- moduleType: m.moduleType,
- }
+type bpPropertyTransformer interface {
+ // Transform the property set, returning the new property set/tag to insert back into the
+ // parent property set (or module if this is the top level property set).
+ //
+ // This will be called before transforming the properties in the supplied set.
+ //
+ // The name will be "" for the top level property set.
+ //
+ // Returning (nil, ...) will cause the property set to be removed.
+ transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+
+ // Transform a property, return the new value/tag to insert back into the property set.
+ //
+ // Returning (nil, ...) will cause the property to be removed.
+ transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
}
+// Interface for transforming bpModule objects.
+type bpTransformer interface {
+ // Transform the module, returning the result.
+ //
+ // The method can either create a new module and return that, or modify the supplied module
+ // in place and return that.
+ //
+ // After this returns the transformer is applied to the contents of the returned module.
+ transformModule(module *bpModule) *bpModule
+
+ bpPropertyTransformer
+}
+
+type identityTransformation struct{}
+
+var _ bpTransformer = (*identityTransformation)(nil)
+
+func (t identityTransformation) transformModule(module *bpModule) *bpModule {
+ return module
+}
+
+func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ return propertySet, tag
+}
+
+func (t identityTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+ return value, tag
+}
+
+func (m *bpModule) deepCopy() *bpModule {
+ return m.transform(deepCopyTransformer)
+}
+
+func (m *bpModule) transform(transformer bpTransformer) *bpModule {
+ transformedModule := transformer.transformModule(m)
+ // Copy the contents of the returned property set into the module and then transform that.
+ transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
+ transformedModule.bpPropertySet.transform(transformer)
+ return transformedModule
+}
+
+type deepCopyTransformation struct{}
+
+func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
+ // Take a shallow copy of the module. Any mutable property values will be copied by the
+ // transformer.
+ moduleCopy := *module
+ return &moduleCopy
+}
+
+func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+ // Create a shallow copy of the properties map. Any mutable property values will be copied by the
+ // transformer.
+ propertiesCopy := make(map[string]interface{})
+ for propertyName, value := range propertySet.properties {
+ propertiesCopy[propertyName] = value
+ }
+
+ // Ditto for tags map.
+ tagsCopy := make(map[string]android.BpPropertyTag)
+ for propertyName, propertyTag := range propertySet.tags {
+ tagsCopy[propertyName] = propertyTag
+ }
+
+ // Create a new property set.
+ return &bpPropertySet{
+ properties: propertiesCopy,
+ tags: tagsCopy,
+ order: append([]string(nil), propertySet.order...),
+ }, tag
+}
+
+func (t deepCopyTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+ // Copy string slice, otherwise return value.
+ if values, ok := value.([]string); ok {
+ valuesCopy := make([]string, len(values))
+ copy(valuesCopy, values)
+ return valuesCopy, tag
+ }
+ return value, tag
+}
+
+var deepCopyTransformer bpTransformer = deepCopyTransformation{}
+
// A .bp file
type bpFile struct {
modules map[string]*bpModule
@@ -134,8 +254,9 @@
func (f *bpFile) newModule(moduleType string) *bpModule {
module := &bpModule{
- moduleType: moduleType,
+ moduleType: moduleType,
+ bpPropertySet: &bpPropertySet{},
}
- (&module.bpPropertySet).init()
+ module.bpPropertySet.init()
return module
}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9a75610..9c8e292 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -75,6 +75,7 @@
cc_library_shared {
name: "sdkmember",
+ system_shared_libs: [],
}
sdk_snapshot {
@@ -337,6 +338,68 @@
)
}
+func TestSnapshotWithCcBinary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "mymodule_exports",
+ native_binaries: ["mynativebinary"],
+ }
+
+ cc_binary {
+ name: "mynativebinary",
+ srcs: [
+ "Test.cpp",
+ ],
+ compile_multilib: "both",
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mymodule_exports", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "mymodule_exports_mynativebinary@current",
+ sdk_member_name: "mynativebinary",
+ compile_multilib: "both",
+ arch: {
+ arm64: {
+ srcs: ["arm64/bin/mynativebinary"],
+ },
+ arm: {
+ srcs: ["arm/bin/mynativebinary"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "mynativebinary",
+ prefer: false,
+ compile_multilib: "both",
+ arch: {
+ arm64: {
+ srcs: ["arm64/bin/mynativebinary"],
+ },
+ arm: {
+ srcs: ["arm/bin/mynativebinary"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "mymodule_exports@current",
+ native_binaries: ["mymodule_exports_mynativebinary@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativebinary/android_arm64_armv8-a/mynativebinary -> arm64/bin/mynativebinary
+.intermediates/mynativebinary/android_arm_armv7-a-neon/mynativebinary -> arm/bin/mynativebinary
+`),
+ )
+}
+
func TestSnapshotWithCcSharedLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 692c205..0737e5e 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -34,7 +34,7 @@
result := testSdkWithJava(t, `
sdk {
name: "mysdk",
- java_header_libs: ["myjavalib"],
+ java_header_libs: ["sdkmember"],
}
sdk_snapshot {
@@ -47,22 +47,36 @@
java_header_libs: ["sdkmember_mysdk_2"],
}
- java_import {
+ java_library {
name: "sdkmember",
- prefer: false,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
java_import {
name: "sdkmember_mysdk_1",
sdk_member_name: "sdkmember",
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
java_import {
name: "sdkmember_mysdk_2",
sdk_member_name: "sdkmember",
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
java_library {
@@ -569,3 +583,170 @@
checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
+
+func TestSnapshotWithJavaSystemModules(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["exported-system-module"],
+ java_system_modules: ["my-system-modules"],
+ }
+
+ java_system_modules {
+ name: "my-system-modules",
+ libs: ["system-module", "exported-system-module"],
+ }
+
+ java_library {
+ name: "system-module",
+ srcs: ["Test.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+
+ java_library {
+ name: "exported-system-module",
+ srcs: ["Test.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_exported-system-module@current",
+ sdk_member_name: "exported-system-module",
+ jars: ["java/exported-system-module.jar"],
+}
+
+java_import {
+ name: "exported-system-module",
+ prefer: false,
+ jars: ["java/exported-system-module.jar"],
+}
+
+java_import {
+ name: "mysdk_system-module@current",
+ sdk_member_name: "system-module",
+ visibility: ["//visibility:private"],
+ jars: ["java/system-module.jar"],
+}
+
+java_import {
+ name: "mysdk_system-module",
+ prefer: false,
+ visibility: ["//visibility:private"],
+ jars: ["java/system-module.jar"],
+}
+
+java_system_modules_import {
+ name: "mysdk_my-system-modules@current",
+ sdk_member_name: "my-system-modules",
+ libs: [
+ "mysdk_system-module@current",
+ "mysdk_exported-system-module@current",
+ ],
+}
+
+java_system_modules_import {
+ name: "my-system-modules",
+ prefer: false,
+ libs: [
+ "mysdk_system-module",
+ "exported-system-module",
+ ],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_header_libs: ["mysdk_exported-system-module@current"],
+ java_system_modules: ["mysdk_my-system-modules@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/exported-system-module/android_common/turbine-combined/exported-system-module.jar -> java/exported-system-module.jar
+.intermediates/system-module/android_common/turbine-combined/system-module.jar -> java/system-module.jar
+`),
+ )
+}
+
+func TestHostSnapshotWithJavaSystemModules(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ java_system_modules: ["my-system-modules"],
+ }
+
+ java_system_modules {
+ name: "my-system-modules",
+ device_supported: false,
+ host_supported: true,
+ libs: ["system-module"],
+ }
+
+ java_library {
+ name: "system-module",
+ device_supported: false,
+ host_supported: true,
+ srcs: ["Test.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_system-module@current",
+ sdk_member_name: "system-module",
+ visibility: ["//visibility:private"],
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/system-module.jar"],
+}
+
+java_import {
+ name: "mysdk_system-module",
+ prefer: false,
+ visibility: ["//visibility:private"],
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/system-module.jar"],
+}
+
+java_system_modules_import {
+ name: "mysdk_my-system-modules@current",
+ sdk_member_name: "my-system-modules",
+ device_supported: false,
+ host_supported: true,
+ libs: ["mysdk_system-module@current"],
+}
+
+java_system_modules_import {
+ name: "my-system-modules",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ libs: ["mysdk_system-module"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ java_system_modules: ["mysdk_my-system-modules@current"],
+}
+`),
+ checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 44e5cbb..dbe9ce2 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,6 +50,9 @@
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
+ // The set of exported members.
+ exportedMembers map[string]struct{}
+
properties sdkProperties
snapshotFile android.OptionalPath
@@ -65,11 +68,6 @@
Module_exports bool `blueprint:"mutated"`
}
-type sdkMemberDependencyTag struct {
- blueprint.BaseDependencyTag
- memberType android.SdkMemberType
-}
-
// Contains information about the sdk properties that list sdk members, e.g.
// Java_header_libs.
type sdkMemberListProperty struct {
@@ -81,7 +79,7 @@
// the dependency tag used for items in this list that can be used to determine the memberType
// for a resolved dependency.
- dependencyTag *sdkMemberDependencyTag
+ dependencyTag android.SdkMemberTypeDependencyTag
}
func (p *sdkMemberListProperty) propertyName() string {
@@ -167,9 +165,7 @@
memberType: memberType,
- dependencyTag: &sdkMemberDependencyTag{
- memberType: memberType,
- },
+ dependencyTag: android.DependencyTagForSdkMemberType(memberType),
}
listProperties = append(listProperties, memberListProperty)
@@ -224,6 +220,33 @@
return s
}
+func (s *sdk) memberListProperties() []*sdkMemberListProperty {
+ return s.dynamicSdkMemberTypes.memberListProperties
+}
+
+func (s *sdk) getExportedMembers() map[string]struct{} {
+ if s.exportedMembers == nil {
+ // Collect all the exported members.
+ s.exportedMembers = make(map[string]struct{})
+
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+
+ // Every member specified explicitly in the properties is exported by the sdk.
+ for _, name := range names {
+ s.exportedMembers[name] = struct{}{}
+ }
+ }
+ }
+
+ return s.exportedMembers
+}
+
+func (s *sdk) isInternalMember(memberName string) bool {
+ _, ok := s.getExportedMembers()[memberName]
+ return !ok
+}
+
func (s *sdk) snapshot() bool {
return s.properties.Snapshot
}
@@ -285,16 +308,19 @@
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
-type sdkMemberVesionedDepTag struct {
+type sdkMemberVersionedDepTag struct {
dependencyTag
member string
version string
}
+// Mark this tag so dependencies that use it are excluded from visibility enforcement.
+func (t sdkMemberVersionedDepTag) ExcludeFromVisibilityEnforcement() {}
+
// Step 1: create dependencies from an SDK module to its members.
func memberMutator(mctx android.BottomUpMutatorContext) {
if s, ok := mctx.Module().(*sdk); ok {
- for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
+ for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
tag := memberListProperty.dependencyTag
memberListProperty.memberType.AddDependencies(mctx, tag, names)
@@ -337,7 +363,7 @@
if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
if !m.ContainingSdk().Unversioned() {
memberName := m.MemberName()
- tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version}
+ tag := sdkMemberVersionedDepTag{member: memberName, version: m.ContainingSdk().Version}
mctx.AddReverseDependency(mctx.Module(), tag, memberName)
}
}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index d376e59..934bdae 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -111,8 +111,14 @@
sdk_version: "none",
}
+ java_defaults {
+ name: "java-defaults",
+ visibility: ["//other/bar"],
+ }
+
java_library {
name: "mypublicjavalib",
+ defaults: ["java-defaults"],
visibility: ["//visibility:public"],
srcs: ["Test.java"],
system_modules: "none",
diff --git a/sdk/testing.go b/sdk/testing.go
index c9cc30f..ae0620d 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -53,6 +53,8 @@
"myapex.pk8": nil,
}
+ cc.GatherRequiredFilesForTest(mockFS)
+
for k, v := range fs {
mockFS[k] = v
}
@@ -72,6 +74,7 @@
java.RegisterJavaBuildComponents(ctx)
java.RegisterAppBuildComponents(ctx)
java.RegisterStubsBuildComponents(ctx)
+ java.RegisterSystemModulesBuildComponents(ctx)
// from cc package
cc.RegisterRequiredBuildComponentsForTest(ctx)
diff --git a/sdk/update.go b/sdk/update.go
index 5bc3b83..ff567be 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -105,23 +105,23 @@
// Collect all the members.
//
// The members are first grouped by type and then grouped by name. The order of
-// the types is the order they are referenced in android.SdkMemberTypes. The
-// names are in order in which the dependencies were added.
+// the types is the order they are referenced in android.SdkMemberTypesRegistry.
+// The names are in the order in which the dependencies were added.
func (s *sdk) collectMembers(ctx android.ModuleContext) []*sdkMember {
byType := make(map[android.SdkMemberType][]*sdkMember)
byName := make(map[string]*sdkMember)
- ctx.VisitDirectDeps(func(m android.Module) {
- tag := ctx.OtherModuleDependencyTag(m)
- if memberTag, ok := tag.(*sdkMemberDependencyTag); ok {
- memberType := memberTag.memberType
+ ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ tag := ctx.OtherModuleDependencyTag(child)
+ if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
+ memberType := memberTag.SdkMemberType()
// Make sure that the resolved module is allowed in the member list property.
- if !memberType.IsInstance(m) {
- ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(m), memberType.SdkPropertyName())
+ if !memberType.IsInstance(child) {
+ ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
}
- name := ctx.OtherModuleName(m)
+ name := ctx.OtherModuleName(child)
member := byName[name]
if member == nil {
@@ -130,12 +130,20 @@
byType[memberType] = append(byType[memberType], member)
}
- member.variants = append(member.variants, m.(android.SdkAware))
+ // Only append new variants to the list. This is needed because a member can be both
+ // exported by the sdk and also be a transitive sdk member.
+ member.variants = appendUniqueVariants(member.variants, child.(android.SdkAware))
+
+ // If the member type supports transitive sdk members then recurse down into
+ // its dependencies, otherwise exit traversal.
+ return memberType.HasTransitiveSdkMembers()
}
+
+ return false
})
var members []*sdkMember
- for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
+ for _, memberListProperty := range s.memberListProperties() {
membersOfType := byType[memberListProperty.memberType]
members = append(members, membersOfType...)
}
@@ -143,6 +151,15 @@
return members
}
+func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
+ for _, v := range variants {
+ if v == newVariant {
+ return variants
+ }
+ }
+ return append(variants, newVariant)
+}
+
// SDK directory structure
// <sdk_root>/
// Android.bp : definition of a 'sdk' module is here. This is a hand-made one.
@@ -194,16 +211,23 @@
member.memberType.BuildSnapshot(ctx, builder, member)
}
+ // Create a transformer that will transform an unversioned module into a versioned module.
+ unversionedToVersionedTransformer := unversionedToVersionedTransformation{builder: builder}
+
+ // Create a transformer that will transform an unversioned module by replacing any references
+ // to internal members with a unique module name and setting prefer: false.
+ unversionedTransformer := unversionedTransformation{builder: builder}
+
for _, unversioned := range builder.prebuiltOrder {
// Copy the unversioned module so it can be modified to make it versioned.
- versioned := unversioned.copy()
- name := versioned.properties["name"].(string)
- versioned.setProperty("name", builder.versionedSdkMemberName(name))
- versioned.insertAfter("name", "sdk_member_name", name)
+ versioned := unversioned.deepCopy()
+
+ // Transform the unversioned module into a versioned one.
+ versioned.transform(unversionedToVersionedTransformer)
bpFile.AddModule(versioned)
- // Set prefer: false - this is not strictly required as that is the default.
- unversioned.insertAfter("name", "prefer", false)
+ // Transform the unversioned module to make it suitable for use in the snapshot.
+ unversioned.transform(unversionedTransformer)
bpFile.AddModule(unversioned)
}
@@ -225,7 +249,7 @@
}
addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
- for _, memberListProperty := range s.dynamicSdkMemberTypes.memberListProperties {
+ for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
if len(names) > 0 {
snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
@@ -281,12 +305,64 @@
return outputZipFile
}
+type propertyTag struct {
+ name string
+}
+
+var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+
+type unversionedToVersionedTransformation struct {
+ identityTransformation
+ builder *snapshotBuilder
+}
+
+func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
+ // Use a versioned name for the module but remember the original name for the
+ // snapshot.
+ name := module.getValue("name").(string)
+ module.setProperty("name", t.builder.versionedSdkMemberName(name))
+ module.insertAfter("name", "sdk_member_name", name)
+ return module
+}
+
+func (t unversionedToVersionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+ if tag == sdkMemberReferencePropertyTag {
+ return t.builder.versionedSdkMemberNames(value.([]string)), tag
+ } else {
+ return value, tag
+ }
+}
+
+type unversionedTransformation struct {
+ identityTransformation
+ builder *snapshotBuilder
+}
+
+func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
+ // If the module is an internal member then use a unique name for it.
+ name := module.getValue("name").(string)
+ module.setProperty("name", t.builder.unversionedSdkMemberName(name))
+
+ // Set prefer: false - this is not strictly required as that is the default.
+ module.insertAfter("name", "prefer", false)
+
+ return module
+}
+
+func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+ if tag == sdkMemberReferencePropertyTag {
+ return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+ } else {
+ return value, tag
+ }
+}
+
func generateBpContents(contents *generatedContents, bpFile *bpFile) {
contents.Printfln("// This is auto-generated. DO NOT EDIT.")
for _, bpModule := range bpFile.order {
contents.Printfln("")
contents.Printfln("%s {", bpModule.moduleType)
- outputPropertySet(contents, &bpModule.bpPropertySet)
+ outputPropertySet(contents, bpModule.bpPropertySet)
contents.Printfln("}")
}
}
@@ -294,7 +370,7 @@
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
contents.Indent()
for _, name := range set.order {
- value := set.properties[name]
+ value := set.getValue(name)
reflectedValue := reflect.ValueOf(value)
t := reflectedValue.Type()
@@ -404,11 +480,17 @@
m := s.bpFile.newModule(moduleType)
m.AddProperty("name", name)
- // Extract visibility information from a member variant. All variants have the same
- // visibility so it doesn't matter which one is used.
- visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
- if len(visibility) != 0 {
- m.AddProperty("visibility", visibility)
+ if s.sdk.isInternalMember(name) {
+ // An internal member is only referenced from the sdk snapshot which is in the
+ // same package so can be marked as private.
+ m.AddProperty("visibility", []string{"//visibility:private"})
+ } else {
+ // Extract visibility information from a member variant. All variants have the same
+ // visibility so it doesn't matter which one is used.
+ visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
+ if len(visibility) != 0 {
+ m.AddProperty("visibility", visibility)
+ }
}
addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
@@ -427,6 +509,10 @@
}
}
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
+ return sdkMemberReferencePropertyTag
+}
+
// Get a versioned name appropriate for the SDK snapshot version being taken.
func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
@@ -440,6 +526,23 @@
return references
}
+// Get an internal name unique to the sdk.
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
+ if s.sdk.isInternalMember(unversionedName) {
+ return s.ctx.ModuleName() + "_" + unversionedName
+ } else {
+ return unversionedName
+ }
+}
+
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+ var references []string = nil
+ for _, m := range members {
+ references = append(references, s.unversionedSdkMemberName(m))
+ }
+ return references
+}
+
var _ android.SdkMember = (*sdkMember)(nil)
type sdkMember struct {
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index c35d8b9..a46dce9 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -44,17 +44,16 @@
CommandDeps: []string{"$template"},
}, "name", "template", "extraConfigs")
-func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool) (path android.Path, autogenPath android.WritablePath) {
+func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
p := getTestConfig(ctx, prop)
if !Bool(autoGenConfig) && p != nil {
return p, nil
- } else if !android.InList("cts", testSuites) && BoolDefault(autoGenConfig, true) {
+ } else if BoolDefault(autoGenConfig, true) && (!android.InList("cts", testSuites) || testConfigTemplateProp != nil) {
outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config")
return nil, outputFile
} else {
// CTS modules can be used for test data, so test config files must be
- // explicitly created using AndroidTest.xml
- // TODO(b/112602712): remove the path check
+ // explicitly created using AndroidTest.xml or test_config_template.
return nil, nil
}
}
@@ -130,7 +129,7 @@
func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -149,7 +148,7 @@
func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -164,7 +163,7 @@
func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -184,7 +183,7 @@
func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp *string,
testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -199,7 +198,7 @@
func AutoGenRustTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePathString := "${RustHostTestConfigTemplate}"
if ctx.Device() {
@@ -226,7 +225,7 @@
func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
template := "${InstrumentationTestConfigTemplate}"
moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp)
diff --git a/ui/build/build.go b/ui/build/build.go
index 1c2d864..f3feac2 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -19,6 +19,8 @@
"os"
"path/filepath"
"text/template"
+
+ "android/soong/ui/metrics"
)
// Ensures the out directory exists, and has the proper files to prevent kati
@@ -46,8 +48,11 @@
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
builddir = {{.OutDir}}
-pool local_pool
+{{if .UseRemoteBuild }}pool local_pool
depth = {{.Parallel}}
+{{end -}}
+pool highmem_pool
+ depth = {{.HighmemParallel}}
build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}}
@@ -139,6 +144,9 @@
ctx.Verboseln("Environment:", config.Environment().Environ())
ctx.Verbosef("Total RAM: %dGB", config.TotalRAM()/1024/1024/1024)
+ ctx.BeginTrace(metrics.Total, "total")
+ defer ctx.EndTrace()
+
if config.SkipMake() {
ctx.Verboseln("Skipping Make/Kati as requested")
what = what & (BuildSoong | BuildNinja)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 1c4f574..36d4f04 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -237,6 +237,7 @@
if fi.IsDir() {
if err := os.Remove(old); err == nil {
ctx.Println("Removed directory that is no longer installed: ", old)
+ cleanEmptyDirs(ctx, filepath.Dir(old))
} else {
ctx.Println("Failed to remove directory that is no longer installed (%q): %v", old, err)
ctx.Println("It's recommended to run `m installclean`")
@@ -244,6 +245,7 @@
} else {
if err := os.Remove(old); err == nil {
ctx.Println("Removed file that is no longer installed: ", old)
+ cleanEmptyDirs(ctx, filepath.Dir(old))
} else if !os.IsNotExist(err) {
ctx.Fatalf("Failed to remove file that is no longer installed (%q): %v", old, err)
}
@@ -254,3 +256,16 @@
// Use the new list as the base for the next build
os.Rename(file, oldFile)
}
+
+func cleanEmptyDirs(ctx Context, dir string) {
+ files, err := ioutil.ReadDir(dir)
+ if err != nil || len(files) > 0 {
+ return
+ }
+ if err := os.Remove(dir); err == nil {
+ ctx.Println("Removed directory that is no longer installed: ", dir)
+ } else {
+ ctx.Fatalf("Failed to remove directory that is no longer installed (%q): %v", dir, err)
+ }
+ cleanEmptyDirs(ctx, filepath.Dir(dir))
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index c084171..5b9d10a 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -722,6 +722,33 @@
return c.parallel
}
+func (c *configImpl) HighmemParallel() int {
+ if i, ok := c.environ.GetInt("NINJA_HIGHMEM_NUM_JOBS"); ok {
+ return i
+ }
+
+ const minMemPerHighmemProcess = 8 * 1024 * 1024 * 1024
+ parallel := c.Parallel()
+ if c.UseRemoteBuild() {
+ // Ninja doesn't support nested pools, and when remote builds are enabled the total ninja parallelism
+ // is set very high (i.e. 500). Using a large value here would cause the total number of running jobs
+ // to be the sum of the sizes of the local and highmem pools, which will cause extra CPU contention.
+ // Return 1/16th of the size of the local pool, rounding up.
+ return (parallel + 15) / 16
+ } else if c.totalRAM == 0 {
+ // Couldn't detect the total RAM, don't restrict highmem processes.
+ return parallel
+ } else if c.totalRAM <= 32*1024*1024*1024 {
+ // Less than 32GB of ram, restrict to 2 highmem processes
+ return 2
+ } else if p := int(c.totalRAM / minMemPerHighmemProcess); p < parallel {
+ // If less than 8GB total RAM per process, reduce the number of highmem processes
+ return p
+ }
+ // No restriction on highmem processes
+ return parallel
+}
+
func (c *configImpl) TotalRAM() uint64 {
return c.totalRAM
}
@@ -760,6 +787,48 @@
return false
}
+func (c *configImpl) UseRBEJAVAC() bool {
+ if !c.UseRBE() {
+ return false
+ }
+
+ if v, ok := c.environ.Get("RBE_JAVAC"); ok {
+ v = strings.TrimSpace(v)
+ if v != "" && v != "false" {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *configImpl) UseRBER8() bool {
+ if !c.UseRBE() {
+ return false
+ }
+
+ if v, ok := c.environ.Get("RBE_R8"); ok {
+ v = strings.TrimSpace(v)
+ if v != "" && v != "false" {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *configImpl) UseRBED8() bool {
+ if !c.UseRBE() {
+ return false
+ }
+
+ if v, ok := c.environ.Get("RBE_D8"); ok {
+ v = strings.TrimSpace(v)
+ if v != "" && v != "false" {
+ return true
+ }
+ }
+ return false
+}
+
func (c *configImpl) StartRBE() bool {
if !c.UseRBE() {
return false
@@ -782,10 +851,11 @@
// gomacc) are run in parallel. Note the parallelism of all other jobs is
// still limited by Parallel()
func (c *configImpl) RemoteParallel() int {
- if v, ok := c.environ.Get("NINJA_REMOTE_NUM_JOBS"); ok {
- if i, err := strconv.Atoi(v); err == nil {
- return i
- }
+ if !c.UseRemoteBuild() {
+ return 0
+ }
+ if i, ok := c.environ.GetInt("NINJA_REMOTE_NUM_JOBS"); ok {
+ return i
}
return 500
}
diff --git a/ui/build/config_darwin.go b/ui/build/config_darwin.go
index 480d8d1..fe74e31 100644
--- a/ui/build/config_darwin.go
+++ b/ui/build/config_darwin.go
@@ -22,7 +22,7 @@
func detectTotalRAM(ctx Context) uint64 {
s, err := syscall.Sysctl("hw.memsize")
if err != nil {
- ctx.Printf("Failed to get system memory size: %s")
+ ctx.Printf("Failed to get system memory size: %v", err)
return 0
}
@@ -32,7 +32,7 @@
}
if len(s) != 8 {
- ctx.Printf("Failed to get system memory size, returned %d bytes, 8", len(s))
+ ctx.Printf("Failed to get system memory size, returned %d bytes, expecting 8 bytes", len(s))
return 0
}
diff --git a/ui/build/config_linux.go b/ui/build/config_linux.go
index 9e1bdc7..162d372 100644
--- a/ui/build/config_linux.go
+++ b/ui/build/config_linux.go
@@ -20,9 +20,8 @@
var info syscall.Sysinfo_t
err := syscall.Sysinfo(&info)
if err != nil {
- ctx.Printf("Failed to get system memory size: %s")
+ ctx.Printf("Failed to get system memory size: %v", err)
return 0
}
- memBytes := uint64(info.Totalram) * uint64(info.Unit)
- return memBytes
+ return uint64(info.Totalram) * uint64(info.Unit)
}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index c3da38b..ce8f968 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -191,6 +191,8 @@
"CC_WRAPPER",
"CXX_WRAPPER",
"JAVAC_WRAPPER",
+ "R8_WRAPPER",
+ "D8_WRAPPER",
// ccache settings
"CCACHE_COMPILERCHECK",
diff --git a/ui/build/environment.go b/ui/build/environment.go
index d8ff7f2..9bca7c0 100644
--- a/ui/build/environment.go
+++ b/ui/build/environment.go
@@ -19,6 +19,7 @@
"fmt"
"io"
"os"
+ "strconv"
"strings"
)
@@ -44,6 +45,17 @@
return "", false
}
+// Get returns the int value associated with the key, and whether it exists
+// and is a valid int.
+func (e *Environment) GetInt(key string) (int, bool) {
+ if v, ok := e.Get(key); ok {
+ if i, err := strconv.Atoi(v); err == nil {
+ return i, true
+ }
+ }
+ return 0, false
+}
+
// Set sets the value associated with the key, overwriting the current value
// if it exists.
func (e *Environment) Set(key, value string) {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 0b56b67..0749fe3 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -133,6 +133,8 @@
"FLAG_invocation_id",
"FLAG_log_dir",
"FLAG_platform",
+ "FLAG_remote_accept_cache",
+ "FLAG_remote_update_cache",
"FLAG_server_address",
// ccache settings
@@ -140,6 +142,7 @@
"CCACHE_SLOPPINESS",
"CCACHE_BASEDIR",
"CCACHE_CPP2",
+ "CCACHE_DIR",
}, config.BuildBrokenNinjaUsesEnvVars()...)...)
}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 64bbbf3..8254e4a 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -30,6 +30,7 @@
RunSoong = "soong"
PrimaryNinja = "ninja"
TestRun = "test"
+ Total = "total"
)
type Metrics struct {
@@ -56,6 +57,8 @@
case PrimaryNinja:
m.metrics.NinjaRuns = append(m.metrics.NinjaRuns, &perf)
break
+ case Total:
+ m.metrics.Total = &perf
default:
// ignored
}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 0fe5a0d..3986d0e 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -195,10 +195,12 @@
// The metrics for calling Soong.
SoongRuns []*PerfInfo `protobuf:"bytes,19,rep,name=soong_runs,json=soongRuns" json:"soong_runs,omitempty"`
// The metrics for calling Ninja.
- NinjaRuns []*PerfInfo `protobuf:"bytes,20,rep,name=ninja_runs,json=ninjaRuns" json:"ninja_runs,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ NinjaRuns []*PerfInfo `protobuf:"bytes,20,rep,name=ninja_runs,json=ninjaRuns" json:"ninja_runs,omitempty"`
+ // The metrics for the whole build
+ Total *PerfInfo `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *MetricsBase) Reset() { *m = MetricsBase{} }
@@ -371,6 +373,13 @@
return nil
}
+func (m *MetricsBase) GetTotal() *PerfInfo {
+ if m != nil {
+ return m.Total
+ }
+ return nil
+}
+
type PerfInfo struct {
// The description for the phase/action/part while the tool running.
Desc *string `protobuf:"bytes,1,opt,name=desc" json:"desc,omitempty"`
@@ -612,58 +621,58 @@
func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
var fileDescriptor_6039342a2ba47b72 = []byte{
- // 834 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x6f, 0x6b, 0xdb, 0x46,
- 0x18, 0xaf, 0x62, 0x25, 0xb6, 0x1e, 0xc5, 0xae, 0x7a, 0xc9, 0xa8, 0xba, 0x12, 0x66, 0xc4, 0x3a,
- 0xf2, 0x62, 0x75, 0x8b, 0x29, 0xa1, 0x98, 0x32, 0x48, 0x1c, 0x53, 0xba, 0x60, 0xbb, 0x28, 0x71,
- 0x57, 0xb6, 0x17, 0x87, 0x22, 0x9d, 0x1b, 0x75, 0x96, 0x4e, 0xdc, 0x9d, 0xca, 0xfc, 0x21, 0xf6,
- 0x4d, 0xf6, 0xb5, 0xf6, 0x3d, 0xc6, 0x3d, 0x27, 0x39, 0x0a, 0x78, 0x34, 0xf4, 0xdd, 0xe9, 0xf9,
- 0xfd, 0xb9, 0xdf, 0x73, 0xd2, 0x3d, 0x82, 0x6e, 0xc6, 0x94, 0x48, 0x63, 0x39, 0x28, 0x04, 0x57,
- 0x9c, 0x1c, 0x48, 0xce, 0xf3, 0x4f, 0xf4, 0xba, 0x4c, 0x57, 0x09, 0xad, 0xa0, 0xe0, 0x1f, 0x07,
- 0xdc, 0xa9, 0x59, 0x9f, 0x45, 0x92, 0x91, 0x97, 0x70, 0x68, 0x08, 0x49, 0xa4, 0x18, 0x55, 0x69,
- 0xc6, 0xa4, 0x8a, 0xb2, 0xc2, 0xb7, 0xfa, 0xd6, 0x71, 0x2b, 0x24, 0x88, 0x9d, 0x47, 0x8a, 0x5d,
- 0xd5, 0x08, 0x79, 0x02, 0x1d, 0xa3, 0x48, 0x13, 0x7f, 0xa7, 0x6f, 0x1d, 0x3b, 0x61, 0x1b, 0x9f,
- 0xdf, 0x25, 0x64, 0x04, 0x4f, 0x8a, 0x55, 0xa4, 0x96, 0x5c, 0x64, 0xf4, 0x0b, 0x13, 0x32, 0xe5,
- 0x39, 0x8d, 0x79, 0xc2, 0xf2, 0x28, 0x63, 0x7e, 0x0b, 0xb9, 0x8f, 0x6b, 0xc2, 0x07, 0x83, 0x8f,
- 0x2b, 0x98, 0x3c, 0x83, 0x9e, 0x8a, 0xc4, 0x27, 0xa6, 0x68, 0x21, 0x78, 0x52, 0xc6, 0xca, 0xb7,
- 0x51, 0xd0, 0x35, 0xd5, 0xf7, 0xa6, 0x48, 0x12, 0x38, 0xac, 0x68, 0x26, 0xc4, 0x97, 0x48, 0xa4,
- 0x51, 0xae, 0xfc, 0xdd, 0xbe, 0x75, 0xdc, 0x1b, 0x3e, 0x1f, 0x6c, 0xe9, 0x79, 0xd0, 0xe8, 0x77,
- 0x70, 0xa6, 0x91, 0x0f, 0x46, 0x34, 0x6a, 0x4d, 0x66, 0x6f, 0x43, 0x62, 0xfc, 0x9a, 0x00, 0x99,
- 0x83, 0x5b, 0xed, 0x12, 0x89, 0xf8, 0xc6, 0xdf, 0x43, 0xf3, 0x67, 0x5f, 0x35, 0x3f, 0x15, 0xf1,
- 0xcd, 0xa8, 0xbd, 0x98, 0x5d, 0xcc, 0xe6, 0xbf, 0xcd, 0x42, 0x30, 0x16, 0xba, 0x48, 0x06, 0x70,
- 0xd0, 0x30, 0xdc, 0xa4, 0x6e, 0x63, 0x8b, 0x8f, 0x6e, 0x89, 0x75, 0x80, 0x9f, 0xa1, 0x8a, 0x45,
- 0xe3, 0xa2, 0xdc, 0xd0, 0x3b, 0x48, 0xf7, 0x0c, 0x32, 0x2e, 0xca, 0x9a, 0x7d, 0x01, 0xce, 0x0d,
- 0x97, 0x55, 0x58, 0xe7, 0x9b, 0xc2, 0x76, 0xb4, 0x01, 0x46, 0x0d, 0xa1, 0x8b, 0x66, 0xc3, 0x3c,
- 0x31, 0x86, 0xf0, 0x4d, 0x86, 0xae, 0x36, 0x19, 0xe6, 0x09, 0x7a, 0x3e, 0x86, 0x36, 0x7a, 0x72,
- 0xe9, 0xbb, 0xd8, 0xc3, 0x9e, 0x7e, 0x9c, 0x4b, 0x12, 0x54, 0x9b, 0x71, 0x49, 0xd9, 0x5f, 0x4a,
- 0x44, 0xfe, 0x3e, 0xc2, 0xae, 0x81, 0x27, 0xba, 0xb4, 0xe1, 0xc4, 0x82, 0x4b, 0xa9, 0x2d, 0xba,
- 0xb7, 0x9c, 0xb1, 0xae, 0xcd, 0x25, 0xf9, 0x09, 0x1e, 0x36, 0x38, 0x18, 0xbb, 0x67, 0x3e, 0x9f,
- 0x0d, 0x0b, 0x83, 0x3c, 0x87, 0x83, 0x06, 0x6f, 0xd3, 0xe2, 0x43, 0x73, 0xb0, 0x1b, 0x6e, 0x23,
- 0x37, 0x2f, 0x15, 0x4d, 0x52, 0xe1, 0x7b, 0x26, 0x37, 0x2f, 0xd5, 0x79, 0x2a, 0xc8, 0x2f, 0xe0,
- 0x4a, 0xa6, 0xca, 0x82, 0x2a, 0xce, 0x57, 0xd2, 0x7f, 0xd4, 0x6f, 0x1d, 0xbb, 0xc3, 0xa3, 0xad,
- 0x47, 0xf4, 0x9e, 0x89, 0xe5, 0xbb, 0x7c, 0xc9, 0x43, 0x40, 0xc5, 0x95, 0x16, 0x90, 0x11, 0x38,
- 0x7f, 0x46, 0x2a, 0xa5, 0xa2, 0xcc, 0xa5, 0x4f, 0xee, 0xa3, 0xee, 0x68, 0x7e, 0x58, 0xe6, 0x92,
- 0xbc, 0x01, 0x30, 0x4c, 0x14, 0x1f, 0xdc, 0x47, 0xec, 0x20, 0x5a, 0xab, 0xf3, 0x34, 0xff, 0x1c,
- 0x19, 0xf5, 0xe1, 0xbd, 0xd4, 0x28, 0xd0, 0xea, 0xe0, 0x25, 0xec, 0xdf, 0xb9, 0x28, 0x1d, 0xb0,
- 0x17, 0x97, 0x93, 0xd0, 0x7b, 0x40, 0xba, 0xe0, 0xe8, 0xd5, 0xf9, 0xe4, 0x6c, 0xf1, 0xd6, 0xb3,
- 0x48, 0x1b, 0xf4, 0xe5, 0xf2, 0x76, 0x82, 0x37, 0x60, 0xe3, 0x51, 0xba, 0x50, 0x7f, 0x1a, 0xde,
- 0x03, 0x8d, 0x9e, 0x86, 0x53, 0xcf, 0x22, 0x0e, 0xec, 0x9e, 0x86, 0xd3, 0x93, 0x57, 0xde, 0x8e,
- 0xae, 0x7d, 0x7c, 0x7d, 0xe2, 0xb5, 0x08, 0xc0, 0xde, 0xc7, 0xd7, 0x27, 0xf4, 0xe4, 0x95, 0x67,
- 0x07, 0x7f, 0x5b, 0xd0, 0xa9, 0x73, 0x10, 0x02, 0x76, 0xc2, 0x64, 0x8c, 0xb3, 0xc9, 0x09, 0x71,
- 0xad, 0x6b, 0x38, 0x5d, 0xcc, 0x24, 0xc2, 0x35, 0x39, 0x02, 0x90, 0x2a, 0x12, 0x0a, 0xc7, 0x19,
- 0xce, 0x1d, 0x3b, 0x74, 0xb0, 0xa2, 0xa7, 0x18, 0x79, 0x0a, 0x8e, 0x60, 0xd1, 0xca, 0xa0, 0x36,
- 0xa2, 0x1d, 0x5d, 0x40, 0xf0, 0x08, 0x20, 0x63, 0x19, 0x17, 0x6b, 0x5a, 0x4a, 0x86, 0x53, 0xc5,
- 0x0e, 0x1d, 0x53, 0x59, 0x48, 0x16, 0xfc, 0x6b, 0x41, 0x6f, 0xca, 0x93, 0x72, 0xc5, 0xae, 0xd6,
- 0x05, 0xc3, 0x54, 0x7f, 0xc0, 0xbe, 0x39, 0x37, 0xb9, 0x96, 0x8a, 0x65, 0x98, 0xae, 0x37, 0x7c,
- 0xb1, 0xfd, 0xba, 0xdc, 0x91, 0x9a, 0x61, 0x74, 0x89, 0xb2, 0xc6, 0xc5, 0xb9, 0xbe, 0xad, 0x92,
- 0x1f, 0xc0, 0xcd, 0x50, 0x43, 0xd5, 0xba, 0xa8, 0xbb, 0x84, 0x6c, 0x63, 0x43, 0x7e, 0x84, 0x5e,
- 0x5e, 0x66, 0x94, 0x2f, 0xa9, 0x29, 0x4a, 0xec, 0xb7, 0x1b, 0xee, 0xe7, 0x65, 0x36, 0x5f, 0x9a,
- 0xfd, 0x64, 0xf0, 0x02, 0xdc, 0xc6, 0x5e, 0x77, 0xdf, 0x85, 0x03, 0xbb, 0x97, 0xf3, 0xf9, 0x4c,
- 0xbf, 0xb4, 0x0e, 0xd8, 0xd3, 0xd3, 0x8b, 0x89, 0xb7, 0x13, 0xac, 0xe0, 0xfb, 0xb1, 0x48, 0x55,
- 0x1a, 0x47, 0xab, 0x85, 0x64, 0xe2, 0x57, 0x5e, 0x8a, 0x9c, 0xad, 0xab, 0xdb, 0xbe, 0x39, 0x74,
- 0xab, 0x71, 0xe8, 0x23, 0x68, 0x57, 0x5d, 0x62, 0x4a, 0x77, 0xd8, 0xff, 0xda, 0xc0, 0x08, 0x6b,
- 0x41, 0x70, 0x0d, 0x4f, 0xb7, 0xec, 0x26, 0xeb, 0xed, 0xc6, 0x60, 0xc7, 0xe5, 0x67, 0xe9, 0x5b,
- 0xf8, 0xb1, 0x6e, 0x3f, 0xd9, 0xff, 0x4f, 0x1b, 0xa2, 0xf8, 0xec, 0xbb, 0xdf, 0xab, 0xff, 0x61,
- 0xa5, 0xa0, 0xf8, 0x93, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x20, 0x07, 0xbc, 0xf0, 0x34, 0x07,
- 0x00, 0x00,
+ // 847 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdd, 0x6e, 0xdb, 0x36,
+ 0x14, 0xae, 0x12, 0x25, 0xb6, 0x8e, 0x62, 0x57, 0x65, 0x52, 0x54, 0x5d, 0x11, 0xcc, 0x10, 0xd6,
+ 0x21, 0x17, 0xab, 0x5b, 0x78, 0x45, 0x50, 0x18, 0xc5, 0x80, 0xc4, 0x31, 0x8a, 0x2e, 0xb0, 0x5d,
+ 0x28, 0x71, 0x57, 0x6c, 0x17, 0x02, 0x23, 0xd1, 0x8d, 0x3a, 0x4b, 0x14, 0x48, 0xaa, 0x98, 0x1f,
+ 0x62, 0x0f, 0xb9, 0x8b, 0xbd, 0xc7, 0xc0, 0x43, 0xc9, 0x51, 0x00, 0x0f, 0x09, 0x7a, 0x47, 0x9d,
+ 0xef, 0x87, 0xdf, 0xa1, 0xc4, 0x23, 0xe8, 0x64, 0x4c, 0x89, 0x34, 0x96, 0xfd, 0x42, 0x70, 0xc5,
+ 0xc9, 0xbe, 0xe4, 0x3c, 0xff, 0x1c, 0x5d, 0x95, 0xe9, 0x32, 0x89, 0x2a, 0x28, 0xf8, 0xc7, 0x01,
+ 0x77, 0x62, 0xd6, 0xa7, 0x54, 0x32, 0xf2, 0x0a, 0x0e, 0x0c, 0x21, 0xa1, 0x8a, 0x45, 0x2a, 0xcd,
+ 0x98, 0x54, 0x34, 0x2b, 0x7c, 0xab, 0x67, 0x1d, 0x6d, 0x87, 0x04, 0xb1, 0x33, 0xaa, 0xd8, 0x65,
+ 0x8d, 0x90, 0xa7, 0xd0, 0x36, 0x8a, 0x34, 0xf1, 0xb7, 0x7a, 0xd6, 0x91, 0x13, 0xb6, 0xf0, 0xf9,
+ 0x7d, 0x42, 0x86, 0xf0, 0xb4, 0x58, 0x52, 0xb5, 0xe0, 0x22, 0x8b, 0xbe, 0x32, 0x21, 0x53, 0x9e,
+ 0x47, 0x31, 0x4f, 0x58, 0x4e, 0x33, 0xe6, 0x6f, 0x23, 0xf7, 0x49, 0x4d, 0xf8, 0x68, 0xf0, 0x51,
+ 0x05, 0x93, 0xe7, 0xd0, 0x55, 0x54, 0x7c, 0x66, 0x2a, 0x2a, 0x04, 0x4f, 0xca, 0x58, 0xf9, 0x36,
+ 0x0a, 0x3a, 0xa6, 0xfa, 0xc1, 0x14, 0x49, 0x02, 0x07, 0x15, 0xcd, 0x84, 0xf8, 0x4a, 0x45, 0x4a,
+ 0x73, 0xe5, 0xef, 0xf4, 0xac, 0xa3, 0xee, 0xe0, 0x45, 0x7f, 0x43, 0xcf, 0xfd, 0x46, 0xbf, 0xfd,
+ 0x53, 0x8d, 0x7c, 0x34, 0xa2, 0xe1, 0xf6, 0x78, 0xfa, 0x2e, 0x24, 0xc6, 0xaf, 0x09, 0x90, 0x19,
+ 0xb8, 0xd5, 0x2e, 0x54, 0xc4, 0xd7, 0xfe, 0x2e, 0x9a, 0x3f, 0xbf, 0xd3, 0xfc, 0x44, 0xc4, 0xd7,
+ 0xc3, 0xd6, 0x7c, 0x7a, 0x3e, 0x9d, 0xfd, 0x36, 0x0d, 0xc1, 0x58, 0xe8, 0x22, 0xe9, 0xc3, 0x7e,
+ 0xc3, 0x70, 0x9d, 0xba, 0x85, 0x2d, 0x3e, 0xba, 0x21, 0xd6, 0x01, 0x7e, 0x82, 0x2a, 0x56, 0x14,
+ 0x17, 0xe5, 0x9a, 0xde, 0x46, 0xba, 0x67, 0x90, 0x51, 0x51, 0xd6, 0xec, 0x73, 0x70, 0xae, 0xb9,
+ 0xac, 0xc2, 0x3a, 0xdf, 0x14, 0xb6, 0xad, 0x0d, 0x30, 0x6a, 0x08, 0x1d, 0x34, 0x1b, 0xe4, 0x89,
+ 0x31, 0x84, 0x6f, 0x32, 0x74, 0xb5, 0xc9, 0x20, 0x4f, 0xd0, 0xf3, 0x09, 0xb4, 0xd0, 0x93, 0x4b,
+ 0xdf, 0xc5, 0x1e, 0x76, 0xf5, 0xe3, 0x4c, 0x92, 0xa0, 0xda, 0x8c, 0xcb, 0x88, 0xfd, 0xa5, 0x04,
+ 0xf5, 0xf7, 0x10, 0x76, 0x0d, 0x3c, 0xd6, 0xa5, 0x35, 0x27, 0x16, 0x5c, 0x4a, 0x6d, 0xd1, 0xb9,
+ 0xe1, 0x8c, 0x74, 0x6d, 0x26, 0xc9, 0x8f, 0xf0, 0xb0, 0xc1, 0xc1, 0xd8, 0x5d, 0xf3, 0xf9, 0xac,
+ 0x59, 0x18, 0xe4, 0x05, 0xec, 0x37, 0x78, 0xeb, 0x16, 0x1f, 0x9a, 0x83, 0x5d, 0x73, 0x1b, 0xb9,
+ 0x79, 0xa9, 0xa2, 0x24, 0x15, 0xbe, 0x67, 0x72, 0xf3, 0x52, 0x9d, 0xa5, 0x82, 0xfc, 0x02, 0xae,
+ 0x64, 0xaa, 0x2c, 0x22, 0xc5, 0xf9, 0x52, 0xfa, 0x8f, 0x7a, 0xdb, 0x47, 0xee, 0xe0, 0x70, 0xe3,
+ 0x11, 0x7d, 0x60, 0x62, 0xf1, 0x3e, 0x5f, 0xf0, 0x10, 0x50, 0x71, 0xa9, 0x05, 0x64, 0x08, 0xce,
+ 0x9f, 0x54, 0xa5, 0x91, 0x28, 0x73, 0xe9, 0x93, 0xfb, 0xa8, 0xdb, 0x9a, 0x1f, 0x96, 0xb9, 0x24,
+ 0x6f, 0x01, 0x0c, 0x13, 0xc5, 0xfb, 0xf7, 0x11, 0x3b, 0x88, 0xd6, 0xea, 0x3c, 0xcd, 0xbf, 0x50,
+ 0xa3, 0x3e, 0xb8, 0x97, 0x1a, 0x05, 0xa8, 0xfe, 0x19, 0x76, 0x14, 0x57, 0x74, 0xe9, 0x3f, 0xee,
+ 0x59, 0x77, 0x0b, 0x0d, 0x37, 0x78, 0x05, 0x7b, 0xb7, 0x6e, 0x57, 0x1b, 0xec, 0xf9, 0xc5, 0x38,
+ 0xf4, 0x1e, 0x90, 0x0e, 0x38, 0x7a, 0x75, 0x36, 0x3e, 0x9d, 0xbf, 0xf3, 0x2c, 0xd2, 0x02, 0x7d,
+ 0x23, 0xbd, 0xad, 0xe0, 0x2d, 0xd8, 0x78, 0xfe, 0x2e, 0xd4, 0xdf, 0x93, 0xf7, 0x40, 0xa3, 0x27,
+ 0xe1, 0xc4, 0xb3, 0x88, 0x03, 0x3b, 0x27, 0xe1, 0xe4, 0xf8, 0xb5, 0xb7, 0xa5, 0x6b, 0x9f, 0xde,
+ 0x1c, 0x7b, 0xdb, 0x04, 0x60, 0xf7, 0xd3, 0x9b, 0xe3, 0xe8, 0xf8, 0xb5, 0x67, 0x07, 0x7f, 0x5b,
+ 0xd0, 0xae, 0x33, 0x10, 0x02, 0x76, 0xc2, 0x64, 0x8c, 0x03, 0xcd, 0x09, 0x71, 0xad, 0x6b, 0x38,
+ 0x92, 0xcc, 0xf8, 0xc2, 0x35, 0x39, 0x04, 0x90, 0x8a, 0x0a, 0x85, 0x33, 0x10, 0x87, 0x95, 0x1d,
+ 0x3a, 0x58, 0xd1, 0xa3, 0x8f, 0x3c, 0x03, 0x47, 0x30, 0xba, 0x34, 0xa8, 0x8d, 0x68, 0x5b, 0x17,
+ 0x10, 0x3c, 0x04, 0xc8, 0x58, 0xc6, 0xc5, 0x2a, 0x2a, 0x25, 0xc3, 0x51, 0x64, 0x87, 0x8e, 0xa9,
+ 0xcc, 0x25, 0x0b, 0xfe, 0xb5, 0xa0, 0x3b, 0xe1, 0x49, 0xb9, 0x64, 0x97, 0xab, 0x82, 0x61, 0xaa,
+ 0x3f, 0x60, 0xcf, 0x9c, 0x99, 0x5c, 0x49, 0xc5, 0x32, 0x4c, 0xd7, 0x1d, 0xbc, 0xdc, 0x7c, 0xc7,
+ 0x6e, 0x49, 0xcd, 0x04, 0xbb, 0x40, 0x59, 0xe3, 0xb6, 0x5d, 0xdd, 0x54, 0xc9, 0xf7, 0xe0, 0x66,
+ 0xa8, 0x89, 0xd4, 0xaa, 0xa8, 0xbb, 0x84, 0x6c, 0x6d, 0x43, 0x7e, 0x80, 0x6e, 0x5e, 0x66, 0x11,
+ 0x5f, 0x44, 0xa6, 0x28, 0xb1, 0xdf, 0x4e, 0xb8, 0x97, 0x97, 0xd9, 0x6c, 0x61, 0xf6, 0x93, 0xc1,
+ 0x4b, 0x70, 0x1b, 0x7b, 0xdd, 0x7e, 0x17, 0x0e, 0xec, 0x5c, 0xcc, 0x66, 0x53, 0xfd, 0xd2, 0xda,
+ 0x60, 0x4f, 0x4e, 0xce, 0xc7, 0xde, 0x56, 0xb0, 0x84, 0xef, 0x46, 0x22, 0x55, 0x69, 0x4c, 0x97,
+ 0x73, 0xc9, 0xc4, 0xaf, 0xbc, 0x14, 0x39, 0x5b, 0x55, 0x23, 0x62, 0x7d, 0xe8, 0x56, 0xe3, 0xd0,
+ 0x87, 0xd0, 0xaa, 0xba, 0xc4, 0x94, 0xee, 0xa0, 0x77, 0xd7, 0x94, 0x09, 0x6b, 0x41, 0x70, 0x05,
+ 0xcf, 0x36, 0xec, 0x26, 0xeb, 0xed, 0x46, 0x60, 0xc7, 0xe5, 0x17, 0xe9, 0x5b, 0xf8, 0x85, 0x6f,
+ 0x3e, 0xd9, 0xff, 0x4f, 0x1b, 0xa2, 0xf8, 0xf4, 0xf1, 0xef, 0xd5, 0x4f, 0xb4, 0x52, 0x44, 0xf8,
+ 0x67, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xbd, 0xe2, 0xb1, 0x69, 0x07, 0x00, 0x00,
}
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 1ea24bf..194aa6b 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -89,6 +89,9 @@
// The metrics for calling Ninja.
repeated PerfInfo ninja_runs = 20;
+
+ // The metrics for the whole build
+ optional PerfInfo total = 21;
}
message PerfInfo {