Merge "Add check_all_apis option for header ABI checker"
diff --git a/Android.bp b/Android.bp
index 0621475..7cdd928 100644
--- a/Android.bp
+++ b/Android.bp
@@ -39,6 +39,7 @@
"soong-android-soongconfig",
"soong-env",
"soong-shared",
+ "soong-ui-metrics_proto",
],
srcs: [
"android/androidmk.go",
@@ -54,6 +55,7 @@
"android/hooks.go",
"android/image.go",
"android/makevars.go",
+ "android/metrics.go",
"android/module.go",
"android/mutator.go",
"android/namespace.go",
@@ -130,6 +132,7 @@
pkgPath: "android/soong/cc/config",
deps: [
"soong-android",
+ "soong-remoteexec",
],
srcs: [
"cc/config/clang.go",
@@ -141,8 +144,6 @@
"cc/config/arm_device.go",
"cc/config/arm64_device.go",
"cc/config/arm64_fuchsia_device.go",
- "cc/config/mips_device.go",
- "cc/config/mips64_device.go",
"cc/config/x86_device.go",
"cc/config/x86_64_device.go",
"cc/config/x86_64_fuchsia_device.go",
@@ -186,6 +187,7 @@
"cc/rs.go",
"cc/sanitize.go",
"cc/sabi.go",
+ "cc/sdk.go",
"cc/snapshot_utils.go",
"cc/stl.go",
"cc/strip.go",
@@ -546,6 +548,22 @@
pluginFor: ["soong_build"],
}
+bootstrap_go_package {
+ name: "soong-remoteexec",
+ pkgPath: "android/soong/remoteexec",
+ deps: [
+ "blueprint",
+ "soong-android",
+ ],
+ srcs: [
+ "remoteexec/remoteexec.go",
+ ],
+ testSrcs: [
+ "remoteexec/remoteexec_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
//
// Defaults to enable various configurations of host bionic
//
@@ -626,7 +644,8 @@
arch: {
arm: {
src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-arm.o", "libunwind.o", "pr-support.o"],
+ repack_objects_to_keep: [],
+ enabled: false,
},
arm64: {
src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
diff --git a/OWNERS b/OWNERS
index 4ae045d..e1db459 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,3 +4,4 @@
per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
per-file tidy.go = srhines@google.com, chh@google.com
per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
+per-file docs/map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
diff --git a/README.md b/README.md
index b1bb425..8b028a8 100644
--- a/README.md
+++ b/README.md
@@ -419,7 +419,9 @@
name: "acme_cc_defaults",
module_type: "cc_defaults",
config_namespace: "acme",
- variables: ["board", "feature"],
+ variables: ["board"],
+ bool_variables: ["feature"],
+ value_variables: ["width"],
properties: ["cflags", "srcs"],
}
@@ -427,15 +429,12 @@
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`.
+`cc_defaults` module type, with three additional conditionals based on
+variables `board`, `feature` and `width`, which can affect properties `cflags`
+and `srcs`.
The values of the variables can be set from a product's `BoardConfig.mk` file:
```
@@ -446,6 +445,7 @@
SOONG_CONFIG_acme_board := soc_a
SOONG_CONFIG_acme_feature := true
+SOONG_CONFIG_acme_width := 200
```
The `acme_cc_defaults` module type can be used anywhere after the definition in
@@ -474,6 +474,9 @@
feature: {
cflags: ["-DFEATURE"],
},
+ width: {
+ cflags: ["-DWIDTH=%s"],
+ },
},
}
@@ -485,7 +488,7 @@
```
With the `BoardConfig.mk` snippet above, libacme_foo would build with
-cflags "-DGENERIC -DSOC_A -DFEATURE".
+cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
`soong_config_module_type` modules will work best when used to wrap defaults
modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
diff --git a/android/androidmk.go b/android/androidmk.go
index dbf3aa8..b5f4b2b 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -29,7 +29,11 @@
)
func init() {
- RegisterSingletonType("androidmk", AndroidMkSingleton)
+ RegisterAndroidMkBuildComponents(InitRegistrationContext)
+}
+
+func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
}
// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
@@ -236,8 +240,8 @@
}
}
- if amod.noticeFile.Valid() {
- a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+ if len(amod.noticeFiles) > 0 {
+ a.SetString("LOCAL_NOTICE_FILE", strings.Join(amod.noticeFiles.Strings(), " "))
}
if host {
diff --git a/android/apex.go b/android/apex.go
index 43a42df..398fbae 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -15,16 +15,32 @@
package android
import (
+ "fmt"
"sort"
+ "strconv"
"sync"
+
+ "github.com/google/blueprint"
+)
+
+const (
+ SdkVersion_Android10 = 29
)
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
+ MinSdkVersion int
+ Updatable bool
+}
+
+// Extracted from ApexModule to make it easier to define custom subsets of the
+// ApexModule interface and improve code navigation within the IDE.
+type DepIsInSameApex interface {
+ // DepIsInSameApex tests if the other module 'dep' is installed to the same
+ // APEX as this module
+ DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
}
// ApexModule is the interface that a module type is expected to implement if
@@ -44,6 +60,8 @@
// respectively.
type ApexModule interface {
Module
+ DepIsInSameApex
+
apexModuleBase() *ApexModuleBase
// Marks that this module should be built for the specified APEXes.
@@ -83,9 +101,18 @@
// Tests if this module is available for the specified APEX or ":platform"
AvailableFor(what string) bool
- // DepIsInSameApex tests if the other module 'dep' is installed to the same
- // APEX as this module
- DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+ // Returns the highest version which is <= maxSdkVersion.
+ // For example, with maxSdkVersion is 10 and versionList is [9,11]
+ // it returns 9 as string
+ ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error)
+
+ // Tests if the module comes from an updatable APEX.
+ Updatable() bool
+
+ // List of APEXes that this module tests. The module has access to
+ // the private part of the listed APEXes even when it is not included in the
+ // APEXes.
+ TestFor() []string
}
type ApexProperties struct {
@@ -101,6 +128,15 @@
Info ApexInfo `blueprint:"mutated"`
}
+// Marker interface that identifies dependencies that are excluded from APEX
+// contents.
+type ExcludeFromApexContentsTag interface {
+ blueprint.DependencyTag
+
+ // Method that differentiates this interface from others.
+ ExcludeFromApexContents()
+}
+
// Provides default implementation for the ApexModule interface. APEX-aware
// modules are expected to include this struct and call InitApexModule().
type ApexModuleBase struct {
@@ -116,6 +152,15 @@
return m
}
+func (m *ApexModuleBase) ApexAvailable() []string {
+ return m.ApexProperties.Apex_available
+}
+
+func (m *ApexModuleBase) TestFor() []string {
+ // To be implemented by concrete types inheriting ApexModuleBase
+ return nil
+}
+
func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock()
@@ -153,7 +198,7 @@
const (
AvailableToPlatform = "//apex_available:platform"
- availableToAnyApex = "//apex_available:anyapex"
+ AvailableToAnyApex = "//apex_available:anyapex"
)
func CheckAvailableForApex(what string, apex_available []string) bool {
@@ -163,7 +208,7 @@
return what == AvailableToPlatform
}
return InList(what, apex_available) ||
- (what != AvailableToPlatform && InList(availableToAnyApex, apex_available))
+ (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
}
func (m *ApexModuleBase) AvailableFor(what string) bool {
@@ -177,9 +222,19 @@
return true
}
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) {
+ for i := range versionList {
+ ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
+ if ver <= maxSdkVersion {
+ return versionList[len(versionList)-i-1], nil
+ }
+ }
+ return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList)
+}
+
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
- if n == AvailableToPlatform || n == availableToAnyApex {
+ if n == AvailableToPlatform || n == AvailableToAnyApex {
continue
}
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
@@ -188,6 +243,10 @@
}
}
+func (m *ApexModuleBase) Updatable() bool {
+ return m.ApexProperties.Info.Updatable
+}
+
type byApexName []ApexInfo
func (a byApexName) Len() int { return len(a) }
diff --git a/android/api_levels.go b/android/api_levels.go
index 4f6efee..b6296d8 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -16,6 +16,7 @@
import (
"encoding/json"
+ "fmt"
"strconv"
)
@@ -73,7 +74,7 @@
"P": 28,
"Q": 29,
}
- for i, codename := range config.PlatformVersionCombinedCodenames() {
+ for i, codename := range config.PlatformVersionActiveCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
}
@@ -84,14 +85,19 @@
// Converts an API level string into its numeric form.
// * Codenames are decoded.
// * Numeric API levels are simply converted.
-// * "minimum" and "current" are not currently handled since the former is
-// NDK specific and the latter has inconsistent meaning.
+// * "current" is mapped to FutureApiLevel(10000)
+// * "minimum" is NDK specific and not handled with this. (refer normalizeNdkApiLevel in cc.go)
func ApiStrToNum(ctx BaseModuleContext, apiLevel string) (int, error) {
- num, ok := getApiLevelsMap(ctx.Config())[apiLevel]
- if ok {
+ if apiLevel == "current" {
+ return FutureApiLevel, nil
+ }
+ if num, ok := getApiLevelsMap(ctx.Config())[apiLevel]; ok {
return num, nil
}
- return strconv.Atoi(apiLevel)
+ if num, err := strconv.Atoi(apiLevel); err == nil {
+ return num, nil
+ }
+ return 0, fmt.Errorf("SDK version should be one of \"current\", <number> or <codename>: %q", apiLevel)
}
func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
diff --git a/android/arch.go b/android/arch.go
index 73a490d..08c0256 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -33,8 +33,6 @@
Arm = newArch("arm", "lib32")
Arm64 = newArch("arm64", "lib64")
- Mips = newArch("mips", "lib32")
- Mips64 = newArch("mips64", "lib64")
X86 = newArch("x86", "lib32")
X86_64 = newArch("x86_64", "lib64")
@@ -46,8 +44,6 @@
var archTypeMap = map[string]ArchType{
"arm": Arm,
"arm64": Arm64,
- "mips": Mips,
- "mips64": Mips64,
"x86": X86,
"x86_64": X86_64,
}
@@ -64,12 +60,6 @@
arm64: {
// Host or device variants with arm64 architecture
},
- mips: {
- // Host or device variants with mips architecture
- },
- mips64: {
- // Host or device variants with mips64 architecture
- },
x86: {
// Host or device variants with x86 architecture
},
@@ -145,18 +135,6 @@
"exynos-m1",
"exynos-m2",
},
- Mips: {
- "mips32_fp",
- "mips32r2_fp",
- "mips32r2_fp_xburst",
- "mips32r2dsp_fp",
- "mips32r2dspr2_fp",
- "mips32r6",
- },
- Mips64: {
- "mips64r2",
- "mips64r6",
- },
X86: {
"amberlake",
"atom",
@@ -193,15 +171,6 @@
Arm: {
"neon",
},
- Mips: {
- "dspr2",
- "rev6",
- "msa",
- },
- Mips64: {
- "rev6",
- "msa",
- },
X86: {
"ssse3",
"sse4",
@@ -239,19 +208,6 @@
"neon",
},
},
- Mips: {
- "mips32r2dspr2_fp": {
- "dspr2",
- },
- "mips32r6": {
- "rev6",
- },
- },
- Mips64: {
- "mips64r6": {
- "rev6",
- },
- },
X86: {
"amberlake": {
"ssse3",
@@ -596,7 +552,7 @@
}()
var (
- osTypeList []OsType
+ OsTypeList []OsType
commonTargetMap = make(map[string]Target)
NoOsType OsType
@@ -607,12 +563,16 @@
Android = NewOsType("android", Device, false)
Fuchsia = NewOsType("fuchsia", Device, false)
+ // A pseudo OSType for a common os variant, which is OSType agnostic and which
+ // has dependencies on all the OS variants.
+ CommonOS = NewOsType("common_os", Generic, false)
+
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
LinuxBionic: []ArchType{X86_64},
Darwin: []ArchType{X86_64},
Windows: []ArchType{X86, X86_64},
- Android: []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64},
+ Android: []ArchType{Arm, Arm64, X86, X86_64},
Fuchsia: []ArchType{Arm64, X86_64},
}
)
@@ -668,7 +628,7 @@
DefaultDisabled: defDisabled,
}
- osTypeList = append(osTypeList, os)
+ OsTypeList = append(OsTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -680,7 +640,7 @@
}
func osByName(name string) OsType {
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
if os.Name == name {
return os
}
@@ -746,7 +706,7 @@
var moduleOSList []OsType
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
supportedClass := false
for _, osClass := range osClasses {
if os.Class == osClass {
@@ -775,12 +735,64 @@
osNames[i] = os.String()
}
- modules := mctx.CreateVariations(osNames...)
- for i, m := range modules {
- m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
- m.(Module).base().setOSProperties(mctx)
+ createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+ if createCommonOSVariant {
+ // A CommonOS variant was requested so add it to the list of OS's variants to
+ // create. It needs to be added to the end because it needs to depend on the
+ // the other variants in the list returned by CreateVariations(...) and inter
+ // variant dependencies can only be created from a later variant in that list to
+ // an earlier one. That is because variants are always processed in the order in
+ // which they are returned from CreateVariations(...).
+ osNames = append(osNames, CommonOS.Name)
+ moduleOSList = append(moduleOSList, CommonOS)
}
+ modules := mctx.CreateVariations(osNames...)
+ for i, m := range modules {
+ m.base().commonProperties.CompileOS = moduleOSList[i]
+ m.base().setOSProperties(mctx)
+ }
+
+ if createCommonOSVariant {
+ // A CommonOS variant was requested so add dependencies from it (the last one in
+ // the list) to the OS type specific variants.
+ last := len(modules) - 1
+ commonOSVariant := modules[last]
+ commonOSVariant.base().commonProperties.CommonOSVariant = true
+ for _, module := range modules[0:last] {
+ // Ignore modules that are enabled. Note, this will only avoid adding
+ // dependencies on OsType variants that are explicitly disabled in their
+ // properties. The CommonOS variant will still depend on disabled variants
+ // if they are disabled afterwards, e.g. in archMutator if
+ if module.Enabled() {
+ mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
+ }
+ }
+ }
+}
+
+// Identifies the dependency from CommonOS variant to the os specific variants.
+type commonOSTag struct{ blueprint.BaseDependencyTag }
+
+var commonOsToOsSpecificVariantTag = commonOSTag{}
+
+// Get the OsType specific variants for the current CommonOS variant.
+//
+// The returned list will only contain enabled OsType specific variants of the
+// module referenced in the supplied context. An empty list is returned if there
+// are no enabled variants or the supplied context is not for an CommonOS
+// variant.
+func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
+ var variants []Module
+ mctx.VisitDirectDeps(func(m Module) {
+ if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
+ if m.Enabled() {
+ variants = append(variants, m)
+ }
+ }
+ })
+
+ return variants
}
// archMutator splits a module into a variant for each Target requested by the module. Target selection
@@ -821,6 +833,15 @@
}
os := base.commonProperties.CompileOS
+ if os == CommonOS {
+ // Make sure that the target related properties are initialized for the
+ // CommonOS variant.
+ addTargetProperties(module, commonTargetMap[os.Name], nil, true)
+
+ // Do not create arch specific variants for the CommonOS variant.
+ return
+ }
+
osTargets := mctx.Config().Targets[os]
image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported
@@ -881,15 +902,17 @@
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
- m.(Module).base().commonProperties.CompileTarget = targets[i]
- m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
- if i == 0 {
- m.(Module).base().commonProperties.CompilePrimary = true
- }
+ addTargetProperties(m, targets[i], multiTargets, i == 0)
m.(Module).base().setArchProperties(mctx)
}
}
+func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
+ m.base().commonProperties.CompileTarget = target
+ m.base().commonProperties.CompileMultiTargets = multiTargets
+ m.base().commonProperties.CompilePrimary = primaryTarget
+}
+
func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
switch class {
case Device:
@@ -1004,7 +1027,7 @@
"Arm_on_x86",
"Arm_on_x86_64",
}
- for _, os := range osTypeList {
+ for _, os := range OsTypeList {
targets = append(targets, os.Field)
for _, archType := range osArchTypeMap[os] {
@@ -1589,15 +1612,6 @@
{"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}},
- {"mips", "mips32-fp", "", []string{"mips"}},
- {"mips", "mips32r2-fp", "", []string{"mips"}},
- {"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
- //{"mips", "mips32r6", "", []string{"mips"}},
- {"mips", "mips32r2dsp-fp", "", []string{"mips"}},
- {"mips", "mips32r2dspr2-fp", "", []string{"mips"}},
- // mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc
- //{"mips64", "mips64r2", "", []string{"mips64"}},
- {"mips64", "mips64r6", "", []string{"mips64"}},
{"x86", "", "", []string{"x86"}},
{"x86", "atom", "", []string{"x86"}},
{"x86", "haswell", "", []string{"x86"}},
@@ -1711,6 +1725,8 @@
return ret
}
+// Return the set of Os specific common architecture targets for each Os in a list of
+// targets.
func getCommonTargets(targets []Target) []Target {
var ret []Target
set := make(map[string]bool)
diff --git a/android/config.go b/android/config.go
index 32e32ae..c297b05 100644
--- a/android/config.go
+++ b/android/config.go
@@ -359,6 +359,9 @@
return Config{}, err
}
+ // Make the CommonOS OsType available for all products.
+ targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
+
var archConfig []archConfig
if Bool(config.Mega_device) {
archConfig = getMegaDeviceConfig()
@@ -570,8 +573,8 @@
return String(c.productVariables.BuildId)
}
-func (c *config) BuildNumberFromFile() string {
- return String(c.productVariables.BuildNumberFromFile)
+func (c *config) BuildNumberFile(ctx PathContext) Path {
+ return PathForOutput(ctx, String(c.productVariables.BuildNumberFile))
}
// DeviceName returns the name of the current device target
@@ -649,22 +652,6 @@
return c.productVariables.Platform_version_active_codenames
}
-// Codenames that are available in the branch but not included in the current
-// lunch target.
-func (c *config) PlatformVersionFutureCodenames() []string {
- return c.productVariables.Platform_version_future_codenames
-}
-
-// All possible codenames in the current branch. NB: Not named AllCodenames
-// because "all" has historically meant "active" in make, and still does in
-// build.prop.
-func (c *config) PlatformVersionCombinedCodenames() []string {
- combined := []string{}
- combined = append(combined, c.PlatformVersionActiveCodenames()...)
- combined = append(combined, c.PlatformVersionFutureCodenames()...)
- return combined
-}
-
func (c *config) ProductAAPTConfig() []string {
return c.productVariables.AAPTConfig
}
@@ -860,16 +847,7 @@
}
func (c *config) LibartImgDeviceBaseAddress() string {
- archType := Common
- if len(c.Targets[Android]) > 0 {
- archType = c.Targets[Android][0].Arch.ArchType
- }
- switch archType {
- default:
- return "0x70000000"
- case Mips, Mips64:
- return "0x5C000000"
- }
+ return "0x70000000"
}
func (c *config) ArtUseReadBarrier() bool {
@@ -878,6 +856,13 @@
func (c *config) EnforceRROForModule(name string) bool {
enforceList := c.productVariables.EnforceRROTargets
+ // TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+ exemptedList := c.productVariables.EnforceRROExemptedTargets
+ if exemptedList != nil {
+ if InList(name, exemptedList) {
+ return false
+ }
+ }
if enforceList != nil {
if InList("*", enforceList) {
return true
@@ -1031,6 +1016,10 @@
return c.config.productVariables.DeviceKernelHeaders
}
+func (c *deviceConfig) SamplingPGO() bool {
+ return Bool(c.config.productVariables.SamplingPGO)
+}
+
func (c *config) NativeLineCoverage() bool {
return Bool(c.productVariables.NativeLineCoverage)
}
diff --git a/android/defs.go b/android/defs.go
index 5c815e6..4552224 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -100,6 +100,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 only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
+ remotePool = blueprint.NewBuiltinPool("remote_pool")
+
// Used for processes that need significant RAM to ensure there are not too many running in parallel.
highmemPool = blueprint.NewBuiltinPool("highmem_pool")
)
diff --git a/android/metrics.go b/android/metrics.go
new file mode 100644
index 0000000..b7aee54
--- /dev/null
+++ b/android/metrics.go
@@ -0,0 +1,87 @@
+// 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 android
+
+import (
+ "io/ioutil"
+ "runtime"
+
+ "github.com/golang/protobuf/proto"
+
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+)
+
+var soongMetricsOnceKey = NewOnceKey("soong metrics")
+
+type SoongMetrics struct {
+ Modules int
+ Variants int
+}
+
+func ReadSoongMetrics(config Config) SoongMetrics {
+ return config.Get(soongMetricsOnceKey).(SoongMetrics)
+}
+
+func init() {
+ RegisterSingletonType("soong_metrics", soongMetricsSingletonFactory)
+}
+
+func soongMetricsSingletonFactory() Singleton { return soongMetricsSingleton{} }
+
+type soongMetricsSingleton struct{}
+
+func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) {
+ metrics := SoongMetrics{}
+ ctx.VisitAllModules(func(m Module) {
+ if ctx.PrimaryModule(m) == m {
+ metrics.Modules++
+ }
+ metrics.Variants++
+ })
+ ctx.Config().Once(soongMetricsOnceKey, func() interface{} {
+ return metrics
+ })
+}
+
+func collectMetrics(config Config) *soong_metrics_proto.SoongBuildMetrics {
+ metrics := &soong_metrics_proto.SoongBuildMetrics{}
+
+ soongMetrics := ReadSoongMetrics(config)
+ metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
+ metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+
+ memStats := runtime.MemStats{}
+ runtime.ReadMemStats(&memStats)
+ metrics.MaxHeapSize = proto.Uint64(memStats.HeapSys)
+ metrics.TotalAllocCount = proto.Uint64(memStats.Mallocs)
+ metrics.TotalAllocSize = proto.Uint64(memStats.TotalAlloc)
+
+ return metrics
+}
+
+func WriteMetrics(config Config, metricsFile string) error {
+ metrics := collectMetrics(config)
+
+ buf, err := proto.Marshal(metrics)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(absolutePath(metricsFile), buf, 0666)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/android/module.go b/android/module.go
index 665a30f..02b2c89 100644
--- a/android/module.go
+++ b/android/module.go
@@ -128,10 +128,20 @@
// and returns a top-down dependency path from a start module to current child module.
GetWalkPath() []Module
+ // GetTagPath is supposed to be called in visit function passed in WalkDeps()
+ // and returns a top-down dependency tags path from a start module to current child module.
+ // It has one less entry than GetWalkPath() as it contains the dependency tags that
+ // exist between each adjacent pair of modules in the GetWalkPath().
+ // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+ GetTagPath() []blueprint.DependencyTag
+
AddMissingDependencies(missingDeps []string)
Target() Target
TargetPrimary() bool
+
+ // The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+ // responsible for creating.
MultiTargets() []Target
Arch() Arch
Os() OsType
@@ -172,6 +182,7 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() *OsType
RequiredModuleNames() []string
HostRequiredModuleNames() []string
@@ -214,11 +225,13 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() *OsType
SkipInstall()
+ IsSkipInstall() bool
ExportedToMake() bool
InitRc() Paths
VintfFragments() Paths
- NoticeFile() OptionalPath
+ NoticeFiles() Paths
AddProperties(props ...interface{})
GetProperties() []interface{}
@@ -242,6 +255,8 @@
RequiredModuleNames() []string
HostRequiredModuleNames() []string
TargetRequiredModuleNames() []string
+
+ filesToInstall() InstallPaths
}
// Qualified id for a module
@@ -360,6 +375,10 @@
}
}
+ // If set to true then the archMutator will create variants for each arch specific target
+ // (e.g. 32/64) that the module is required to produce. If set to false then it will only
+ // create a variant for the architecture and will list the additional arch specific targets
+ // that the variant needs to produce in the CompileMultiTargets property.
UseTargetVariants bool `blueprint:"mutated"`
Default_multilib string `blueprint:"mutated"`
@@ -438,16 +457,56 @@
Suffix *string `android:"arch_variant"`
} `android:"arch_variant"`
- // Set by TargetMutator
- CompileOS OsType `blueprint:"mutated"`
- CompileTarget Target `blueprint:"mutated"`
+ // The OsType of artifacts that this module variant is responsible for creating.
+ //
+ // Set by osMutator
+ CompileOS OsType `blueprint:"mutated"`
+
+ // The Target of artifacts that this module variant is responsible for creating.
+ //
+ // Set by archMutator
+ CompileTarget Target `blueprint:"mutated"`
+
+ // The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+ // responsible for creating.
+ //
+ // By default this is nil as, where necessary, separate variants are created for the
+ // different multilib types supported and that information is encapsulated in the
+ // CompileTarget so the module variant simply needs to create artifacts for that.
+ //
+ // However, if UseTargetVariants is set to false (e.g. by
+ // InitAndroidMultiTargetsArchModule) then no separate variants are created for the
+ // multilib targets. Instead a single variant is created for the architecture and
+ // this contains the multilib specific targets that this variant should create.
+ //
+ // Set by archMutator
CompileMultiTargets []Target `blueprint:"mutated"`
- CompilePrimary bool `blueprint:"mutated"`
+
+ // True if the module variant's CompileTarget is the primary target
+ //
+ // Set by archMutator
+ CompilePrimary bool `blueprint:"mutated"`
// Set by InitAndroidModule
HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
ArchSpecific bool `blueprint:"mutated"`
+ // If set to true then a CommonOS variant will be created which will have dependencies
+ // on all its OsType specific variants. Used by sdk/module_exports to create a snapshot
+ // that covers all os and architecture variants.
+ //
+ // The OsType specific variants can be retrieved by calling
+ // GetOsSpecificVariantsOfCommonOSVariant
+ //
+ // Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
+ CreateCommonOSVariant bool `blueprint:"mutated"`
+
+ // If set to true then this variant is the CommonOS variant that has dependencies on its
+ // OsType specific variants.
+ //
+ // Set by osMutator.
+ CommonOSVariant bool `blueprint:"mutated"`
+
SkipInstall bool `blueprint:"mutated"`
NamespaceExportedToMake bool `blueprint:"mutated"`
@@ -580,6 +639,14 @@
m.base().commonProperties.UseTargetVariants = false
}
+// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that
+// has dependencies on all the OsType specific variants.
+func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
+ InitAndroidArchModule(m, hod, defaultMultilib)
+ m.base().commonProperties.UseTargetVariants = false
+ m.base().commonProperties.CreateCommonOSVariant = true
+}
+
// A ModuleBase object contains the properties that are common to all Android
// modules. It should be included as an anonymous field in every module
// struct definition. InitAndroidModule should then be called from the module's
@@ -643,9 +710,9 @@
primaryVisibilityProperty visibilityProperty
noAddressSanitizer bool
- installFiles Paths
+ installFiles InstallPaths
checkbuildFiles Paths
- noticeFile OptionalPath
+ noticeFiles Paths
// Used by buildTargetSingleton to create checkbuild and per-directory build targets
// Only set on the final variant of each module
@@ -771,6 +838,11 @@
return m.commonProperties.ArchSpecific
}
+// True if the current variant is a CommonOS variant, false otherwise.
+func (m *ModuleBase) IsCommonOSVariant() bool {
+ return m.commonProperties.CommonOSVariant
+}
+
func (m *ModuleBase) OsClassSupported() []OsClass {
switch m.commonProperties.HostOrDeviceSupported {
case HostSupported:
@@ -830,6 +902,40 @@
return Bool(m.commonProperties.System_ext_specific)
}
+func (m *ModuleBase) PartitionTag(config DeviceConfig) string {
+ partition := "system"
+ if m.SocSpecific() {
+ // A SoC-specific module could be on the vendor partition at
+ // "vendor" or the system partition at "system/vendor".
+ if config.VendorPath() == "vendor" {
+ partition = "vendor"
+ }
+ } else if m.DeviceSpecific() {
+ // A device-specific module could be on the odm partition at
+ // "odm", the vendor partition at "vendor/odm", or the system
+ // partition at "system/vendor/odm".
+ if config.OdmPath() == "odm" {
+ partition = "odm"
+ } else if strings.HasPrefix(config.OdmPath(), "vendor/") {
+ partition = "vendor"
+ }
+ } else if m.ProductSpecific() {
+ // A product-specific module could be on the product partition
+ // at "product" or the system partition at "system/product".
+ if config.ProductPath() == "product" {
+ partition = "product"
+ }
+ } else if m.SystemExtSpecific() {
+ // A system_ext-specific module could be on the system_ext
+ // partition at "system_ext" or the system partition at
+ // "system/system_ext".
+ if config.SystemExtPath() == "system_ext" {
+ partition = "system_ext"
+ }
+ }
+ return partition
+}
+
func (m *ModuleBase) Enabled() bool {
if m.commonProperties.Enabled == nil {
return !m.Os().DefaultDisabled
@@ -845,26 +951,28 @@
m.commonProperties.SkipInstall = true
}
+func (m *ModuleBase) IsSkipInstall() bool {
+ return m.commonProperties.SkipInstall == true
+}
+
func (m *ModuleBase) ExportedToMake() bool {
return m.commonProperties.NamespaceExportedToMake
}
-func (m *ModuleBase) computeInstallDeps(
- ctx blueprint.ModuleContext) Paths {
+func (m *ModuleBase) computeInstallDeps(ctx blueprint.ModuleContext) InstallPaths {
- result := Paths{}
+ var result InstallPaths
// TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation
- ctx.VisitDepsDepthFirstIf(isFileInstaller,
- func(m blueprint.Module) {
- fileInstaller := m.(fileInstaller)
- files := fileInstaller.filesToInstall()
- result = append(result, files...)
- })
+ ctx.VisitDepsDepthFirst(func(m blueprint.Module) {
+ if a, ok := m.(Module); ok {
+ result = append(result, a.filesToInstall()...)
+ }
+ })
return result
}
-func (m *ModuleBase) filesToInstall() Paths {
+func (m *ModuleBase) filesToInstall() InstallPaths {
return m.installFiles
}
@@ -900,12 +1008,16 @@
return false
}
+func (m *ModuleBase) InstallForceOS() *OsType {
+ return nil
+}
+
func (m *ModuleBase) Owner() string {
return String(m.commonProperties.Owner)
}
-func (m *ModuleBase) NoticeFile() OptionalPath {
- return m.noticeFile
+func (m *ModuleBase) NoticeFiles() Paths {
+ return m.noticeFiles
}
func (m *ModuleBase) setImageVariation(variant string) {
@@ -919,6 +1031,16 @@
}
}
+func (m *ModuleBase) getVariationByMutatorName(mutator string) string {
+ for i, v := range m.commonProperties.DebugMutators {
+ if v == mutator {
+ return m.commonProperties.DebugVariations[i]
+ }
+ }
+
+ return ""
+}
+
func (m *ModuleBase) InRamdisk() bool {
return m.base().commonProperties.ImageVariation == RamdiskVariation
}
@@ -948,8 +1070,8 @@
}
func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
- allInstalledFiles := Paths{}
- allCheckbuildFiles := Paths{}
+ var allInstalledFiles InstallPaths
+ var allCheckbuildFiles Paths
ctx.VisitAllModuleVariants(func(module Module) {
a := module.base()
allInstalledFiles = append(allInstalledFiles, a.installFiles...)
@@ -968,7 +1090,7 @@
ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
Output: name,
- Implicits: allInstalledFiles,
+ Implicits: allInstalledFiles.Paths(),
Default: !ctx.Config().EmbeddedInMake(),
})
deps = append(deps, name)
@@ -1097,8 +1219,11 @@
blueprintCtx.GetMissingDependencies()
// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and
- // are enabled.
- ctx.baseModuleContext.strictVisitDeps = true
+ // are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants
+ // (because the dependencies are added before the modules are disabled). The
+ // GetOsSpecificVariantsOfCommonOSVariant(...) method will ensure that the disabled variants are
+ // ignored.
+ ctx.baseModuleContext.strictVisitDeps = !m.IsCommonOSVariant()
if ctx.config.captureBuild {
ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
@@ -1151,12 +1276,25 @@
}
})
- notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
+ m.noticeFiles = make([]Path, 0)
+ optPath := OptionalPath{}
+ notice := proptools.StringDefault(m.commonProperties.Notice, "")
if module := SrcIsModule(notice); module != "" {
- m.noticeFile = ctx.ExpandOptionalSource(¬ice, "notice")
- } else {
+ optPath = ctx.ExpandOptionalSource(¬ice, "notice")
+ } else if notice != "" {
noticePath := filepath.Join(ctx.ModuleDir(), notice)
- m.noticeFile = ExistentPathForSource(ctx, noticePath)
+ optPath = ExistentPathForSource(ctx, noticePath)
+ }
+ if optPath.Valid() {
+ m.noticeFiles = append(m.noticeFiles, optPath.Path())
+ } else {
+ for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} {
+ noticePath := filepath.Join(ctx.ModuleDir(), notice)
+ optPath = ExistentPathForSource(ctx, noticePath)
+ if optPath.Valid() {
+ m.noticeFiles = append(m.noticeFiles, optPath.Path())
+ }
+ }
}
m.module.GenerateAndroidBuildActions(ctx)
@@ -1274,20 +1412,25 @@
debug bool
walkPath []Module
+ tagPath []blueprint.DependencyTag
strictVisitDeps bool // If true, enforce that all dependencies are enabled
}
-func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) }
-func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
+func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
+ return b.bp.OtherModuleName(m)
+}
+func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
b.bp.OtherModuleErrorf(m, fmt, args...)
}
func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
return b.bp.OtherModuleDependencyTag(m)
}
-func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
-func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) }
+func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
+ return b.bp.OtherModuleType(m)
+}
func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
return b.bp.GetDirectDepWithTag(name, tag)
@@ -1296,8 +1439,8 @@
type moduleContext struct {
bp blueprint.ModuleContext
baseModuleContext
- installDeps Paths
- installFiles Paths
+ installDeps InstallPaths
+ installFiles InstallPaths
checkbuildFiles Paths
module Module
@@ -1376,10 +1519,17 @@
func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
- 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
+ if m.config.UseRemoteBuild() {
+ if 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
+ } else if params.Pool == remotePool {
+ // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+ // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+ // parallelism.
+ params.Pool = nil
+ }
}
rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
@@ -1559,6 +1709,7 @@
func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
b.walkPath = []Module{b.Module()}
+ b.tagPath = []blueprint.DependencyTag{}
b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
childAndroidModule, _ := child.(Module)
parentAndroidModule, _ := parent.(Module)
@@ -1566,8 +1717,10 @@
// record walkPath before visit
for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+ b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
}
b.walkPath = append(b.walkPath, childAndroidModule)
+ b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
return visit(childAndroidModule, parentAndroidModule)
} else {
return false
@@ -1579,6 +1732,10 @@
return b.walkPath
}
+func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
+ return b.tagPath
+}
+
func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
visit(module.(Module))
@@ -1703,6 +1860,10 @@
return m.module.InstallBypassMake()
}
+func (m *moduleContext) InstallForceOS() *OsType {
+ return m.module.InstallForceOS()
+}
+
func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool {
if m.module.base().commonProperties.SkipInstall {
return true
@@ -1746,7 +1907,7 @@
if !m.skipInstall(fullInstallPath) {
- deps = append(deps, m.installDeps...)
+ deps = append(deps, m.installDeps.Paths()...)
var implicitDeps, orderOnlyDeps Paths
@@ -1827,20 +1988,6 @@
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
}
-type fileInstaller interface {
- filesToInstall() Paths
-}
-
-func isFileInstaller(m blueprint.Module) bool {
- _, ok := m.(fileInstaller)
- return ok
-}
-
-func isAndroidModule(m blueprint.Module) bool {
- _, ok := m.(Module)
- return ok
-}
-
func findStringInSlice(str string, slice []string) int {
for i, s := range slice {
if s == str {
diff --git a/android/mutator.go b/android/mutator.go
index a46d4be..10a815a 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -103,7 +103,7 @@
registerPathDepsMutator,
RegisterPrebuiltsPostDepsMutators,
RegisterVisibilityRuleEnforcer,
- registerNeverallowMutator,
+ RegisterNeverallowMutator,
RegisterOverridePostDepsMutators,
}
diff --git a/android/neverallow.go b/android/neverallow.go
index 0cb2029..cf09792 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -17,6 +17,7 @@
import (
"path/filepath"
"reflect"
+ "regexp"
"strconv"
"strings"
@@ -41,7 +42,7 @@
// counts as a match
// - it has none of the "Without" properties matched (same rules as above)
-func registerNeverallowMutator(ctx RegisterMutatorsContext) {
+func RegisterNeverallowMutator(ctx RegisterMutatorsContext) {
ctx.BottomUp("neverallow", neverallowMutator).Parallel()
}
@@ -53,6 +54,7 @@
AddNeverAllowRules(createLibcoreRules()...)
AddNeverAllowRules(createMediaRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...)
+ AddNeverAllowRules(createCcSdkVariantRules()...)
}
// Add a NeverAllow rule to the set of rules to apply.
@@ -102,6 +104,7 @@
In("vendor", "device").
With("vndk.enabled", "true").
Without("vendor", "true").
+ Without("product_specific", "true").
Because("the VNDK can never contain a library that is device dependent."),
NeverAllow().
With("vndk.enabled", "true").
@@ -145,7 +148,8 @@
rules := []Rule{
NeverAllow().
NotIn(coreLibraryProjects...).
- With("sdk_version", "none"),
+ With("sdk_version", "none").
+ WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
}
return rules
@@ -174,6 +178,37 @@
}
}
+func createCcSdkVariantRules() []Rule {
+ sdkVersionOnlyWhitelist := []string{
+ // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk.
+ // This sometimes works because the APEX modules that contain derive_sdk and
+ // derive_sdk_prefer32 suppress the platform installation rules, but fails when
+ // the APEX modules contain the SDK variant and the platform variant still exists.
+ "frameworks/base/apex/sdkextensions/derive_sdk",
+ }
+
+ platformVariantPropertiesWhitelist := []string{
+ // android_native_app_glue and libRSSupport use native_window.h but target old
+ // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist,
+ // so they can't add libnativewindow to shared_libs to get the header directory
+ // for the platform variant. Allow them to use the platform variant
+ // property to set shared_libs.
+ "prebuilts/ndk",
+ "frameworks/rs",
+ }
+
+ return []Rule{
+ NeverAllow().
+ NotIn(sdkVersionOnlyWhitelist...).
+ WithMatcher("sdk_variant_only", isSetMatcherInstance).
+ Because("sdk_variant_only can only be used in whitelisted projects"),
+ NeverAllow().
+ NotIn(platformVariantPropertiesWhitelist...).
+ WithMatcher("platform.shared_libs", isSetMatcherInstance).
+ Because("platform variant properties can only be used in whitelisted projects"),
+ }
+}
+
func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
@@ -212,7 +247,7 @@
}
type ValueMatcher interface {
- test(string) bool
+ Test(string) bool
String() string
}
@@ -220,7 +255,7 @@
expected string
}
-func (m *equalMatcher) test(value string) bool {
+func (m *equalMatcher) Test(value string) bool {
return m.expected == value
}
@@ -231,7 +266,7 @@
type anyMatcher struct {
}
-func (m *anyMatcher) test(value string) bool {
+func (m *anyMatcher) Test(value string) bool {
return true
}
@@ -245,7 +280,7 @@
prefix string
}
-func (m *startsWithMatcher) test(value string) bool {
+func (m *startsWithMatcher) Test(value string) bool {
return strings.HasPrefix(value, m.prefix)
}
@@ -253,6 +288,30 @@
return ".starts-with(" + m.prefix + ")"
}
+type regexMatcher struct {
+ re *regexp.Regexp
+}
+
+func (m *regexMatcher) Test(value string) bool {
+ return m.re.MatchString(value)
+}
+
+func (m *regexMatcher) String() string {
+ return ".regexp(" + m.re.String() + ")"
+}
+
+type isSetMatcher struct{}
+
+func (m *isSetMatcher) Test(value string) bool {
+ return value != ""
+}
+
+func (m *isSetMatcher) String() string {
+ return ".is-set"
+}
+
+var isSetMatcherInstance = &isSetMatcher{}
+
type ruleProperty struct {
fields []string // e.x.: Vndk.Enabled
matcher ValueMatcher
@@ -456,6 +515,14 @@
return &startsWithMatcher{prefix}
}
+func Regexp(re string) ValueMatcher {
+ r, err := regexp.Compile(re)
+ if err != nil {
+ panic(err)
+ }
+ return ®exMatcher{r}
+}
+
// assorted utils
func cleanPaths(paths []string) []string {
@@ -506,7 +573,7 @@
}
check := func(value string) bool {
- return prop.matcher.test(value)
+ return prop.matcher.Test(value)
}
if matchValue(propertiesValue, check) {
@@ -563,6 +630,6 @@
// Overrides the default neverallow rules for the supplied config.
//
// For testing only.
-func setTestNeverallowRules(config Config, testRules []Rule) {
+func SetTestNeverallowRules(config Config, testRules []Rule) {
config.Once(neverallowRulesKey, func() interface{} { return testRules })
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 6f07a4a..2fc42e3 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -227,6 +227,16 @@
},
},
{
+ name: "sdk_version: \"none\" on android_*stubs_current stub",
+ fs: map[string][]byte{
+ "frameworks/base/Android.bp": []byte(`
+ java_library {
+ name: "android_stubs_current",
+ sdk_version: "none",
+ }`),
+ },
+ },
+ {
name: "sdk_version: \"none\" outside core libraries",
fs: map[string][]byte{
"Android.bp": []byte(`
@@ -249,6 +259,50 @@
}`),
},
},
+ // CC sdk rule tests
+ {
+ name: `"sdk_variant_only" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ sdk_version: "current",
+ sdk_variant_only: true,
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
+ {
+ name: `"sdk_variant_only: false" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ sdk_version: "current",
+ sdk_variant_only: false,
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
+ {
+ name: `"platform" outside whitelist`,
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ cc_library {
+ name: "outside_whitelist",
+ platform: {
+ shared_libs: ["libfoo"],
+ },
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outside_whitelist": violates neverallow`,
+ },
+ },
}
func TestNeverallow(t *testing.T) {
@@ -259,7 +313,7 @@
t.Run(test.name, func(t *testing.T) {
// If the test has its own rules then use them instead of the default ones.
if test.rules != nil {
- setTestNeverallowRules(config, test.rules)
+ SetTestNeverallowRules(config, test.rules)
}
_, errs := testNeverallow(config)
CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
@@ -273,7 +327,7 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
- ctx.PostDepsMutators(registerNeverallowMutator)
+ ctx.PostDepsMutators(RegisterNeverallowMutator)
ctx.Register(config)
_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -289,6 +343,8 @@
Include_dirs []string
Vendor_available *bool
Static_libs []string
+ Sdk_version *string
+ Sdk_variant_only *bool
Vndk struct {
Enabled *bool
@@ -305,6 +361,10 @@
Cflags []string
}
}
+
+ Platform struct {
+ Shared_libs []string
+ }
}
type mockCcLibraryModule struct {
diff --git a/android/notices.go b/android/notices.go
index bf273b5..07cf3e4 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -22,7 +22,7 @@
func init() {
pctx.SourcePathVariable("merge_notices", "build/soong/scripts/mergenotice.py")
- pctx.SourcePathVariable("generate_notice", "build/make/tools/generate-notice-files.py")
+ pctx.SourcePathVariable("generate_notice", "build/soong/scripts/generate-notice-files.py")
pctx.HostBinToolVariable("minigzip", "minigzip")
}
diff --git a/android/paths.go b/android/paths.go
index 66725c6..8bb9a96 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -53,6 +53,7 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() *OsType
}
var _ ModuleInstallPathContext = ModuleContext(nil)
@@ -469,6 +470,14 @@
// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each. It
// modifies the Paths slice contents in place, and returns a subslice of the original slice.
func FirstUniquePaths(list Paths) Paths {
+ // 128 was chosen based on BenchmarkFirstUniquePaths results.
+ if len(list) > 128 {
+ return firstUniquePathsMap(list)
+ }
+ return firstUniquePathsList(list)
+}
+
+func firstUniquePathsList(list Paths) Paths {
k := 0
outer:
for i := 0; i < len(list); i++ {
@@ -483,6 +492,20 @@
return list[:k]
}
+func firstUniquePathsMap(list Paths) Paths {
+ k := 0
+ seen := make(map[Path]bool, len(list))
+ for i := 0; i < len(list); i++ {
+ if seen[list[i]] {
+ continue
+ }
+ seen[list[i]] = true
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
+}
+
// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each. It
// modifies the Paths slice contents in place, and returns a subslice of the original slice.
func LastUniquePaths(list Paths) Paths {
@@ -1205,22 +1228,40 @@
// PathForModuleInstall returns a Path representing the install path for the
// module appended with paths...
func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+ os := ctx.Os()
+ if forceOS := ctx.InstallForceOS(); forceOS != nil {
+ os = *forceOS
+ }
+ partition := modulePartition(ctx, os)
+
+ ret := pathForInstall(ctx, os, partition, ctx.Debug(), pathComponents...)
+
+ if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
+ ret = ret.ToMakePath()
+ }
+
+ return ret
+}
+
+func pathForInstall(ctx PathContext, os OsType, partition string, debug bool,
+ pathComponents ...string) InstallPath {
+
var outPaths []string
- if ctx.Device() {
- partition := modulePartition(ctx)
+
+ if os.Class == Device {
outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
- switch ctx.Os() {
+ switch os {
case Linux:
- outPaths = []string{"host", "linux-x86"}
+ outPaths = []string{"host", "linux-x86", partition}
case LinuxBionic:
// TODO: should this be a separate top level, or shared with linux-x86?
- outPaths = []string{"host", "linux_bionic-x86"}
+ outPaths = []string{"host", "linux_bionic-x86", partition}
default:
- outPaths = []string{"host", ctx.Os().String() + "-x86"}
+ outPaths = []string{"host", os.String() + "-x86", partition}
}
}
- if ctx.Debug() {
+ if debug {
outPaths = append([]string{"debug"}, outPaths...)
}
outPaths = append(outPaths, pathComponents...)
@@ -1231,15 +1272,12 @@
}
ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
- if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
- ret = ret.ToMakePath()
- }
return ret
}
-func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
- paths = append([]string{"ndk"}, paths...)
+func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
+ paths = append([]string{prefix}, paths...)
path, err := validatePath(paths...)
if err != nil {
reportPathError(ctx, err)
@@ -1247,53 +1285,90 @@
return InstallPath{basePath{path, ctx.Config(), ""}, ""}
}
+func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
+ return pathForNdkOrSdkInstall(ctx, "ndk", paths)
+}
+
+func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
+ return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
+}
+
func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
return "/" + rel
}
-func modulePartition(ctx ModuleInstallPathContext) string {
+func modulePartition(ctx ModuleInstallPathContext, os OsType) string {
var partition string
- if ctx.InstallInData() {
- partition = "data"
- } else if ctx.InstallInTestcases() {
+ if ctx.InstallInTestcases() {
+ // "testcases" install directory can be used for host or device modules.
partition = "testcases"
- } else if ctx.InstallInRamdisk() {
- if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
- partition = "recovery/root/first_stage_ramdisk"
+ } else if os.Class == Device {
+ if ctx.InstallInData() {
+ partition = "data"
+ } 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"
+ } else {
+ // the layout of recovery partion is the same as that of system partition
+ partition = "recovery/root/system"
+ }
+ } else if ctx.SocSpecific() {
+ partition = ctx.DeviceConfig().VendorPath()
+ } else if ctx.DeviceSpecific() {
+ partition = ctx.DeviceConfig().OdmPath()
+ } else if ctx.ProductSpecific() {
+ partition = ctx.DeviceConfig().ProductPath()
+ } else if ctx.SystemExtSpecific() {
+ partition = ctx.DeviceConfig().SystemExtPath()
+ } else if ctx.InstallInRoot() {
+ partition = "root"
} else {
- partition = "ramdisk"
+ partition = "system"
}
- if !ctx.InstallInRoot() {
- partition += "/system"
+ if ctx.InstallInSanitizerDir() {
+ partition = "data/asan/" + partition
}
- } else if ctx.InstallInRecovery() {
- if ctx.InstallInRoot() {
- partition = "recovery/root"
- } else {
- // the layout of recovery partion is the same as that of system partition
- partition = "recovery/root/system"
- }
- } else if ctx.SocSpecific() {
- partition = ctx.DeviceConfig().VendorPath()
- } else if ctx.DeviceSpecific() {
- partition = ctx.DeviceConfig().OdmPath()
- } else if ctx.ProductSpecific() {
- partition = ctx.DeviceConfig().ProductPath()
- } else if ctx.SystemExtSpecific() {
- partition = ctx.DeviceConfig().SystemExtPath()
- } else if ctx.InstallInRoot() {
- partition = "root"
- } else {
- partition = "system"
- }
- if ctx.InstallInSanitizerDir() {
- partition = "data/asan/" + partition
}
return partition
}
+type InstallPaths []InstallPath
+
+// Paths returns the InstallPaths as a Paths
+func (p InstallPaths) Paths() Paths {
+ if p == nil {
+ return nil
+ }
+ ret := make(Paths, len(p))
+ for i, path := range p {
+ ret[i] = path
+ }
+ return ret
+}
+
+// Strings returns the string forms of the install paths.
+func (p InstallPaths) Strings() []string {
+ if p == nil {
+ return nil
+ }
+ ret := make([]string, len(p))
+ for i, path := range p {
+ ret[i] = path.String()
+ }
+ return ret
+}
+
// validateSafePath validates a path that we trust (may contain ninja variables).
// Ensures that each path component does not attempt to leave its component.
func validateSafePath(pathComponents ...string) (string, error) {
diff --git a/android/paths_test.go b/android/paths_test.go
index 7a32026..9b45d3f 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -18,6 +18,7 @@
"errors"
"fmt"
"reflect"
+ "strconv"
"strings"
"testing"
@@ -205,6 +206,7 @@
inRamdisk bool
inRecovery bool
inRoot bool
+ forceOS *OsType
}
func (m moduleInstallPathContextImpl) Config() Config {
@@ -241,6 +243,10 @@
return false
}
+func (m moduleInstallPathContextImpl) InstallForceOS() *OsType {
+ return m.forceOS
+}
+
func pathTestConfig(buildDir string) Config {
return TestConfig(buildDir, nil, "", nil)
}
@@ -598,6 +604,40 @@
},
in: []string{"nativetest", "my_test"},
out: "target/product/test_device/data/asan/data/nativetest/my_test",
+ }, {
+ name: "device testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inTestcases: true,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "target/product/test_device/testcases/my_test/my_test_bin",
+ }, {
+ name: "host testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: hostTarget.Os,
+ target: hostTarget,
+ },
+ inTestcases: true,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "host/linux-x86/testcases/my_test/my_test_bin",
+ }, {
+ name: "forced host testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inTestcases: true,
+ forceOS: &Linux,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "host/linux-x86/testcases/my_test/my_test_bin",
},
}
@@ -1216,3 +1256,51 @@
// out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
// boot.art oat/arm/boot.vdex
}
+
+func BenchmarkFirstUniquePaths(b *testing.B) {
+ implementations := []struct {
+ name string
+ f func(Paths) Paths
+ }{
+ {
+ name: "list",
+ f: firstUniquePathsList,
+ },
+ {
+ name: "map",
+ f: firstUniquePathsMap,
+ },
+ }
+ const maxSize = 1024
+ uniquePaths := make(Paths, maxSize)
+ for i := range uniquePaths {
+ uniquePaths[i] = PathForTesting(strconv.Itoa(i))
+ }
+ samePath := make(Paths, maxSize)
+ for i := range samePath {
+ samePath[i] = uniquePaths[0]
+ }
+
+ f := func(b *testing.B, imp func(Paths) Paths, paths Paths) {
+ for i := 0; i < b.N; i++ {
+ b.ReportAllocs()
+ paths = append(Paths(nil), paths...)
+ imp(paths)
+ }
+ }
+
+ for n := 1; n <= maxSize; n <<= 1 {
+ b.Run(strconv.Itoa(n), func(b *testing.B) {
+ for _, implementation := range implementations {
+ b.Run(implementation.name, func(b *testing.B) {
+ b.Run("same", func(b *testing.B) {
+ f(b, implementation.f, samePath[:n])
+ })
+ b.Run("unique", func(b *testing.B) {
+ f(b, implementation.f, uniquePaths[:n])
+ })
+ })
+ }
+ })
+ }
+}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2d16f65..82745a4 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -39,6 +39,12 @@
// Mark this tag so dependencies that use it are excluded from visibility enforcement.
func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {}
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t prebuiltDependencyTag) ExcludeFromApexContents() {}
+
+var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
+var _ ExcludeFromApexContentsTag = PrebuiltDepTag
+
type PrebuiltProperties struct {
// When prefer is set to true the prebuilt will be used instead of any source module with
// a matching name.
@@ -50,12 +56,9 @@
type Prebuilt struct {
properties PrebuiltProperties
- module Module
- srcs *[]string
- // Metadata for single source Prebuilt modules.
- srcProps reflect.Value
- srcField reflect.StructField
+ srcsSupplier PrebuiltSrcsSupplier
+ srcsPropertyName string
}
func (p *Prebuilt) Name(name string) string {
@@ -72,31 +75,26 @@
// preference configs. We'll want to add native support for dynamic source cases if we end up having
// more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
- if p.srcs != nil {
- if len(*p.srcs) == 0 {
- ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+ if p.srcsSupplier != nil {
+ srcs := p.srcsSupplier()
+
+ if len(srcs) == 0 {
+ ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
return nil
}
- if len(*p.srcs) > 1 {
- ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+ if len(srcs) > 1 {
+ ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
return nil
}
// Return the singleton source after expanding any filegroup in the
// sources.
- return PathForModuleSrc(ctx, (*p.srcs)[0])
- } else {
- if !p.srcProps.IsValid() {
- ctx.ModuleErrorf("prebuilt source was not set")
- }
- src := p.getSingleSourceFieldValue()
- if src == "" {
- ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
- "missing prebuilt source file")
- return nil
- }
+ src := srcs[0]
return PathForModuleSrc(ctx, src)
+ } else {
+ ctx.ModuleErrorf("prebuilt source was not set")
+ return nil
}
}
@@ -104,18 +102,80 @@
return p.properties.UsePrebuilt
}
-func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+// Called to provide the srcs value for the prebuilt module.
+//
+// Return the src value or nil if it is not available.
+type PrebuiltSrcsSupplier func() []string
+
+// Initialize the module as a prebuilt module that uses the provided supplier to access the
+// prebuilt sources of the module.
+//
+// The supplier will be called multiple times and must return the same values each time it
+// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
+// as a replacement for a source module with the same name even if prefer = true.
+//
+// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
+// containing exactly one source file.
+//
+// The provided property name is used to provide helpful error messages in the event that
+// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
+func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
p := module.Prebuilt()
module.AddProperties(&p.properties)
- p.srcs = srcs
+
+ if srcsSupplier == nil {
+ panic(fmt.Errorf("srcsSupplier must not be nil"))
+ }
+ if srcsPropertyName == "" {
+ panic(fmt.Errorf("srcsPropertyName must not be empty"))
+ }
+
+ p.srcsSupplier = srcsSupplier
+ p.srcsPropertyName = srcsPropertyName
+}
+
+func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+ if srcs == nil {
+ panic(fmt.Errorf("srcs must not be nil"))
+ }
+
+ srcsSupplier := func() []string {
+ return *srcs
+ }
+
+ InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
}
func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
- p := module.Prebuilt()
- module.AddProperties(&p.properties)
- p.srcProps = reflect.ValueOf(srcProps).Elem()
- p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
- p.checkSingleSourceProperties()
+ srcPropsValue := reflect.ValueOf(srcProps).Elem()
+ srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
+ if !srcPropsValue.IsValid() || srcStructField.Name == "" {
+ panic(fmt.Errorf("invalid single source prebuilt %+v", module))
+ }
+
+ if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
+ panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
+ }
+
+ srcFieldIndex := srcStructField.Index
+ srcPropertyName := proptools.PropertyNameForField(srcField)
+
+ srcsSupplier := func() []string {
+ value := srcPropsValue.FieldByIndex(srcFieldIndex)
+ if value.Kind() == reflect.Ptr {
+ value = value.Elem()
+ }
+ if value.Kind() != reflect.String {
+ panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
+ }
+ src := value.String()
+ if src == "" {
+ return nil
+ }
+ return []string{src}
+ }
+
+ InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
}
type PrebuiltInterface interface {
@@ -152,7 +212,7 @@
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt()
- if p.srcs == nil && !p.srcProps.IsValid() {
+ if p.srcsSupplier == nil {
panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
}
if !p.properties.SourceExists {
@@ -191,11 +251,7 @@
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
- if p.srcs != nil && len(*p.srcs) == 0 {
- return false
- }
-
- if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
+ if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
return false
}
@@ -210,24 +266,3 @@
func (p *Prebuilt) SourceExists() bool {
return p.properties.SourceExists
}
-
-func (p *Prebuilt) checkSingleSourceProperties() {
- if !p.srcProps.IsValid() || p.srcField.Name == "" {
- panic(fmt.Errorf("invalid single source prebuilt %+v", p))
- }
-
- if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
- panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
- }
-}
-
-func (p *Prebuilt) getSingleSourceFieldValue() string {
- value := p.srcProps.FieldByIndex(p.srcField.Index)
- if value.Kind() == reflect.Ptr {
- value = value.Elem()
- }
- if value.Kind() != reflect.String {
- panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
- }
- return value.String()
-}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index b4f144a..6226548 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -162,9 +162,10 @@
r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
}
-// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such
-// as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command
-// that are also outputs of another command in the same RuleBuilder are filtered out.
+// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// input paths, such as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or
+// RuleBuilderCommand.FlagWithInput. Inputs to a command that are also outputs of another command
+// in the same RuleBuilder are filtered out. The list is sorted and duplicates removed.
func (r *RuleBuilder) Inputs() Paths {
outputs := r.outputSet()
depFiles := r.depFileSet()
@@ -193,6 +194,28 @@
return inputList
}
+// OrderOnlys returns the list of paths that were passed to the RuleBuilderCommand.OrderOnly or
+// RuleBuilderCommand.OrderOnlys. The list is sorted and duplicates removed.
+func (r *RuleBuilder) OrderOnlys() Paths {
+ orderOnlys := make(map[string]Path)
+ for _, c := range r.commands {
+ for _, orderOnly := range c.orderOnlys {
+ orderOnlys[orderOnly.String()] = orderOnly
+ }
+ }
+
+ var orderOnlyList Paths
+ for _, orderOnly := range orderOnlys {
+ orderOnlyList = append(orderOnlyList, orderOnly)
+ }
+
+ sort.Slice(orderOnlyList, func(i, j int) bool {
+ return orderOnlyList[i].String() < orderOnlyList[j].String()
+ })
+
+ return orderOnlyList
+}
+
func (r *RuleBuilder) outputSet() map[string]WritablePath {
outputs := make(map[string]WritablePath)
for _, c := range r.commands {
@@ -203,8 +226,9 @@
return outputs
}
-// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such
-// as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput.
+// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take
+// output paths, such as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or
+// RuleBuilderCommand.FlagWithInput. The list is sorted and duplicates removed.
func (r *RuleBuilder) Outputs() WritablePaths {
outputs := r.outputSet()
@@ -262,7 +286,8 @@
return tools
}
-// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.
+// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. The
+// list is sorted and duplicates removed.
func (r *RuleBuilder) Tools() Paths {
toolsSet := r.toolsSet()
@@ -337,6 +362,7 @@
ctx.Build(pctx, BuildParams{
Rule: ErrorRule,
Outputs: r.Outputs(),
+ OrderOnly: r.OrderOnlys(),
Description: desc,
Args: map[string]string{
"error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
@@ -420,7 +446,8 @@
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.
+ // When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
+ pool = remotePool
} else if r.highmem {
pool = highmemPool
} else if ctx.Config().UseRemoteBuild() {
@@ -453,6 +480,7 @@
type RuleBuilderCommand struct {
buf strings.Builder
inputs Paths
+ orderOnlys Paths
outputs WritablePaths
depFiles WritablePaths
tools Paths
@@ -475,6 +503,10 @@
return path.String()
}
+func (c *RuleBuilderCommand) addOrderOnly(path Path) {
+ c.orderOnlys = append(c.orderOnlys, path)
+}
+
func (c *RuleBuilderCommand) outputStr(path Path) string {
if c.sbox {
// Errors will be handled in RuleBuilder.Build where we have a context to report them
@@ -604,6 +636,22 @@
return c
}
+// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
+ c.addOrderOnly(path)
+ return c
+}
+
+// OrderOnlys adds the specified input paths to the dependencies returned by RuleBuilder.OrderOnlys
+// without modifying the command line.
+func (c *RuleBuilderCommand) OrderOnlys(paths Paths) *RuleBuilderCommand {
+ for _, path := range paths {
+ c.addOrderOnly(path)
+ }
+ return c
+}
+
// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
// RuleBuilder.Outputs.
func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index acf8127..c41b067 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -265,14 +265,16 @@
func TestRuleBuilder(t *testing.T) {
fs := map[string][]byte{
- "dep_fixer": nil,
- "input": nil,
- "Implicit": nil,
- "Input": nil,
- "Tool": nil,
- "input2": nil,
- "tool2": nil,
- "input3": nil,
+ "dep_fixer": nil,
+ "input": nil,
+ "Implicit": nil,
+ "Input": nil,
+ "OrderOnly": nil,
+ "OrderOnlys": nil,
+ "Tool": nil,
+ "input2": nil,
+ "tool2": nil,
+ "input3": nil,
}
ctx := PathContextForTesting(TestConfig("out", nil, "", fs))
@@ -290,6 +292,7 @@
ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")).
Input(PathForSource(ctx, "Input")).
Output(PathForOutput(ctx, "Output")).
+ OrderOnly(PathForSource(ctx, "OrderOnly")).
Text("Text").
Tool(PathForSource(ctx, "Tool"))
@@ -298,6 +301,7 @@
DepFile(PathForOutput(ctx, "depfile2")).
Input(PathForSource(ctx, "input2")).
Output(PathForOutput(ctx, "output2")).
+ OrderOnlys(PathsForSource(ctx, []string{"OrderOnlys"})).
Tool(PathForSource(ctx, "tool2"))
// Test updates to the first command after the second command has been started
@@ -317,6 +321,7 @@
wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"})
wantDepFiles := PathsForOutput(ctx, []string{"DepFile", "depfile", "ImplicitDepFile", "depfile2"})
wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
+ wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
t.Run("normal", func(t *testing.T) {
rule := NewRuleBuilder()
@@ -346,6 +351,9 @@
if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
}
+ if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
+ }
if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
@@ -380,6 +388,9 @@
if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
t.Errorf("\nwant rule.Tools() = %#v\n got %#v", w, g)
}
+ if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+ t.Errorf("\nwant rule.OrderOnlys() = %#v\n got %#v", w, g)
+ }
if g, w := rule.depFileMergerCmd(ctx, rule.DepFiles()).String(), wantDepMergerCommand; g != w {
t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n got %#v", w, g)
diff --git a/android/sdk.go b/android/sdk.go
index d13ad7d..6f62f55 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -22,17 +22,30 @@
"github.com/google/blueprint/proptools"
)
+// Extracted from SdkAware to make it easier to define custom subsets of the
+// SdkAware interface and improve code navigation within the IDE.
+//
+// In addition to its use in SdkAware this interface must also be implemented by
+// APEX to specify the SDKs required by that module and its contents. e.g. APEX
+// is expected to implement RequiredSdks() by reading its own properties like
+// `uses_sdks`.
+type RequiredSdks interface {
+ // The set of SDKs required by an APEX and its contents.
+ RequiredSdks() SdkRefs
+}
+
// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
// built with SDK
type SdkAware interface {
Module
+ RequiredSdks
+
sdkBase() *SdkBase
MakeMemberOf(sdk SdkRef)
IsInAnySdk() bool
ContainingSdk() SdkRef
MemberName() string
BuildWithSdks(sdks SdkRefs)
- RequiredSdks() SdkRefs
}
// SdkRef refers to a version of an SDK
@@ -145,10 +158,6 @@
return s.properties.RequiredSdks
}
-func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
- sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
-}
-
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
// SdkBase.
func InitSdkAwareModule(m SdkAware) {
@@ -186,9 +195,33 @@
// is correctly output for both versioned and unversioned prebuilts in the
// snapshot.
//
+ // "required: true" means that the property must only contain references
+ // to other members of the sdk. Passing a reference to a module that is not a
+ // member of the sdk will result in a build error.
+ //
+ // "required: false" means that the property can contain references to modules
+ // that are either members or not members of the sdk. If a reference is to a
+ // module that is a non member then the reference is left unchanged, i.e. it
+ // is not transformed as references to members are.
+ //
+ // The handling of the member names is dependent on whether it is an internal or
+ // exported member. An exported member is one whose name is specified in one of
+ // the member type specific properties. An internal member is one that is added
+ // due to being a part of an exported (or other internal) member and is not itself
+ // an exported member.
+ //
+ // Member names are handled as follows:
+ // * When creating the unversioned form of the module the name is left unchecked
+ // unless the member is internal in which case it is transformed into an sdk
+ // specific name, i.e. by prefixing with the sdk name.
+ //
+ // * When creating the versioned form of the module the name is transformed into
+ // a versioned sdk specific name, i.e. by prefixing with the sdk name and
+ // suffixing with the version.
+ //
// e.g.
- // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
- SdkMemberReferencePropertyTag() BpPropertyTag
+ // bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
+ SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
type BpPropertyTag interface{}
@@ -280,10 +313,11 @@
// 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
- // supplied tag.
+ // Add dependencies from the SDK module to all the module variants the member
+ // type contributes to the SDK. `names` is the list of module names given in
+ // the member type property (as returned by SdkPropertyName()) in the SDK
+ // module. The exact set of variants required is determined by the SDK and its
+ // properties. The dependencies must be added with the supplied tag.
//
// The BottomUpMutatorContext provided is for the SDK module.
AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string)
@@ -295,14 +329,36 @@
// the module is not allowed in whichever sdk property it was added.
IsInstance(module Module) bool
- // Build the snapshot for the SDK member
+ // Add a prebuilt module that the sdk will populate.
//
- // The ModuleContext provided is for the SDK module, so information for
- // variants in the supplied member can be accessed using the Other... methods.
+ // Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
+ // method to build the snapshot. That method is deprecated because it requires the SdkMemberType
+ // implementation to do all the word.
//
- // The SdkMember is guaranteed to contain variants for which the
- // IsInstance(Module) method returned true.
- BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
+ // Otherwise, returning a non-nil value from this will cause the sdk module type to do the
+ // majority of the work to generate the snapshot. The sdk module code generates the snapshot
+ // as follows:
+ //
+ // * A properties struct of type SdkMemberProperties is created for each variant and
+ // populated with information from the variant by calling PopulateFromVariant(SdkAware)
+ // on the struct.
+ //
+ // * An additional properties struct is created into which the common properties will be
+ // added.
+ //
+ // * The variant property structs are analysed to find exported (capitalized) fields which
+ // have common values. Those fields are cleared and the common value added to the common
+ // properties. A field annotated with a tag of `sdk:"keep"` will be treated as if it
+ // was not capitalized, i.e. not optimized for common values.
+ //
+ // * The sdk module type populates the BpModule structure, creating the arch specific
+ // structure and calls AddToPropertySet(...) on the properties struct to add the member
+ // specific properties in the correct place in the structure.
+ //
+ AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
+
+ // Create a structure into which variant specific properties can be added.
+ CreateVariantPropertiesStruct() SdkMemberProperties
}
// Base type for SdkMemberType implementations.
@@ -389,3 +445,84 @@
SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
}
}
+
+// Base structure for all implementations of SdkMemberProperties.
+//
+// Contains common properties that apply across many different member types. These
+// are not affected by the optimization to extract common values.
+type SdkMemberPropertiesBase struct {
+ // The number of unique os types supported by the member variants.
+ //
+ // If a member has a variant with more than one os type then it will need to differentiate
+ // the locations of any of their prebuilt files in the snapshot by os type to prevent them
+ // from colliding. See OsPrefix().
+ //
+ // This property is the same for all variants of a member and so would be optimized away
+ // if it was not explicitly kept.
+ Os_count int `sdk:"keep"`
+
+ // The os type for which these properties refer.
+ //
+ // Provided to allow a member to differentiate between os types in the locations of their
+ // prebuilt files when it supports more than one os type.
+ //
+ // This property is the same for all os type specific variants of a member and so would be
+ // optimized away if it was not explicitly kept.
+ Os OsType `sdk:"keep"`
+
+ // The setting to use for the compile_multilib property.
+ //
+ // This property is set after optimization so there is no point in trying to optimize it.
+ Compile_multilib string `sdk:"keep"`
+}
+
+// The os prefix to use for any file paths in the sdk.
+//
+// Is an empty string if the member only provides variants for a single os type, otherwise
+// is the OsType.Name.
+func (b *SdkMemberPropertiesBase) OsPrefix() string {
+ if b.Os_count == 1 {
+ return ""
+ } else {
+ return b.Os.Name
+ }
+}
+
+func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
+ return b
+}
+
+// Interface to be implemented on top of a structure that contains variant specific
+// information.
+//
+// Struct fields that are capitalized are examined for common values to extract. Fields
+// that are not capitalized are assumed to be arch specific.
+type SdkMemberProperties interface {
+ // Access the base structure.
+ Base() *SdkMemberPropertiesBase
+
+ // Populate this structure with information from the variant.
+ PopulateFromVariant(ctx SdkMemberContext, variant Module)
+
+ // Add the information from this structure to the property set.
+ AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
+}
+
+// Provides access to information common to a specific member.
+type SdkMemberContext interface {
+
+ // The module context of the sdk common os variant which is creating the snapshot.
+ SdkModuleContext() ModuleContext
+
+ // The builder of the snapshot.
+ SnapshotBuilder() SnapshotBuilder
+
+ // The type of the member.
+ MemberType() SdkMemberType
+
+ // The name of the member.
+ //
+ // Provided for use by sdk members to create a member specific location within the snapshot
+ // into which to copy the prebuilt files.
+ Name() string
+}
diff --git a/android/singleton.go b/android/singleton.go
index 45a9b82..568398c 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -128,10 +128,17 @@
}
func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
- 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
+ if s.Config().UseRemoteBuild() {
+ if 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
+ } else if params.Pool == remotePool {
+ // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+ // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+ // parallelism.
+ params.Pool = nil
+ }
}
rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
if s.Config().captureBuild {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 198108d..619cf86 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -73,6 +73,9 @@
// feature: {
// cflags: ["-DFEATURE"],
// },
+// width: {
+// cflags: ["-DWIDTH=%s"],
+// },
// },
// }
//
@@ -88,7 +91,9 @@
// name: "acme_cc_defaults",
// module_type: "cc_defaults",
// config_namespace: "acme",
-// variables: ["board", "feature"],
+// variables: ["board"],
+// bool_variables: ["feature"],
+// value_variables: ["width"],
// properties: ["cflags", "srcs"],
// }
//
@@ -97,10 +102,6 @@
// values: ["soc_a", "soc_b"],
// }
//
-// soong_config_bool_variable {
-// name: "feature",
-// }
-//
// If an acme BoardConfig.mk file contained:
//
// SOONG_CONFIG_NAMESPACES += acme
@@ -110,8 +111,9 @@
//
// SOONG_CONFIG_acme_board := soc_a
// SOONG_CONFIG_acme_feature := true
+// SOONG_CONFIG_acme_width := 200
//
-// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
func soongConfigModuleTypeImportFactory() Module {
module := &soongConfigModuleTypeImport{}
@@ -125,7 +127,10 @@
}
func (m *soongConfigModuleTypeImport) Name() string {
- return "soong_config_module_type_import_" + soongconfig.CanonicalizeToProperty(m.properties.From)
+ // The generated name is non-deterministic, but it does not
+ // matter because this module does not emit any rules.
+ return soongconfig.CanonicalizeToProperty(m.properties.From) +
+ "soong_config_module_type_import_" + fmt.Sprintf("%p", m)
}
func (*soongConfigModuleTypeImport) Nameless() {}
@@ -149,7 +154,9 @@
// name: "acme_cc_defaults",
// module_type: "cc_defaults",
// config_namespace: "acme",
-// variables: ["board", "feature"],
+// variables: ["board"],
+// bool_variables: ["feature"],
+// value_variables: ["width"],
// properties: ["cflags", "srcs"],
// }
//
@@ -158,10 +165,6 @@
// values: ["soc_a", "soc_b"],
// }
//
-// soong_config_bool_variable {
-// name: "feature",
-// }
-//
// acme_cc_defaults {
// name: "acme_defaults",
// cflags: ["-DGENERIC"],
@@ -177,6 +180,9 @@
// feature: {
// cflags: ["-DFEATURE"],
// },
+// width: {
+// cflags: ["-DWIDTH=%s"],
+// },
// },
// }
//
@@ -195,6 +201,7 @@
//
// SOONG_CONFIG_acme_board := soc_a
// SOONG_CONFIG_acme_feature := true
+// SOONG_CONFIG_acme_width := 200
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
func soongConfigModuleTypeFactory() Module {
@@ -355,7 +362,12 @@
AddLoadHook(module, func(ctx LoadHookContext) {
config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
- for _, ps := range soongconfig.PropertiesToApply(moduleType, conditionalProps, config) {
+ newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
+ if err != nil {
+ ctx.ModuleErrorf("%s", err)
+ return
+ }
+ for _, ps := range newProps {
ctx.AppendProperties(ps)
}
})
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 6ad88a2..f905b1a 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -43,7 +43,9 @@
name: "acme_test_defaults",
module_type: "test_defaults",
config_namespace: "acme",
- variables: ["board", "feature1", "feature2", "FEATURE3"],
+ variables: ["board", "feature1", "FEATURE3"],
+ bool_variables: ["feature2"],
+ value_variables: ["size"],
properties: ["cflags", "srcs"],
}
@@ -57,10 +59,6 @@
}
soong_config_bool_variable {
- name: "feature2",
- }
-
- soong_config_bool_variable {
name: "FEATURE3",
}
`
@@ -85,6 +83,9 @@
cflags: ["-DSOC_B"],
},
},
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
feature1: {
cflags: ["-DFEATURE1"],
},
@@ -104,6 +105,7 @@
config.TestProductVariables.VendorVars = map[string]map[string]string{
"acme": map[string]string{
"board": "soc_a",
+ "size": "42",
"feature1": "true",
"feature2": "false",
// FEATURE3 unset
@@ -124,7 +126,7 @@
FailIfErrored(t, errs)
foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
- if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
+ if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted foo cflags %q, got %q", w, g)
}
}
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index aa4f5c5..142a813 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -109,6 +109,13 @@
// the list of SOONG_CONFIG variables that this module type will read
Variables []string
+ // the list of boolean SOONG_CONFIG variables that this module type will read
+ Bool_variables []string
+
+ // the list of SOONG_CONFIG variables that this module type will read. The value will be
+ // inserted into the properties with %s substitution.
+ Value_variables []string
+
// the list of properties that this module type will extend.
Properties []string
}
@@ -146,6 +153,30 @@
}
v.ModuleTypes[props.Name] = mt
+ for _, name := range props.Bool_variables {
+ if name == "" {
+ return []error{fmt.Errorf("bool_variable name must not be blank")}
+ }
+
+ mt.Variables = append(mt.Variables, &boolVariable{
+ baseVariable: baseVariable{
+ variable: name,
+ },
+ })
+ }
+
+ for _, name := range props.Value_variables {
+ if name == "" {
+ return []error{fmt.Errorf("value_variables entry must not be blank")}
+ }
+
+ mt.Variables = append(mt.Variables, &valueVariable{
+ baseVariable: baseVariable{
+ variable: name,
+ },
+ })
+ }
+
return nil
}
@@ -389,15 +420,17 @@
// 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{} {
+func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
var ret []interface{}
props = props.Elem().FieldByName(soongConfigProperty)
for i, c := range moduleType.Variables {
- if ps := c.PropertiesToApply(config, props.Field(i)); ps != nil {
+ if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
+ return nil, err
+ } else if ps != nil {
ret = append(ret, ps)
}
}
- return ret
+ return ret, nil
}
type ModuleType struct {
@@ -423,7 +456,7 @@
// PropertiesToApply should return one of the interface{} values set by initializeProperties to be applied
// to the module.
- PropertiesToApply(config SoongConfig, values reflect.Value) interface{}
+ PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error)
}
type baseVariable struct {
@@ -458,14 +491,14 @@
}
}
-func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
for j, v := range s.values {
if config.String(s.variable) == v {
- return values.Field(j).Interface()
+ return values.Field(j).Interface(), nil
}
}
- return nil
+ return nil, nil
}
type boolVariable struct {
@@ -480,11 +513,83 @@
v.Set(reflect.Zero(typ))
}
-func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) interface{} {
+func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
if config.Bool(b.variable) {
- return values.Interface()
+ return values.Interface(), nil
}
+ return nil, nil
+}
+
+type valueVariable struct {
+ baseVariable
+}
+
+func (s *valueVariable) variableValuesType() reflect.Type {
+ return emptyInterfaceType
+}
+
+func (s *valueVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
+ v.Set(reflect.Zero(typ))
+}
+
+func (s *valueVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
+ if !config.IsSet(s.variable) {
+ return nil, nil
+ }
+ configValue := config.String(s.variable)
+
+ propStruct := values.Elem().Elem()
+ for i := 0; i < propStruct.NumField(); i++ {
+ field := propStruct.Field(i)
+ kind := field.Kind()
+ if kind == reflect.Ptr {
+ if field.IsNil() {
+ continue
+ }
+ field = field.Elem()
+ }
+ switch kind {
+ case reflect.String:
+ err := printfIntoProperty(field, configValue)
+ if err != nil {
+ return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ }
+ case reflect.Slice:
+ for j := 0; j < field.Len(); j++ {
+ err := printfIntoProperty(field.Index(j), configValue)
+ if err != nil {
+ return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ }
+ }
+ case reflect.Bool:
+ // Nothing to do
+ default:
+ return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
+ }
+ }
+
+ return values.Interface(), nil
+}
+
+func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
+ s := propertyValue.String()
+
+ count := strings.Count(s, "%")
+ if count == 0 {
+ return nil
+ }
+
+ if count > 1 {
+ return fmt.Errorf("value variable properties only support a single '%%'")
+ }
+
+ if !strings.Contains(s, "%s") {
+ return fmt.Errorf("unsupported %% in value variable property")
+ }
+
+ propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, configValue)))
+
return nil
}
diff --git a/android/testing.go b/android/testing.go
index 9aff039..90989ef 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -410,6 +410,10 @@
}
+func SetInMakeForTests(config Config) {
+ config.inMake = true
+}
+
func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) []AndroidMkEntries {
var p AndroidMkEntriesProvider
var ok bool
diff --git a/android/util.go b/android/util.go
index ade851e..e74b64e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -193,6 +193,14 @@
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func FirstUniqueStrings(list []string) []string {
+ // 128 was chosen based on BenchmarkFirstUniqueStrings results.
+ if len(list) > 128 {
+ return firstUniqueStringsMap(list)
+ }
+ return firstUniqueStringsList(list)
+}
+
+func firstUniqueStringsList(list []string) []string {
k := 0
outer:
for i := 0; i < len(list); i++ {
@@ -207,6 +215,20 @@
return list[:k]
}
+func firstUniqueStringsMap(list []string) []string {
+ k := 0
+ seen := make(map[string]bool, len(list))
+ for i := 0; i < len(list); i++ {
+ if seen[list[i]] {
+ continue
+ }
+ seen[list[i]] = true
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
+}
+
// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func LastUniqueStrings(list []string) []string {
diff --git a/android/util_test.go b/android/util_test.go
index 1f9ca36..25b52ca 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "strconv"
"testing"
)
@@ -59,15 +60,25 @@
}
func TestFirstUniqueStrings(t *testing.T) {
- for _, testCase := range firstUniqueStringsTestCases {
- out := FirstUniqueStrings(testCase.in)
- if !reflect.DeepEqual(out, testCase.out) {
+ f := func(t *testing.T, imp func([]string) []string, in, want []string) {
+ t.Helper()
+ out := imp(in)
+ if !reflect.DeepEqual(out, want) {
t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", testCase.in)
- t.Errorf(" expected: %#v", testCase.out)
+ t.Errorf(" input: %#v", in)
+ t.Errorf(" expected: %#v", want)
t.Errorf(" got: %#v", out)
}
}
+
+ for _, testCase := range firstUniqueStringsTestCases {
+ t.Run("list", func(t *testing.T) {
+ f(t, firstUniqueStringsList, testCase.in, testCase.out)
+ })
+ t.Run("map", func(t *testing.T) {
+ f(t, firstUniqueStringsMap, testCase.in, testCase.out)
+ })
+ }
}
var lastUniqueStringsTestCases = []struct {
@@ -568,3 +579,51 @@
})
}
}
+
+func BenchmarkFirstUniqueStrings(b *testing.B) {
+ implementations := []struct {
+ name string
+ f func([]string) []string
+ }{
+ {
+ name: "list",
+ f: firstUniqueStringsList,
+ },
+ {
+ name: "map",
+ f: firstUniqueStringsMap,
+ },
+ }
+ const maxSize = 1024
+ uniqueStrings := make([]string, maxSize)
+ for i := range uniqueStrings {
+ uniqueStrings[i] = strconv.Itoa(i)
+ }
+ sameString := make([]string, maxSize)
+ for i := range sameString {
+ sameString[i] = uniqueStrings[0]
+ }
+
+ f := func(b *testing.B, imp func([]string) []string, s []string) {
+ for i := 0; i < b.N; i++ {
+ b.ReportAllocs()
+ s = append([]string(nil), s...)
+ imp(s)
+ }
+ }
+
+ for n := 1; n <= maxSize; n <<= 1 {
+ b.Run(strconv.Itoa(n), func(b *testing.B) {
+ for _, implementation := range implementations {
+ b.Run(implementation.name, func(b *testing.B) {
+ b.Run("same", func(b *testing.B) {
+ f(b, implementation.f, sameString[:n])
+ })
+ b.Run("unique", func(b *testing.B) {
+ f(b, implementation.f, uniqueStrings[:n])
+ })
+ })
+ }
+ })
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index 9cbe624..3b3916e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -95,6 +95,9 @@
Sanitize struct {
Address *bool
}
+ Optimize struct {
+ Enabled *bool
+ }
}
Pdk struct {
@@ -140,16 +143,14 @@
// Suffix to add to generated Makefiles
Make_suffix *string `json:",omitempty"`
- BuildId *string `json:",omitempty"`
- BuildNumberFromFile *string `json:",omitempty"`
- DateFromFile *string `json:",omitempty"`
+ BuildId *string `json:",omitempty"`
+ BuildNumberFile *string `json:",omitempty"`
Platform_version_name *string `json:",omitempty"`
Platform_sdk_version *int `json:",omitempty"`
Platform_sdk_codename *string `json:",omitempty"`
Platform_sdk_final *bool `json:",omitempty"`
Platform_version_active_codenames []string `json:",omitempty"`
- Platform_version_future_codenames []string `json:",omitempty"`
Platform_vndk_version *string `json:",omitempty"`
Platform_systemsdk_versions []string `json:",omitempty"`
Platform_security_patch *string `json:",omitempty"`
@@ -189,9 +190,11 @@
CrossHostArch *string `json:",omitempty"`
CrossHostSecondaryArch *string `json:",omitempty"`
- DeviceResourceOverlays []string `json:",omitempty"`
- ProductResourceOverlays []string `json:",omitempty"`
- EnforceRROTargets []string `json:",omitempty"`
+ DeviceResourceOverlays []string `json:",omitempty"`
+ ProductResourceOverlays []string `json:",omitempty"`
+ EnforceRROTargets []string `json:",omitempty"`
+ // TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+ EnforceRROExemptedTargets []string `json:",omitempty"`
EnforceRROExcludedOverlays []string `json:",omitempty"`
AAPTCharacteristics *string `json:",omitempty"`
@@ -251,6 +254,8 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
+ SamplingPGO *bool `json:",omitempty"`
+
NativeLineCoverage *bool `json:",omitempty"`
Native_coverage *bool `json:",omitempty"`
ClangCoverage *bool `json:",omitempty"`
@@ -345,14 +350,13 @@
func (v *productVariables) SetDefaultConfig() {
*v = productVariables{
- BuildNumberFromFile: stringPtr("123456789"),
+ BuildNumberFile: stringPtr("build_number.txt"),
Platform_version_name: stringPtr("Q"),
Platform_sdk_version: intPtr(28),
Platform_sdk_codename: stringPtr("Q"),
Platform_sdk_final: boolPtr(false),
Platform_version_active_codenames: []string{"Q"},
- Platform_version_future_codenames: []string{"Q"},
Platform_vndk_version: stringPtr("Q"),
HostArch: stringPtr("x86_64"),
diff --git a/android/vts_config.go b/android/vts_config.go
index 9a1df7c..77fb9fe 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -53,7 +53,7 @@
fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
*me.properties.Test_config)
}
- fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n",
+ fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts10 %s\n",
strings.Join(me.properties.Test_suites, " "))
},
}
@@ -64,7 +64,7 @@
me.AddProperties(&me.properties)
}
-// vts_config generates a Vendor Test Suite (VTS) configuration file from the
+// vts_config generates a Vendor Test Suite (VTS10) configuration file from the
// <test_config> xml file and stores it in a subdirectory of $(HOST_OUT).
func VtsConfigFactory() Module {
module := &VtsConfig{}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 8860984..f863f8d 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -383,11 +383,15 @@
if err != nil {
return err
}
- if val.(*bpparser.Bool).Value {
+ boolValue, ok := val.(*bpparser.Bool)
+ if !ok {
+ return fmt.Errorf("value should evaluate to boolean literal")
+ }
+ if boolValue.Value {
thirtyTwo := &bpparser.String{
Value: "32",
}
- setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
+ return setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
}
return nil
}
@@ -825,8 +829,6 @@
var propertyPrefixes = []struct{ mk, bp string }{
{"arm", "arch.arm"},
{"arm64", "arch.arm64"},
- {"mips", "arch.mips"},
- {"mips64", "arch.mips64"},
{"x86", "arch.x86"},
{"x86_64", "arch.x86_64"},
{"32", "multilib.lib32"},
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 7e1a72c..3e1d486 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1341,6 +1341,25 @@
}
`,
},
+ {
+ desc: "undefined_boolean_var",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= a.cpp
+LOCAL_MODULE:= test
+LOCAL_32_BIT_ONLY := $(FLAG)
+include $(BUILD_EXECUTABLE)
+`,
+ expected: `
+cc_binary {
+ name: "test",
+ srcs: ["a.cpp"],
+ // ANDROIDMK TRANSLATION ERROR: value should evaluate to boolean literal
+ // LOCAL_32_BIT_ONLY := $(FLAG)
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 0abec0d..db1048e 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/java"
"github.com/google/blueprint/proptools"
)
@@ -120,8 +121,8 @@
fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
}
- if fi.module != nil && fi.module.NoticeFile().Valid() {
- fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", fi.module.NoticeFile().Path().String())
+ if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
+ fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(fi.module.NoticeFiles().Strings(), " "))
}
} else {
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated)
@@ -181,6 +182,9 @@
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
// we will have foo.apk.apk
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".apk"))
+ if app, ok := fi.module.(*java.AndroidApp); ok && len(app.JniCoverageOutputs()) > 0 {
+ fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " "))
+ }
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk")
} else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
@@ -308,7 +312,7 @@
}
if a.installedFilesFile != nil {
- goal := "droidcore"
+ goal := "checkbuild"
distFile := name + "-installed-files.txt"
fmt.Fprintln(w, ".PHONY:", goal)
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
diff --git a/apex/apex.go b/apex/apex.go
index 6d4b17b..6863c8a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
"fmt"
"path"
"path/filepath"
+ "regexp"
"sort"
"strings"
"sync"
@@ -52,6 +53,7 @@
var (
sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
+ jniLibTag = dependencyTag{name: "jniLib", payload: true}
executableTag = dependencyTag{name: "executable", payload: true}
javaLibTag = dependencyTag{name: "javaLib", payload: true}
prebuiltTag = dependencyTag{name: "prebuilt", payload: true}
@@ -61,8 +63,26 @@
usesTag = dependencyTag{name: "uses"}
androidAppTag = dependencyTag{name: "androidApp", payload: true}
apexAvailWl = makeApexAvailableWhitelist()
+
+ inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
)
+// Transform the map of apex -> modules to module -> apexes.
+func invertApexWhiteList(m map[string][]string) map[string][]string {
+ r := make(map[string][]string)
+ for apex, modules := range m {
+ for _, module := range modules {
+ r[module] = append(r[module], apex)
+ }
+ }
+ return r
+}
+
+// Retrieve the while list of apexes to which the supplied module belongs.
+func WhitelistedApexAvailable(moduleName string) []string {
+ return inverseApexAvailWl[normalizeModuleName(moduleName)]
+}
+
// This is a map from apex to modules, which overrides the
// apex_available setting for that particular module to make
// it available for the apex regardless of its setting.
@@ -73,58 +93,10 @@
//
// Module separator
//
- 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{
+ artApexContents := []string{
"art_cmdlineparser_headers",
"art_disassembler_headers",
"art_libartbase_headers",
- "bcm_object",
"bionic_libc_platform_headers",
"core-repackaged-icu4j",
"cpp-define-generator-asm-support",
@@ -133,12 +105,9 @@
"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",
@@ -147,29 +116,17 @@
"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",
@@ -180,7 +137,6 @@
"libopenjdkjvmti_headers",
"libperfetto_client_experimental",
"libprocinfo",
- "libprotobuf-cpp-lite",
"libunwind_llvm",
"libunwindstack",
"libv8",
@@ -195,6 +151,8 @@
"libziparchive",
"perfetto_trace_protos",
}
+ m["com.android.art.debug"] = artApexContents
+ m["com.android.art.release"] = artApexContents
//
// Module separator
//
@@ -215,12 +173,12 @@
"android.hidl.token@1.0-utils",
"avrcp-target-service",
"avrcp_headers",
- "bcm_object",
"bluetooth-protos-lite",
"bluetooth.mapsapi",
"com.android.vcard",
- "fmtlib",
- "guava",
+ "dnsresolver_aidl_interface-V2-java",
+ "ipmemorystore-aidl-interfaces-V5-java",
+ "ipmemorystore-aidl-interfaces-java",
"internal_include_headers",
"lib-bt-packets",
"lib-bt-packets-avrcp",
@@ -228,9 +186,6 @@
"libFraunhoferAAC",
"libaudio-a2dp-hw-utils",
"libaudio-hearing-aid-hw-utils",
- "libbacktrace_headers",
- "libbase",
- "libbase_headers",
"libbinder_headers",
"libbluetooth",
"libbluetooth-types",
@@ -252,40 +207,28 @@
"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",
"libudrv-uipc",
- "libutils_headers",
"libz",
"media_plugin_headers",
+ "net-utils-services-common",
+ "netd_aidl_interface-unstable-java",
+ "netd_event_listener_interface-java",
+ "netlink-client",
+ "networkstack-aidl-interfaces-unstable-java",
+ "networkstack-client",
"sap-api-java-static",
"services.net",
}
@@ -297,12 +240,7 @@
// Module separator
//
m["com.android.conscrypt"] = []string{
- "bcm_object",
- "boringssl_self_test",
- "libc++",
- "libcrypto",
"libnativehelper_header_only",
- "libssl",
}
//
// Module separator
@@ -320,17 +258,6 @@
//
// 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",
@@ -340,44 +267,11 @@
"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
@@ -406,9 +300,7 @@
"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",
@@ -420,7 +312,6 @@
"libaacextractor",
"libamrextractor",
"libarect",
- "libasync_safe",
"libaudio_system_headers",
"libaudioclient",
"libaudioclient_headers",
@@ -430,23 +321,14 @@
"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",
@@ -458,14 +340,7 @@
"libgui",
"libgui_headers",
"libhardware_headers",
- "libhidlbase",
- "libhidlbase-impl-internal",
- "libhidlmemory",
- "libhidltransport-impl-internal",
- "libhwbinder-impl-internal",
"libinput",
- "libjsoncpp",
- "liblog_headers",
"liblzma",
"libmath",
"libmedia",
@@ -490,15 +365,11 @@
"libnblog",
"liboggextractor",
"libpackagelistparser",
- "libpcre2",
"libpdx",
"libpdx_default_transport",
"libpdx_headers",
"libpdx_uds",
- "libprocessgroup",
- "libprocessgroup_headers",
"libprocinfo",
- "libselinux",
"libsonivox",
"libspeexresampler",
"libspeexresampler",
@@ -514,11 +385,9 @@
"libstagefright_mpeg2extractor",
"libstagefright_mpeg2support",
"libsync",
- "libsystem_headers",
"libui",
"libui_headers",
"libunwindstack",
- "libutils_headers",
"libvibrator",
"libvorbisidec",
"libwavextractor",
@@ -558,14 +427,13 @@
"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",
+ "libLibGuiProperties",
"libarect",
- "libasync_safe",
"libaudio_system_headers",
"libaudioutils",
"libaudioutils",
@@ -574,16 +442,11 @@
"libavcenc",
"libavservices_minijail",
"libavservices_minijail",
- "libbacktrace",
- "libbacktrace_headers",
- "libbase",
- "libbase_headers",
"libbinder_headers",
+ "libbinderthreadstateutils",
"libbluetooth-types-header",
"libbufferhub_headers",
- "libc++",
"libc_scudo",
- "libcap",
"libcodec2",
"libcodec2_headers",
"libcodec2_hidl@1.0",
@@ -621,8 +484,6 @@
"libcodec2_soft_vp9dec",
"libcodec2_soft_vp9enc",
"libcodec2_vndk",
- "libcutils",
- "libcutils_headers",
"libdexfile_support",
"libdvr_headers",
"libfmq",
@@ -638,34 +499,18 @@
"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",
@@ -684,11 +529,9 @@
"libstagefright_m4vh263enc",
"libstagefright_mp3dec",
"libsync",
- "libsystem_headers",
"libui",
"libui_headers",
"libunwindstack",
- "libutils_headers",
"libvorbisidec",
"libvpx",
"libyuv",
@@ -704,7 +547,6 @@
"MediaProvider",
"MediaProviderGoogle",
"fmtlib_ndk",
- "guava",
"libbase_ndk",
"libfuse",
"libfuse_jni",
@@ -728,7 +570,6 @@
"kotlinx-coroutines-android-nodeps",
"kotlinx-coroutines-core",
"kotlinx-coroutines-core-nodeps",
- "libprotobuf-java-lite",
"permissioncontroller-statsd",
}
//
@@ -736,14 +577,7 @@
//
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",
@@ -757,7 +591,6 @@
"libc_freebsd",
"libc_freebsd_large_stack",
"libc_gdtoa",
- "libc_headers",
"libc_init_dynamic",
"libc_init_static",
"libc_jemalloc_wrapper",
@@ -772,8 +605,6 @@
"libc_syscalls",
"libc_tzcode",
"libc_unwind_static",
- "libcutils",
- "libcutils_headers",
"libdebuggerd",
"libdebuggerd_common_headers",
"libdebuggerd_handler_core",
@@ -781,88 +612,31 @@
"libdexfile_external_headers",
"libdexfile_support",
"libdexfile_support_static",
- "libgtest_prod",
+ "libdl_static",
"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++",
"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",
}
@@ -872,6 +646,7 @@
m["com.android.wifi"] = []string{
"PlatformProperties",
"android.hardware.wifi-V1.0-java",
+ "android.hardware.wifi-V1.0-java-constants",
"android.hardware.wifi-V1.1-java",
"android.hardware.wifi-V1.2-java",
"android.hardware.wifi-V1.3-java",
@@ -892,23 +667,12 @@
"bouncycastle-unbundled",
"dnsresolver_aidl_interface-V2-java",
"error_prone_annotations",
+ "framework-wifi-pre-jarjar",
+ "framework-wifi-util-lib",
"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",
@@ -936,34 +700,13 @@
// 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",
+ m[android.AvailableToAnyApex] = []string{
"libatomic",
- "libc++_static",
- "libc++abi",
- "libc++demangle",
- "libc_headers",
"libclang_rt",
"libgcc_stripped",
"libprofile-clang-extras",
@@ -971,22 +714,6 @@
"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
}
@@ -1024,10 +751,17 @@
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
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)}}
+ apexBundles = []android.ApexInfo{{
+ ApexName: mctx.ModuleName(),
+ MinSdkVersion: a.minSdkVersion(mctx),
+ Updatable: proptools.Bool(a.properties.Updatable),
+ }}
directDep = true
} else if am, ok := mctx.Module().(android.ApexModule); ok {
apexBundles = am.ApexVariations()
@@ -1038,18 +772,33 @@
return
}
+ cur := mctx.Module().(android.DepIsInSameApex)
+
mctx.VisitDirectDeps(func(child android.Module) {
depName := mctx.OtherModuleName(child)
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
- (directDep || am.DepIsInSameApex(mctx, child)) {
+ (cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) {
android.UpdateApexDependency(apexBundles, depName, directDep)
am.BuildForApexes(apexBundles)
}
})
}
+// If a module in an APEX depends on a module from an SDK then it needs an APEX
+// specific variant created for it. Refer to sdk.sdkDepsReplaceMutator.
+func inAnySdk(module android.Module) bool {
+ if sa, ok := module.(android.SdkAware); ok {
+ return sa.IsInAnySdk()
+ }
+
+ return false
+}
+
// Create apex variations if a module is included in APEX(s).
func apexMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
am.CreateApexVariations(mctx)
} else if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
@@ -1087,6 +836,9 @@
}
func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
if ab, ok := mctx.Module().(*apexBundle); ok {
var variants []string
switch proptools.StringDefault(ab.properties.Payload_type, "image") {
@@ -1155,10 +907,13 @@
})
}
-type apexNativeDependencies struct {
+type ApexNativeDependencies struct {
// List of native libraries
Native_shared_libs []string
+ // List of JNI libraries
+ Jni_libs []string
+
// List of native executables
Binaries []string
@@ -1168,19 +923,19 @@
type apexMultilibProperties struct {
// Native dependencies whose compile_multilib is "first"
- First apexNativeDependencies
+ First ApexNativeDependencies
// Native dependencies whose compile_multilib is "both"
- Both apexNativeDependencies
+ Both ApexNativeDependencies
// Native dependencies whose compile_multilib is "prefer32"
- Prefer32 apexNativeDependencies
+ Prefer32 ApexNativeDependencies
// Native dependencies whose compile_multilib is "32"
- Lib32 apexNativeDependencies
+ Lib32 ApexNativeDependencies
// Native dependencies whose compile_multilib is "64"
- Lib64 apexNativeDependencies
+ Lib64 ApexNativeDependencies
}
type apexBundleProperties struct {
@@ -1202,11 +957,7 @@
// Default: /system/sepolicy/apex/<module_name>_file_contexts.
File_contexts *string `android:"path"`
- // List of native shared libs that are embedded inside this APEX bundle
- Native_shared_libs []string
-
- // List of executables that are embedded inside this APEX bundle
- Binaries []string
+ ApexNativeDependencies
// List of java libraries that are embedded inside this APEX bundle
Java_libs []string
@@ -1214,9 +965,6 @@
// List of prebuilt files that are embedded inside this APEX bundle
Prebuilts []string
- // List of tests that are embedded inside this APEX bundle
- Tests []string
-
// Name of the apex_key module that provides the private key to sign APEX
Key *string
@@ -1270,10 +1018,6 @@
// Should be only used in tests#.
Test_only_no_hashtree *bool
- // Whether this APEX should support Android10. Default is false. If this is set true, then apex_manifest.json is bundled as well
- // because Android10 requires legacy apex_manifest.json instead of apex_manifest.pb
- Legacy_android10_support *bool
-
IsCoverageVariant bool `blueprint:"mutated"`
// Whether this APEX is considered updatable or not. When set to true, this will enforce additional
@@ -1322,6 +1066,10 @@
// Logging Parent value
Logging_parent string
+
+ // Apex Container Package Name.
+ // Override value for attribute package:name in AndroidManifest.xml
+ Package_name string
}
type apexPackaging int
@@ -1413,6 +1161,9 @@
jacocoReportClassesFile android.Path // only for javalibs and apps
certificate java.Certificate // only for apps
+ overriddenPackageName string // only for apps
+
+ isJniLib bool
}
func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile {
@@ -1531,7 +1282,7 @@
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
- native_shared_libs []string, binaries []string, tests []string,
+ nativeModules ApexNativeDependencies,
target android.Target, imageVariation string) {
// Use *FarVariation* to be able to depend on modules having
// conflicting variations with this module. This is required since
@@ -1541,16 +1292,22 @@
{Mutator: "image", Variation: imageVariation},
{Mutator: "link", Variation: "shared"},
{Mutator: "version", Variation: ""}, // "" is the non-stub variant
- }...), sharedLibTag, native_shared_libs...)
+ }...), sharedLibTag, nativeModules.Native_shared_libs...)
+
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: imageVariation},
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: ""}, // "" is the non-stub variant
+ }...), jniLibTag, nativeModules.Jni_libs...)
ctx.AddFarVariationDependencies(append(target.Variations(),
blueprint.Variation{Mutator: "image", Variation: imageVariation}),
- executableTag, binaries...)
+ executableTag, nativeModules.Binaries...)
ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: imageVariation},
{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }...), testTag, tests...)
+ }...), testTag, nativeModules.Tests...)
}
func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -1583,41 +1340,39 @@
}
}
for i, target := range targets {
- // When multilib.* is omitted for native_shared_libs, it implies
- // multilib.both.
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(config)},
- {Mutator: "link", Variation: "shared"},
- }...), sharedLibTag, a.properties.Native_shared_libs...)
-
- // When multilib.* is omitted for tests, it implies
- // multilib.both.
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(config)},
- {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }...), testTag, a.properties.Tests...)
+ // When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies
+ // multilib.both
+ addDependenciesForNativeModules(ctx,
+ ApexNativeDependencies{
+ Native_shared_libs: a.properties.Native_shared_libs,
+ Tests: a.properties.Tests,
+ Jni_libs: a.properties.Jni_libs,
+ Binaries: nil,
+ },
+ target, a.getImageVariation(config))
// Add native modules targetting both ABIs
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Both.Native_shared_libs,
- a.properties.Multilib.Both.Binaries,
- a.properties.Multilib.Both.Tests,
+ a.properties.Multilib.Both,
target,
a.getImageVariation(config))
isPrimaryAbi := i == 0
if isPrimaryAbi {
// When multilib.* is omitted for binaries, it implies
- // multilib.first.
- ctx.AddFarVariationDependencies(append(target.Variations(),
- blueprint.Variation{Mutator: "image", Variation: a.getImageVariation(config)}),
- executableTag, a.properties.Binaries...)
+ // multilib.first
+ addDependenciesForNativeModules(ctx,
+ ApexNativeDependencies{
+ Native_shared_libs: nil,
+ Tests: nil,
+ Jni_libs: nil,
+ Binaries: a.properties.Binaries,
+ },
+ target, a.getImageVariation(config))
// Add native modules targetting the first ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.First.Native_shared_libs,
- a.properties.Multilib.First.Binaries,
- a.properties.Multilib.First.Tests,
+ a.properties.Multilib.First,
target,
a.getImageVariation(config))
}
@@ -1626,32 +1381,24 @@
case "lib32":
// Add native modules targetting 32-bit ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Lib32.Native_shared_libs,
- a.properties.Multilib.Lib32.Binaries,
- a.properties.Multilib.Lib32.Tests,
+ a.properties.Multilib.Lib32,
target,
a.getImageVariation(config))
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Prefer32.Native_shared_libs,
- a.properties.Multilib.Prefer32.Binaries,
- a.properties.Multilib.Prefer32.Tests,
+ a.properties.Multilib.Prefer32,
target,
a.getImageVariation(config))
case "lib64":
// Add native modules targetting 64-bit ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Lib64.Native_shared_libs,
- a.properties.Multilib.Lib64.Binaries,
- a.properties.Multilib.Lib64.Tests,
+ a.properties.Multilib.Lib64,
target,
a.getImageVariation(config))
if !has32BitTarget {
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Prefer32.Native_shared_libs,
- a.properties.Multilib.Prefer32.Binaries,
- a.properties.Multilib.Prefer32.Tests,
+ a.properties.Multilib.Prefer32,
target,
a.getImageVariation(config))
}
@@ -1660,8 +1407,8 @@
for _, sanitizer := range ctx.Config().SanitizeDevice() {
if sanitizer == "hwaddress" {
addDependenciesForNativeModules(ctx,
- []string{"libclang_rt.hwasan-aarch64-android"},
- nil, nil, target, a.getImageVariation(config))
+ ApexNativeDependencies{[]string{"libclang_rt.hwasan-aarch64-android"}, nil, nil, nil},
+ target, a.getImageVariation(config))
break
}
}
@@ -1820,10 +1567,10 @@
case "lib64":
dirInApex = "lib64"
}
- dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), ctx.Config()) {
// Special case for Bionic libs and other libs installed with them. This is
// to prevent those libs from being included in the search path
@@ -1843,10 +1590,11 @@
}
func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFile {
- dirInApex := filepath.Join("bin", cc.RelativeInstallPath())
+ dirInApex := "bin"
if cc.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
fileToCopy := cc.OutputFile().Path()
af := newApexFile(ctx, fileToCopy, cc.Name(), dirInApex, nativeExecutable, cc)
af.symlinks = cc.Symlinks()
@@ -1909,19 +1657,26 @@
func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
android.Module
Privileged() bool
+ InstallApkName() string
OutputFile() android.Path
JacocoReportClassesFile() android.Path
Certificate() java.Certificate
-}, pkgName string) apexFile {
+}) apexFile {
appDir := "app"
if aapp.Privileged() {
appDir = "priv-app"
}
- dirInApex := filepath.Join(appDir, pkgName)
+ dirInApex := filepath.Join(appDir, aapp.InstallApkName())
fileToCopy := aapp.OutputFile()
af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
af.certificate = aapp.Certificate()
+
+ if app, ok := aapp.(interface {
+ OverriddenManifestPackageName() string
+ }); ok {
+ af.overriddenPackageName = app.OverriddenManifestPackageName()
+ }
return af
}
@@ -1934,10 +1689,14 @@
return true
}
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
+
// 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 {
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+ ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
return false
@@ -1946,25 +1705,48 @@
// 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 do(ctx, parent, am, false /* externalDep */)
}
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
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
+ if am.ApexName() != "" {
+ return do(ctx, parent, am, false /* externalDep */)
}
- do(ctx, parent, am, true /* externalDep */)
-
- // As soon as the dependency graph crosses the APEX boundary, don't go further.
- return false
+ return do(ctx, parent, am, true /* externalDep */)
})
}
+func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
+ ver := proptools.StringDefault(a.properties.Min_sdk_version, "current")
+ intVer, err := android.ApiStrToNum(ctx, ver)
+ if err != nil {
+ ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
+ }
+ return intVer
+}
+
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
+
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+ // Use tag's custom String() method if available.
+ if stringer, ok := tag.(fmt.Stringer); ok {
+ return stringer.String()
+ }
+
+ // Otherwise, get a default string representation of the tag's struct.
+ tagString := fmt.Sprintf("%#v", tag)
+
+ // Remove the boilerplate from BaseDependencyTag as it adds no value.
+ tagString = tagCleaner.ReplaceAllString(tagString, "")
+ return tagString
+}
+
// 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
@@ -1972,22 +1754,54 @@
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
+ // Coverage build adds additional dependencies for the coverage-only runtime libraries.
+ // Requiring them and their transitive depencies with apex_available is not right
+ // because they just add noise.
+ if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || a.IsNativeCoverageNeeded(ctx) {
+ return
+ }
+
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if externalDep {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
}
- ctx.ModuleErrorf("requires %q that is not available for the APEX.", to.Name())
+
+ apexName := ctx.ModuleName()
+ fromName := ctx.OtherModuleName(from)
+ toName := ctx.OtherModuleName(to)
+
+ // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+ // do any of its dependencies.
+ if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
+ }
+
+ if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+ return true
+ }
+ message := ""
+ tagPath := ctx.GetTagPath()
+ // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
+ walkPath := ctx.GetWalkPath()[1:]
+ for i, m := range walkPath {
+ message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
+ }
+ ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+ // Visit this module's dependencies to check and report any issues with their availability.
+ return true
})
}
// 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) {
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
- return
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
}
if info, exists := a.depInfos[to.Name()]; exists {
@@ -2003,6 +1817,9 @@
isExternal: externalDep,
}
}
+
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return !externalDep
})
}
@@ -2079,19 +1896,29 @@
// TODO(jiyong) do this using walkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
depName := ctx.OtherModuleName(child)
if _, isDirectDep := parent.(*apexBundle); isDirectDep {
switch depTag {
- case sharedLibTag:
+ case sharedLibTag, jniLibTag:
+ isJniLib := depTag == jniLibTag
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, c, handleSpecialLibs))
+ fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
+ fi.isJniLib = isJniLib
+ filesInfo = append(filesInfo, fi)
return true // track transitive dependencies
} else {
- ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
+ propertyName := "native_shared_libs"
+ if isJniLib {
+ propertyName = "jni_libs"
+ }
+ ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
}
case executableTag:
if cc, ok := child.(*cc.Module); ok {
@@ -2127,14 +1954,13 @@
ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
}
case androidAppTag:
- pkgName := ctx.DeviceConfig().OverridePackageNameFor(depName)
if ap, ok := child.(*java.AndroidApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
return true // track transitive dependencies
} else if ap, ok := child.(*java.AndroidAppImport); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
} else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap, pkgName))
+ filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
} else {
ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
}
@@ -2240,7 +2066,7 @@
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
}
}
}
@@ -2327,6 +2153,11 @@
a.linkToSystemLib = false
}
+ // We also don't want the optimization for host APEXes, because it doesn't make sense.
+ if ctx.Host() {
+ a.linkToSystemLib = false
+ }
+
// prepare apex_manifest.json
a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
@@ -2342,13 +2173,23 @@
a.buildApexDependencyInfo(ctx)
}
-func whitelistedApexAvailable(apex string, module android.Module) bool {
+func whitelistedApexAvailable(apex, moduleName string) 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 = normalizeModuleName(moduleName)
- moduleName := module.Name()
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ key = android.AvailableToAnyApex
+ if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+ return true
+ }
+
+ return false
+}
+
+func normalizeModuleName(moduleName string) string {
// 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_")
@@ -2357,17 +2198,7 @@
// 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
+ return moduleName
}
func newApexBundle() *apexBundle {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 10fc8d6..8807d00 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/dexpreopt"
"android/soong/java"
)
@@ -87,6 +88,30 @@
}
}
+// withNativeBridgeTargets sets configuration with targets including:
+// - X86_64 (primary)
+// - X86 (secondary)
+// - Arm64 on X86_64 (native bridge)
+// - Arm on X86 (native bridge)
+func withNativeBridgeEnabled(fs map[string][]byte, config android.Config) {
+ config.Targets[android.Android] = []android.Target{
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
+ }
+}
+
+func withManifestPackageNameOverrides(specs []string) testCustomizer {
+ return func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.ManifestPackageNameOverrides = specs
+ }
+}
+
func withBinder32bit(fs map[string][]byte, config android.Config) {
config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
}
@@ -134,6 +159,7 @@
"my_include": nil,
"foo/bar/MyClass.java": nil,
"prebuilt.jar": nil,
+ "prebuilt.so": nil,
"vendor/foo/devkeys/test.x509.pem": nil,
"vendor/foo/devkeys/test.pk8": nil,
"testkey.x509.pem": nil,
@@ -144,6 +170,7 @@
"vendor/foo/devkeys/testkey.pem": nil,
"NOTICE": nil,
"custom_notice": nil,
+ "custom_notice_for_static_lib": nil,
"testkey2.avbpubkey": nil,
"testkey2.pem": nil,
"myapex-arm64.apex": nil,
@@ -226,6 +253,14 @@
os.RemoveAll(buildDir)
}
+// ensure that 'result' equals 'expected'
+func ensureEquals(t *testing.T, result string, expected string) {
+ t.Helper()
+ if result != expected {
+ t.Errorf("%q != %q", expected, result)
+ }
+}
+
// ensure that 'result' contains 'expected'
func ensureContains(t *testing.T, result string, expected string) {
t.Helper()
@@ -334,12 +369,36 @@
apex_available: [ "myapex" ],
}
- cc_library {
+ cc_library_shared {
name: "mylib2",
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
notice: "custom_notice",
+ static_libs: ["libstatic"],
+ // TODO: remove //apex_available:platform
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "mylib2",
+ srcs: ["prebuilt.so"],
+ // TODO: remove //apex_available:platform
+ apex_available: [
+ "//apex_available:platform",
+ "myapex",
+ ],
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice_for_static_lib",
// TODO: remove //apex_available:platform
apex_available: [
"//apex_available:platform",
@@ -438,11 +497,12 @@
mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule")
noticeInputs := mergeNoticesRule.Inputs.Strings()
- if len(noticeInputs) != 2 {
- t.Errorf("number of input notice files: expected = 2, actual = %q", len(noticeInputs))
+ if len(noticeInputs) != 3 {
+ t.Errorf("number of input notice files: expected = 3, actual = %q", len(noticeInputs))
}
ensureListContains(t, noticeInputs, "NOTICE")
ensureListContains(t, noticeInputs, "custom_notice")
+ ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")
depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n")
ensureListContains(t, depsInfo, "myjar <- myapex")
@@ -796,7 +856,6 @@
stubs: {
versions: ["10", "20", "30"],
},
- apex_available: [ "myapex" ],
}
cc_library {
@@ -827,58 +886,89 @@
}
-func TestApexDependencyToLLNDK(t *testing.T) {
- ctx, _ := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- use_vendor: true,
- native_shared_libs: ["mylib"],
- }
+func TestApexDependsOnLLNDKTransitively(t *testing.T) {
+ testcases := []struct {
+ name string
+ minSdkVersion string
+ shouldLink string
+ shouldNotLink []string
+ }{
+ {
+ name: "should link to the latest",
+ minSdkVersion: "current",
+ shouldLink: "30",
+ shouldNotLink: []string{"29"},
+ },
+ {
+ name: "should link to llndk#29",
+ minSdkVersion: "29",
+ shouldLink: "29",
+ shouldNotLink: []string{"30"},
+ },
+ }
+ for _, tc := range testcases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ use_vendor: true,
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "`+tc.minSdkVersion+`",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- vendor_available: true,
- shared_libs: ["libbar"],
- system_shared_libs: [],
- stl: "none",
- apex_available: [ "myapex" ],
- }
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
- cc_library {
- name: "libbar",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- }
+ cc_library {
+ name: "libbar",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: { versions: ["29","30"] },
+ }
- llndk_library {
- name: "libbar",
- symbol_file: "",
- }
- `, func(fs map[string][]byte, config android.Config) {
- setUseVendorWhitelistForTest(config, []string{"myapex"})
- })
+ llndk_library {
+ name: "libbar",
+ symbol_file: "",
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ setUseVendorWhitelistForTest(config, []string{"myapex"})
+ }, withUnbundledBuild)
- apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
- copyCmds := apexRule.Args["copy_commands"]
+ // Ensure that LLNDK dep is not included
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "lib64/mylib.so",
+ })
- // Ensure that LLNDK dep is not included
- ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
+ // Ensure that LLNDK dep is required
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
- apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
- ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
+ for _, ver := range tc.shouldNotLink {
+ ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
+ }
- // Ensure that LLNDK dep is required
- ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
-
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink)
+ })
+ }
}
func TestApexWithSystemLibsStubs(t *testing.T) {
@@ -971,6 +1061,348 @@
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
+func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) {
+ // there are three links between liba --> libz
+ // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1
+ // 2) otherapex -> liby -> liba -> libz : this should be #3 link
+ // 3) (platform) -> liba -> libz : this should be non-stub link
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "2",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["liby"],
+ min_sdk_version: "3",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["liba"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "liby",
+ shared_libs: ["liba"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "otherapex" ],
+ }
+
+ cc_library {
+ name: "liba",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "3"],
+ },
+ }
+ `, withUnbundledBuild)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ // platform liba is linked to non-stub version
+ expectLink("liba", "shared", "libz", "shared")
+ // liba in myapex is linked to #1
+ expectLink("liba", "shared_myapex", "libz", "shared_1")
+ expectNoLink("liba", "shared_myapex", "libz", "shared_3")
+ expectNoLink("liba", "shared_myapex", "libz", "shared")
+ // liba in otherapex is linked to #3
+ expectLink("liba", "shared_otherapex", "libz", "shared_3")
+ expectNoLink("liba", "shared_otherapex", "libz", "shared_1")
+ expectNoLink("liba", "shared_otherapex", "libz", "shared")
+}
+
+func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "R",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["29", "R"],
+ },
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ })
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ // 9000 is quite a magic number.
+ // Finalized SDK codenames are mapped as P(28), Q(29), ...
+ // And, codenames which are not finalized yet(active_codenames + future_codenames) are numbered from 9000, 9001, ...
+ // to distinguish them from finalized and future_api(10000)
+ // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000
+ // (refer android/api_levels.go)
+ expectLink("libx", "shared_myapex", "libz", "shared_9000")
+ expectNoLink("libx", "shared_myapex", "libz", "shared_29")
+ expectNoLink("libx", "shared_myapex", "libz", "shared")
+}
+
+func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+ `)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libx", "shared_myapex", "libz", "shared_2")
+ expectNoLink("libx", "shared_myapex", "libz", "shared_1")
+ expectNoLink("libx", "shared_myapex", "libz", "shared")
+}
+
+func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ stubs: {
+ versions: ["1", "2"],
+ },
+ }
+
+ cc_library {
+ name: "libz",
+ shared_libs: ["libx"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectNoLink := func(from, from_variant, to, to_variant string) {
+ ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+ ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libz", "shared", "libx", "shared_2")
+ expectNoLink("libz", "shared", "libz", "shared_1")
+ expectNoLink("libz", "shared", "libz", "shared")
+}
+
+func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libbar"],
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: {
+ versions: ["29", "30"],
+ },
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+ })
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
+ libFlags := ld.Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
+}
+
+func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ apex_available: [ "myapex" ],
+ }
+ `)
+
+ // ensure apex variant of c++ is linked with static unwinder
+ cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
+ ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+ // note that platform variant is not.
+ cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+ ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+}
+
+func TestInvalidMinSdkVersion(t *testing.T) {
+ testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libx"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libx",
+ shared_libs: ["libz"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libz",
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["30"],
+ },
+ }
+ `)
+
+ testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ min_sdk_version: "abc",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1033,6 +1465,64 @@
ensureListContains(t, dirs, "bin/foo/bar")
}
+func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ multilib: {
+ both: {
+ native_shared_libs: ["mylib"],
+ binaries: ["mybin"],
+ },
+ },
+ compile_multilib: "both",
+ native_bridge_supported: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ }
+
+ cc_binary {
+ name: "mybin",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ static_executable: true,
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ compile_multilib: "both", // default is "first" for binary
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ },
+ }
+ `, withNativeBridgeEnabled)
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/foo/bar/mybin",
+ "bin/foo/bar/mybin64",
+ "bin/arm/foo/bar/mybin",
+ "bin/arm64/foo/bar/mybin64",
+ "lib/foo/bar/mylib.so",
+ "lib/arm/foo/bar/mylib.so",
+ "lib64/foo/bar/mylib.so",
+ "lib64/arm64/foo/bar/mylib.so",
+ })
+}
+
func TestUseVendor(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1376,13 +1866,14 @@
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ native_shared_libs: ["mylib", "mylib2"],
}
apex {
name: "otherapex",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ native_shared_libs: ["mylib", "mylib2"],
+ min_sdk_version: "29",
}
apex_key {
@@ -1396,32 +1887,65 @@
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
- // TODO: remove //apex_available:platform
apex_available: [
- "//apex_available:platform",
"myapex",
"otherapex",
],
+ recovery_available: true,
+ }
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "otherapex",
+ ],
+ use_apex_name_macro: true,
}
`)
- // non-APEX variant does not have __ANDROID_APEX(_NAME)__ defined
+ // non-APEX variant does not have __ANDROID_APEX__ defined
mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
+
+ // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+
+ // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
- // APEX variant has __ANDROID_APEX(_NAME)__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ // When cc_library sets use_apex_name_macro: true
+ // apex variants define additional macro to distinguish which apex variant it is built for
+
+ // non-APEX variant does not have __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
- // APEX variant has __ANDROID_APEX(_NAME)__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+ // recovery variant does not set __ANDROID_SDK_VERSION__
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
}
func TestHeaderLibsDependency(t *testing.T) {
@@ -1532,13 +2056,17 @@
var surplus []string
filesMatched := make(map[string]bool)
for _, file := range getFiles(t, ctx, moduleName, variant) {
+ mactchFound := false
for _, expected := range files {
if matched, _ := path.Match(expected, file.path); matched {
filesMatched[expected] = true
- return
+ mactchFound = true
+ break
}
}
- surplus = append(surplus, file.path)
+ if !mactchFound {
+ surplus = append(surplus, file.path)
+ }
}
if len(surplus) > 0 {
@@ -1605,8 +2133,10 @@
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
"lib/libvndksp.so",
+ "lib/libc++.so",
"lib64/libvndk.so",
"lib64/libvndksp.so",
+ "lib64/libc++.so",
"etc/llndk.libraries.VER.txt",
"etc/vndkcore.libraries.VER.txt",
"etc/vndksp.libraries.VER.txt",
@@ -1666,6 +2196,8 @@
"lib/libvndk.so",
"lib/libvndk.arm.so",
"lib64/libvndk.so",
+ "lib/libc++.so",
+ "lib64/libc++.so",
"etc/*",
})
}
@@ -1864,19 +2396,13 @@
stl: "none",
apex_available: [ "myapex" ],
}
- `+vndkLibrariesTxtFiles("current"),
- withTargets(map[android.OsType][]android.Target{
- android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
- },
- }))
+ `+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled)
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
"lib64/libvndk.so",
+ "lib/libc++.so",
+ "lib64/libc++.so",
"etc/*",
})
}
@@ -1965,7 +2491,8 @@
withBinder32bit,
withTargets(map[android.OsType][]android.Target{
android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
},
}),
)
@@ -2826,6 +3353,7 @@
stl: "none",
system_shared_libs: [],
enabled: false,
+ apex_available: ["myapex"],
}
`)
testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, `
@@ -2847,6 +3375,7 @@
sdk_version: "none",
system_modules: "none",
enabled: false,
+ apex_available: ["myapex"],
}
`)
}
@@ -2921,7 +3450,7 @@
}
// JNI libraries including transitive deps are
for _, jni := range []string{"libjni", "libfoo"} {
- jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
+ jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
// ... embedded inside APK (jnilibs.zip)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX
@@ -2953,6 +3482,7 @@
dex_preopt: {
enabled: false,
},
+ apex_available: ["myapex"],
}
android_app_import {
@@ -2963,6 +3493,8 @@
dex_preopt: {
enabled: false,
},
+ filename: "AwesomePrebuiltAppFooPriv.apk",
+ apex_available: ["myapex"],
}
`)
@@ -2971,7 +3503,48 @@
copyCmds := apexRule.Args["copy_commands"]
ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt/AppFooPrebuilt.apk")
- ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AppFooPrivPrebuilt.apk")
+ ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AwesomePrebuiltAppFooPriv.apk")
+}
+
+func TestApexWithAppImportsPrefer(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: [
+ "AppFoo",
+ ],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ android_app_import {
+ name: "AppFoo",
+ apk: "AppFooPrebuilt.apk",
+ filename: "AppFooPrebuilt.apk",
+ presigned: true,
+ prefer: true,
+ apex_available: ["myapex"],
+ }
+ `, withFiles(map[string][]byte{
+ "AppFooPrebuilt.apk": nil,
+ }))
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "app/AppFoo/AppFooPrebuilt.apk",
+ })
}
func TestApexWithTestHelperApp(t *testing.T) {
@@ -3007,7 +3580,7 @@
func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
// libfoo's apex_available comes from cc_defaults
- testApexError(t, `"myapex" .*: requires "libfoo" that is not available for the APEX`, `
+ testApexError(t, `requires "libfoo" that is not available for the APEX`, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3039,7 +3612,7 @@
}`)
}
-func TestApexAvailable(t *testing.T) {
+func TestApexAvailable_DirectDep(t *testing.T) {
// libfoo is not available to myapex, but only to otherapex
testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
apex {
@@ -3072,9 +3645,17 @@
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
+}
- // libbar is an indirect dep
- testApexError(t, "requires \"libbar\" that is not available for the APEX", `
+func TestApexAvailable_IndirectDep(t *testing.T) {
+ // libbbaz is an indirect dep
+ testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
+.*via tag apex\.dependencyTag.*"sharedLib".*
+.*-> libfoo.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbar.*link:shared.*
+.*via tag cc\.DependencyTag.*"shared".*
+.*-> libbaz.*link:shared.*`, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3087,33 +3668,30 @@
private_key: "testkey.pem",
}
- apex {
- name: "otherapex",
- key: "otherapex.key",
- native_shared_libs: ["libfoo"],
- }
-
- apex_key {
- name: "otherapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
cc_library {
name: "libfoo",
stl: "none",
shared_libs: ["libbar"],
system_shared_libs: [],
- apex_available: ["myapex", "otherapex"],
+ apex_available: ["myapex"],
}
cc_library {
name: "libbar",
stl: "none",
+ shared_libs: ["libbaz"],
system_shared_libs: [],
- apex_available: ["otherapex"],
- }`)
+ apex_available: ["myapex"],
+ }
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ }`)
+}
+
+func TestApexAvailable_InvalidApexName(t *testing.T) {
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
name: "myapex",
@@ -3134,7 +3712,7 @@
apex_available: ["otherapex"],
}`)
- ctx, _ := testApex(t, `
+ testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3151,6 +3729,7 @@
name: "libfoo",
stl: "none",
system_shared_libs: [],
+ runtime_libs: ["libbaz"],
apex_available: ["myapex"],
}
@@ -3159,8 +3738,19 @@
stl: "none",
system_shared_libs: [],
apex_available: ["//apex_available:anyapex"],
- }`)
+ }
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ stubs: {
+ versions: ["10", "20", "30"],
+ },
+ }`)
+}
+
+func TestApexAvailable_CreatedForPlatform(t *testing.T) {
// check that libfoo and libbar are created only for myapex, but not for the platform
// 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
@@ -3172,7 +3762,7 @@
// ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
// ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
- ctx, _ = testApex(t, `
+ ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3194,8 +3784,10 @@
// check that libfoo is created only for the platform
ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+}
- ctx, _ = testApex(t, `
+func TestApexAvailable_CreatedForApex(t *testing.T) {
+ testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -3246,6 +3838,7 @@
apps: ["override_app"],
overrides: ["unknownapex"],
logging_parent: "com.foo.bar",
+ package_name: "test.overridden.package",
}
apex_key {
@@ -3268,7 +3861,7 @@
base: "app",
package_name: "bar",
}
- `)
+ `, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule)
@@ -3284,7 +3877,7 @@
copyCmds := apexRule.Args["copy_commands"]
ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
- ensureContains(t, copyCmds, "image.apex/app/app/override_app.apk")
+ ensureContains(t, copyCmds, "image.apex/app/override_app/override_app.apk")
apexBundle := module.Module().(*apexBundle)
name := apexBundle.Name()
@@ -3296,6 +3889,9 @@
t.Errorf("override_myapex should have logging parent (com.foo.bar), but was %q.", apexBundle.overridableProperties.Logging_parent)
}
+ optFlags := apexRule.Args["opt_flags"]
+ ensureContains(t, optFlags, "--override_apk_package_name test.overridden.package")
+
data := android.AndroidMkDataForTest(t, config, "", apexBundle)
var builder strings.Builder
data.Custom(&builder, name, "TARGET_", "", data)
@@ -3316,7 +3912,7 @@
name: "myapex",
key: "myapex.key",
native_shared_libs: ["mylib"],
- legacy_android10_support: true,
+ min_sdk_version: "29",
}
apex_key {
@@ -3445,6 +4041,7 @@
sdk_version: "none",
system_modules: "none",
compile_dex: false,
+ apex_available: ["myapex"],
}
`)
}
@@ -3611,6 +4208,383 @@
ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
}
+func TestApexWithJniLibs(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ jni_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+ `)
+
+ rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ // Notice mylib2.so (transitive dep) is not added as a jni_lib
+ ensureEquals(t, rule.Args["opt"], "-a jniLibs mylib.so")
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "lib64/mylib.so",
+ "lib64/mylib2.so",
+ })
+}
+
+func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ delete(config.Targets, android.Android)
+ config.AndroidCommonTarget = android.Target{}
+ })
+
+ if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) {
+ t.Errorf("Expected variants: %v, but got: %v", expected, got)
+ }
+}
+
+func TestApexWithJniLibs_Errors(t *testing.T) {
+ testApexError(t, `jni_libs: "xxx" is not a cc_library`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ jni_libs: ["xxx"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ prebuilt_etc {
+ name: "xxx",
+ src: "xxx",
+ }
+ `, withFiles(map[string][]byte{
+ "xxx": nil,
+ }))
+}
+
+func TestAppBundle(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: ["AppFoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+ `, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"}))
+
+ bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("Bundle Config")
+ content := bundleConfigRule.Args["content"]
+
+ ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
+ ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
+}
+
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+ t.Helper()
+
+ bp = bp + `
+ filegroup {
+ name: "some-updatable-apex-file_contexts",
+ srcs: [
+ "system/sepolicy/apex/some-updatable-apex-file_contexts",
+ ],
+ }
+
+ filegroup {
+ name: "some-non-updatable-apex-file_contexts",
+ srcs: [
+ "system/sepolicy/apex/some-non-updatable-apex-file_contexts",
+ ],
+ }
+ `
+ bp += cc.GatherRequiredDepsForTest(android.Android)
+ bp += java.GatherRequiredDepsForTest()
+ bp += dexpreopt.BpToolModulesForTest()
+
+ fs := map[string][]byte{
+ "a.java": nil,
+ "a.jar": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "AndroidManifest.xml": nil,
+ "system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
+ "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
+ "system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+ "framework/aidl/a.aidl": nil,
+ }
+ cc.GatherRequiredFilesForTest(fs)
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("apex", BundleFactory)
+ ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ cc.RegisterRequiredBuildComponentsForTest(ctx)
+ java.RegisterJavaBuildComponents(ctx)
+ java.RegisterSystemModulesBuildComponents(ctx)
+ java.RegisterAppBuildComponents(ctx)
+ java.RegisterDexpreoptBootJarsComponents(ctx)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+ ctx.PreDepsMutators(RegisterPreDepsMutators)
+ ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+ config := android.TestArchConfig(buildDir, nil, bp, fs)
+ ctx.Register(config)
+
+ _ = dexpreopt.GlobalSoongConfigForTests(config)
+ dexpreopt.RegisterToolModulesForTest(ctx)
+ pathCtx := android.PathContextForTesting(config)
+ dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+ transformDexpreoptConfig(dexpreoptConfig)
+ dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+ _, errs := ctx.ParseBlueprintsFiles("Android.bp")
+ android.FailIfErrored(t, errs)
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if errmsg == "" {
+ android.FailIfErrored(t, errs)
+ } else if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, errmsg, errs)
+ return
+ } else {
+ t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
+ }
+}
+
+func TestNoUpdatableJarsInBootImage(t *testing.T) {
+ bp := `
+ java_library {
+ name: "some-updatable-apex-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "some-updatable-apex",
+ ],
+ }
+
+ java_library {
+ name: "some-non-updatable-apex-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "some-non-updatable-apex",
+ ],
+ }
+
+ java_library {
+ name: "some-platform-lib",
+ srcs: ["a.java"],
+ installable: true,
+ }
+
+ java_library {
+ name: "some-art-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "com.android.art.something",
+ ],
+ hostdex: true,
+ }
+
+ apex {
+ name: "some-updatable-apex",
+ key: "some-updatable-apex.key",
+ java_libs: ["some-updatable-apex-lib"],
+ updatable: true,
+ }
+
+ apex {
+ name: "some-non-updatable-apex",
+ key: "some-non-updatable-apex.key",
+ java_libs: ["some-non-updatable-apex-lib"],
+ }
+
+ apex_key {
+ name: "some-updatable-apex.key",
+ }
+
+ apex_key {
+ name: "some-non-updatable-apex.key",
+ }
+
+ apex {
+ name: "com.android.art.something",
+ key: "com.android.art.something.key",
+ java_libs: ["some-art-lib"],
+ updatable: true,
+ }
+
+ apex_key {
+ name: "com.android.art.something.key",
+ }
+ `
+
+ var error string
+ var transform func(*dexpreopt.GlobalConfig)
+
+ // updatable jar from ART apex in the ART boot image => ok
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", bp, transform)
+
+ // updatable jar from ART apex in the framework boot image => error
+ error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // updatable jar from some other apex in the ART boot image => error
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // non-updatable jar from some other apex in the ART boot image => error
+ error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-non-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // updatable jar from some other apex in the framework boot image => error
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // non-updatable jar from some other apex in the framework boot image => ok
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-non-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", bp, transform)
+
+ // nonexistent jar in the ART boot image => error
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // nonexistent jar in the framework boot image => error
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // platform jar in the ART boot image => error
+ error = "module 'some-platform-lib' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, bp, transform)
+
+ // platform jar in the framework boot image => ok
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", bp, transform)
+}
+
+func TestTestFor(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "myprivlib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1"],
+ },
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "myprivlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex"],
+ }
+
+
+ cc_test {
+ name: "mytest",
+ gtest: false,
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ shared_libs: ["mylib", "myprivlib"],
+ test_for: ["myapex"]
+ }
+ `)
+
+ // the test 'mytest' is a test for the apex, therefore is linked to the
+ // actual implementation of mylib instead of its stub.
+ ldFlags := ctx.ModuleForTests("mytest", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
+ ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
+ ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/builder.go b/apex/builder.go
index adb3219..5a2134a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -15,10 +15,12 @@
package apex
import (
+ "encoding/json"
"fmt"
"path/filepath"
"runtime"
"sort"
+ "strconv"
"strings"
"android/soong/android"
@@ -136,15 +138,18 @@
})
apexBundleRule = pctx.StaticRule("apexBundleRule", blueprint.RuleParams{
- Command: `${zip2zip} -i $in -o $out ` +
+ Command: `${zip2zip} -i $in -o $out.base ` +
`apex_payload.img:apex/${abi}.img ` +
+ `apex_build_info.pb:apex/${abi}.build_info.pb ` +
`apex_manifest.json:root/apex_manifest.json ` +
`apex_manifest.pb:root/apex_manifest.pb ` +
`AndroidManifest.xml:manifest/AndroidManifest.xml ` +
- `assets/NOTICE.html.gz:assets/NOTICE.html.gz`,
- CommandDeps: []string{"${zip2zip}"},
+ `assets/NOTICE.html.gz:assets/NOTICE.html.gz &&` +
+ `${soong_zip} -o $out.config -C $$(dirname ${config}) -f ${config} && ` +
+ `${merge_zips} $out $out.base $out.config`,
+ CommandDeps: []string{"${zip2zip}", "${soong_zip}", "${merge_zips}"},
Description: "app bundle",
- }, "abi")
+ }, "abi", "config")
emitApexContentRule = pctx.StaticRule("emitApexContentRule", blueprint.RuleParams{
Command: `rm -f ${out} && touch ${out} && (. ${out}.emit_commands)`,
@@ -180,6 +185,17 @@
optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
}
+ // collect jniLibs. Notice that a.filesInfo is already sorted
+ var jniLibs []string
+ for _, fi := range a.filesInfo {
+ if fi.isJniLib {
+ jniLibs = append(jniLibs, fi.builtFile.Base())
+ }
+ }
+ if len(jniLibs) > 0 {
+ optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: apexManifestRule,
Input: manifestSrc,
@@ -191,7 +207,7 @@
},
})
- if proptools.Bool(a.properties.Legacy_android10_support) {
+ if a.minSdkVersion(ctx) == android.SdkVersion_Android10 {
// b/143654022 Q apexd can't understand newly added keys in apex_manifest.json
// prepare stripped-down version so that APEX modules built from R+ can be installed to Q
a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json")
@@ -212,19 +228,19 @@
}
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
- noticeFiles := []android.Path{}
- for _, f := range a.filesInfo {
- if f.module != nil {
- notice := f.module.NoticeFile()
- if notice.Valid() {
- noticeFiles = append(noticeFiles, notice.Path())
- }
+ var noticeFiles android.Paths
+
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if externalDep {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
}
- }
- // append the notice file specified in the apex module itself
- if a.NoticeFile().Valid() {
- noticeFiles = append(noticeFiles, a.NoticeFile().Path())
- }
+
+ notices := to.NoticeFiles()
+ noticeFiles = append(noticeFiles, notices...)
+
+ return true
+ })
if len(noticeFiles) == 0 {
return android.NoticeOutputs{}
@@ -246,6 +262,61 @@
return output.OutputPath
}
+func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
+ output := android.PathForModuleOut(ctx, "bundle_config.json")
+
+ type ApkConfig struct {
+ Package_name string `json:"package_name"`
+ Apk_path string `json:"path"`
+ }
+ config := struct {
+ Compression struct {
+ Uncompressed_glob []string `json:"uncompressed_glob"`
+ } `json:"compression"`
+ Apex_config struct {
+ Apex_embedded_apk_config []ApkConfig `json:"apex_embedded_apk_config,omitempty"`
+ } `json:"apex_config,omitempty"`
+ }{}
+
+ config.Compression.Uncompressed_glob = []string{
+ "apex_payload.img",
+ "apex_manifest.*",
+ }
+
+ // collect the manifest names and paths of android apps
+ // if their manifest names are overridden
+ for _, fi := range a.filesInfo {
+ if fi.class != app {
+ continue
+ }
+ packageName := fi.overriddenPackageName
+ if packageName != "" {
+ config.Apex_config.Apex_embedded_apk_config = append(
+ config.Apex_config.Apex_embedded_apk_config,
+ ApkConfig{
+ Package_name: packageName,
+ Apk_path: fi.Path(),
+ })
+ }
+ }
+
+ j, err := json.Marshal(config)
+ if err != nil {
+ panic(fmt.Errorf("error while marshalling to %q: %#v", output, err))
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: output,
+ Description: "Bundle Config " + output.String(),
+ Args: map[string]string{
+ "content": string(j),
+ },
+ })
+
+ return output.OutputPath
+}
+
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
var abis []string
for _, target := range ctx.MultiTargets() {
@@ -285,7 +356,7 @@
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) {
+ if a.minSdkVersion(ctx) == android.SdkVersion_Android10 {
emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
}
for _, fi := range a.filesInfo {
@@ -384,21 +455,17 @@
targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
minSdkVersion := ctx.Config().DefaultAppTargetSdk()
- if proptools.Bool(a.properties.Legacy_android10_support) {
- if !java.UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion = "29"
- }
- if !java.UseApiFingerprint(ctx, minSdkVersion) {
- minSdkVersion = "29"
- }
+ if a.minSdkVersion(ctx) == android.SdkVersion_Android10 {
+ minSdkVersion = strconv.Itoa(a.minSdkVersion(ctx))
+ targetSdkVersion = strconv.Itoa(a.minSdkVersion(ctx))
}
- if java.UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ if java.UseApiFingerprint(ctx) {
+ targetSdkVersion = ctx.Config().PlatformSdkCodename() + 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())
+ if java.UseApiFingerprint(ctx) {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
}
optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
@@ -419,7 +486,7 @@
ctx.PropertyErrorf("test_only_no_hashtree", "not available")
return
}
- if !proptools.Bool(a.properties.Legacy_android10_support) || a.testOnlyShouldSkipHashtreeGeneration() {
+ if a.minSdkVersion(ctx) > android.SdkVersion_Android10 || a.testOnlyShouldSkipHashtreeGeneration() {
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
// don't need hashtree for activation. Therefore, by removing hashtree from
// apex bundle (filesystem image in it, to be specific), we can save storage.
@@ -432,7 +499,7 @@
optFlags = append(optFlags, "--do_not_check_keyname")
}
- if proptools.Bool(a.properties.Legacy_android10_support) {
+ if a.minSdkVersion(ctx) == android.SdkVersion_Android10 {
implicitInputs = append(implicitInputs, a.manifestJsonOut)
optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
}
@@ -465,13 +532,17 @@
Description: "apex proto convert",
})
+ bundleConfig := a.buildBundleConfig(ctx)
+
ctx.Build(pctx, android.BuildParams{
Rule: apexBundleRule,
Input: apexProtoFile,
+ Implicit: bundleConfig,
Output: a.bundleModuleFile,
Description: "apex bundle module",
Args: map[string]string{
- "abi": strings.Join(abis, "."),
+ "abi": strings.Join(abis, "."),
+ "config": bundleConfig.String(),
},
})
} else {
@@ -587,7 +658,10 @@
}
return ""
}
- manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(a.Name())
+ if a.overridableProperties.Package_name != "" {
+ return a.overridableProperties.Package_name
+ }
+ manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
if overridden {
return manifestPackageName
}
diff --git a/apex/key.go b/apex/key.go
index ffde315..607cac5 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -133,17 +133,18 @@
module := apexModulesMap[key]
if m, ok := module.(*apexBundle); ok {
fmt.Fprintf(&filecontent,
- "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+ "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
m.Name()+".apex",
m.public_key_file.String(),
m.private_key_file.String(),
m.container_certificate_file.String(),
- m.container_private_key_file.String())
+ m.container_private_key_file.String(),
+ m.PartitionTag(ctx.DeviceConfig()))
} else if m, ok := module.(*Prebuilt); ok {
fmt.Fprintf(&filecontent,
- "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+ "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
m.InstallFilename(),
- "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
+ "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", m.PartitionTag(ctx.DeviceConfig()))
}
}
diff --git a/apex/vndk.go b/apex/vndk.go
index f2e913e..f948d76 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -16,6 +16,7 @@
import (
"path/filepath"
+ "strconv"
"strings"
"sync"
@@ -95,6 +96,10 @@
func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
vndkVersion := m.VndkVersion()
+ // For VNDK-Lite device, we gather core-variants of VNDK-Sp libraries, which doesn't have VNDK version defined
+ if vndkVersion == "" {
+ vndkVersion = mctx.DeviceConfig().PlatformVndkVersion()
+ }
vndkApexList := vndkApexList(mctx.Config())
if vndkApex, ok := vndkApexList[vndkVersion]; ok {
mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApex)
@@ -117,10 +122,13 @@
// When all hard-coded references are fixed, remove symbolic links
// Note that we should keep following symlinks for older VNDKs (<=29)
// Since prebuilt vndk libs still depend on system/lib/vndk path
- if strings.HasPrefix(name, vndkApexName) {
- vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
- if strings.HasPrefix(name, vndkApexNamePrefix) {
- vndkVersion = strings.TrimPrefix(name, vndkApexNamePrefix)
+ if strings.HasPrefix(name, vndkApexNamePrefix) {
+ vndkVersion := strings.TrimPrefix(name, vndkApexNamePrefix)
+ if numVer, err := strconv.Atoi(vndkVersion); err != nil {
+ ctx.ModuleErrorf("apex_vndk should be named as %v<ver:number>: %s", vndkApexNamePrefix, name)
+ return
+ } else if numVer > android.SdkVersion_Android10 {
+ return
}
// the name of vndk apex is formatted "com.android.vndk.v" + version
apexName := vndkApexNamePrefix + vndkVersion
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index a9e26ad..523ac26 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -8,6 +8,59 @@
"android/soong/android"
)
+func TestVndkApexForVndkLite(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libvndksp",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+ `+vndkLibrariesTxtFiles("current"), func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("")
+ })
+ // VNDK-Lite contains only core variants of VNDK-Sp libraries
+ ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
+ "lib/libvndksp.so",
+ "lib/libc++.so",
+ "lib64/libvndksp.so",
+ "lib64/libc++.so",
+ "etc/llndk.libraries.VER.txt",
+ "etc/vndkcore.libraries.VER.txt",
+ "etc/vndksp.libraries.VER.txt",
+ "etc/vndkprivate.libraries.VER.txt",
+ })
+}
+
func TestVndkApexUsesVendorVariant(t *testing.T) {
bp := `
apex_vndk {
@@ -90,6 +143,7 @@
system_shared_libs: [],
stl: "none",
notice: "custom_notice",
+ sdk_version: "current",
}
cc_library {
name: "libprofile-clang-extras_ndk",
@@ -98,6 +152,7 @@
system_shared_libs: [],
stl: "none",
notice: "custom_notice",
+ sdk_version: "current",
}
`, func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 59d1502..4cdfb31 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -60,6 +60,10 @@
func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cflags := []string{
"-nostdlibinc",
+
+ // Make paths in deps files relative
+ "-no-canonical-prefixes",
+
"-O2",
"-isystem bionic/libc/include",
"-isystem bionic/libc/kernel/uapi",
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 0516279..a1c5de1 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -124,6 +124,10 @@
Name: "removeHidlInterfaceTypes",
Fix: removeHidlInterfaceTypes,
},
+ {
+ Name: "removeSoongConfigBoolVariable",
+ Fix: removeSoongConfigBoolVariable,
+ },
}
func NewFixRequest() FixRequest {
@@ -714,6 +718,78 @@
return nil
}
+func removeSoongConfigBoolVariable(f *Fixer) error {
+ found := map[string]bool{}
+ newDefs := make([]parser.Definition, 0, len(f.tree.Defs))
+ for _, def := range f.tree.Defs {
+ if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" {
+ if name, ok := getLiteralStringPropertyValue(mod, "name"); ok {
+ found[name] = true
+ } else {
+ return fmt.Errorf("Found soong_config_bool_variable without a name")
+ }
+ } else {
+ newDefs = append(newDefs, def)
+ }
+ }
+ f.tree.Defs = newDefs
+
+ if len(found) == 0 {
+ return nil
+ }
+
+ return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+ if mod.Type != "soong_config_module_type" {
+ return nil
+ }
+
+ variables, ok := getLiteralListProperty(mod, "variables")
+ if !ok {
+ return nil
+ }
+
+ boolValues := strings.Builder{}
+ empty := true
+ for _, item := range variables.Values {
+ nameValue, ok := item.(*parser.String)
+ if !ok {
+ empty = false
+ continue
+ }
+ if found[nameValue.Value] {
+ patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
+
+ boolValues.WriteString(`"`)
+ boolValues.WriteString(nameValue.Value)
+ boolValues.WriteString(`",`)
+ } else {
+ empty = false
+ }
+ }
+ if empty {
+ *patchList = parser.PatchList{}
+
+ prop, _ := mod.GetProperty("variables")
+ patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "")
+ }
+ if boolValues.Len() == 0 {
+ return nil
+ }
+
+ bool_variables, ok := getLiteralListProperty(mod, "bool_variables")
+ if ok {
+ patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String())
+ } else {
+ patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2,
+ fmt.Sprintf(`bool_variables: [%s],`, boolValues.String()))
+ }
+
+ return nil
+ })(f)
+
+ 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 38cefdd..64a7b93 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -918,3 +918,67 @@
})
}
}
+
+func TestRemoveSoongConfigBoolVariable(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "remove bool",
+ in: `
+ soong_config_module_type {
+ name: "foo",
+ variables: ["bar", "baz"],
+ }
+
+ soong_config_bool_variable {
+ name: "bar",
+ }
+
+ soong_config_string_variable {
+ name: "baz",
+ }
+ `,
+ out: `
+ soong_config_module_type {
+ name: "foo",
+ variables: [
+ "baz"
+ ],
+ bool_variables: ["bar"],
+ }
+
+ soong_config_string_variable {
+ name: "baz",
+ }
+ `,
+ },
+ {
+ name: "existing bool_variables",
+ in: `
+ soong_config_module_type {
+ name: "foo",
+ variables: ["baz"],
+ bool_variables: ["bar"],
+ }
+
+ soong_config_bool_variable {
+ name: "baz",
+ }
+ `,
+ out: `
+ soong_config_module_type {
+ name: "foo",
+ bool_variables: ["bar", "baz"],
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, removeSoongConfigBoolVariable)
+ })
+ }
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 008030f..0018ea9 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -19,16 +19,20 @@
# The extraction might fail for some source files, so run with -k and then check that
# sufficiently many files were generated.
declare -r out="${OUT_DIR:-out}"
+
# Build extraction files for C++ and Java. Build `merge_zips` which we use later.
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.
+
+# Build extraction file for Go the files in build/{blueprint,soong} directories.
declare -r abspath_out=$(realpath "${out}")
declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor)
declare -r go_root=$(realpath prebuilts/go/linux-x86)
+declare -r vnames_path=$(realpath build/soong/vnames.go.json)
+declare -r source_root=$PWD
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" ./...
+ KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" --rules="${vnames_path}" \
+ --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
)
done
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a78e455..5438b14 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -29,12 +29,13 @@
vendorSuffix = ".vendor"
ramdiskSuffix = ".ramdisk"
recoverySuffix = ".recovery"
+ sdkSuffix = ".sdk"
)
type AndroidMkContext interface {
Name() string
Target() android.Target
- subAndroidMk(*android.AndroidMkData, interface{})
+ subAndroidMk(*android.AndroidMkEntries, interface{})
Arch() android.Arch
Os() android.OsType
Host() bool
@@ -46,29 +47,29 @@
}
type subAndroidMkProvider interface {
- AndroidMk(AndroidMkContext, *android.AndroidMkData)
+ AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries)
}
-func (c *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
if c.subAndroidMkOnce == nil {
c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
}
if androidmk, ok := obj.(subAndroidMkProvider); ok {
if !c.subAndroidMkOnce[androidmk] {
c.subAndroidMkOnce[androidmk] = true
- androidmk.AndroidMk(c, data)
+ androidmk.AndroidMkEntries(c, entries)
}
}
}
-func (c *Module) AndroidMk() android.AndroidMkData {
+func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
if c.Properties.HideFromMake || !c.IsForPlatform() {
- return android.AndroidMkData{
+ return []android.AndroidMkEntries{{
Disabled: true,
- }
+ }}
}
- ret := android.AndroidMkData{
+ entries := android.AndroidMkEntries{
OutputFile: c.outputFile,
// TODO(jiyong): add the APEXes providing shared libs to the required modules
// Currently, adding c.Properties.ApexesProvidingSharedLibs is causing multiple
@@ -77,53 +78,75 @@
Required: c.Properties.AndroidMkRuntimeLibs,
Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if len(c.Properties.Logtags) > 0 {
- fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(c.Properties.Logtags, " "))
+ entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...)
}
if len(c.Properties.AndroidMkSharedLibs) > 0 {
- fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(c.Properties.AndroidMkSharedLibs, " "))
+ entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
}
if len(c.Properties.AndroidMkStaticLibs) > 0 {
- fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkStaticLibs, " "))
+ entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...)
}
if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
- fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
+ entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
}
- fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
+ entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
if c.UseVndk() {
- fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+ entries.SetBool("LOCAL_USE_VNDK", true)
if c.IsVndk() && !c.static() {
- fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.VndkVersion())
+ entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
// VNDK libraries available to vendor are not installed because
// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
if !c.isVndkExt() {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
}
}
}
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ // Make the SDK variant uninstallable so that there are not two rules to install
+ // to the same location.
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+ // dependencies to the .sdk suffix when building a module that uses the SDK.
+ entries.SetString("SOONG_SDK_VARIANT_MODULES",
+ "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
+ }
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
+ c.CcLibraryInterface() && c.Shared() {
+ // Using the SDK variant as a JNI library needs a copy of the .so that
+ // is not named .sdk.so so that it can be packaged into the APK with
+ // the right name.
+ fmt.Fprintln(w, "$(eval $(call copy-one-file,",
+ "$(LOCAL_BUILT_MODULE),",
+ "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
+ }
},
},
}
for _, feature := range c.features {
- c.subAndroidMk(&ret, feature)
+ c.subAndroidMk(&entries, feature)
}
- c.subAndroidMk(&ret, c.compiler)
- c.subAndroidMk(&ret, c.linker)
+ c.subAndroidMk(&entries, c.compiler)
+ c.subAndroidMk(&entries, c.linker)
if c.sanitize != nil {
- c.subAndroidMk(&ret, c.sanitize)
+ c.subAndroidMk(&entries, c.sanitize)
}
- c.subAndroidMk(&ret, c.installer)
+ c.subAndroidMk(&entries, c.installer)
- ret.SubName += c.Properties.SubName
+ entries.SubName += c.Properties.SubName
- return ret
+ return []android.AndroidMkEntries{entries}
}
-func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, ret *android.AndroidMkData) {
+func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
var testFiles []string
for _, d := range data {
rel := d.Rel()
@@ -135,8 +158,8 @@
testFiles = append(testFiles, path+":"+rel)
}
if len(testFiles) > 0 {
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
})
}
}
@@ -153,7 +176,7 @@
return overrides
}
-func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
+func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
exportedFlags := library.exportedFlags()
for _, dir := range library.exportedDirs() {
exportedFlags = append(exportedFlags, "-I"+dir.String())
@@ -162,166 +185,195 @@
exportedFlags = append(exportedFlags, "-isystem "+dir.String())
}
if len(exportedFlags) > 0 {
- fmt.Fprintln(w, "LOCAL_EXPORT_CFLAGS :=", strings.Join(exportedFlags, " "))
+ entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...)
}
exportedDeps := library.exportedDeps()
if len(exportedDeps) > 0 {
- fmt.Fprintln(w, "LOCAL_EXPORT_C_INCLUDE_DEPS :=", strings.Join(exportedDeps.Strings(), " "))
+ entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...)
}
}
-func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
if library.sAbiOutputFile.Valid() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+ "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiOutputFile.String())
if library.sAbiDiff.Valid() && !library.static() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
- fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+ "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiDiff.String())
+ entries.SetString("HEADER_ABI_DIFFS",
+ "$(HEADER_ABI_DIFFS) "+library.sAbiDiff.String())
}
}
}
-func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+ if library.sAbiOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+ library.sAbiOutputFile.String())
+ if library.sAbiDiff.Valid() && !library.static() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+ library.sAbiDiff.String())
+ fmt.Fprintln(w, "HEADER_ABI_DIFFS := $(HEADER_ABI_DIFFS) ",
+ library.sAbiDiff.String())
+ }
+ }
+}
+
+func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
if library.static() {
- ret.Class = "STATIC_LIBRARIES"
+ entries.Class = "STATIC_LIBRARIES"
} else if library.shared() {
- ret.Class = "SHARED_LIBRARIES"
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", library.toc().String())
+ entries.Class = "SHARED_LIBRARIES"
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
if !library.buildStubs() {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
}
if len(library.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
+ entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
}
if len(library.post_install_cmds) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.post_install_cmds, "&& "))
}
})
} else if library.header() {
- ret.Class = "HEADER_LIBRARIES"
+ entries.Class = "HEADER_LIBRARIES"
}
- ret.DistFile = library.distFile
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- library.androidMkWriteExportedFlags(w)
- library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+ entries.DistFile = library.distFile
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ library.androidMkWriteExportedFlags(entries)
+ library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
- _, _, ext := android.SplitFileExt(outputFile.Base())
+ _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
- fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
if library.coverageOutputFile.Valid() {
- fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", library.coverageOutputFile.String())
+ entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
}
if library.useCoreVariant {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
- fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
- fmt.Fprintln(w, "LOCAL_VNDK_DEPEND_ON_CORE_VARIANT := true")
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+ entries.SetBool("LOCAL_VNDK_DEPEND_ON_CORE_VARIANT", true)
}
if library.checkSameCoreVariant {
- fmt.Fprintln(w, "LOCAL_CHECK_SAME_VNDK_VARIANTS := true")
+ entries.SetBool("LOCAL_CHECK_SAME_VNDK_VARIANTS", true)
}
})
if library.shared() && !library.buildStubs() {
- ctx.subAndroidMk(ret, library.baseInstaller)
+ ctx.subAndroidMk(entries, library.baseInstaller)
} else {
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ if library.buildStubs() {
+ entries.SubName = "." + library.stubsVersion()
+ }
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ // Note library.skipInstall() has a special case to get here for static
+ // libraries that otherwise would have skipped installation and hence not
+ // have executed AndroidMkEntries at all. The reason is to ensure they get
+ // a NOTICE file make target which other libraries might depend on.
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
if library.buildStubs() {
- fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
}
})
}
if len(library.Properties.Stubs.Versions) > 0 &&
android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
!ctx.static() {
+ if library.buildStubs() && library.isLatestStubVersion() {
+ // reference the latest version via its name without suffix when it is provided by apex
+ entries.SubName = ""
+ }
if !library.buildStubs() {
- ret.SubName = ".bootstrap"
+ entries.SubName = ".bootstrap"
}
}
}
-func (object *objectLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- out := ret.OutputFile.Path()
- varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, data.SubName)
+func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "STATIC_LIBRARIES"
+ entries.ExtraFooters = append(entries.ExtraFooters,
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ out := entries.OutputFile.Path()
+ varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
- fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
- fmt.Fprintln(w, ".KATI_READONLY: "+varname)
- }
+ fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
+ fmt.Fprintln(w, ".KATI_READONLY: "+varname)
+ })
}
-func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, binary.baseInstaller)
+func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, binary.baseInstaller)
- ret.Class = "EXECUTABLES"
- ret.DistFile = binary.distFile
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+ entries.Class = "EXECUTABLES"
+ entries.DistFile = binary.distFile
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
if len(binary.symlinks) > 0 {
- fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(binary.symlinks, " "))
+ entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
}
if binary.coverageOutputFile.Valid() {
- fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", binary.coverageOutputFile.String())
+ entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
}
if len(binary.Properties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
+ entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
}
if len(binary.post_install_cmds) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.post_install_cmds, "&& "))
}
})
}
-func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, benchmark.binaryDecorator)
- ret.Class = "NATIVE_TESTS"
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, benchmark.binaryDecorator)
+ entries.Class = "NATIVE_TESTS"
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
if len(benchmark.Properties.Test_suites) > 0 {
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+ entries.SetString("LOCAL_COMPATIBILITY_SUITE",
strings.Join(benchmark.Properties.Test_suites, " "))
}
if benchmark.testConfig != nil {
- fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", benchmark.testConfig.String())
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
}
- fmt.Fprintln(w, "LOCAL_NATIVE_BENCHMARK := true")
+ entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
- fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+ entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
}
})
- androidMkWriteTestData(benchmark.data, ctx, ret)
+ androidMkWriteTestData(benchmark.data, ctx, entries)
}
-func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, test.binaryDecorator)
- ret.Class = "NATIVE_TESTS"
+func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, test.binaryDecorator)
+ entries.Class = "NATIVE_TESTS"
if Bool(test.Properties.Test_per_src) {
- ret.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
+ entries.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
}
-
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
if len(test.Properties.Test_suites) > 0 {
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+ entries.SetString("LOCAL_COMPATIBILITY_SUITE",
strings.Join(test.Properties.Test_suites, " "))
}
if test.testConfig != nil {
- fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String())
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
}
if !BoolDefault(test.Properties.Auto_gen_config, true) {
- fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+ entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
}
})
- androidMkWriteTestData(test.data, ctx, ret)
+ androidMkWriteTestData(test.data, ctx, entries)
}
-func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, fuzz.binaryDecorator)
+func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, fuzz.binaryDecorator)
var fuzzFiles []string
for _, d := range fuzz.corpus {
@@ -344,199 +396,201 @@
filepath.Dir(fuzz.config.String())+":config.json")
}
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
if len(fuzzFiles) > 0 {
- fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+ entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
}
if fuzz.installedSharedDeps != nil {
- fmt.Fprintln(w, "LOCAL_FUZZ_INSTALLED_SHARED_DEPS :="+
- strings.Join(fuzz.installedSharedDeps, " "))
+ entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
}
})
}
-func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, test.libraryDecorator)
+func (test *testLibrary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, test.libraryDecorator)
}
-func (library *toolchainLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "STATIC_LIBRARIES"
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- _, suffix, _ := android.SplitFileExt(outputFile.Base())
- fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "STATIC_LIBRARIES"
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ _, suffix, _ := android.SplitFileExt(entries.OutputFile.Path().Base())
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
})
}
-func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ if installer.path == (android.InstallPath{}) {
+ return
+ }
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.
if ctx.Target().Os.Class == android.Host {
- ret.OutputFile = android.OptionalPathForPath(installer.path)
+ entries.OutputFile = android.OptionalPathForPath(installer.path)
}
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
path, file := filepath.Split(installer.path.ToMakePath().String())
stem, suffix, _ := android.SplitFileExt(file)
- fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
- fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_PATH", path)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
})
}
-func (c *stubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
- ret.Class = "SHARED_LIBRARIES"
+func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
+ entries.Class = "SHARED_LIBRARIES"
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
path, file := filepath.Split(c.installPath.String())
stem, suffix, _ := android.SplitFileExt(file)
- fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
- fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
- fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_PATH", path)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
})
}
-func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "SHARED_LIBRARIES"
+func (c *llndkStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "SHARED_LIBRARIES"
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- c.libraryDecorator.androidMkWriteExportedFlags(w)
- _, _, ext := android.SplitFileExt(outputFile.Base())
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ c.libraryDecorator.androidMkWriteExportedFlags(entries)
+ _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
- fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
- fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
- fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", c.toc().String())
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+ entries.SetString("LOCAL_SOONG_TOC", c.toc().String())
})
}
-func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "SHARED_LIBRARIES"
+func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "SHARED_LIBRARIES"
- ret.SubName = c.androidMkSuffix
+ entries.SubName = c.androidMkSuffix
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- c.libraryDecorator.androidMkWriteExportedFlags(w)
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ c.libraryDecorator.androidMkWriteExportedFlags(entries)
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_PATH := "+path)
- fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_PATH", path)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
if c.tocFile.Valid() {
- fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+ entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
}
})
}
-func (c *vendorSnapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
// 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"
+ entries.Class = "SHARED_LIBRARIES"
} else if c.static() {
- ret.Class = "STATIC_LIBRARIES"
+ entries.Class = "STATIC_LIBRARIES"
} else if c.header() {
- ret.Class = "HEADER_LIBRARIES"
+ entries.Class = "HEADER_LIBRARIES"
}
if c.androidMkVendorSuffix {
- ret.SubName = vendorSuffix
+ entries.SubName = vendorSuffix
} else {
- ret.SubName = ""
+ entries.SubName = ""
}
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- c.libraryDecorator.androidMkWriteExportedFlags(w)
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ c.libraryDecorator.androidMkWriteExportedFlags(entries)
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)
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+ entries.SetString("LOCAL_MODULE_STEM", stem)
if c.shared() {
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
+ entries.SetString("LOCAL_MODULE_PATH", path)
}
if c.tocFile.Valid() {
- fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+ entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
}
}
if !c.shared() { // static or header
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
}
})
}
-func (c *vendorSnapshotBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "EXECUTABLES"
+func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "EXECUTABLES"
if c.androidMkVendorSuffix {
- ret.SubName = vendorSuffix
+ entries.SubName = vendorSuffix
} else {
- ret.SubName = ""
+ entries.SubName = ""
}
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(c.Properties.Symlinks, " "))
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_MODULE_SYMLINKS", c.Properties.Symlinks...)
})
}
-func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "SHARED_LIBRARIES"
+func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "SHARED_LIBRARIES"
}
-func (c *vendorPublicLibraryStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Class = "SHARED_LIBRARIES"
- ret.SubName = vendorPublicLibrarySuffix
+func (c *vendorPublicLibraryStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.Class = "SHARED_LIBRARIES"
+ entries.SubName = vendorPublicLibrarySuffix
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- c.libraryDecorator.androidMkWriteExportedFlags(w)
- _, _, ext := android.SplitFileExt(outputFile.Base())
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ c.libraryDecorator.androidMkWriteExportedFlags(entries)
+ _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
- fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
- fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
})
}
-func (p *prebuiltLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
if p.properties.Check_elf_files != nil {
- fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES :=", *p.properties.Check_elf_files)
+ entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
} else {
// soong_cc_prebuilt.mk does not include check_elf_file.mk by default
// because cc_library_shared and cc_binary use soong_cc_prebuilt.mk as well.
// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
// true if `p.properties.Check_elf_files` is not specified.
- fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := true")
+ entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
}
})
}
-func (p *prebuiltLibraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, p.libraryDecorator)
+func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, p.libraryDecorator)
if p.shared() {
- ctx.subAndroidMk(ret, &p.prebuiltLinker)
- androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+ ctx.subAndroidMk(entries, &p.prebuiltLinker)
+ androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
}
}
-func (p *prebuiltBinaryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, p.binaryDecorator)
- ctx.subAndroidMk(ret, &p.prebuiltLinker)
- androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ ctx.subAndroidMk(entries, p.binaryDecorator)
+ ctx.subAndroidMk(entries, &p.prebuiltLinker)
+ androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
}
-func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, ret *android.AndroidMkData) {
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- allow := linker.Properties.Allow_undefined_symbols
- if allow != nil {
- fmt.Fprintln(w, "LOCAL_ALLOW_UNDEFINED_SYMBOLS :=", *allow)
- }
- })
+func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) {
+ allow := linker.Properties.Allow_undefined_symbols
+ if allow != nil {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
+ })
+ }
}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 58d6ad0..1d9cc54 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -16,9 +16,9 @@
import (
"path/filepath"
- "strings"
"android/soong/android"
+
"github.com/google/blueprint"
)
@@ -64,65 +64,12 @@
return false
}
-func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- buildSharedNativeBinarySnapshot(info, builder, member)
+func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
}
-// 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")
- archVariantCount := len(info.archVariantProperties)
-
- // Choose setting for compile_multilib that is appropriate for the arch variants supplied.
- var multilib string
- if archVariantCount == 2 {
- multilib = "both"
- } else if archVariantCount == 1 {
- if strings.HasSuffix(info.archVariantProperties[0].archType, "64") {
- multilib = "64"
- } else {
- multilib = "32"
- }
- }
- if multilib != "" {
- pbm.AddProperty("compile_multilib", multilib)
- }
-
- 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))
- }
+func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeBinaryInfoProperties{}
}
const (
@@ -131,7 +78,7 @@
// path to the native binary. Relative to <sdk_root>/<api_dir>
func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
- return filepath.Join(lib.archType,
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeBinaryDir, lib.outputFile.Base())
}
@@ -140,8 +87,7 @@
// 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
+ android.SdkMemberPropertiesBase
// archType is not exported as if set (to a non default value) it is always arch specific.
// This is "" for common properties.
@@ -149,12 +95,52 @@
// outputFile is not exported as it is always arch specific.
outputFile android.Path
+
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
}
-// nativeBinaryInfo represents a collection of arch-specific modules having the same name
-type nativeBinaryInfo struct {
- name string
- memberType *binarySdkMemberType
- archVariantProperties []nativeBinaryInfoProperties
- commonProperties nativeBinaryInfoProperties
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ ccModule := variant.(*Module)
+
+ p.archType = ccModule.Target().Arch.ArchType.String()
+ p.outputFile = ccModule.OutputFile().Path()
+
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+}
+
+func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if p.Compile_multilib != "" {
+ propertySet.AddProperty("compile_multilib", p.Compile_multilib)
+ }
+
+ builder := ctx.SnapshotBuilder()
+ if p.outputFile != nil {
+ propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
+
+ builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
+ }
+
+ if len(p.SharedLibs) > 0 {
+ propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ // SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
+ // so check for non-nil instead of nonzero length.
+ if p.SystemSharedLibs != nil {
+ propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
}
diff --git a/cc/builder.go b/cc/builder.go
index efdbbb2..990069d 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -29,6 +29,7 @@
"android/soong/android"
"android/soong/cc/config"
+ "android/soong/remoteexec"
)
const (
@@ -55,7 +56,7 @@
},
"ccCmd", "cFlags")
- ld = pctx.AndroidStaticRule("ld",
+ ld, ldRE = remoteexec.StaticRules(pctx, "ld",
blueprint.RuleParams{
Command: "$ldCmd ${crtBegin} @${out}.rsp " +
"${libFlags} ${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}",
@@ -65,16 +66,28 @@
// clang -Wl,--out-implib doesn't update its output file if it hasn't changed.
Restat: true,
},
- "ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags")
+ &remoteexec.REParams{Labels: map[string]string{"type": "link", "tool": "clang"},
+ ExecStrategy: "${config.RECXXLinksExecStrategy}",
+ Inputs: []string{"${out}.rsp"},
+ RSPFile: "${out}.rsp",
+ OutputFiles: []string{"${out}"},
+ ToolchainInputs: []string{"$ldCmd"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
+ }, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, nil)
- partialLd = pctx.AndroidStaticRule("partialLd",
+ partialLd, partialLdRE = remoteexec.StaticRules(pctx, "partialLd",
blueprint.RuleParams{
// Without -no-pie, clang 7.0 adds -pie to link Android files,
// but -r and -pie cannot be used together.
Command: "$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}",
CommandDeps: []string{"$ldCmd"},
- },
- "ldCmd", "ldFlags")
+ }, &remoteexec.REParams{
+ Labels: map[string]string{"type": "link", "tool": "clang"},
+ ExecStrategy: "${config.RECXXLinksExecStrategy}", Inputs: []string{"$inCommaList"},
+ OutputFiles: []string{"${out}"},
+ ToolchainInputs: []string{"$ldCmd"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"},
+ }, []string{"ldCmd", "ldFlags"}, []string{"inCommaList"})
ar = pctx.AndroidStaticRule("ar",
blueprint.RuleParams{
@@ -254,6 +267,7 @@
}
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
+ pctx.Import("android/soong/remoteexec")
}
type builderFlags struct {
@@ -285,7 +299,7 @@
rsFlags string
toolchain config.Toolchain
tidy bool
- coverage bool
+ gcovCoverage bool
sAbiDump bool
emitXrefs bool
@@ -347,7 +361,7 @@
tidyFiles = make(android.Paths, 0, len(srcFiles))
}
var coverageFiles android.Paths
- if flags.coverage {
+ if flags.gcovCoverage {
coverageFiles = make(android.Paths, 0, len(srcFiles))
}
var kytheFiles android.Paths
@@ -448,7 +462,7 @@
var ccCmd string
tidy := flags.tidy
- coverage := flags.coverage
+ coverage := flags.gcovCoverage
dump := flags.sAbiDump
rule := cc
emitXref := flags.emitXrefs
@@ -649,8 +663,13 @@
deps = append(deps, crtBegin.Path(), crtEnd.Path())
}
+ rule := ld
+ if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+ rule = ldRE
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: ld,
+ Rule: rule,
Description: "link " + outputFile.Base(),
Output: outputFile,
ImplicitOutputs: implicitOutputs,
@@ -799,16 +818,22 @@
ldCmd := "${config.ClangBin}/clang++"
+ rule := partialLd
+ args := map[string]string{
+ "ldCmd": ldCmd,
+ "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
+ }
+ if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+ rule = partialLdRE
+ args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: partialLd,
+ Rule: rule,
Description: "link " + outputFile.Base(),
Output: outputFile,
Inputs: objFiles,
Implicits: deps,
- Args: map[string]string{
- "ldCmd": ldCmd,
- "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
- },
+ Args: args,
})
}
diff --git a/cc/cc.go b/cc/cc.go
index 5af8459..66425c7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -42,6 +42,7 @@
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("sdk", sdkMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
@@ -181,11 +182,11 @@
// These must be after any module include flags, which will be in CommonFlags.
SystemIncludeFlags []string
- Toolchain config.Toolchain
- Tidy bool
- Coverage bool
- SAbiDump bool
- EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
+ Toolchain config.Toolchain
+ Tidy bool
+ GcovCoverage bool
+ SAbiDump bool
+ EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
RequiredInstructionSet string
DynamicLinker string
@@ -208,9 +209,16 @@
// Deprecated. true is the default, false is invalid.
Clang *bool `android:"arch_variant"`
- // Minimum sdk version supported when compiling against the ndk
+ // Minimum sdk version supported when compiling against the ndk. Setting this property causes
+ // two variants to be built, one for the platform and one for apps.
Sdk_version *string
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ Min_sdk_version *string
+
+ // If true, always create an sdk variant and don't create a platform variant.
+ Sdk_variant_only *bool
+
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
@@ -250,6 +258,18 @@
// Used by vendor snapshot to record dependencies from snapshot modules.
SnapshotSharedLibs []string `blueprint:"mutated"`
SnapshotRuntimeLibs []string `blueprint:"mutated"`
+
+ Installable *bool
+
+ // Set by factories of module types that can only be referenced from variants compiled against
+ // the SDK.
+ AlwaysSdk bool `blueprint:"mutated"`
+
+ // Variant is an SDK variant created by sdkMutator
+ IsSdkVariant bool `blueprint:"mutated"`
+ // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
+ // variant to have a ".sdk" suffix.
+ SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
}
type VendorProperties struct {
@@ -290,6 +310,7 @@
staticBinary() bool
header() bool
toolchain() config.Toolchain
+ canUseSdk() bool
useSdk() bool
sdkVersion() string
useVndk() bool
@@ -313,6 +334,7 @@
useClangLld(actx ModuleContext) bool
isForPlatform() bool
apexName() string
+ apexSdkVersion() int
hasStubsVariants() bool
isStubs() bool
bootstrap() bool
@@ -366,15 +388,26 @@
nativeCoverage() bool
coverageOutputFilePath() android.OptionalPath
+
+ // Get the deps that have been explicitly specified in the properties.
+ // Only updates the
+ linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+}
+
+type specifiedDeps struct {
+ sharedLibs []string
+ systemSharedLibs []string // Note nil and [] are semantically distinct.
}
type installer interface {
installerProps() []interface{}
install(ctx ModuleContext, path android.Path)
+ everInstallable() bool
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
relativeInstallPath() string
+ skipInstall(mod *Module)
}
type xref interface {
@@ -474,6 +507,9 @@
makeLinkType string
// Kythe (source file indexer) paths for this compilation module
kytheFiles android.Paths
+
+ // For apex variants, this is set as apex.min_sdk_version
+ apexSdkVersion int
}
func (c *Module) Toc() android.OptionalPath {
@@ -513,7 +549,10 @@
}
func (c *Module) SelectedStl() string {
- return c.stl.Properties.SelectedStl
+ if c.stl != nil {
+ return c.stl.Properties.SelectedStl
+ }
+ return ""
}
func (c *Module) ToolchainLibrary() bool {
@@ -541,6 +580,10 @@
return String(c.Properties.Sdk_version)
}
+func (c *Module) AlwaysSdk() bool {
+ return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
+}
+
func (c *Module) IncludeDirs() android.Paths {
if c.linker != nil {
if library, ok := c.linker.(exportedFlagsProducer); ok {
@@ -608,6 +651,10 @@
c.Properties.PreventInstall = true
return
}
+ if _, ok := c.linker.(*llndkStubDecorator); ok {
+ c.Properties.HideFromMake = true
+ return
+ }
}
panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
}
@@ -627,10 +674,26 @@
library.MutatedProperties.StubsVersion = version
return
}
+ if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+ llndk.libraryDecorator.MutatedProperties.StubsVersion = version
+ return
+ }
}
panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
}
+func (c *Module) StubsVersion() string {
+ if c.linker != nil {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return library.MutatedProperties.StubsVersion
+ }
+ if llndk, ok := c.linker.(*llndkStubDecorator); ok {
+ return llndk.libraryDecorator.MutatedProperties.StubsVersion
+ }
+ }
+ panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
+}
+
func (c *Module) SetStatic() {
if c.linker != nil {
if library, ok := c.linker.(libraryInterface); ok {
@@ -780,6 +843,17 @@
return c.Properties.VndkVersion != ""
}
+func (c *Module) canUseSdk() bool {
+ return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery()
+}
+
+func (c *Module) UseSdk() bool {
+ if c.canUseSdk() {
+ return String(c.Properties.Sdk_version) != ""
+ }
+ return false
+}
+
func (c *Module) isCoverageVariant() bool {
return c.coverage.Properties.IsCoverageVariant
}
@@ -1036,18 +1110,19 @@
return ctx.mod.header()
}
+func (ctx *moduleContextImpl) canUseSdk() bool {
+ return ctx.mod.canUseSdk()
+}
+
func (ctx *moduleContextImpl) useSdk() bool {
- if ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() {
- return String(ctx.mod.Properties.Sdk_version) != ""
- }
- return false
+ return ctx.mod.UseSdk()
}
func (ctx *moduleContextImpl) sdkVersion() string {
if ctx.ctx.Device() {
if ctx.useVndk() {
vndkVer := ctx.mod.VndkVersion()
- if inList(vndkVer, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
+ if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) {
return "current"
}
return vndkVer
@@ -1123,6 +1198,11 @@
return false
}
+ // Coverage builds have extra symbols.
+ if ctx.mod.isCoverageVariant() {
+ return false
+ }
+
if ctx.ctx.Fuchsia() {
return false
}
@@ -1170,6 +1250,10 @@
return ctx.mod.ApexName()
}
+func (ctx *moduleContextImpl) apexSdkVersion() int {
+ return ctx.mod.apexSdkVersion
+}
+
func (ctx *moduleContextImpl) hasStubsVariants() bool {
return ctx.mod.HasStubsVariants()
}
@@ -1355,6 +1439,8 @@
c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix
+ } else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ c.Properties.SubName += sdkSuffix
}
ctx := &moduleContext{
@@ -1465,6 +1551,13 @@
c.Properties.HideFromMake = false // unhide
// Note: this is still non-installable
}
+
+ // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current.
+ if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" {
+ if isSnapshotAware(ctx, c) {
+ i.collectHeadersForSnapshot(ctx)
+ }
+ }
}
if c.installable() {
@@ -1472,6 +1565,13 @@
if ctx.Failed() {
return
}
+ } else if !proptools.BoolDefault(c.Properties.Installable, true) {
+ // If the module has been specifically configure to not be installed then
+ // skip the installation as otherwise it will break when running inside make
+ // as the output path to install will not be specified. Not all uninstallable
+ // modules can skip installation as some are needed for resolving make side
+ // dependencies.
+ c.SkipInstall()
}
}
@@ -1791,7 +1891,10 @@
}, depTag, lib)
}
- if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+ // staticUnwinderDep is treated as staticDep for Q apexes
+ // so that native libraries/binaries are linked with static unwinder
+ // because Q libc doesn't have unwinder APIs
+ if deps.StaticUnwinderIfLegacy {
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, staticUnwinderDepTag, staticUnwinder(actx))
@@ -1806,24 +1909,24 @@
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() && !c.InRamdisk()
- if version != "" && versionVariantAvail {
+ if version != "" && VersionVariantAvailable(c) {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
depTag.ExplicitlyVersioned = true
}
actx.AddVariationDependencies(variations, depTag, name)
- // If the version is not specified, add dependency to the latest stubs library.
+ // If the version is not specified, add dependency to all stubs libraries.
// The stubs library will be used when the depending module is built for APEX and
// the dependent module is not in the same APEX.
- latestVersion := LatestStubsVersionFor(actx.Config(), name)
- if version == "" && latestVersion != "" && versionVariantAvail {
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- {Mutator: "version", Variation: latestVersion},
- }, depTag, name)
- // Note that depTag.ExplicitlyVersioned is false in this case.
+ if version == "" && VersionVariantAvailable(c) {
+ for _, ver := range stubsVersionsFor(actx.Config())[name] {
+ // Note that depTag.ExplicitlyVersioned is false in this case.
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: ver},
+ }, depTag, name)
+ }
}
}
@@ -2140,13 +2243,17 @@
if depTag == android.ProtoPluginDepTag {
return
}
+ if depTag == llndkImplDep {
+ return
+ }
if dep.Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
return
}
if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
- ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+ ctx.ModuleErrorf("Arch mismatch between %q(%v) and %q(%v)",
+ ctx.ModuleName(), ctx.Arch().ArchType, depName, dep.Target().Arch.ArchType)
return
}
@@ -2170,8 +2277,22 @@
}
}
+ // For the dependency from platform to apex, use the latest stubs
+ c.apexSdkVersion = android.FutureApiLevel
+ if !c.IsForPlatform() {
+ c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
+ }
+
+ if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+ // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+ // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+ // (b/144430859)
+ c.apexSdkVersion = android.FutureApiLevel
+ }
+
if depTag == staticUnwinderDepTag {
- if c.ApexProperties.Info.LegacyAndroid10Support {
+ // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+ if c.apexSdkVersion <= android.SdkVersion_Android10 {
depTag = StaticDepTag
} else {
return
@@ -2196,7 +2317,7 @@
}
if ccDep.CcLibrary() && !depIsStatic {
depIsStubs := ccDep.BuildStubs()
- depHasStubs := ccDep.HasStubsVariants()
+ depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
@@ -2212,21 +2333,62 @@
// If not building for APEX, use stubs only when it is from
// an APEX (and not from platform)
useThisDep = (depInPlatform != depIsStubs)
- if c.InRamdisk() || c.InRecovery() || c.bootstrap() {
- // However, for ramdisk, recovery or bootstrap modules,
+ if c.bootstrap() {
+ // However, for host, ramdisk, recovery or bootstrap modules,
// always link to non-stub variant
useThisDep = !depIsStubs
}
+ for _, testFor := range c.TestFor() {
+ // Another exception: if this module is bundled with an APEX, then
+ // it is linked with the non-stub variant of a module in the APEX
+ // as if this is part of the APEX.
+ if android.DirectlyInApex(testFor, depName) {
+ useThisDep = !depIsStubs
+ break
+ }
+ }
} else {
// If building for APEX, use stubs only when it is not from
// the same APEX
useThisDep = (depInSameApex != depIsStubs)
}
+ // when to use (unspecified) stubs, check min_sdk_version and choose the right one
+ if useThisDep && depIsStubs && !explicitlyVersioned {
+ versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion)
+ if err != nil {
+ ctx.OtherModuleErrorf(dep, err.Error())
+ return
+ }
+ if versionToUse != ccDep.StubsVersion() {
+ useThisDep = false
+ }
+ }
+
if !useThisDep {
return // stop processing this dep
}
}
+ if c.UseVndk() {
+ if m, ok := ccDep.(*Module); ok && m.IsStubs() { // LLNDK
+ // by default, use current version of LLNDK
+ versionToUse := ""
+ versions := stubsVersionsFor(ctx.Config())[depName]
+ if c.ApexName() != "" && len(versions) > 0 {
+ // if this is for use_vendor apex && dep has stubsVersions
+ // apply the same rule of apex sdk enforcement to choose right version
+ var err error
+ versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion)
+ if err != nil {
+ ctx.OtherModuleErrorf(dep, err.Error())
+ return
+ }
+ }
+ if versionToUse != ccDep.StubsVersion() {
+ return
+ }
+ }
+ }
depPaths.IncludeDirs = append(depPaths.IncludeDirs, ccDep.IncludeDirs()...)
@@ -2373,8 +2535,13 @@
if c, ok := ccDep.(*Module); ok {
// Use base module name for snapshots when exporting to Makefile.
- if c.isSnapshotPrebuilt() && !c.IsVndk() {
+ if c.isSnapshotPrebuilt() {
baseName := c.BaseModuleName()
+
+ if c.IsVndk() {
+ return baseName + ".vendor"
+ }
+
if vendorSuffixModules[baseName] {
return baseName + ".vendor"
} else {
@@ -2489,6 +2656,14 @@
return c.InRecovery()
}
+func (c *Module) SkipInstall() {
+ if c.installer == nil {
+ c.ModuleBase.SkipInstall()
+ return
+ }
+ c.installer.skipInstall(c)
+}
+
func (c *Module) HostToolPath() android.OptionalPath {
if c.installer == nil {
return android.OptionalPath{}
@@ -2598,8 +2773,28 @@
}
}
+func (c *Module) TestFor() []string {
+ if test, ok := c.linker.(interface {
+ testFor() []string
+ }); ok {
+ return test.testFor()
+ } else {
+ return c.ApexModuleBase.TestFor()
+ }
+}
+
+// Return true if the module is ever installable.
+func (c *Module) EverInstallable() bool {
+ return c.installer != nil &&
+ // Check to see whether the module is actually ever installable.
+ c.installer.everInstallable()
+}
+
func (c *Module) installable() bool {
- ret := c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid()
+ ret := c.EverInstallable() &&
+ // Check to see whether the module has been configured to not be installed.
+ proptools.BoolDefault(c.Properties.Installable, true) &&
+ !c.Properties.PreventInstall && c.outputFile.Valid()
// The platform variant doesn't need further condition. Apex variants however might not
// be installable because it will likely to be included in the APEX and won't appear
@@ -2631,9 +2826,15 @@
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 {
- if cc.HasStubsVariants() && depTag.Shared && depTag.Library {
- // dynamic dep to a stubs lib crosses APEX boundary
- return false
+ if cc.HasStubsVariants() {
+ if depTag.Shared && depTag.Library {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ if IsRuntimeDepTag(depTag) {
+ // runtime dep to a stubs lib also crosses APEX boundary
+ return false
+ }
}
if depTag.FromStatic {
// shared_lib dependency from a static lib is considered as crossing
@@ -2734,19 +2935,18 @@
if vndkdep := m.vndkdep; vndkdep != nil {
if vndkdep.isVndk() {
- if productSpecific {
- mctx.PropertyErrorf("product_specific",
- "product_specific must not be true when `vndk: {enabled: true}`")
- }
- if vendorSpecific {
+ if vendorSpecific || productSpecific {
if !vndkdep.isVndkExt() {
mctx.PropertyErrorf("vndk",
"must set `extends: \"...\"` to vndk extension")
+ } else if m.VendorProperties.Vendor_available != nil {
+ mctx.PropertyErrorf("vendor_available",
+ "must not set at the same time as `vndk: {extends: \"...\"}`")
}
} else {
if vndkdep.isVndkExt() {
mctx.PropertyErrorf("vndk",
- "must set `vendor: true` to set `extends: %q`",
+ "must set `vendor: true` or `product_specific: true` to set `extends: %q`",
m.getVndkExtendsModuleName())
}
if m.VendorProperties.Vendor_available == nil {
@@ -2819,7 +3019,7 @@
} else {
mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
}
- } else if m.HasVendorVariant() && !vendorSpecific {
+ } else if m.HasVendorVariant() && !m.isVndkExt() {
// This will be available in /system, /vendor and /product
// or a /system directory that is available to vendor and product.
coreVariantNeeded = true
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 30ba733..67eb248 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -218,13 +218,13 @@
}
func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
- isVndkSp bool, extends string) {
+ isVndkSp bool, extends string, variant string) {
t.Helper()
- mod := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
if !mod.HasVendorVariant() {
- t.Errorf("%q must have vendor variant", name)
+ t.Errorf("%q must have variant %q", name, variant)
}
// Check library properties.
@@ -375,10 +375,10 @@
ctx := testCcWithConfig(t, config)
- checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
- checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
- checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
- checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+ checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "", vendorVariant)
+ checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "", vendorVariant)
+ checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "", vendorVariant)
+ checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "", vendorVariant)
// Check VNDK snapshot output.
@@ -1001,24 +1001,9 @@
`)
}
-func TestVndkMustNotBeProductSpecific(t *testing.T) {
- // Check whether an error is emitted when a vndk lib has 'product_specific: true'.
- testCcError(t, "product_specific must not be true when `vndk: {enabled: true}`", `
- cc_library {
- name: "libvndk",
- product_specific: true, // Cause error
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- nocrt: true,
- }
- `)
-}
-
func TestVndkExt(t *testing.T) {
// This test checks the VNDK-Ext properties.
- ctx := testCc(t, `
+ bp := `
cc_library {
name: "libvndk",
vendor_available: true,
@@ -1060,12 +1045,42 @@
},
nocrt: true,
}
- `)
- checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk")
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
- mod := ctx.ModuleForTests("libvndk2_ext", vendorVariant).Module().(*Module)
- assertString(t, mod.outputFile.Path().Base(), "libvndk2-suffix.so")
+ cc_library {
+ name: "libvndk2_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk2",
+ },
+ nocrt: true,
+ }
+ `
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.ProductVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ ctx := testCcWithConfig(t, config)
+
+ checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk", vendorVariant)
+ checkVndkModule(t, ctx, "libvndk_ext_product", "vndk", false, "libvndk", productVariant)
+
+ mod_vendor := ctx.ModuleForTests("libvndk2_ext", vendorVariant).Module().(*Module)
+ assertString(t, mod_vendor.outputFile.Path().Base(), "libvndk2-suffix.so")
+
+ mod_product := ctx.ModuleForTests("libvndk2_ext_product", productVariant).Module().(*Module)
+ assertString(t, mod_product.outputFile.Path().Base(), "libvndk2-suffix.so")
}
func TestVndkExtWithoutBoardVndkVersion(t *testing.T) {
@@ -1098,9 +1113,39 @@
}
}
+func TestVndkExtWithoutProductVndkVersion(t *testing.T) {
+ // This test checks the VNDK-Ext properties when PRODUCT_PRODUCT_VNDK_VERSION is not set.
+ ctx := testCc(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
+
+ // Ensures that the core variant of "libvndk_ext_product" can be found.
+ mod := ctx.ModuleForTests("libvndk_ext_product", coreVariant).Module().(*Module)
+ if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
+ t.Errorf("\"libvndk_ext_product\" must extend from \"libvndk\" but get %q", extends)
+ }
+}
+
func TestVndkExtError(t *testing.T) {
// This test ensures an error is emitted in ill-formed vndk-ext definition.
- testCcError(t, "must set `vendor: true` to set `extends: \".*\"`", `
+ testCcError(t, "must set `vendor: true` or `product_specific: true` to set `extends: \".*\"`", `
cc_library {
name: "libvndk",
vendor_available: true,
@@ -1139,6 +1184,48 @@
nocrt: true,
}
`)
+
+ testCcErrorProductVndk(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+ `)
+
+ testCcErrorProductVndk(t, "must not set at the same time as `vndk: {extends: \"\\.\\.\\.\"}`", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
}
func TestVndkExtInconsistentSupportSystemProcessError(t *testing.T) {
@@ -1211,6 +1298,27 @@
nocrt: true,
}
`)
+
+ testCcErrorProductVndk(t, "`extends` refers module \".*\" which does not have `vendor_available: true`", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
}
func TestVendorModuleUseVndkExt(t *testing.T) {
@@ -1236,7 +1344,6 @@
}
cc_library {
-
name: "libvndk_sp",
vendor_available: true,
vndk: {
@@ -1328,6 +1435,71 @@
`)
}
+func TestProductVndkExtDependency(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ shared_libs: ["libproduct_for_vndklibs"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext_product",
+ product_specific: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ support_system_process: true,
+ },
+ shared_libs: ["libproduct_for_vndklibs"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libproduct",
+ product_specific: true,
+ shared_libs: ["libvndk_ext_product", "libvndk_sp_ext_product"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libproduct_for_vndklibs",
+ product_specific: true,
+ nocrt: true,
+ }
+ `
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.ProductVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ testCcWithConfig(t, config)
+}
+
func TestVndkSpExtUseVndkError(t *testing.T) {
// This test ensures an error is emitted if a VNDK-SP-Ext library depends on a VNDK
// library.
@@ -1619,8 +1791,8 @@
ctx := testCcWithConfig(t, config)
- checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
- checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
+ checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "", productVariant)
+ checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "", productVariant)
}
func TestEnforceProductVndkVersionErrors(t *testing.T) {
@@ -2215,6 +2387,45 @@
}
}
+func checkEquals(t *testing.T, message string, expected, actual interface{}) {
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf(message+
+ "\nactual: %v"+
+ "\nexpected: %v",
+ actual,
+ expected,
+ )
+ }
+}
+
+func TestLlndkLibrary(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "libllndk",
+ stubs: { versions: ["1", "2"] },
+ }
+ llndk_library {
+ name: "libllndk",
+ }
+ `)
+ actual := ctx.ModuleVariantsForTests("libllndk.llndk")
+ expected := []string{
+ "android_vendor.VER_arm64_armv8-a_shared",
+ "android_vendor.VER_arm64_armv8-a_shared_1",
+ "android_vendor.VER_arm64_armv8-a_shared_2",
+ "android_vendor.VER_arm_armv7-a-neon_shared",
+ "android_vendor.VER_arm_armv7-a-neon_shared_1",
+ "android_vendor.VER_arm_armv7-a-neon_shared_2",
+ }
+ checkEquals(t, "variants for llndk stubs", expected, actual)
+
+ params := ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
+ checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
+
+ params = ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
+ checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
+}
+
func TestLlndkHeaders(t *testing.T) {
ctx := testCc(t, `
llndk_headers {
@@ -2358,6 +2569,7 @@
}
func checkStaticLibs(t *testing.T, expected []string, module *Module) {
+ t.Helper()
actual := module.Properties.AndroidMkStaticLibs
if !reflect.DeepEqual(actual, expected) {
t.Errorf("incorrect static_libs"+
@@ -2644,6 +2856,18 @@
}
}
+func TestVersioningMacro(t *testing.T) {
+ for _, tc := range []struct{ moduleName, expected string }{
+ {"libc", "__LIBC_API__"},
+ {"libfoo", "__LIBFOO_API__"},
+ {"libfoo@1", "__LIBFOO_1_API__"},
+ {"libfoo-v1", "__LIBFOO_V1_API__"},
+ {"libfoo.v1", "__LIBFOO_V1_API__"},
+ } {
+ checkEquals(t, tc.moduleName, tc.expected, versioningMacroName(tc.moduleName))
+ }
+}
+
func TestStaticExecutable(t *testing.T) {
ctx := testCc(t, `
cc_binary {
diff --git a/cc/compiler.go b/cc/compiler.go
index c1a8d96..681b1ab 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -176,6 +176,9 @@
// Build and link with OpenMP
Openmp *bool `android:"arch_variant"`
+
+ // Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__
+ Use_apex_name_macro *bool
}
func NewBaseCompiler() *baseCompiler {
@@ -321,9 +324,13 @@
}
if ctx.apexName() != "" {
- flags.Global.CommonFlags = append(flags.Global.CommonFlags,
- "-D__ANDROID_APEX__",
- "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__")
+ if Bool(compiler.Properties.Use_apex_name_macro) {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
+ }
+ if ctx.Device() {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion()))
+ }
}
instructionSet := String(compiler.Properties.Instruction_set)
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 1ca1656..5575baa 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -37,9 +37,8 @@
}
arm64Ldflags = []string{
- "-Wl,-m,aarch64_elf64_le_vec",
"-Wl,--hash-style=gnu",
- "-fuse-ld=gold",
+ "-Wl,-z,separate-code",
"-Wl,--icf=safe",
}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index d849906..bdd9030 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -49,7 +49,7 @@
"-Wunused-but-set-variable",
"-fdiagnostics-color",
- // arm + arm64 + mips + mips64
+ // arm + arm64
"-fgcse-after-reload",
"-frerun-cse-after-loop",
"-frename-registers",
@@ -68,11 +68,6 @@
"-fno-tree-copy-prop",
"-fno-tree-loop-optimize",
- // mips + mips64
- "-msynci",
- "-mno-synci",
- "-mno-fused-madd",
-
// x86 + x86_64
"-finline-limit=300",
"-fno-inline-functions-called-once",
@@ -85,10 +80,8 @@
// Ldflags that should be filtered out when linking with clang lld
var ClangUnknownLldflags = sorted([]string{
- "-fuse-ld=gold",
"-Wl,--fix-cortex-a8",
"-Wl,--no-fix-cortex-a8",
- "-Wl,-m,aarch64_elf64_le_vec",
})
var ClangLibToolingUnknownCflags = sorted([]string{})
diff --git a/cc/config/global.go b/cc/config/global.go
index d01dd84..d85ac5f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -18,6 +18,7 @@
"strings"
"android/soong/android"
+ "android/soong/remoteexec"
)
var (
@@ -127,8 +128,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r377782b"
- ClangDefaultShortVersion = "10.0.4"
+ ClangDefaultVersion = "clang-r377782d"
+ ClangDefaultShortVersion = "10.0.6"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
@@ -255,6 +256,9 @@
}
return ""
})
+
+ pctx.VariableFunc("RECXXLinksPool", envOverrideFunc("RBE_CXX_LINKS_POOL", remoteexec.DefaultPool))
+ pctx.VariableFunc("RECXXLinksExecStrategy", envOverrideFunc("RBE_CXX_LINKS_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
}
var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
@@ -268,3 +272,12 @@
"-isystem bionic/libc/kernel/android/uapi",
}, " ")
}
+
+func envOverrideFunc(envVar, defaultVal string) func(ctx android.PackageVarContext) string {
+ return func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv(envVar); override != "" {
+ return override
+ }
+ return defaultVal
+ }
+}
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
deleted file mode 100644
index c2af951..0000000
--- a/cc/config/mips64_device.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015 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 config
-
-import (
- "strings"
-
- "android/soong/android"
-)
-
-var (
- mips64Cflags = []string{
- "-Umips",
-
- // Help catch common 32/64-bit errors.
- "-Werror=implicit-function-declaration",
- }
-
- mips64ClangCflags = append(mips64Cflags, []string{
- "-fintegrated-as",
- }...)
-
- mips64Cppflags = []string{}
-
- mips64Ldflags = []string{
- "-Wl,--allow-shlib-undefined",
- }
-
- mips64ArchVariantCflags = map[string][]string{
- "mips64r2": []string{
- "-mips64r2",
- "-msynci",
- },
- "mips64r6": []string{
- "-mips64r6",
- "-msynci",
- },
- }
-)
-
-const (
- mips64GccVersion = "4.9"
-)
-
-func init() {
- pctx.StaticVariable("mips64GccVersion", mips64GccVersion)
-
- pctx.SourcePathVariable("Mips64GccRoot",
- "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mips64GccVersion}")
-
- pctx.StaticVariable("Mips64IncludeFlags", bionicHeaders("mips"))
-
- // Clang cflags
- pctx.StaticVariable("Mips64ClangCflags", strings.Join(ClangFilterUnknownCflags(mips64ClangCflags), " "))
- pctx.StaticVariable("Mips64ClangLdflags", strings.Join(ClangFilterUnknownCflags(mips64Ldflags), " "))
- pctx.StaticVariable("Mips64ClangCppflags", strings.Join(ClangFilterUnknownCflags(mips64Cppflags), " "))
-
- // Extended cflags
-
- // Architecture variant cflags
- for variant, cflags := range mips64ArchVariantCflags {
- pctx.StaticVariable("Mips64"+variant+"VariantClangCflags",
- strings.Join(ClangFilterUnknownCflags(cflags), " "))
- }
-}
-
-type toolchainMips64 struct {
- toolchain64Bit
- clangCflags string
- toolchainClangCflags string
-}
-
-func (t *toolchainMips64) Name() string {
- return "mips64"
-}
-
-func (t *toolchainMips64) GccRoot() string {
- return "${config.Mips64GccRoot}"
-}
-
-func (t *toolchainMips64) GccTriple() string {
- return "mips64el-linux-android"
-}
-
-func (t *toolchainMips64) GccVersion() string {
- return mips64GccVersion
-}
-
-func (t *toolchainMips64) IncludeFlags() string {
- return "${config.Mips64IncludeFlags}"
-}
-
-func (t *toolchainMips64) ClangTriple() string {
- return t.GccTriple()
-}
-
-func (t *toolchainMips64) ToolchainClangCflags() string {
- return t.toolchainClangCflags
-}
-
-func (t *toolchainMips64) ClangAsflags() string {
- return "-fno-integrated-as"
-}
-
-func (t *toolchainMips64) ClangCflags() string {
- return t.clangCflags
-}
-
-func (t *toolchainMips64) ClangCppflags() string {
- return "${config.Mips64ClangCppflags}"
-}
-
-func (t *toolchainMips64) ClangLdflags() string {
- return "${config.Mips64ClangLdflags}"
-}
-
-func (t *toolchainMips64) ClangLldflags() string {
- // TODO: define and use Mips64ClangLldflags
- return "${config.Mips64ClangLdflags}"
-}
-
-func (toolchainMips64) LibclangRuntimeLibraryArch() string {
- return "mips64"
-}
-
-func mips64ToolchainFactory(arch android.Arch) Toolchain {
- return &toolchainMips64{
- clangCflags: "${config.Mips64ClangCflags}",
- toolchainClangCflags: "${config.Mips64" + arch.ArchVariant + "VariantClangCflags}",
- }
-}
-
-func init() {
- registerToolchainFactory(android.Android, android.Mips64, mips64ToolchainFactory)
-}
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
deleted file mode 100644
index ddbc41b..0000000
--- a/cc/config/mips_device.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2015 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 config
-
-import (
- "strings"
-
- "android/soong/android"
-)
-
-var (
- mipsCflags = []string{
- "-fomit-frame-pointer",
- "-Umips",
- }
-
- mipsClangCflags = append(mipsCflags, []string{
- "-fPIC",
- "-fintegrated-as",
- }...)
-
- mipsCppflags = []string{}
-
- mipsLdflags = []string{
- "-Wl,--allow-shlib-undefined",
- }
-
- mipsToolchainLdflags = []string{
- "-Wl,-melf32ltsmip",
- }
-
- mipsArchVariantCflags = map[string][]string{
- "mips32-fp": []string{
- "-mips32",
- "-mfp32",
- "-modd-spreg",
- "-mno-synci",
- },
- "mips32r2-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-msynci",
- },
- "mips32r2-fp-xburst": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mno-fused-madd",
- "-mno-synci",
- },
- "mips32r2dsp-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mdsp",
- "-msynci",
- },
- "mips32r2dspr2-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mdspr2",
- "-msynci",
- },
- "mips32r6": []string{
- "-mips32r6",
- "-mfp64",
- "-mno-odd-spreg",
- "-msynci",
- },
- }
-)
-
-const (
- mipsGccVersion = "4.9"
-)
-
-func init() {
- pctx.StaticVariable("mipsGccVersion", mipsGccVersion)
-
- pctx.SourcePathVariable("MipsGccRoot",
- "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mipsGccVersion}")
-
- pctx.StaticVariable("MipsToolchainLdflags", strings.Join(mipsToolchainLdflags, " "))
- pctx.StaticVariable("MipsIncludeFlags", bionicHeaders("mips"))
-
- // Clang cflags
- pctx.StaticVariable("MipsClangCflags", strings.Join(ClangFilterUnknownCflags(mipsClangCflags), " "))
- pctx.StaticVariable("MipsClangLdflags", strings.Join(ClangFilterUnknownCflags(mipsLdflags), " "))
- pctx.StaticVariable("MipsClangCppflags", strings.Join(ClangFilterUnknownCflags(mipsCppflags), " "))
-
- // Extended cflags
-
- // Architecture variant cflags
- for variant, cflags := range mipsArchVariantCflags {
- pctx.StaticVariable("Mips"+variant+"VariantClangCflags",
- strings.Join(ClangFilterUnknownCflags(cflags), " "))
- }
-}
-
-type toolchainMips struct {
- toolchain32Bit
- clangCflags string
- toolchainClangCflags string
-}
-
-func (t *toolchainMips) Name() string {
- return "mips"
-}
-
-func (t *toolchainMips) GccRoot() string {
- return "${config.MipsGccRoot}"
-}
-
-func (t *toolchainMips) GccTriple() string {
- return "mips64el-linux-android"
-}
-
-func (t *toolchainMips) GccVersion() string {
- return mipsGccVersion
-}
-
-func (t *toolchainMips) IncludeFlags() string {
- return "${config.MipsIncludeFlags}"
-}
-
-func (t *toolchainMips) ClangTriple() string {
- return "mipsel-linux-android"
-}
-
-func (t *toolchainMips) ToolchainClangLdflags() string {
- return "${config.MipsToolchainLdflags}"
-}
-
-func (t *toolchainMips) ToolchainClangCflags() string {
- return t.toolchainClangCflags
-}
-
-func (t *toolchainMips) ClangAsflags() string {
- return "-fPIC -fno-integrated-as"
-}
-
-func (t *toolchainMips) ClangCflags() string {
- return t.clangCflags
-}
-
-func (t *toolchainMips) ClangCppflags() string {
- return "${config.MipsClangCppflags}"
-}
-
-func (t *toolchainMips) ClangLdflags() string {
- return "${config.MipsClangLdflags}"
-}
-
-func (t *toolchainMips) ClangLldflags() string {
- // TODO: define and use MipsClangLldflags
- return "${config.MipsClangLdflags}"
-}
-
-func (toolchainMips) LibclangRuntimeLibraryArch() string {
- return "mips"
-}
-
-func mipsToolchainFactory(arch android.Arch) Toolchain {
- return &toolchainMips{
- clangCflags: "${config.MipsClangCflags}",
- toolchainClangCflags: "${config.Mips" + arch.ArchVariant + "VariantClangCflags}",
- }
-}
-
-func init() {
- registerToolchainFactory(android.Android, android.Mips, mipsToolchainFactory)
-}
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index dd52a0e..4ac9e58 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -30,10 +30,12 @@
}
return strings.Join([]string{
"-*",
+ "bugprone*",
"clang-diagnostic-unused-command-line-argument",
"google*",
"misc-macro-parentheses",
"performance*",
+ "-bugprone-narrowing-conversions",
"-google-readability*",
"-google-runtime-references",
}, ",")
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 25225b5..8eb79e3 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -15,9 +15,11 @@
package config
import (
+ "fmt"
"os/exec"
"path/filepath"
"strings"
+ "sync"
"android/soong/android"
)
@@ -89,28 +91,20 @@
)
func init() {
- pctx.VariableFunc("macSdkPath", func(ctx android.PackageVarContext) string {
- xcodeselect := ctx.Config().HostSystemTool("xcode-select")
- bytes, err := exec.Command(xcodeselect, "--print-path").Output()
- if err != nil {
- ctx.Errorf("xcode-select failed with: %q", err.Error())
- }
- return strings.TrimSpace(string(bytes))
- })
pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
- return xcrunSdk(ctx, "--show-sdk-path")
+ return getMacTools(ctx).sdkRoot
})
pctx.StaticVariable("macMinVersion", "10.10")
pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
- return xcrun(ctx, "--find", "ar")
+ return getMacTools(ctx).arPath
})
pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
- return xcrun(ctx, "--find", "strip")
+ return getMacTools(ctx).stripPath
})
pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
- return filepath.Dir(xcrun(ctx, "--find", "ld"))
+ return getMacTools(ctx).toolPath
})
pctx.StaticVariable("DarwinGccVersion", darwinGccVersion)
@@ -126,38 +120,66 @@
pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64")
}
-func xcrun(ctx android.PackageVarContext, args ...string) string {
- xcrun := ctx.Config().HostSystemTool("xcrun")
- bytes, err := exec.Command(xcrun, args...).Output()
- if err != nil {
- ctx.Errorf("xcrun failed with: %q", err.Error())
- }
- return strings.TrimSpace(string(bytes))
+type macPlatformTools struct {
+ once sync.Once
+ err error
+
+ sdkRoot string
+ arPath string
+ stripPath string
+ toolPath string
}
-func xcrunSdk(ctx android.PackageVarContext, arg string) string {
- xcrun := ctx.Config().HostSystemTool("xcrun")
- if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
- if !inList(selected, darwinSupportedSdkVersions) {
- ctx.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+var macTools = &macPlatformTools{}
+
+func getMacTools(ctx android.PackageVarContext) *macPlatformTools {
+ macTools.once.Do(func() {
+ xcrunTool := ctx.Config().HostSystemTool("xcrun")
+
+ xcrun := func(args ...string) string {
+ if macTools.err != nil {
+ return ""
+ }
+
+ bytes, err := exec.Command(xcrunTool, args...).Output()
+ if err != nil {
+ macTools.err = fmt.Errorf("xcrun %q failed with: %q", args, err)
+ return ""
+ }
+
+ return strings.TrimSpace(string(bytes))
+ }
+
+ xcrunSdk := func(arg string) string {
+ if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
+ if !inList(selected, darwinSupportedSdkVersions) {
+ macTools.err = fmt.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+ return ""
+ }
+
+ return xcrun("--sdk", "macosx"+selected, arg)
+ }
+
+ for _, sdk := range darwinSupportedSdkVersions {
+ bytes, err := exec.Command(xcrunTool, "--sdk", "macosx"+sdk, arg).Output()
+ if err == nil {
+ return strings.TrimSpace(string(bytes))
+ }
+ }
+ macTools.err = fmt.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
return ""
}
- bytes, err := exec.Command(xcrun, "--sdk", "macosx"+selected, arg).Output()
- if err != nil {
- ctx.Errorf("MAC_SDK_VERSION %s is not installed", selected)
- }
- return strings.TrimSpace(string(bytes))
- }
+ macTools.sdkRoot = xcrunSdk("--show-sdk-path")
- for _, sdk := range darwinSupportedSdkVersions {
- bytes, err := exec.Command(xcrun, "--sdk", "macosx"+sdk, arg).Output()
- if err == nil {
- return strings.TrimSpace(string(bytes))
- }
+ macTools.arPath = xcrun("--find", "ar")
+ macTools.stripPath = xcrun("--find", "strip")
+ macTools.toolPath = filepath.Dir(xcrun("--find", "ld"))
+ })
+ if macTools.err != nil {
+ ctx.Errorf("%q", macTools.err)
}
- ctx.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
- return ""
+ return macTools
}
type toolchainDarwin struct {
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 43e8c85..cd0a508 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -58,8 +58,11 @@
"-Wl,--dynamicbase",
"-Wl,--nxcompat",
}
+ windowsLldflags = []string{
+ "-Wl,--Xlink=-Brepro", // Enable deterministic build
+ }
windowsClangLdflags = append(ClangFilterUnknownCflags(windowsLdflags), []string{}...)
- windowsClangLldflags = ClangFilterUnknownLldflags(windowsClangLdflags)
+ windowsClangLldflags = append(ClangFilterUnknownLldflags(windowsClangLdflags), windowsLldflags...)
windowsX86Cflags = []string{
"-m32",
diff --git a/cc/coverage.go b/cc/coverage.go
index b94b628..bde07fd 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -82,10 +82,10 @@
}
if cov.Properties.CoverageEnabled {
- flags.Coverage = true
cov.linkCoverage = true
if gcovCoverage {
+ flags.GcovCoverage = true
flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
// Override -Wframe-larger-than and non-default optimization
diff --git a/cc/fuzz.go b/cc/fuzz.go
index ee24300..b7173a3 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -198,6 +198,11 @@
return installLocation
}
+// Get the device-only shared library symbols install directory.
+func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
+ return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
+}
+
func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -269,6 +274,12 @@
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
sharedLibraryInstallLocation(
lib, ctx.Host(), ctx.Arch().ArchType.String()))
+
+ // Also add the dependency on the shared library symbols dir.
+ if !ctx.Host() {
+ fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+ sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
+ }
}
}
@@ -367,8 +378,6 @@
return
}
- s.fuzzTargets[module.Name()] = true
-
hostOrTargetString := "target"
if ccModule.Host() {
hostOrTargetString = "host"
@@ -421,12 +430,24 @@
continue
}
sharedLibraryInstalled[installDestination] = true
+
// Escape all the variables, as the install destination here will be called
// via. $(eval) in Make.
installDestination = strings.ReplaceAll(
installDestination, "$", "$$")
s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
library.String()+":"+installDestination)
+
+ // Ensure that on device, the library is also reinstalled to the /symbols/
+ // dir. Symbolized DSO's are always installed to the device when fuzzing, but
+ // we want symbolization tools (like `stack`) to be able to find the symbols
+ // in $ANDROID_PRODUCT_OUT/symbols automagically.
+ if !ccModule.Host() {
+ symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
+ symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
+ s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
+ library.String()+":"+symbolsInstallDestination)
+ }
}
// The executable.
@@ -458,6 +479,17 @@
builder.Build(pctx, ctx, "create-"+fuzzZip.String(),
"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
+ // Don't add modules to 'make haiku' that are set to not be exported to the
+ // fuzzing infrastructure.
+ if config := fuzzModule.Properties.Fuzz_config; config != nil {
+ if ccModule.Host() && !BoolDefault(config.Fuzz_on_haiku_host, true) {
+ return
+ } else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
+ return
+ }
+ }
+
+ s.fuzzTargets[module.Name()] = true
archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
})
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 0de703c..7deb804 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -26,8 +26,6 @@
ALL_ARCHITECTURES = (
'arm',
'arm64',
- 'mips',
- 'mips64',
'x86',
'x86_64',
)
diff --git a/cc/genrule.go b/cc/genrule.go
index 155e410..9331448 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -27,6 +27,7 @@
Vendor_available *bool
Ramdisk_available *bool
Recovery_available *bool
+ Sdk_version *string
}
// cc_genrule is a genrule that can depend on other cc_* objects.
diff --git a/cc/installer.go b/cc/installer.go
index 2f55ac5..0b4a68c 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -86,6 +86,11 @@
installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
+func (installer *baseInstaller) everInstallable() bool {
+ // Most cc modules are installable.
+ return true
+}
+
func (installer *baseInstaller) inData() bool {
return installer.location == InstallInData
}
@@ -101,3 +106,7 @@
func (installer *baseInstaller) relativeInstallPath() string {
return String(installer.Properties.Relative_install_path)
}
+
+func (installer *baseInstaller) skipInstall(mod *Module) {
+ mod.ModuleBase.SkipInstall()
+}
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index 825b920..b63338d 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -10,4 +10,8 @@
enabled: true,
},
},
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
diff --git a/cc/library.go b/cc/library.go
index a5de54b..ecea2ea 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -199,6 +199,7 @@
module.sdkMemberTypes = []android.SdkMemberType{
sharedLibrarySdkMemberType,
staticLibrarySdkMemberType,
+ staticAndSharedLibrarySdkMemberType,
}
return module.Init()
}
@@ -379,10 +380,72 @@
useCoreVariant bool
checkSameCoreVariant bool
- // Decorated interafaces
+ // Decorated interfaces
*baseCompiler
*baseLinker
*baseInstaller
+
+ collectedSnapshotHeaders android.Paths
+}
+
+// collectHeadersForSnapshot collects all exported headers from library.
+// It globs header files in the source tree for exported include directories,
+// and tracks generated header files separately.
+//
+// This is to be called from GenerateAndroidBuildActions, and then collected
+// header files can be retrieved by snapshotHeaders().
+func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext) {
+ 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.ModuleErrorf("glob failed: %#v", err)
+ return
+ }
+ 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)
+ }
+
+ l.collectedSnapshotHeaders = ret
+}
+
+// This returns all exported header files, both generated ones and headers from source tree.
+// collectHeadersForSnapshot() must be called before calling this.
+func (l *libraryDecorator) snapshotHeaders() android.Paths {
+ if l.collectedSnapshotHeaders == nil {
+ panic("snapshotHeaders() must be called after collectHeadersForSnapshot()")
+ }
+ return l.collectedSnapshotHeaders
}
func (library *libraryDecorator) linkerProps() []interface{} {
@@ -690,10 +753,12 @@
func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
if library.static() {
+ // Compare with nil because an empty list needs to be propagated.
if library.StaticProperties.Static.System_shared_libs != nil {
library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs
}
} else if library.shared() {
+ // Compare with nil because an empty list needs to be propagated.
if library.SharedProperties.Shared.System_shared_libs != nil {
library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs
}
@@ -759,6 +824,34 @@
return deps
}
+func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
+ var properties StaticOrSharedProperties
+ if library.static() {
+ properties = library.StaticProperties.Static
+ } else if library.shared() {
+ properties = library.SharedProperties.Shared
+ }
+
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
+
+ // Must distinguish nil and [] in system_shared_libs - ensure that [] in
+ // either input list doesn't come out as nil.
+ if specifiedDeps.systemSharedLibs == nil {
+ specifiedDeps.systemSharedLibs = properties.System_shared_libs
+ } else {
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
+ }
+
+ specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
+ if len(specifiedDeps.systemSharedLibs) > 0 {
+ // Skip this if systemSharedLibs is either nil or [], to ensure they are
+ // retained.
+ specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
+ }
+ return specifiedDeps
+}
+
func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@@ -935,8 +1028,9 @@
}
func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
+ // The logic must be consistent with classifySourceAbiDump.
isNdk := ctx.isNdk()
- isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || ctx.isVndk()
+ isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || (ctx.useVndk() && ctx.isVndk())
refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false)
refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true)
@@ -1149,7 +1243,7 @@
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() &&
- !library.buildStubs() {
+ !library.buildStubs() && ctx.sdkVersion() == "" {
installPath := getNdkSysrootBase(ctx).Join(
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
@@ -1164,6 +1258,12 @@
}
}
+func (library *libraryDecorator) everInstallable() bool {
+ // Only shared and static libraries are installed. Header libraries (which are
+ // neither static or shared) are not installed.
+ return library.shared() || library.static()
+}
+
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}
@@ -1217,6 +1317,11 @@
return library.MutatedProperties.StubsVersion
}
+func (library *libraryDecorator) isLatestStubVersion() bool {
+ versions := library.Properties.Stubs.Versions
+ return versions[len(versions)-1] == library.stubsVersion()
+}
+
func (library *libraryDecorator) availableFor(what string) bool {
var list []string
if library.static() {
@@ -1230,6 +1335,18 @@
return android.CheckAvailableForApex(what, list)
}
+func (library *libraryDecorator) skipInstall(mod *Module) {
+ if library.static() && library.buildStatic() && !library.buildStubs() {
+ // If we're asked to skip installation of a static library (in particular
+ // when it's not //apex_available:platform) we still want an AndroidMk entry
+ // for it to ensure we get the relevant NOTICE file targets (cf.
+ // notice_files.mk) that other libraries might depend on. AndroidMkEntries
+ // always sets LOCAL_UNINSTALLABLE_MODULE for these entries.
+ return
+ }
+ mod.ModuleBase.SkipInstall()
+}
+
var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
func versioningMacroNamesList(config android.Config) *map[string]string {
@@ -1245,7 +1362,7 @@
func versioningMacroName(moduleName string) string {
macroName := charsNotForMacro.ReplaceAllString(moduleName, "_")
- macroName = strings.ToUpper(moduleName)
+ macroName = strings.ToUpper(macroName)
return "__" + macroName + "_API__"
}
@@ -1286,6 +1403,8 @@
len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 &&
len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 &&
len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 &&
+ // Compare System_shared_libs properties with nil because empty lists are
+ // semantically significant for them.
staticCompiler.StaticProperties.Static.System_shared_libs == nil &&
sharedCompiler.SharedProperties.Shared.System_shared_libs == nil {
@@ -1388,49 +1507,85 @@
return ""
}
-// Version mutator splits a module into the mandatory non-stubs variant
+func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+ numVersions := make([]int, len(versions))
+ for i, v := range versions {
+ numVer, err := android.ApiStrToNum(ctx, v)
+ if err != nil {
+ ctx.PropertyErrorf("versions", "%s", err.Error())
+ return
+ }
+ numVersions[i] = numVer
+ }
+ if !sort.IsSorted(sort.IntSlice(numVersions)) {
+ ctx.PropertyErrorf("versions", "not sorted: %v", versions)
+ }
+ for i, v := range numVersions {
+ versions[i] = strconv.Itoa(v)
+ }
+}
+
+func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
+ // "" is for the non-stubs variant
+ versions = append([]string{""}, versions...)
+
+ modules := mctx.CreateVariations(versions...)
+ for i, m := range modules {
+ if versions[i] != "" {
+ m.(LinkableInterface).SetBuildStubs()
+ m.(LinkableInterface).SetStubsVersions(versions[i])
+ }
+ }
+}
+
+func VersionVariantAvailable(module interface {
+ Host() bool
+ InRamdisk() bool
+ InRecovery() bool
+}) bool {
+ return !module.Host() && !module.InRamdisk() && !module.InRecovery()
+}
+
+// VersionMutator splits a module into the mandatory non-stubs variant
// (which is unnamed) and zero or more stubs variants.
func VersionMutator(mctx android.BottomUpMutatorContext) {
- if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
+ if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
- versions := []string{}
- for _, v := range library.StubsVersions() {
- if _, err := strconv.Atoi(v); err != nil {
- mctx.PropertyErrorf("versions", "%q is not a number", v)
- }
- versions = append(versions, v)
+ versions := library.StubsVersions()
+ normalizeVersions(mctx, versions)
+ if mctx.Failed() {
+ return
}
- sort.Slice(versions, func(i, j int) bool {
- left, _ := strconv.Atoi(versions[i])
- right, _ := strconv.Atoi(versions[j])
- return left < right
- })
- // save the list of versions for later use
- copiedVersions := make([]string, len(versions))
- copy(copiedVersions, versions)
stubsVersionsLock.Lock()
defer stubsVersionsLock.Unlock()
- stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = copiedVersions
+ // save the list of versions for later use
+ stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
- // "" is for the non-stubs variant
- versions = append([]string{""}, versions...)
-
- modules := mctx.CreateVariations(versions...)
- for i, m := range modules {
- if versions[i] != "" {
- m.(LinkableInterface).SetBuildStubs()
- m.(LinkableInterface).SetStubsVersions(versions[i])
- }
- }
- } else {
- mctx.CreateVariations("")
+ createVersionVariations(mctx, versions)
+ return
}
+
+ if c, ok := library.(*Module); ok && c.IsStubs() {
+ stubsVersionsLock.Lock()
+ defer stubsVersionsLock.Unlock()
+ // For LLNDK llndk_library, we borrow vstubs.ersions from its implementation library.
+ // Since llndk_library has dependency to its implementation library,
+ // we can safely access stubsVersionsFor() with its baseModuleName.
+ versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()]
+ // save the list of versions for later use
+ stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
+
+ createVersionVariations(mctx, versions)
+ return
+ }
+
+ mctx.CreateVariations("")
return
}
if genrule, ok := mctx.Module().(*genrule.Module); ok {
if _, ok := genrule.Extra.(*GenruleExtraProperties); ok {
- if !genrule.InRecovery() {
+ if VersionVariantAvailable(genrule) {
mctx.CreateVariations("")
return
}
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 88cf7af..b7ab390 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -29,7 +29,7 @@
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_library_headers",
- linkTypes: nil,
+ noOutputFiles: true,
}
func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a36917e..754b96a 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -16,10 +16,11 @@
import (
"path/filepath"
- "reflect"
"android/soong/android"
+
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// This file contains support for using cc library modules within an sdk.
@@ -42,10 +43,20 @@
linkTypes: []string{"static"},
}
+var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "native_libs",
+ SupportsSdk: true,
+ },
+ prebuiltModuleType: "cc_prebuilt_library",
+ linkTypes: []string{"static", "shared"},
+}
+
func init() {
// Register sdk member types.
android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
android.RegisterSdkMemberType(staticLibrarySdkMemberType)
+ android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType)
}
type librarySdkMemberType struct {
@@ -53,7 +64,10 @@
prebuiltModuleType string
- // The set of link types supported, set of "static", "shared".
+ noOutputFiles bool // True if there are no srcs files.
+
+ // The set of link types supported. A set of "static", "shared", or nil to
+ // skip link type variations.
linkTypes []string
}
@@ -96,48 +110,25 @@
return false
}
-// copy exported header files and stub *.so files
-func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- info := mt.organizeVariants(member)
- info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
+
+ ccModule := member.Variants()[0].(*Module)
+
+ sdkVersion := ccModule.SdkVersion()
+ if sdkVersion != "" {
+ pbm.AddProperty("sdk_version", sdkVersion)
+ }
+
+ stl := ccModule.stl.Properties.Stl
+ if stl != nil {
+ pbm.AddProperty("stl", proptools.String(stl))
+ }
+ return pbm
}
-// Organize the variants by architecture.
-func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
- memberName := member.Name()
- info := &nativeLibInfo{
- name: memberName,
- memberType: mt,
- }
-
- for _, variant := range member.Variants() {
- ccModule := variant.(*Module)
-
- // Separate out the generated include dirs (which are arch specific) from the
- // include dirs (which may not be).
- exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
- ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
-
- info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
- name: memberName,
- archType: ccModule.Target().Arch.ArchType.String(),
- ExportedIncludeDirs: exportedIncludeDirs,
- exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
- ExportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
- ExportedFlags: ccModule.ExportedFlags(),
- exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
- 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 (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &nativeLibInfoProperties{memberType: mt}
}
func isGeneratedHeaderDirectory(p android.Path) bool {
@@ -145,94 +136,9 @@
return gen
}
-// Extract common properties from a slice of property structures of the same type.
-//
-// All the property structures must be of the same type.
-// commonProperties - must be a pointer to the structure into which common properties will be added.
-// inputPropertiesSlice - must be a slice of input properties structures.
-//
-// Iterates over each exported field (capitalized name) and checks to see whether they
-// have the same value (using DeepEquals) across all the input properties. If it does not then no
-// change is made. Otherwise, the common value is stored in the field in the commonProperties
-// and the field in each of the input properties structure is set to its default value.
-func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
- commonStructValue := reflect.ValueOf(commonProperties).Elem()
- propertiesStructType := commonStructValue.Type()
-
- // Create an empty structure from which default values for the field can be copied.
- emptyStructValue := reflect.New(propertiesStructType).Elem()
-
- for f := 0; f < propertiesStructType.NumField(); f++ {
- // Check to see if all the structures have the same value for the field. The commonValue
- // is nil on entry to the loop and if it is nil on exit then there is no common value,
- // otherwise it points to the common value.
- var commonValue *reflect.Value
- sliceValue := reflect.ValueOf(inputPropertiesSlice)
-
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- if !fieldValue.CanInterface() {
- // The field is not exported so ignore it.
- continue
- }
-
- if commonValue == nil {
- // Use the first value as the commonProperties value.
- commonValue = &fieldValue
- } else {
- // If the value does not match the current common value then there is
- // no value in common so break out.
- if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
- commonValue = nil
- break
- }
- }
- }
-
- // If the fields all have a common value then store it in the common struct field
- // and set the input struct's field to the empty value.
- if commonValue != nil {
- emptyValue := emptyStructValue.Field(f)
- commonStructValue.Field(f).Set(*commonValue)
- for i := 0; i < sliceValue.Len(); i++ {
- structValue := sliceValue.Index(i)
- fieldValue := structValue.Field(f)
- fieldValue.Set(emptyValue)
- }
- }
- }
-}
-
-func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-
- pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
-
- addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
-
- archProperties := pbm.AddPropertySet("arch")
- for _, av := range info.archVariantProperties {
- archTypeProperties := archProperties.AddPropertySet(av.archType)
-
- // If the library has some link types then it produces an output binary file, otherwise it
- // is header only.
- if info.memberType.linkTypes != nil {
- // Copy the generated library to the snapshot and add a reference to it in the .bp module.
- nativeLibraryPath := nativeLibraryPathFor(av)
- builder.CopyToSnapshot(av.outputFile, nativeLibraryPath)
- archTypeProperties.AddProperty("srcs", []string{nativeLibraryPath})
- }
-
- // Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
- addPossiblyArchSpecificProperties(sdkModuleContext, builder, av, archTypeProperties)
- }
- pbm.AddProperty("stl", "none")
- pbm.AddProperty("system_shared_libs", []string{})
-}
-
type includeDirsProperty struct {
// Accessor to retrieve the paths
- pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
+ pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
// The name of the property in the prebuilt library, "" means there is no property.
propertyName string
@@ -252,7 +158,7 @@
// ExportedIncludeDirs lists directories that contains some header files to be
// copied into a directory in the snapshot. The snapshot directories must be added to
// the export_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
@@ -262,7 +168,7 @@
// ExportedSystemIncludeDirs lists directories that contains some system header files to
// be copied into a directory in the snapshot. The snapshot directories must be added to
// the export_system_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
propertyName: "export_system_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
@@ -273,7 +179,7 @@
// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
// of these directories do not need to be copied, but these directories do need adding to
// the export_include_dirs property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeGeneratedIncludeDir,
copy: false,
@@ -284,7 +190,7 @@
// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
// property in the prebuilt module in the snapshot.
- pathsGetter: func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
+ pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
propertyName: "",
snapshotDir: nativeGeneratedIncludeDir,
copy: true,
@@ -293,7 +199,24 @@
}
// Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+
+ // Copy the generated library to the snapshot and add a reference to it in the .bp module.
+ if libInfo.outputFile != nil {
+ nativeLibraryPath := nativeLibraryPathFor(libInfo)
+ builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
+ outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
+ }
+
+ if len(libInfo.SharedLibs) > 0 {
+ outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
+ // SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
+ // so check for non-nil instead of nonzero length.
+ if libInfo.SystemSharedLibs != nil {
+ outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
includeDirs := make(map[string][]string)
@@ -346,6 +269,11 @@
for property, dirs := range includeDirs {
outputProperties.AddProperty(property, dirs)
}
+
+ if len(libInfo.StubsVersion) > 0 {
+ stubsSet := outputProperties.AddPropertySet("stubs")
+ stubsSet.AddProperty("versions", []string{libInfo.StubsVersion})
+ }
}
const (
@@ -355,8 +283,8 @@
)
// path to the native library. Relative to <sdk_root>/<api_dir>
-func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
- return filepath.Join(lib.archType,
+func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
+ return filepath.Join(lib.OsPrefix(), lib.archType,
nativeStubDir, lib.outputFile.Base())
}
@@ -365,6 +293,10 @@
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeLibInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ memberType *librarySdkMemberType
+
// The name of the library, is not exported as this must not be changed during optimization.
name string
@@ -397,14 +329,62 @@
// This field is exported as its contents may not be arch specific.
ExportedFlags []string
+ // The set of shared libraries
+ //
+ // This field is exported as its contents may not be arch specific.
+ SharedLibs []string
+
+ // The set of system shared libraries. Note nil and [] are semantically
+ // distinct - see BaseLinkerProperties.System_shared_libs.
+ //
+ // This field is exported as its contents may not be arch specific.
+ SystemSharedLibs []string
+
+ // The specific stubs version for the lib variant, or empty string if stubs
+ // are not in use.
+ StubsVersion string
+
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
- name string
- memberType *librarySdkMemberType
- archVariantProperties []nativeLibInfoProperties
- commonProperties nativeLibInfoProperties
+func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ ccModule := variant.(*Module)
+
+ // If the library has some link types then it produces an output binary file, otherwise it
+ // is header only.
+ if !p.memberType.noOutputFiles {
+ p.outputFile = ccModule.OutputFile().Path()
+ }
+
+ // Separate out the generated include dirs (which are arch specific) from the
+ // include dirs (which may not be).
+ exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
+ ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+
+ p.name = variant.Name()
+ p.archType = ccModule.Target().Arch.ArchType.String()
+
+ // Make sure that the include directories are unique.
+ p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
+ p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
+ p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
+ p.ExportedFlags = ccModule.ExportedFlags()
+ if ccModule.linker != nil {
+ specifiedDeps := specifiedDeps{}
+ specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
+
+ p.SharedLibs = specifiedDeps.sharedLibs
+ p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ }
+ p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+
+ if ccModule.HasStubsVariants() {
+ p.StubsVersion = ccModule.StubsVersion()
+ }
+}
+
+func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
}
diff --git a/cc/library_test.go b/cc/library_test.go
index b8d8895..cb16725 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -17,6 +17,8 @@
import (
"reflect"
"testing"
+
+ "android/soong/android"
)
func TestLibraryReuse(t *testing.T) {
@@ -186,3 +188,55 @@
}
})
}
+
+func TestStubsVersions(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ stubs: {
+ versions: ["29", "R", "10000"],
+ },
+ }
+ `
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ ctx := testCcWithConfig(t, config)
+
+ variants := ctx.ModuleVariantsForTests("libfoo")
+ for _, expectedVer := range []string{"29", "9000", "10000"} {
+ expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer
+ if !inList(expectedVariant, variants) {
+ t.Errorf("missing expected variant: %q", expectedVariant)
+ }
+ }
+}
+
+func TestStubsVersions_NotSorted(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ stubs: {
+ versions: ["29", "10000", "R"],
+ },
+ }
+ `
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
+ testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config)
+}
+
+func TestStubsVersions_ParseError(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ stubs: {
+ versions: ["29", "10000", "X"],
+ },
+ }
+ `
+
+ testCcError(t, `"libfoo" .*: versions: SDK version should be`, bp)
+}
diff --git a/cc/linkable.go b/cc/linkable.go
index e4f034c..4a70d48 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -26,6 +26,7 @@
BuildStubs() bool
SetBuildStubs()
SetStubsVersions(string)
+ StubsVersion() string
HasStubsVariants() bool
SelectedStl() string
ApiLevel() string
@@ -38,18 +39,22 @@
Shared() bool
Toc() android.OptionalPath
+ Host() bool
+
InRamdisk() bool
OnlyInRamdisk() bool
InRecovery() bool
OnlyInRecovery() bool
+ UseSdk() bool
UseVndk() bool
MustUseVendorVariant() bool
IsVndk() bool
HasVendorVariant() bool
SdkVersion() string
+ AlwaysSdk() bool
ToolchainLibrary() bool
NdkPrebuiltStl() bool
diff --git a/cc/linker.go b/cc/linker.go
index af4cbf3..57a0c01 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -158,6 +158,13 @@
// the ramdisk variant of the C/C++ module.
Exclude_static_libs []string
}
+ Platform struct {
+ // list of shared libs that should be use to build the platform variant
+ // of a module that sets sdk_version. This should rarely be necessary,
+ // in most cases the same libraries are available for the SDK and platform
+ // variants.
+ Shared_libs []string
+ }
}
// make android::build:GetBuildNumber() available containing the build ID.
@@ -255,6 +262,10 @@
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
}
+ if !ctx.useSdk() {
+ deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
+ }
+
if ctx.toolchain().Bionic() {
// libclang_rt.builtins and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
@@ -438,11 +449,10 @@
}
}
- if ctx.useSdk() && (ctx.Arch().ArchType != android.Mips && ctx.Arch().ArchType != android.Mips64) {
+ if ctx.useSdk() {
// The bionic linker now has support gnu style hashes (which are much faster!), but shipping
// to older devices requires the old style hash. Fortunately, we can build with both and
// it'll work anywhere.
- // This is not currently supported on MIPS architectures.
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both")
}
@@ -490,6 +500,20 @@
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
+func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
+ specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
+
+ // Must distinguish nil and [] in system_shared_libs - ensure that [] in
+ // either input list doesn't come out as nil.
+ if specifiedDeps.systemSharedLibs == nil {
+ specifiedDeps.systemSharedLibs = linker.Properties.System_shared_libs
+ } else {
+ specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
+ }
+
+ return specifiedDeps
+}
+
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.
@@ -501,19 +525,21 @@
var injectVersionSymbol = pctx.AndroidStaticRule("injectVersionSymbol",
blueprint.RuleParams{
Command: "$symbolInjectCmd -i $in -o $out -s soong_build_number " +
- "-from 'SOONG BUILD NUMBER PLACEHOLDER' -v $buildNumberFromFile",
+ "-from 'SOONG BUILD NUMBER PLACEHOLDER' -v $$(cat $buildNumberFile)",
CommandDeps: []string{"$symbolInjectCmd"},
},
- "buildNumberFromFile")
+ "buildNumberFile")
func (linker *baseLinker) injectVersionSymbol(ctx ModuleContext, in android.Path, out android.WritablePath) {
+ buildNumberFile := ctx.Config().BuildNumberFile(ctx)
ctx.Build(pctx, android.BuildParams{
Rule: injectVersionSymbol,
Description: "inject version symbol",
Input: in,
Output: out,
+ OrderOnly: android.Paths{buildNumberFile},
Args: map[string]string{
- "buildNumberFromFile": proptools.NinjaEscape(ctx.Config().BuildNumberFromFile()),
+ "buildNumberFile": buildNumberFile.String(),
},
})
}
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 3dee692..7ff20f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -19,8 +19,14 @@
"strings"
"android/soong/android"
+
+ "github.com/google/blueprint"
)
+var llndkImplDep = struct {
+ blueprint.DependencyTag
+}{}
+
var (
llndkLibrarySuffix = ".llndk"
llndkHeadersSuffix = ".llndk"
@@ -77,10 +83,13 @@
func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
vndkVer := ctx.Module().(*Module).VndkVersion()
- if !inList(vndkVer, ctx.Config().PlatformVersionCombinedCodenames()) || vndkVer == "" {
+ if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
vndkVer = "current"
}
+ if stub.stubsVersion() != "" {
+ vndkVer = stub.stubsVersion()
+ }
objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), vndkVer, "--llndk")
stub.versionScriptPath = versionScript
return objs
@@ -154,6 +163,10 @@
stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{}
}
+ if stub.stubsVersion() != "" {
+ stub.reexportFlags("-D" + versioningMacroName(ctx.baseModuleName()) + "=" + stub.stubsVersion())
+ }
+
return stub.libraryDecorator.link(ctx, flags, deps, objs)
}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5744bb2..60f931d 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -17,7 +17,6 @@
import (
"fmt"
"path/filepath"
- "strings"
"github.com/google/blueprint"
@@ -131,14 +130,6 @@
m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
- // When generating NDK prebuilts, skip installing MIPS headers,
- // but keep them when doing regular platform build.
- // Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
- // TODO: Revert this once MIPS is supported in NDK again.
- if ctx.Config().NdkAbis() && strings.Contains(ctx.ModuleName(), "mips") {
- return
- }
-
srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
for _, header := range srcFiles {
installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 00338b9..1597b88 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -96,6 +96,8 @@
Unversioned_until *string
// Private property for use by the mutator that splits per-API level.
+ // can be one of <number:sdk_version> or <codename> or "current"
+ // passed to "gen_stub_libs.py" as it is
ApiLevel string `blueprint:"mutated"`
// True if this API is not yet ready to be shipped in the NDK. It will be
@@ -133,8 +135,6 @@
firstArchVersions := map[android.ArchType]int{
android.Arm: minVersion,
android.Arm64: 21,
- android.Mips: minVersion,
- android.Mips64: 21,
android.X86: minVersion,
android.X86_64: 21,
}
@@ -383,6 +383,9 @@
module.linker = stub
module.installer = stub
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
+
module.AddProperties(&stub.properties, &library.MutatedProperties)
return module
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index e849aee..c4d7708 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -76,6 +76,8 @@
baseLinker: NewBaseLinker(nil),
},
}
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
module.Properties.HideFromMake = true
return module.Init()
}
@@ -90,6 +92,11 @@
return ndkPrebuiltModuleToPath(ctx, flags.Toolchain, objectExtension, ctx.sdkVersion())
}
+func (*ndkPrebuiltObjectLinker) availableFor(what string) bool {
+ // ndk prebuilt objects are available to everywhere
+ return true
+}
+
type ndkPrebuiltStlLinker struct {
*libraryDecorator
}
@@ -103,6 +110,11 @@
return deps
}
+func (*ndkPrebuiltStlLinker) availableFor(what string) bool {
+ // ndk prebuilt objects are available to everywhere
+ return true
+}
+
// ndk_prebuilt_shared_stl exports a precompiled ndk shared standard template
// library (stl) library for linking operation. The soong's module name format
// is ndk_<NAME>.so where the library is located under
@@ -115,10 +127,9 @@
libraryDecorator: library,
}
module.installer = nil
- minVersionString := "minimum"
- noStlString := "none"
- module.Properties.Sdk_version = &minVersionString
- module.stl.Properties.Stl = &noStlString
+ module.Properties.Sdk_version = StringPtr("minimum")
+ module.Properties.AlwaysSdk = true
+ module.stl.Properties.Stl = StringPtr("none")
return module.Init()
}
@@ -135,6 +146,9 @@
}
module.installer = nil
module.Properties.HideFromMake = true
+ module.Properties.AlwaysSdk = true
+ module.Properties.Sdk_version = StringPtr("current")
+ module.stl.Properties.Stl = StringPtr("none")
module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module.Init()
}
diff --git a/cc/object.go b/cc/object.go
index ad31d09..19decec 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -26,6 +26,16 @@
func init() {
android.RegisterModuleType("cc_object", ObjectFactory)
+ android.RegisterSdkMemberType(ccObjectSdkMemberType)
+}
+
+var ccObjectSdkMemberType = &librarySdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "native_objects",
+ SupportsSdk: true,
+ },
+ prebuiltModuleType: "cc_prebuilt_object",
+ linkTypes: nil,
}
type objectLinker struct {
@@ -47,12 +57,18 @@
Linker_script *string `android:"path,arch_variant"`
}
+func newObject() *Module {
+ module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
+ module.sanitize = &sanitize{}
+ module.stl = &stl{}
+ return module
+}
+
// cc_object runs the compiler without running the linker. It is rarely
// necessary, but sometimes used to generate .s files from .c files to use as
// input to a cc_genrule module.
func ObjectFactory() android.Module {
- module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
- module.sanitize = &sanitize{}
+ module := newObject()
module.linker = &objectLinker{
baseLinker: NewBaseLinker(module.sanitize),
}
@@ -61,7 +77,7 @@
// Clang's address-significance tables are incompatible with ld -r.
module.compiler.appendCflags([]string{"-fno-addrsig"})
- module.stl = &stl{}
+ module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
return module.Init()
}
diff --git a/cc/pgo.go b/cc/pgo.go
index d5c4b87..88903bb 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -88,20 +88,21 @@
return []interface{}{&pgo.Properties}
}
-func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
- if props.isInstrumentation() {
- flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
- // The profile runtime is added below in deps(). Add the below
- // flag, which is the only other link-time action performed by
- // the Clang driver during link.
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
- }
- if props.isSampling() {
- flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
- flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
- }
+ flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
+ // The profile runtime is added below in deps(). Add the below
+ // flag, which is the only other link-time action performed by
+ // the Clang driver during link.
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
+ return flags
+}
+func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+ flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
+
+ flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
return flags
}
@@ -286,8 +287,12 @@
props := pgo.Properties
// Add flags to profile this module based on its profile_kind
- if props.ShouldProfileModule {
- return props.addProfileGatherFlags(ctx, flags)
+ if props.ShouldProfileModule && props.isInstrumentation() {
+ return props.addInstrumentationProfileGatherFlags(ctx, flags)
+ } else if props.ShouldProfileModule && props.isSampling() {
+ return props.addSamplingProfileGatherFlags(ctx, flags)
+ } else if ctx.DeviceConfig().SamplingPGO() {
+ return props.addSamplingProfileGatherFlags(ctx, flags)
}
if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 2c18ac3..ac990f3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -23,8 +23,10 @@
}
func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
+ ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory)
ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
}
@@ -41,6 +43,11 @@
// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
// symbols, etc), default true.
Check_elf_files *bool
+
+ // Optionally provide an import library if this is a Windows PE DLL prebuilt.
+ // This is needed only if this library is linked by other modules in build time.
+ // Only makes sense for the Windows target.
+ Windows_import_lib *string `android:"path,arch_variant"`
}
type prebuiltLinker struct {
@@ -96,14 +103,27 @@
p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
// TODO(ccross): verify shared library dependencies
- if len(p.properties.Srcs) > 0 {
+ srcs := p.prebuiltSrcs()
+ if len(srcs) > 0 {
builderFlags := flagsToBuilderFlags(flags)
- in := p.Prebuilt.SingleSourcePath(ctx)
+ if len(srcs) > 1 {
+ ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+ return nil
+ }
+
+ in := android.PathForModuleSrc(ctx, srcs[0])
+
+ if p.static() {
+ return in
+ }
if p.shared() {
p.unstrippedOutputFile = in
libName := p.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+ outputFile := android.PathForModuleOut(ctx, libName)
+ var implicits android.Paths
+
if p.needsStrip(ctx) {
stripped := android.PathForModuleOut(ctx, "stripped", libName)
p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
@@ -114,15 +134,58 @@
// 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)
- }
+ TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
- return in
+ if ctx.Windows() && p.properties.Windows_import_lib != nil {
+ // Consumers of this library actually links to the import library in build
+ // time and dynamically links to the DLL in run time. i.e.
+ // a.exe <-- static link --> foo.lib <-- dynamic link --> foo.dll
+ importLibSrc := android.PathForModuleSrc(ctx, String(p.properties.Windows_import_lib))
+ importLibName := p.libraryDecorator.getLibName(ctx) + ".lib"
+ importLibOutputFile := android.PathForModuleOut(ctx, importLibName)
+ implicits = append(implicits, importLibOutputFile)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Description: "prebuilt import library",
+ Input: importLibSrc,
+ Output: importLibOutputFile,
+ Args: map[string]string{
+ "cpFlags": "-L",
+ },
+ })
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Description: "prebuilt shared library",
+ Implicits: implicits,
+ Input: in,
+ Output: outputFile,
+ Args: map[string]string{
+ "cpFlags": "-L",
+ },
+ })
+
+ return outputFile
+ }
}
return nil
}
+func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
+ srcs := p.properties.Srcs
+ if p.static() {
+ srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
+ }
+ if p.shared() {
+ srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
+ }
+
+ return srcs
+}
+
func (p *prebuiltLibraryLinker) shared() bool {
return p.libraryDecorator.shared()
}
@@ -135,6 +198,10 @@
p.properties.Srcs = nil
}
+func (p *prebuiltLibraryLinker) skipInstall(mod *Module) {
+ mod.ModuleBase.SkipInstall()
+}
+
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewLibrary(hod)
module.compiler = nil
@@ -143,16 +210,32 @@
libraryDecorator: library,
}
module.linker = prebuilt
+ module.installer = prebuilt
module.AddProperties(&prebuilt.properties)
- android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+ srcsSupplier := func() []string {
+ return prebuilt.prebuiltSrcs()
+ }
+
+ android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
// Prebuilt libraries can be used in SDKs.
android.InitSdkAwareModule(module)
return module, library
}
+// cc_prebuilt_library installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
+func PrebuiltLibraryFactory() android.Module {
+ module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+
+ // Prebuilt shared libraries can be included in APEXes
+ android.InitApexModule(module)
+
+ return module.Init()
+}
+
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltSharedLibraryFactory() android.Module {
@@ -183,6 +266,50 @@
return module, library
}
+type prebuiltObjectProperties struct {
+ Srcs []string `android:"path,arch_variant"`
+}
+
+type prebuiltObjectLinker struct {
+ android.Prebuilt
+ objectLinker
+
+ properties prebuiltObjectProperties
+}
+
+func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
+ return &p.Prebuilt
+}
+
+var _ prebuiltLinkerInterface = (*prebuiltObjectLinker)(nil)
+
+func (p *prebuiltObjectLinker) link(ctx ModuleContext,
+ flags Flags, deps PathDeps, objs Objects) android.Path {
+ if len(p.properties.Srcs) > 0 {
+ return p.Prebuilt.SingleSourcePath(ctx)
+ }
+ return nil
+}
+
+func newPrebuiltObject() *Module {
+ module := newObject()
+ prebuilt := &prebuiltObjectLinker{
+ objectLinker: objectLinker{
+ baseLinker: NewBaseLinker(nil),
+ },
+ }
+ module.linker = prebuilt
+ module.AddProperties(&prebuilt.properties)
+ android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+ android.InitSdkAwareModule(module)
+ return module
+}
+
+func prebuiltObjectFactory() android.Module {
+ module := newPrebuiltObject()
+ return module.Init()
+}
+
type prebuiltBinaryLinker struct {
*binaryDecorator
prebuiltLinker
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 3d809fc..adb44bd 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -22,6 +22,25 @@
"github.com/google/blueprint"
)
+func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext {
+ config := TestConfig(buildDir, android.Android, nil, bp, fs)
+ ctx := CreateTestContext()
+
+ // Enable androidmk support.
+ // * Register the singleton
+ // * Configure that we are inside make
+ // * Add CommonOS to ensure that androidmk processing works.
+ android.RegisterAndroidMkBuildComponents(ctx)
+ android.SetInMakeForTests(config)
+
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+ return ctx
+}
+
func TestPrebuilt(t *testing.T) {
bp := `
cc_library {
@@ -59,36 +78,57 @@
name: "libe",
srcs: ["libe.a"],
}
+
+ cc_library {
+ name: "libf",
+ }
+
+ cc_prebuilt_library {
+ name: "libf",
+ static: {
+ srcs: ["libf.a"],
+ },
+ shared: {
+ srcs: ["libf.so"],
+ },
+ }
+
+ cc_object {
+ name: "crtx",
+ }
+
+ cc_prebuilt_object {
+ name: "crtx",
+ srcs: ["crtx.o"],
+ }
`
- fs := map[string][]byte{
+ ctx := testPrebuilt(t, bp, map[string][]byte{
"liba.so": nil,
"libb.a": nil,
"libd.so": nil,
"libe.a": nil,
- }
-
- config := TestConfig(buildDir, android.Android, nil, bp, fs)
-
- ctx := CreateTestContext()
-
- ctx.Register(config)
-
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
+ "libf.a": nil,
+ "libf.so": nil,
+ "crtx.o": nil,
+ })
// Verify that all the modules exist and that their dependencies were connected correctly
liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module()
libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module()
libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module()
+ libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module()
+ libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module()
+ crtx := ctx.ModuleForTests("crtx", "android_arm64_armv8-a").Module()
prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module()
prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module()
prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module()
prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module()
+ prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module()
+ prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module()
+ prebuiltCrtx := ctx.ModuleForTests("prebuilt_crtx", "android_arm64_armv8-a").Module()
hasDep := func(m android.Module, wantDep android.Module) bool {
t.Helper()
@@ -116,4 +156,118 @@
if !hasDep(libe, prebuiltLibe) {
t.Errorf("libe missing dependency on prebuilt_libe")
}
+
+ if !hasDep(libfStatic, prebuiltLibfStatic) {
+ t.Errorf("libf static missing dependency on prebuilt_libf")
+ }
+
+ if !hasDep(libfShared, prebuiltLibfShared) {
+ t.Errorf("libf shared missing dependency on prebuilt_libf")
+ }
+
+ if !hasDep(crtx, prebuiltCrtx) {
+ t.Errorf("crtx missing dependency on prebuilt_crtx")
+ }
+}
+
+func TestPrebuiltLibraryShared(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_shared {
+ name: "libtest",
+ srcs: ["libf.so"],
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libf.so": nil,
+ })
+
+ shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libtest.so")
+}
+
+func TestPrebuiltLibraryStatic(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_static {
+ name: "libtest",
+ srcs: ["libf.a"],
+ }
+ `, map[string][]byte{
+ "libf.a": nil,
+ })
+
+ static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().Path().Base(), "libf.a")
+}
+
+func TestPrebuiltLibrary(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library {
+ name: "libtest",
+ static: {
+ srcs: ["libf.a"],
+ },
+ shared: {
+ srcs: ["libf.so"],
+ },
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libf.a": nil,
+ "libf.so": nil,
+ })
+
+ shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libtest.so")
+
+ static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().Path().Base(), "libf.a")
+}
+
+func TestPrebuiltLibraryStem(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library {
+ name: "libfoo",
+ stem: "libbar",
+ static: {
+ srcs: ["libfoo.a"],
+ },
+ shared: {
+ srcs: ["libfoo.so"],
+ },
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libfoo.a": nil,
+ "libfoo.so": nil,
+ })
+
+ static := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().Path().Base(), "libfoo.a")
+
+ shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libbar.so")
+}
+
+func TestPrebuiltLibrarySharedStem(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_shared {
+ name: "libfoo",
+ stem: "libbar",
+ srcs: ["libfoo.so"],
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libfoo.so": nil,
+ })
+
+ shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libbar.so")
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5ea8ee08..d32efda 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -307,8 +307,8 @@
}
}
- // CFI needs gold linker, and mips toolchain does not have one.
- if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
+ // Is CFI actually enabled?
+ if !ctx.Config().EnableCFI() {
s.Cfi = nil
s.Diag.Cfi = nil
}
@@ -609,18 +609,18 @@
return flags
}
-func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (sanitize *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
// both the sanitized and non-sanitized variants to make without a name conflict.
- if ret.Class == "STATIC_LIBRARIES" || ret.Class == "HEADER_LIBRARIES" {
+ if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
if Bool(sanitize.Properties.Sanitize.Cfi) {
- ret.SubName += ".cfi"
+ entries.SubName += ".cfi"
}
if Bool(sanitize.Properties.Sanitize.Hwaddress) {
- ret.SubName += ".hwasan"
+ entries.SubName += ".hwasan"
}
if Bool(sanitize.Properties.Sanitize.Scs) {
- ret.SubName += ".scs"
+ entries.SubName += ".scs"
}
}
}
@@ -900,6 +900,11 @@
c.sanitize.Properties.Sanitizers = sanitizers
c.sanitize.Properties.DiagSanitizers = diagSanitizers
+ // TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used.
+ if c.Host() {
+ diagSanitizers = sanitizers
+ }
+
// Determine the runtime library required
runtimeLibrary := ""
var extraStaticDeps []string
@@ -995,11 +1000,6 @@
modules[0].(*Module).sanitize.SetSanitizer(t, true)
} else if c.sanitize.isSanitizerEnabled(t) || c.sanitize.Properties.SanitizeDep {
isSanitizerEnabled := c.sanitize.isSanitizerEnabled(t)
- if mctx.Device() && t.incompatibleWithCfi() {
- // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
- // are incompatible with cfi
- c.sanitize.SetSanitizer(cfi, false)
- }
if c.static() || c.header() || t == asan || t == fuzzer {
// Static and header libs are split into non-sanitized and sanitized variants.
// Shared libs are not split. However, for asan and fuzzer, we split even for shared
@@ -1021,6 +1021,12 @@
modules[0].(*Module).sanitize.Properties.SanitizeDep = false
modules[1].(*Module).sanitize.Properties.SanitizeDep = false
+ if mctx.Device() && t.incompatibleWithCfi() {
+ // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
+ // are incompatible with cfi
+ modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
+ }
+
// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
// to Make, because the sanitized version has a different suffix in name.
// For other types of sanitizers, suppress the variation that is disabled.
@@ -1058,6 +1064,12 @@
if mctx.Device() && t == asan && isSanitizerEnabled {
modules[0].(*Module).sanitize.Properties.InSanitizerDir = true
}
+
+ if mctx.Device() && t.incompatibleWithCfi() {
+ // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
+ // are incompatible with cfi
+ modules[0].(*Module).sanitize.SetSanitizer(cfi, false)
+ }
}
}
c.sanitize.Properties.SanitizeDep = false
diff --git a/cc/sdk.go b/cc/sdk.go
new file mode 100644
index 0000000..d05a04a
--- /dev/null
+++ b/cc/sdk.go
@@ -0,0 +1,65 @@
+// 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 (
+ "android/soong/android"
+ "android/soong/genrule"
+)
+
+// sdkMutator sets a creates a platform and an SDK variant for modules
+// that set sdk_version, and ignores sdk_version for the platform
+// variant. The SDK variant will be used for embedding in APKs
+// that may be installed on older platforms. Apexes use their own
+// variants that enforce backwards compatibility.
+func sdkMutator(ctx android.BottomUpMutatorContext) {
+ if ctx.Os() != android.Android {
+ return
+ }
+
+ switch m := ctx.Module().(type) {
+ case LinkableInterface:
+ if m.AlwaysSdk() {
+ if !m.UseSdk() {
+ ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
+ }
+ ctx.CreateVariations("sdk")
+ } else if m.UseSdk() {
+ modules := ctx.CreateVariations("", "sdk")
+ modules[0].(*Module).Properties.Sdk_version = nil
+ modules[1].(*Module).Properties.IsSdkVariant = true
+
+ if ctx.Config().UnbundledBuild() {
+ modules[0].(*Module).Properties.HideFromMake = true
+ } else {
+ modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+ modules[1].(*Module).Properties.PreventInstall = true
+ }
+ ctx.AliasVariation("")
+ } else {
+ ctx.CreateVariations("")
+ ctx.AliasVariation("")
+ }
+ case *genrule.Module:
+ if p, ok := m.Extra.(*GenruleExtraProperties); ok {
+ if String(p.Sdk_version) != "" {
+ ctx.CreateVariations("", "sdk")
+ } else {
+ ctx.CreateVariations("")
+ }
+ ctx.AliasVariation("")
+ }
+ }
+}
diff --git a/cc/sdk_test.go b/cc/sdk_test.go
new file mode 100644
index 0000000..5a3c181
--- /dev/null
+++ b/cc/sdk_test.go
@@ -0,0 +1,102 @@
+// 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 (
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestSdkMutator(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libsdk",
+ shared_libs: ["libsdkdep"],
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ cc_library {
+ name: "libsdkdep",
+ sdk_version: "current",
+ stl: "c++_shared",
+ }
+
+ cc_library {
+ name: "libplatform",
+ shared_libs: ["libsdk"],
+ stl: "libc++",
+ }
+
+ cc_binary {
+ name: "platformbinary",
+ shared_libs: ["libplatform"],
+ stl: "libc++",
+ }
+
+ cc_binary {
+ name: "sdkbinary",
+ shared_libs: ["libsdk"],
+ sdk_version: "current",
+ stl: "libc++",
+ }
+ `
+
+ assertDep := func(t *testing.T, from, to android.TestingModule) {
+ t.Helper()
+ found := false
+
+ var toFile android.Path
+ m := to.Module().(*Module)
+ if toc := m.Toc(); toc.Valid() {
+ toFile = toc.Path()
+ } else {
+ toFile = m.outputFile.Path()
+ }
+
+ rule := from.Description("link")
+ for _, dep := range rule.Implicits {
+ if dep.String() == toFile.String() {
+ found = true
+ }
+ }
+ if !found {
+ t.Errorf("expected %q in %q", toFile.String(), rule.Implicits.Strings())
+ }
+ }
+
+ ctx := testCc(t, bp)
+
+ libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared")
+ libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared")
+ libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared")
+ libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared")
+ libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared")
+ platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a")
+ sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk")
+
+ libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared")
+ libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared")
+
+ assertDep(t, libsdkNDK, libsdkdepNDK)
+ assertDep(t, libsdkPlatform, libsdkdepPlatform)
+ assertDep(t, libplatform, libsdkPlatform)
+ assertDep(t, platformbinary, libplatform)
+ assertDep(t, sdkbinary, libsdkNDK)
+
+ assertDep(t, libsdkNDK, libcxxNDK)
+ assertDep(t, libsdkPlatform, libcxxPlatform)
+}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 8f48f86..4012def 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -14,8 +14,6 @@
package cc
import (
- "strings"
-
"android/soong/android"
)
@@ -26,6 +24,8 @@
type snapshotLibraryInterface interface {
exportedFlagsProducer
libraryInterface
+ collectHeadersForSnapshot(ctx android.ModuleContext)
+ snapshotHeaders() android.Paths
}
var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
@@ -58,49 +58,13 @@
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))
- }
- }
+func isSnapshotAware(ctx android.ModuleContext, m *Module) bool {
+ if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok {
+ return ctx.Config().VndkSnapshotBuildArtifacts()
+ } else if isVendorSnapshotModule(m, ctx.ModuleDir()) {
+ return true
}
-
- // 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
+ return false
}
func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
@@ -117,6 +81,17 @@
return outPath
}
+func combineNotices(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cat,
+ Inputs: paths,
+ Output: outPath,
+ Description: "combine notices for " + out,
+ })
+ return outPath
+}
+
func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
outPath := android.PathForOutput(ctx, out)
ctx.Build(pctx, android.BuildParams{
diff --git a/cc/stl.go b/cc/stl.go
index eda8a4f..4e74c7f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -115,9 +115,13 @@
switch s {
case "libc++", "libc++_static":
return s
+ case "c++_shared":
+ return "libc++"
+ case "c++_static":
+ return "libc++_static"
case "none":
return ""
- case "":
+ case "", "system":
if ctx.static() {
return "libc++_static"
} else {
@@ -235,11 +239,6 @@
flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
if ctx.Windows() {
- if stl.Properties.SelectedStl == "libc++_static" {
- // These are transitively needed by libc++_static.
- flags.extraLibFlags = append(flags.extraLibFlags,
- "-lmsvcrt", "-lucrt")
- }
// Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj
// exception model for 32-bit.
if ctx.Arch().ArchType == android.X86 {
diff --git a/cc/test.go b/cc/test.go
index 05e6fe5..f51cf01 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -29,6 +29,11 @@
// if set, use the isolated gtest runner. Defaults to false.
Isolated *bool
+
+ // List of APEXes that this module tests. The module has access to
+ // the private part of the listed APEXes even when it is not included in the
+ // APEXes.
+ Test_for []string
}
// Test option struct.
@@ -49,7 +54,7 @@
// list of files or filegroup modules that provide data that should be installed alongside
// the test
- Data []string `android:"path"`
+ Data []string `android:"path,arch_variant"`
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
@@ -215,6 +220,10 @@
return BoolDefault(test.Properties.Gtest, true)
}
+func (test *testDecorator) testFor() []string {
+ return test.Properties.Test_for
+}
+
func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
if !test.gtest() {
return flags
diff --git a/cc/testing.go b/cc/testing.go
index a22763a..53f0995 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -34,7 +34,7 @@
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
}
-func GatherRequiredDepsForTest(os android.OsType) string {
+func GatherRequiredDepsForTest(oses ...android.OsType) string {
ret := `
toolchain_library {
name: "libatomic",
@@ -67,6 +67,20 @@
src: "",
}
+ cc_prebuilt_library_shared {
+ name: "libclang_rt.hwasan-aarch64-android",
+ nocrt: true,
+ vendor_available: true,
+ recovery_available: true,
+ system_shared_libs: [],
+ stl: "none",
+ srcs: [""],
+ check_elf_files: false,
+ sanitize: {
+ never: true,
+ },
+ }
+
toolchain_library {
name: "libclang_rt.builtins-i686-android",
vendor_available: true,
@@ -138,6 +152,7 @@
name: "libgcc_stripped",
vendor_available: true,
recovery_available: true,
+ sdk_version: "current",
src: "",
}
@@ -155,6 +170,7 @@
llndk_library {
name: "libc",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libm",
@@ -174,6 +190,7 @@
llndk_library {
name: "libm",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libdl",
@@ -193,6 +210,7 @@
llndk_library {
name: "libdl",
symbol_file: "",
+ sdk_version: "current",
}
cc_library {
name: "libft2",
@@ -205,6 +223,7 @@
name: "libft2",
symbol_file: "",
vendor_available: false,
+ sdk_version: "current",
}
cc_library {
name: "libc++_static",
@@ -215,6 +234,10 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
cc_library {
name: "libc++",
@@ -243,6 +266,10 @@
host_supported: false,
vendor_available: true,
recovery_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
}
cc_library {
name: "libunwind_llvm",
@@ -254,8 +281,21 @@
recovery_available: true,
}
+ cc_defaults {
+ name: "crt_defaults",
+ recovery_available: true,
+ vendor_available: true,
+ native_bridge_supported: true,
+ stl: "none",
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ }
+
cc_object {
name: "crtbegin_so",
+ defaults: ["crt_defaults"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
@@ -264,6 +304,7 @@
cc_object {
name: "crtbegin_dynamic",
+ defaults: ["crt_defaults"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
@@ -272,6 +313,7 @@
cc_object {
name: "crtbegin_static",
+ defaults: ["crt_defaults"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
@@ -280,6 +322,7 @@
cc_object {
name: "crtend_so",
+ defaults: ["crt_defaults"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
@@ -288,6 +331,7 @@
cc_object {
name: "crtend_android",
+ defaults: ["crt_defaults"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
@@ -336,13 +380,24 @@
sdk_version: "27",
}
+ ndk_prebuilt_object {
+ name: "ndk_crtbegin_dynamic.27",
+ sdk_version: "27",
+ }
+
+ ndk_prebuilt_object {
+ name: "ndk_crtend_android.27",
+ sdk_version: "27",
+ }
+
ndk_prebuilt_shared_stl {
name: "ndk_libc++_shared",
}
`
- if os == android.Fuchsia {
- ret += `
+ for _, os := range oses {
+ if os == android.Fuchsia {
+ ret += `
cc_library {
name: "libbioniccompat",
stl: "none",
@@ -352,6 +407,22 @@
stl: "none",
}
`
+ }
+ if os == android.Windows {
+ ret += `
+ toolchain_library {
+ name: "libwinpthread",
+ host_supported: true,
+ enabled: false,
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ src: "",
+ }
+ `
+ }
}
return ret
}
diff --git a/cc/tidy.go b/cc/tidy.go
index 5455392..cfb5b68 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -117,6 +117,10 @@
// which is used in many Android files.
tidyChecks = tidyChecks + ",-cert-dcl16-c"
}
+ // https://b.corp.google.com/issues/153464409
+ // many local projects enable cert-* checks, which
+ // trigger bugprone-reserved-identifier.
+ tidyChecks = tidyChecks + ",-bugprone-reserved-identifier*,-cert-dcl51-cpp,-cert-dcl37-c"
flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index dfc6f76..042e012 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -67,6 +67,7 @@
module.stl = nil
module.sanitize = nil
module.installer = nil
+ module.Properties.Sdk_version = StringPtr("current")
return module.Init()
}
diff --git a/cc/util.go b/cc/util.go
index 60070bb..af26268 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -82,7 +82,7 @@
tidyFlags: strings.Join(in.TidyFlags, " "),
sAbiFlags: strings.Join(in.SAbiFlags, " "),
toolchain: in.Toolchain,
- coverage: in.Coverage,
+ gcovCoverage: in.GcovCoverage,
tidy: in.Tidy,
sAbiDump: in.SAbiDump,
emitXrefs: in.EmitXrefs,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index aed7918..5801fc7 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -428,12 +428,12 @@
// 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 {
+func isVendorSnapshotModule(m *Module, moduleDir string) bool {
if !m.Enabled() {
return false
}
// skip proprietary modules, but include all VNDK (static)
- if isVendorProprietaryPath(ctx.ModuleDir(m)) && !m.IsVndk() {
+ if isVendorProprietaryPath(moduleDir) && !m.IsVndk() {
return false
}
if m.Target().Os.Class != android.Device {
@@ -525,14 +525,6 @@
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 != "" {
@@ -588,7 +580,7 @@
var propOut string
- if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
+ if l, ok := m.linker.(snapshotLibraryInterface); ok {
// library flags
prop.ExportedFlags = l.exportedFlags()
for _, dir := range l.exportedDirs() {
@@ -652,23 +644,28 @@
ctx.VisitAllModules(func(module android.Module) {
m, ok := module.(*Module)
- if !ok || !isVendorSnapshotModule(ctx, m) {
+ if !ok {
+ return
+ }
+
+ moduleDir := ctx.ModuleDir(module)
+ if !isVendorSnapshotModule(m, moduleDir) {
return
}
snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
- if l, ok := m.linker.(vendorSnapshotLibraryInterface); ok {
- headers = append(headers, exportedHeaders(ctx, l)...)
+ if l, ok := m.linker.(snapshotLibraryInterface); ok {
+ headers = append(headers, l.snapshotHeaders()...)
}
- if m.NoticeFile().Valid() {
+ if len(m.NoticeFiles()) > 0 {
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))
+ snapshotOutputs = append(snapshotOutputs, combineNotices(
+ ctx, m.NoticeFiles(), noticeOut))
}
}
})
diff --git a/cc/vndk.go b/cc/vndk.go
index 4578a7d..dbe1f3b 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -297,6 +297,9 @@
if !Bool(lib.Properties.Vendor_available) {
vndkPrivateLibraries(mctx.Config())[name] = filename
}
+ if mctx.OtherModuleExists(name) {
+ mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name)
+ }
}
func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
@@ -306,6 +309,10 @@
panic(err)
}
+ if m.HasStubsVariants() {
+ mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
+ }
+
vndkLibrariesLock.Lock()
defer vndkLibrariesLock.Unlock()
@@ -347,6 +354,15 @@
}
if lib, ok := m.linker.(libraryInterface); ok {
+ // VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
+ if mctx.DeviceConfig().VndkVersion() == "" {
+ // b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
+ if mctx.ModuleName() == "libz" {
+ return false
+ }
+ return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.isVndkSp()
+ }
+
useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
@@ -496,6 +512,28 @@
vndkSnapshotZipFile android.OptionalPath
}
+func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+ if m.Target().NativeBridge == android.NativeBridgeEnabled {
+ return nil, "", false
+ }
+ if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
+ return nil, "", false
+ }
+ l, ok := m.linker.(snapshotLibraryInterface)
+ if !ok || !l.shared() {
+ return nil, "", false
+ }
+ if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
+ if m.isVndkSp() {
+ return l, "vndk-sp", true
+ } else {
+ return l, "vndk-core", true
+ }
+ }
+
+ return nil, "", false
+}
+
func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
c.buildVndkLibrariesTxtFiles(ctx)
@@ -598,35 +636,13 @@
return ret, true
}
- isVndkSnapshotLibrary := func(m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
- if m.Target().NativeBridge == android.NativeBridgeEnabled {
- return nil, "", false
- }
- if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
- return nil, "", false
- }
- l, ok := m.linker.(snapshotLibraryInterface)
- if !ok || !l.shared() {
- return nil, "", false
- }
- if m.VndkVersion() == ctx.DeviceConfig().PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
- if m.isVndkSp() {
- return l, "vndk-sp", true
- } else {
- return l, "vndk-core", true
- }
- }
-
- return nil, "", false
- }
-
ctx.VisitAllModules(func(module android.Module) {
m, ok := module.(*Module)
if !ok || !m.Enabled() {
return
}
- l, vndkType, ok := isVndkSnapshotLibrary(m)
+ l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m)
if !ok {
return
}
@@ -644,18 +660,18 @@
moduleNames[stem] = ctx.ModuleName(m)
modulePaths[stem] = ctx.ModuleDir(m)
- if m.NoticeFile().Valid() {
+ if len(m.NoticeFiles()) > 0 {
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)))
+ snapshotOutputs = append(snapshotOutputs, combineNotices(
+ ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
}
}
if ctx.Config().VndkSnapshotBuildArtifacts() {
- headers = append(headers, exportedHeaders(ctx, l)...)
+ headers = append(headers, l.snapshotHeaders()...)
}
})
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 2536a53..6b79823 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -17,9 +17,11 @@
deps: [
"blueprint",
"blueprint-bootstrap",
+ "golang-protobuf-proto",
"soong",
"soong-android",
"soong-env",
+ "soong-ui-metrics_proto",
],
srcs: [
"main.go",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 30381e0..bd1a9ed 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -131,4 +131,15 @@
os.Exit(1)
}
}
+
+ // TODO(ccross): make this a command line argument. Requires plumbing through blueprint
+ // to affect the command line of the primary builder.
+ if docFile == "" {
+ metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
+ err = android.WriteMetrics(configuration, metricsFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
+ os.Exit(1)
+ }
+ }
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index db61fba..1d94f02 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -173,6 +173,7 @@
stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
stat.AddOutput(status.NewCriticalPath(log))
+ stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, c.logsPrefix+"build_progress.pb")))
buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
diff --git a/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go
index a6023d3..294e5ef 100644
--- a/cmd/zipsync/zipsync.go
+++ b/cmd/zipsync/zipsync.go
@@ -115,7 +115,7 @@
filename := filepath.Join(*outputDir, name)
if f.FileInfo().IsDir() {
- must(os.MkdirAll(filename, f.FileInfo().Mode()))
+ must(os.MkdirAll(filename, 0777))
} else {
must(os.MkdirAll(filepath.Dir(filename), 0777))
in, err := f.Open()
diff --git a/cuj/cuj.go b/cuj/cuj.go
index c7ff8ff..3333012 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -33,8 +33,9 @@
)
type Test struct {
- name string
- args []string
+ name string
+ args []string
+ before func() error
results TestResults
}
@@ -119,6 +120,15 @@
t.results.metrics = met
}
+// Touch the Intent.java file to cause a rebuild of the frameworks to monitor the
+// incremental build speed as mentioned b/152046247. Intent.java file was chosen
+// as it is a key component of the framework and is often modified.
+func touchIntentFile() error {
+ const intentFileName = "frameworks/base/core/java/android/content/Intent.java"
+ currentTime := time.Now().Local()
+ return os.Chtimes(intentFileName, currentTime, currentTime)
+}
+
func main() {
outDir := os.Getenv("OUT_DIR")
if outDir == "" {
@@ -170,6 +180,36 @@
name: "framework_rebuild_twice",
args: []string{"framework"},
},
+ {
+ // Scenario major_inc_build (b/152046247): tracking build speed of major incremental build.
+ name: "major_inc_build_droid",
+ args: []string{"droid"},
+ },
+ {
+ name: "major_inc_build_framework_minus_apex_after_droid_build",
+ args: []string{"framework-minus-apex"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_framework_after_droid_build",
+ args: []string{"framework"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_sync_after_droid_build",
+ args: []string{"sync"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_droid_rebuild",
+ args: []string{"droid"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_update_api_after_droid_rebuild",
+ args: []string{"update-api"},
+ before: touchIntentFile,
+ },
}
cujMetrics := metrics.NewCriticalUserJourneysMetrics()
@@ -178,6 +218,12 @@
for i, t := range tests {
logsSubDir := fmt.Sprintf("%02d_%s", i, t.name)
logsDir := filepath.Join(cujDir, "logs", logsSubDir)
+ if t.before != nil {
+ if err := t.before(); err != nil {
+ fmt.Printf("error running before function on test %q: %v\n", t.name, err)
+ break
+ }
+ }
t.Run(logsDir)
if t.results.err != nil {
fmt.Printf("error running test %q: %s\n", t.name, t.results.err)
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 6cb9873..0e1bfc6 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -41,21 +41,12 @@
"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, globalSoong *GlobalSoongConfig,
@@ -116,13 +107,6 @@
}
}
- // 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
- }
- }
-
// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
// Also preopt system server jars since selinux prevents system server from loading anything from
// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
@@ -239,6 +223,8 @@
invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
+ systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
// The class loader context using paths in the build
var classLoaderContextHost android.Paths
@@ -253,8 +239,8 @@
var conditionalClassLoaderContextHost29 android.Paths
var conditionalClassLoaderContextTarget29 []string
- var classLoaderContextHostString, classLoaderContextDeviceString string
- var classLoaderDeps android.Paths
+ // A flag indicating if the '&' class loader context is used.
+ unknownClassLoaderContext := false
if module.EnforceUsesLibraries {
usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
@@ -298,49 +284,38 @@
pathForLibrary(module, hidlBase))
conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
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.")
+ } else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+ // System server jars should be dexpreopted together: class loader context of each jar
+ // should include all preceding jars on the system server classpath.
+ for _, otherJar := range systemServerJars[:jarIndex] {
+ classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar))
+ classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar")
}
- // 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
+ // Copy the system server jar to a predefined location where dex2oat will find it.
+ dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
+ rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
+ rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
} else {
// Pass special class loader context to skip the classpath and collision check.
// This will get removed once LOCAL_USES_LIBRARIES is enforced.
// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
// to the &.
- classLoaderContextHostString = `\&`
+ unknownClassLoaderContext = true
}
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.
- if classLoaderContextHostString == `\&` {
- rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`)
- rule.Command().Text(`stored_class_loader_context_arg=""`)
+ if unknownClassLoaderContext {
+ rule.Command().
+ Text(`class_loader_context_arg=--class-loader-context=\&`).
+ 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 + "]")
+ rule.Command().
+ Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]").
+ Implicits(classLoaderContextHost).
+ Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]")
}
if module.EnforceUsesLibraries {
@@ -395,7 +370,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}").Implicits(classLoaderDeps).
+ Flag("${stored_class_loader_context_arg}").
FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
FlagWithInput("--dex-file=", module.DexPath).
FlagWithArg("--dex-location=", dexLocationArg).
@@ -609,6 +584,14 @@
}).([]string)
}
+// A predefined location for the system server dex jars. This is needed in order to generate
+// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
+// at that time (Soong processes the jars in dependency order, which may be different from the
+// the system server classpath order).
+func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath {
+ return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar")
+}
+
func contains(l []string, s string) bool {
for _, e := range l {
if e == s {
diff --git a/doc.go b/doc.go
index 543c460..299fd2b 100644
--- a/doc.go
+++ b/doc.go
@@ -46,8 +46,8 @@
//
// Target architecture
// The target architecture is the preferred architecture supported by the selected
-// device. It is most commonly 32-bit arm, but may also be 64-bit arm, 32-bit or
-// 64-bit x86, or mips.
+// device. It is most commonly 32-bit arm, but may also be 64-bit arm, 32-bit
+// x86, or 64-bit x86.
//
// Secondary architecture
// The secondary architecture specifies the architecture to compile a second copy
diff --git a/docs/map_files.md b/docs/map_files.md
new file mode 100644
index 0000000..9fc0d14
--- /dev/null
+++ b/docs/map_files.md
@@ -0,0 +1,174 @@
+# Native API Map Files
+
+Native APIs such as those exposed by the NDK, LL-NDK, or APEX are described by
+map.txt files. These files are [linker version scripts] with comments that are
+semantically meaningful to [gen_stub_libs.py]. For an example of a map file, see
+[libc.map.txt].
+
+[gen_stub_libs.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/gen_stub_libs.py
+[libc.map.txt]: https://cs.android.com/android/platform/superproject/+/master:bionic/libc/libc.map.txt
+[linker version scripts]: https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html
+
+## Basic format
+
+A linker version script defines at least one alphanumeric "version" definition,
+each of which contain a list of symbols. For example:
+
+```txt
+MY_API_R { # introduced=R
+ global:
+ api_foo;
+ api_bar;
+ local:
+ *;
+};
+
+MY_API_S { # introduced=S
+ global:
+ api_baz;
+} MY_API_R;
+```
+
+Comments on the same line as either a version definition or a symbol name have
+meaning. If you need to add any comments that should not be interpreted by the
+stub generator, keep them on their own line. For a list of supported comments,
+see the "Tags" section.
+
+Here, `api_foo` and `api_bar` are exposed in the generated stubs with the
+`MY_API_R` version and `api_baz` is exposed with the `MY_API_S` version. No
+other symbols are defined as public by this API. `MY_API_S` inherits all symbols
+defined by `MY_API_R`.
+
+When generating NDK API stubs from this version script, the stub library for R
+will define `api_foo` and `api_bar`. The stub library for S will define all
+three APIs.
+
+Note that, with few exceptions (see "Special version names" below), the name of
+the version has no inherent meaning.
+
+These map files can (and should) also be used as version scripts for building
+the implementation library rather than just defining the stub interface by using
+the `version_script` property of `cc_library`. This has the effect of limiting
+symbol visibility of the library to expose only the interface named by the map
+file. Without this, APIs that you have not explicitly exposed will still be
+available to users via `dlsym`. Note: All comments are ignored in this case. Any
+symbol named in any `global:` group will be visible.
+
+## Special version names
+
+Version names that end with `_PRIVATE` or `_PLATFORM` will not be exposed in any
+stubs, but will be exposed in the implementation library. Using either of these
+naming schemes is equivalent to marking the version with the `platform-only`
+tag. See the docs for `platform-only` for more information.
+
+## Tags
+
+Comments on the same line as a version definition or a symbol name are
+interpreted by the stub generator. Multiple space-delimited tags may be used on
+the same line. The supported tags are:
+
+### apex
+
+Indicates that the version or symbol is to be exposed in the APEX stubs rather
+than the NDK. May be used in combination with `llndk` if the symbol is exposed
+to both APEX and the LL-NDK.
+
+### future
+
+Indicates that the version or symbol is first introduced in the "future" API
+level. This is an abitrarily high API level used to define APIs that have not
+yet been added to a specific release.
+
+### introduced
+
+Indicates the version in which an API was first introduced. For example,
+`introduced=21` specifies that the API was first added (or first made public) in
+API level 21. This tag can be applied to either a version definition or an
+individual symbol. If applied to a version, all symbols contained in the version
+will have the tag applied. An `introduced` tag on a symbol overrides the value
+set for the version, if both are defined.
+
+Note: The map file alone does not contain all the information needed to
+determine which API level an API was added in. The `first_version` property of
+`ndk_library` will dictate which API levels stubs are generated for. If the
+module sets `first_version: "21"`, no symbols were introduced before API 21.
+
+Codenames can (and typically should) be used when defining new APIs. This allows
+the actual number of the API level to remain vague during development of that
+release. For example, `introduced=S` can be used to define APIs added in S. Any
+code name known to the build system can be used. For a list of versions known to
+the build system, see `out/soong/api_levels.json` (if not present, run `m
+out/soong/api_levels.json` to generate it).
+
+Architecture-specific variants of this tag exist:
+
+* `introduced-arm=VERSION`
+* `introduced-arm64=VERSION`
+* `introduced-x86=VERSION`
+* `introduced-x86_64=VERSION`
+
+The architecture-specific tag will take precedence over the architecture-generic
+tag when generating stubs for that architecture if both are present. If the
+symbol is defined with only architecture-specific tags, it will not be present
+for architectures that are not named.
+
+Note: The architecture-specific tags should, in general, not be used. These are
+primarily needed for APIs that were wrongly inconsistently exposed by libc/libm
+in old versions of Android before the stubs were well maintained. Think hard
+before using an architecture-specific tag for a new API.
+
+### llndk
+
+Indicates that the version or symbol is to be exposed in the LL-NDK stubs rather
+than the NDK. May be used in combination with `apex` if the symbol is exposed to
+both APEX and the LL-NDK.
+
+### platform-only
+
+Indicates that the version or symbol is public in the implementation library but
+should not be exposed in the stub library. Developers can still access them via
+`dlsym`, but they will not be exposed in the stubs so it should at least be
+clear to the developer that they are up to no good.
+
+The typical use for this tag is for exposing an API to the platform that is not
+for use by the NDK, LL-NDK, or APEX. It is preferable to keep such APIs in an
+entirely separate library to protect them from access via `dlsym`, but this is
+not always possible.
+
+### var
+
+Used to define a public global variable. By default all symbols are exposed as
+functions. In the uncommon situation of exposing a global variable, the `var`
+tag may be used.
+
+### versioned=VERSION
+
+Behaves similarly to `introduced` but defines the first version that the stub
+library should apply symbol versioning. For example:
+
+```txt
+R { # introduced=R
+ global:
+ foo;
+ bar; # versioned=S
+ local:
+ *;
+};
+```
+
+The stub library for R will contain symbols for both `foo` and `bar`, but only
+`foo` will include a versioned symbol `foo@R`. The stub library for S will
+contain both symbols, as well as the versioned symbols `foo@R` and `bar@R`.
+
+This tag is not commonly needed and is only used to hide symbol versioning
+mistakes that shipped as part of the platform.
+
+Note: Like `introduced`, the map file does not tell the whole story. The
+`ndk_library` Soong module may define a `unversioned_until` property that sets
+the default for the entire map file.
+
+### weak
+
+Indicates that the symbol should be [weak] in the stub library.
+
+[weak]: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 9a71be2..8280cb1 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -99,8 +99,8 @@
if err != nil {
ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
}
- if UseApiFingerprint(ctx, targetSdkVersion) {
- targetSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ if UseApiFingerprint(ctx) {
+ targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
}
@@ -108,8 +108,8 @@
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
- if UseApiFingerprint(ctx, minSdkVersion) {
- minSdkVersion += fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
+ if UseApiFingerprint(ctx) {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
}
diff --git a/java/androidmk.go b/java/androidmk.go
index d76e29b..68da23e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -72,6 +72,7 @@
if !hideFromMake {
mainEntries = android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
+ DistFile: android.OptionalPathForPath(library.distFile),
OutputFile: android.OptionalPathForPath(library.outputFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -275,7 +276,7 @@
}
func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
- if !app.IsForPlatform() {
+ if !app.IsForPlatform() || app.appProperties.HideFromMake {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Disabled: true,
}}
@@ -288,6 +289,7 @@
func(entries *android.AndroidMkEntries) {
// App module names can be overridden.
entries.SetString("LOCAL_MODULE", app.installApkName)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
if app.dexJarFile != nil {
entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile)
@@ -347,6 +349,9 @@
for _, jniLib := range app.installJniLibs {
entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name)
}
+ if len(app.jniCoverageOutputs) > 0 {
+ entries.AddStrings("LOCAL_PREBUILT_COVERAGE_ARCHIVE", app.jniCoverageOutputs.Strings()...)
+ }
if len(app.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled)
}
@@ -467,34 +472,6 @@
if ddoc.Javadoc.stubsSrcJar != nil {
entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar)
}
- apiFilePrefix := "INTERNAL_PLATFORM_"
- if String(ddoc.properties.Api_tag_name) != "" {
- apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_"
- }
- if ddoc.apiFile != nil {
- entries.SetPath(apiFilePrefix+"API_FILE", ddoc.apiFile)
- }
- if ddoc.dexApiFile != nil {
- entries.SetPath(apiFilePrefix+"DEX_API_FILE", ddoc.dexApiFile)
- }
- if ddoc.privateApiFile != nil {
- entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", ddoc.privateApiFile)
- }
- if ddoc.privateDexApiFile != nil {
- entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", ddoc.privateDexApiFile)
- }
- if ddoc.removedApiFile != nil {
- entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", ddoc.removedApiFile)
- }
- if ddoc.removedDexApiFile != nil {
- entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", ddoc.removedDexApiFile)
- }
- if ddoc.exactApiFile != nil {
- entries.SetPath(apiFilePrefix+"EXACT_API_FILE", ddoc.exactApiFile)
- }
- if ddoc.proguardFile != nil {
- entries.SetPath(apiFilePrefix+"PROGUARD_FILE", ddoc.proguardFile)
- }
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -540,9 +517,21 @@
}
func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries {
+ // If the stubsSrcJar is not generated (because generate_stubs is false) then
+ // use the api file as the output file to ensure the relevant phony targets
+ // are created in make if only the api txt file is being generated. This is
+ // needed because an invalid output file would prevent the make entries from
+ // being written.
+ // TODO(b/146727827): Revert when we do not need to generate stubs and API separately.
+ distFile := android.OptionalPathForPath(dstubs.apiFile)
+ outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
+ if !outputFile.Valid() {
+ outputFile = distFile
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar),
+ DistFile: distFile,
+ OutputFile: outputFile,
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
@@ -561,35 +550,18 @@
if dstubs.metadataZip != nil {
entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.metadataZip)
}
- apiFilePrefix := "INTERNAL_PLATFORM_"
- if String(dstubs.properties.Api_tag_name) != "" {
- apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_"
- }
- if dstubs.apiFile != nil {
- entries.SetPath(apiFilePrefix+"API_FILE", dstubs.apiFile)
- }
- if dstubs.dexApiFile != nil {
- entries.SetPath(apiFilePrefix+"DEX_API_FILE", dstubs.dexApiFile)
- }
- if dstubs.privateApiFile != nil {
- entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", dstubs.privateApiFile)
- }
- if dstubs.privateDexApiFile != nil {
- entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", dstubs.privateDexApiFile)
- }
- if dstubs.removedApiFile != nil {
- entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", dstubs.removedApiFile)
- }
- if dstubs.removedDexApiFile != nil {
- entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", dstubs.removedDexApiFile)
- }
- if dstubs.exactApiFile != nil {
- entries.SetPath(apiFilePrefix+"EXACT_API_FILE", dstubs.exactApiFile)
- }
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ if dstubs.apiFile != nil {
+ fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
+ fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.apiFile)
+ }
+ if dstubs.removedApiFile != nil {
+ fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name())
+ fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.removedApiFile)
+ }
if dstubs.checkCurrentApiTimestamp != nil {
fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api")
fmt.Fprintln(w, dstubs.Name()+"-check-current-api:",
@@ -616,14 +588,12 @@
fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:",
dstubs.checkLastReleasedApiTimestamp.String())
- if dstubs.Name() != "android.car-system-stubs-docs" {
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- dstubs.checkLastReleasedApiTimestamp.String())
+ fmt.Fprintln(w, ".PHONY: checkapi")
+ fmt.Fprintln(w, "checkapi:",
+ dstubs.checkLastReleasedApiTimestamp.String())
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
+ fmt.Fprintln(w, ".PHONY: droidcore")
+ fmt.Fprintln(w, "droidcore: checkapi")
}
if dstubs.apiLintTimestamp != nil {
fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-api-lint")
@@ -656,6 +626,11 @@
}
func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries {
+ if !a.IsForPlatform() {
+ // The non-platform variant is placed inside APEX. No reason to
+ // make it available to Make.
+ return nil
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "APPS",
OutputFile: android.OptionalPathForPath(a.outputFile),
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index acc6bf0..7daa624 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -16,6 +16,7 @@
import (
"reflect"
+ "strings"
"testing"
"android/soong/android"
@@ -133,3 +134,38 @@
t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual)
}
}
+
+func TestDistWithTag(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_library {
+ name: "foo_without_tag",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dist: {
+ targets: ["hi"],
+ },
+ }
+ java_library {
+ name: "foo_with_tag",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dist: {
+ targets: ["hi"],
+ tag: ".jar",
+ },
+ }
+ `)
+
+ without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
+ with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
+
+ if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 {
+ t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries))
+ }
+ if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") {
+ t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile)
+ }
+ if without_tag_entries[0].DistFile.Valid() {
+ t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
+ }
+}
diff --git a/java/app.go b/java/app.go
index 0745bf0..afc4a60 100755
--- a/java/app.go
+++ b/java/app.go
@@ -105,6 +105,15 @@
// If set, find and merge all NOTICE files that this module and its dependencies have and store
// it in the APK as an asset.
Embed_notices *bool
+
+ // cc.Coverage related properties
+ PreventInstall bool `blueprint:"mutated"`
+ HideFromMake bool `blueprint:"mutated"`
+ IsCoverageVariant bool `blueprint:"mutated"`
+
+ // Whether this app is considered mainline updatable or not. When set to true, this will enforce
+ // additional rules for making sure that the APK is truly updatable. Default is false.
+ Updatable *bool
}
// android_app properties that can be overridden by override_android_app
@@ -133,7 +142,8 @@
overridableAppProperties overridableAppProperties
- installJniLibs []jniLib
+ installJniLibs []jniLib
+ jniCoverageOutputs android.Paths
bundleFile android.Path
@@ -147,6 +157,8 @@
additionalAaptFlags []string
noticeOutputs android.NoticeOutputs
+
+ overriddenManifestPackageName string
}
func (a *AndroidApp) IsInstallable() bool {
@@ -169,6 +181,10 @@
return a.certificate
}
+func (a *AndroidApp) JniCoverageOutputs() android.Paths {
+ return a.jniCoverageOutputs
+}
+
var _ AndroidLibraryDependency = (*AndroidApp)(nil)
type Certificate struct {
@@ -202,6 +218,13 @@
for _, jniTarget := range ctx.MultiTargets() {
variation := append(jniTarget.Variations(),
blueprint.Variation{Mutator: "link", Variation: "shared"})
+
+ // If the app builds against an Android SDK use the SDK variant of JNI dependencies
+ // unless jni_uses_platform_apis is set.
+ if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform &&
+ !Bool(a.appProperties.Jni_uses_platform_apis) {
+ variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
+ }
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
}
@@ -230,11 +253,21 @@
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.checkPlatformAPI(ctx)
- a.checkSdkVersion(ctx)
+ a.checkAppSdkVersions(ctx)
a.generateAndroidBuildActions(ctx)
}
+func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
+ if Bool(a.appProperties.Updatable) {
+ if !a.sdkVersion().stable() {
+ ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion())
+ }
+ }
+
+ a.checkPlatformAPI(ctx)
+ a.checkSdkVersions(ctx)
+}
+
// 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 {
@@ -271,6 +304,10 @@
!a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
}
+func (a *AndroidApp) OverriddenManifestPackageName() string {
+ return a.overriddenManifestPackageName
+}
+
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
@@ -304,6 +341,7 @@
manifestPackageName = *a.overridableAppProperties.Package_name
}
aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+ a.overriddenManifestPackageName = manifestPackageName
}
aaptLinkFlags = append(aaptLinkFlags, a.additionalAaptFlags...)
@@ -366,6 +404,22 @@
if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
+ for _, jni := range jniLibs {
+ if jni.coverageFile.Valid() {
+ // Only collect coverage for the first target arch if this is a multilib target.
+ // TODO(jungjw): Ideally, we want to collect both reports, but that would cause coverage
+ // data file path collisions since the current coverage file path format doesn't contain
+ // arch-related strings. This is fine for now though; the code coverage team doesn't use
+ // multi-arch targets such as test_suite_* for coverage collections yet.
+ //
+ // Work with the team to come up with a new format that handles multilib modules properly
+ // and change this.
+ if len(ctx.Config().Targets[android.Android]) == 1 ||
+ ctx.Config().Targets[android.Android][0].Arch.ArchType == jni.target.Arch.ArchType {
+ a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+ }
+ }
+ }
} else {
a.installJniLibs = jniLibs
}
@@ -390,16 +444,20 @@
return false
}
- path := child.(android.Module).NoticeFile()
- if path.Valid() {
- noticePathSet[path.Path()] = true
+ paths := child.(android.Module).NoticeFiles()
+ if len(paths) > 0 {
+ for _, path := range paths {
+ noticePathSet[path] = true
+ }
}
return true
})
// If the app has one, add it too.
- if a.NoticeFile().Valid() {
- noticePathSet[a.NoticeFile().Path()] = true
+ if len(a.NoticeFiles()) > 0 {
+ for _, path := range a.NoticeFiles() {
+ noticePathSet[path] = true
+ }
}
if len(noticePathSet) == 0 {
@@ -453,6 +511,10 @@
return certificates
}
+func (a *AndroidApp) InstallApkName() string {
+ return a.installApkName
+}
+
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
var apkDeps android.Paths
@@ -503,14 +565,28 @@
// Build a final signed app package.
packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
- CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
+ v4SigningRequested := Bool(a.Module.deviceProperties.V4_signature)
+ var v4SignatureFile android.WritablePath = nil
+ if v4SigningRequested {
+ v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig")
+ }
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile)
a.outputFile = packageFile
+ if v4SigningRequested {
+ a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
+ }
for _, split := range a.aapt.splits {
// Sign the split APKs
packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk")
- CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps)
+ if v4SigningRequested {
+ v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
+ }
+ CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
+ if v4SigningRequested {
+ a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
+ }
}
// Build an app bundle.
@@ -564,9 +640,10 @@
if lib.Valid() {
jniLibs = append(jniLibs, jniLib{
- name: ctx.OtherModuleName(module),
- path: path,
- target: module.Target(),
+ name: ctx.OtherModuleName(module),
+ path: path,
+ target: module.Target(),
+ coverageFile: dep.CoverageOutputFile(),
})
} else {
ctx.ModuleErrorf("dependency %q missing output file", otherName)
@@ -620,6 +697,24 @@
return Bool(a.appProperties.Privileged)
}
+func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+ return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+}
+
+func (a *AndroidApp) PreventInstall() {
+ a.appProperties.PreventInstall = true
+}
+
+func (a *AndroidApp) HideFromMake() {
+ a.appProperties.HideFromMake = true
+}
+
+func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) {
+ a.appProperties.IsCoverageVariant = coverage
+}
+
+var _ cc.Coverage = (*AndroidApp)(nil)
+
// android_app compiles sources and Android resources into an Android application package `.apk` file.
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@@ -891,6 +986,7 @@
type AndroidAppImport struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.ApexModuleBase
prebuilt android.Prebuilt
properties AndroidAppImportProperties
@@ -1043,6 +1139,10 @@
a.generateAndroidBuildActions(ctx)
}
+func (a *AndroidAppImport) InstallApkName() string {
+ return a.BaseModuleName()
+}
+
func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
numCertPropsSet := 0
if String(a.properties.Certificate) != "" {
@@ -1100,6 +1200,8 @@
dexOutput = dexUncompressed
}
+ apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
+
// Sign or align the package
// TODO: Handle EXTERNAL
if !Bool(a.properties.Presigned) {
@@ -1110,11 +1212,11 @@
ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
}
a.certificate = certificates[0]
- signed := android.PathForModuleOut(ctx, "signed", ctx.ModuleName()+".apk")
- SignAppPackage(ctx, signed, dexOutput, certificates)
+ signed := android.PathForModuleOut(ctx, "signed", apkFilename)
+ SignAppPackage(ctx, signed, dexOutput, certificates, nil)
a.outputFile = signed
} else {
- alignedApk := android.PathForModuleOut(ctx, "zip-aligned", ctx.ModuleName()+".apk")
+ alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
TransformZipAlign(ctx, alignedApk, dexOutput)
a.outputFile = alignedApk
a.certificate = presignedCertificate
@@ -1122,8 +1224,9 @@
// TODO: Optionally compress the output apk.
- a.installPath = ctx.InstallFile(installDir,
- proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk"), a.outputFile)
+ if a.IsForPlatform() {
+ a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
+ }
// TODO: androidmk converter jni libs
}
@@ -1174,6 +1277,13 @@
return Bool(a.properties.Privileged)
}
+func (a *AndroidAppImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ // android_app_import might have extra dependencies via uses_libs property.
+ // Don't track the dependency as we don't automatically add those libraries
+ // to the classpath. It should be explicitly added to java_libs property of APEX
+ return false
+}
+
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
@@ -1220,6 +1330,7 @@
module.processVariants(ctx)
})
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
@@ -1257,6 +1368,7 @@
module.processVariants(ctx)
})
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
@@ -1292,6 +1404,12 @@
// 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
+
+ // list of android_library modules whose resources are extracted and linked against statically
+ Static_libs []string
+
+ // list of android_app modules whose resources are extracted and linked against
+ Resource_libs []string
}
func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1304,6 +1422,9 @@
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
+
+ ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+ ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
}
func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1316,7 +1437,7 @@
_, certificates := collectAppDeps(ctx, false, 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)
+ SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil)
r.certificate = certificates[0]
r.outputFile = signed
diff --git a/java/app_builder.go b/java/app_builder.go
index 5e7fbe6..b2780bc 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -45,7 +45,7 @@
})
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
- packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths) {
+ packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -66,10 +66,10 @@
Implicits: deps,
})
- SignAppPackage(ctx, outputFile, unsignedApk, certificates)
+ SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile)
}
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath) {
var certificateArgs []string
var deps android.Paths
@@ -78,14 +78,22 @@
deps = append(deps, c.Pem, c.Key)
}
+ outputFiles := android.WritablePaths{signedApk}
+ var flag string = ""
+ if v4SignatureFile != nil {
+ outputFiles = append(outputFiles, v4SignatureFile)
+ flag = "--enable-v4"
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: Signapk,
Description: "signapk",
- Output: signedApk,
+ Outputs: outputFiles,
Input: unsignedApk,
Implicits: deps,
Args: map[string]string{
"certificates": strings.Join(certificateArgs, " "),
+ "flags": flag,
},
})
}
diff --git a/java/app_test.go b/java/app_test.go
index 0c6da7a..7b04e46 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -264,6 +264,108 @@
`)
}
+func TestUpdatableApps(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ expectedError string
+ }{
+ {
+ name: "Stable public SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "29",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "Stable system SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "system_29",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "Current public SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "Current system SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "system_current",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "Current module SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "module_current",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "Current core SDK",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "core_current",
+ updatable: true,
+ }`,
+ },
+ {
+ name: "No Platform APIs",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ platform_apis: true,
+ updatable: true,
+ }`,
+ expectedError: "Updatable apps must use stable SDKs",
+ },
+ {
+ name: "No Core Platform APIs",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "core_platform",
+ updatable: true,
+ }`,
+ expectedError: "Updatable apps must use stable SDKs",
+ },
+ {
+ name: "No unspecified APIs",
+ bp: `android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ }`,
+ expectedError: "Updatable apps must use stable SDK",
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ if test.expectedError == "" {
+ testJava(t, test.bp)
+ } else {
+ testJavaError(t, test.expectedError, test.bp)
+ }
+ })
+ }
+}
+
func TestResourceDirs(t *testing.T) {
testCases := []struct {
name string
@@ -791,6 +893,7 @@
cc_library {
name: "libjni",
system_shared_libs: [],
+ sdk_version: "current",
stl: "none",
}
@@ -928,26 +1031,26 @@
android_test {
name: "test",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
}
android_test {
name: "test_noembed",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
use_embedded_native_libs: false,
}
android_test_helper_app {
name: "test_helper",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
}
android_test_helper_app {
name: "test_helper_noembed",
- sdk_version: "core_platform",
+ sdk_version: "current",
jni_libs: ["libjni"],
use_embedded_native_libs: false,
}
@@ -979,6 +1082,10 @@
if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
t.Errorf("expected jni compressed %v, got %v", w, g)
}
+
+ if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") {
+ t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String())
+ }
}
})
}
@@ -1074,6 +1181,66 @@
}
}
+func TestRequestV4SigningFlag(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ expected string
+ }{
+ {
+ name: "default",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+ `,
+ expected: "",
+ },
+ {
+ name: "default",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ v4_signature: false,
+ }
+ `,
+ expected: "",
+ },
+ {
+ name: "module certificate property",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ v4_signature: true,
+ }
+ `,
+ expected: "--enable-v4",
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ config := testAppConfig(nil, test.bp, nil)
+ ctx := testContext()
+
+ run(t, ctx, config)
+ foo := ctx.ModuleForTests("foo", "android_common")
+
+ signapk := foo.Output("foo.apk")
+ signFlags := signapk.Args["flags"]
+ if test.expected != signFlags {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
+ }
+ })
+ }
+}
+
func TestPackageNameOverride(t *testing.T) {
testCases := []struct {
name string
@@ -2284,11 +2451,17 @@
}
func TestRuntimeResourceOverlay(t *testing.T) {
- ctx, config := testJava(t, `
+ fs := map[string][]byte{
+ "baz/res/res/values/strings.xml": nil,
+ "bar/res/res/values/strings.xml": nil,
+ }
+ bp := `
runtime_resource_overlay {
name: "foo",
certificate: "platform",
product_specific: true,
+ static_libs: ["bar"],
+ resource_libs: ["baz"],
aaptflags: ["--keep-raw-values"],
}
@@ -2298,7 +2471,21 @@
product_specific: true,
theme: "faza",
}
- `)
+
+ android_library {
+ name: "bar",
+ resource_dirs: ["bar/res"],
+ }
+
+ android_app {
+ name: "baz",
+ sdk_version: "current",
+ resource_dirs: ["baz/res"],
+ }
+ `
+ config := testAppConfig(nil, bp, fs)
+ ctx := testContext()
+ run(t, ctx, config)
m := ctx.ModuleForTests("foo", "android_common")
@@ -2310,6 +2497,19 @@
t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
}
+ // Check overlay.list output for static_libs dependency.
+ overlayList := m.Output("aapt2/overlay.list").Inputs.Strings()
+ staticLibPackage := buildDir + "/.intermediates/bar/android_common/package-res.apk"
+ if !inList(staticLibPackage, overlayList) {
+ t.Errorf("Stactic lib res package %q missing in overlay list: %q", staticLibPackage, overlayList)
+ }
+
+ // Check AAPT2 link flags for resource_libs dependency.
+ resourceLibFlag := "-I " + buildDir + "/.intermediates/baz/android_common/package-res.apk"
+ if !strings.Contains(aapt2Flags, resourceLibFlag) {
+ t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
+ }
+
// Check cert signing flag.
signedApk := m.Output("signed/foo.apk")
signingFlag := signedApk.Args["certificates"]
diff --git a/java/builder.go b/java/builder.go
index f9b5367..6844809 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -38,7 +38,8 @@
// 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.RemoteRuleSupports{Goma: true, RBE: true, RBEFlag: android.RBE_JAVAC},
+ // TODO(b/143658984): goma can't handle the --system argument to javac.
+ javac = pctx.AndroidRemoteStaticRule("javac", android.RemoteRuleSupports{Goma: false, 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 && ` +
@@ -146,7 +147,12 @@
jarjar = pctx.AndroidStaticRule("jarjar",
blueprint.RuleParams{
- Command: "${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JarjarCmd} process $rulesFile $in $out",
+ Command: "${config.JavaCmd} ${config.JavaVmFlags}" +
+ // b/146418363 Enable Android specific jarjar transformer to drop compat annotations
+ // for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
+ // avoids adding new hiddenapis after jarjar'ing.
+ " -DremoveAndroidCompatAnnotations=true" +
+ " -jar ${config.JarjarCmd} process $rulesFile $in $out",
CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
},
"rulesFile")
@@ -190,7 +196,7 @@
classpath classpath
java9Classpath classpath
processorPath classpath
- processor string
+ processors []string
systemModules *systemModules
aidlFlags string
aidlDeps android.Paths
@@ -264,8 +270,8 @@
deps = append(deps, flags.processorPath...)
processor := "-proc:none"
- if flags.processor != "" {
- processor = "-processor " + flags.processor
+ if len(flags.processors) > 0 {
+ processor = "-processor " + strings.Join(flags.processors, ",")
}
intermediatesDir := "xref"
@@ -379,8 +385,8 @@
deps = append(deps, flags.processorPath...)
processor := "-proc:none"
- if flags.processor != "" {
- processor = "-processor " + flags.processor
+ if len(flags.processors) > 0 {
+ processor = "-processor " + strings.Join(flags.processors, ",")
}
srcJarDir := "srcjars"
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 4313964..fba0b97 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -127,34 +127,37 @@
global := dexpreopt.GetGlobalConfig(ctx)
bootImage := defaultBootImageConfig(ctx)
dexFiles := bootImage.dexPathsDeps.Paths()
- dexLocations := bootImage.dexLocationsDeps
+ // The dex locations for all Android variants are identical.
+ dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
if global.UseArtImage {
bootImage = artBootImageConfig(ctx)
}
- var archs []android.ArchType
- for _, a := range ctx.MultiTargets() {
- archs = append(archs, a.Arch.ArchType)
- }
- if len(archs) == 0 {
+ targets := ctx.MultiTargets()
+ if len(targets) == 0 {
// assume this is a java library, dexpreopt for all arches for now
for _, target := range ctx.Config().Targets[android.Android] {
if target.NativeBridge == android.NativeBridgeDisabled {
- archs = append(archs, target.Arch.ArchType)
+ targets = append(targets, target)
}
}
if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary {
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
- archs = archs[:1]
+ targets = targets[:1]
}
}
+ var archs []android.ArchType
var images android.Paths
var imagesDeps []android.OutputPaths
- for _, arch := range archs {
- images = append(images, bootImage.images[arch])
- imagesDeps = append(imagesDeps, bootImage.imagesDeps[arch])
+ for _, target := range targets {
+ archs = append(archs, target.Arch.ArchType)
+ variant := bootImage.getVariant(target)
+ images = append(images, variant.images)
+ imagesDeps = append(imagesDeps, variant.imagesDeps)
}
+ // The image locations for all Android variants are identical.
+ imageLocations := bootImage.getAnyAndroidVariant().imageLocations()
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
@@ -198,7 +201,7 @@
Archs: archs,
DexPreoptImages: images,
DexPreoptImagesDeps: imagesDeps,
- DexPreoptImageLocations: bootImage.imageLocations,
+ DexPreoptImageLocations: imageLocations,
PreoptBootClassPathDexFiles: dexFiles,
PreoptBootClassPathDexLocations: dexLocations,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 655a476..c3825cb 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -26,31 +26,13 @@
)
func init() {
- android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+ RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
}
-// The image "location" is a symbolic path that with multiarchitecture
-// support doesn't really exist on the device. Typically it is
-// /system/framework/boot.art and should be the same for all supported
-// architectures on the device. The concrete architecture specific
-// content actually ends up in a "filename" that contains an
-// architecture specific directory name such as arm, arm64, mips,
-// mips64, x86, x86_64.
-//
-// Here are some example values for an x86_64 / x86 configuration:
-//
-// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
-// will then reconstruct the real path, so the rules must have a dependency on the real path.
-
+// Target-independent description of pre-compiled boot image.
type bootImageConfig struct {
- // Whether this image is an extension.
- extension bool
+ // If this image is an extension, the image that it extends.
+ extends *bootImageConfig
// Image name (used in directory names and ninja rule names).
name string
@@ -67,32 +49,64 @@
// Subdirectory where the image files are installed.
installSubdir string
- // Targets for which the image is generated.
- targets []android.Target
-
// The names of jars that constitute this image.
modules []string
- // The "locations" of jars.
- dexLocations []string // for this image
- dexLocationsDeps []string // for the dependency images and in this image
-
// File paths to jars.
dexPaths android.WritablePaths // for this image
dexPathsDeps android.WritablePaths // for the dependency images and in this image
- // The "locations" of the dependency images and in this image.
- imageLocations []string
-
- // Paths to image files (grouped by target).
- 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
+
+ // Rules which should be used in make to install the outputs.
+ profileInstalls android.RuleBuilderInstalls
+
+ // Target-dependent fields.
+ variants []*bootImageVariant
+}
+
+// Target-dependent description of pre-compiled boot image.
+type bootImageVariant struct {
+ *bootImageConfig
+
+ // Target for which the image is generated.
+ target android.Target
+
+ // The "locations" of jars.
+ dexLocations []string // for this image
+ dexLocationsDeps []string // for the dependency images and in this image
+
+ // Paths to image files.
+ images android.OutputPath // first image file
+ imagesDeps android.OutputPaths // all files
+
+ // Only for extensions, paths to the primary boot images.
+ primaryImages android.OutputPath
+
+ // Rules which should be used in make to install the outputs.
+ installs android.RuleBuilderInstalls
+ vdexInstalls android.RuleBuilderInstalls
+ unstrippedInstalls android.RuleBuilderInstalls
+}
+
+func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant {
+ for _, variant := range image.variants {
+ if variant.target.Os == target.Os && variant.target.Arch.ArchType == target.Arch.ArchType {
+ return variant
+ }
+ }
+ return nil
+}
+
+// Return any (the first) variant which is for the device (as opposed to for the host)
+func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
+ for _, variant := range image.variants {
+ if variant.target.Os == android.Android {
+ return variant
+ }
+ }
+ return nil
}
func (image bootImageConfig) moduleName(idx int) string {
@@ -101,7 +115,7 @@
// exists), and the rest are converted to 'name'-<jar>.art.
m := image.modules[idx]
name := image.stem
- if idx != 0 || image.extension {
+ if idx != 0 || image.extends != nil {
name += "-" + stemOf(m)
}
return name
@@ -126,26 +140,22 @@
return ret
}
-type bootImage struct {
- bootImageConfig
-
- installs map[android.ArchType]android.RuleBuilderInstalls
- vdexInstalls map[android.ArchType]android.RuleBuilderInstalls
- unstrippedInstalls map[android.ArchType]android.RuleBuilderInstalls
-
- profileInstalls android.RuleBuilderInstalls
-}
-
-func newBootImage(ctx android.PathContext, config bootImageConfig) *bootImage {
- image := &bootImage{
- bootImageConfig: config,
-
- installs: make(map[android.ArchType]android.RuleBuilderInstalls),
- vdexInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
- unstrippedInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
+// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
+// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the
+// same for all supported architectures on the device. The concrete architecture specific files
+// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64.
+//
+// For example a physical file
+// "/apex/com.android.art/javalib/x86/boot.art" has "image location"
+// "/apex/com.android.art/javalib/boot.art" (which is not an actual file).
+//
+// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
+// ART tools will then reconstruct the architecture-specific real path.
+func (image *bootImageVariant) imageLocations() (imageLocations []string) {
+ if image.extends != nil {
+ imageLocations = image.extends.getVariant(image.target).imageLocations()
}
-
- return image
+ return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
}
func concat(lists ...[]string) []string {
@@ -164,6 +174,10 @@
return &dexpreoptBootJars{}
}
+func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+}
+
func skipDexpreoptBootJars(ctx android.PathContext) bool {
if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
return true
@@ -173,17 +187,12 @@
return true
}
- if len(ctx.Config().Targets[android.Android]) == 0 {
- // Host-only build
- return true
- }
-
return false
}
type dexpreoptBootJars struct {
- defaultBootImage *bootImage
- otherImages []*bootImage
+ defaultBootImage *bootImageConfig
+ otherImages []*bootImageConfig
dexpreoptConfigForMake android.WritablePath
}
@@ -193,10 +202,14 @@
if skipDexpreoptBootJars(ctx) {
return nil
}
-
// Include dexpreopt files for the primary boot image.
- files := artBootImageConfig(ctx).imagesDeps
-
+ files := map[android.ArchType]android.OutputPaths{}
+ for _, variant := range artBootImageConfig(ctx).variants {
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
+ }
return files
}
@@ -233,18 +246,67 @@
dumpOatRules(ctx, d.defaultBootImage)
}
-// buildBootImage takes a bootImageConfig, creates rules to build it, and returns a *bootImage.
-func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootImage {
- image := newBootImage(ctx, config)
+// Inspect this module to see if it contains a bootclasspath dex jar.
+// Note that the same jar may occur in multiple modules.
+// This logic is tested in the apex package to avoid import cycle apex <-> java.
+func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
+ // All apex Java libraries have non-installable platform variants, skip them.
+ if module.IsSkipInstall() {
+ return -1, nil
+ }
+ jar, hasJar := module.(interface{ DexJar() android.Path })
+ if !hasJar {
+ return -1, nil
+ }
+
+ name := ctx.ModuleName(module)
+ index := android.IndexList(name, image.modules)
+ if index == -1 {
+ return -1, nil
+ }
+
+ // Check that this module satisfies constraints for a particular boot image.
+ apex, isApexModule := module.(android.ApexModule)
+ fromUpdatableApex := isApexModule && apex.Updatable()
+ if image.name == artBootImageName {
+ if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
+ // ok: found the jar in the ART apex
+ } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
+ // exception (skip and continue): special "hostdex" platform variant
+ return -1, nil
+ } else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+ // exception (skip and continue): Jacoco platform variant for a coverage build
+ return -1, nil
+ } else if fromUpdatableApex {
+ // error: this jar is part of an updatable apex other than ART
+ ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
+ } else {
+ // error: this jar is part of the platform or a non-updatable apex
+ ctx.Errorf("module '%s' is not allowed in the ART boot image", name)
+ }
+ } else if image.name == frameworkBootImageName {
+ if !fromUpdatableApex {
+ // ok: this jar is part of the platform or a non-updatable apex
+ } else {
+ // error: this jar is part of an updatable apex
+ ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
+ }
+ } else {
+ panic("unknown boot image: " + image.name)
+ }
+
+ return index, jar.DexJar()
+}
+
+// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
+func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
+ // Collect dex jar paths for the boot image modules.
+ // This logic is tested in the apex package to avoid import cycle apex <-> java.
bootDexJars := make(android.Paths, len(image.modules))
ctx.VisitAllModules(func(module android.Module) {
- // Collect dex jar paths for the modules listed above.
- if j, ok := module.(interface{ DexJar() android.Path }); ok {
- name := ctx.ModuleName(module)
- if i := android.IndexList(name, image.modules); i != -1 {
- bootDexJars[i] = j.DexJar()
- }
+ if i, j := getBootImageJar(ctx, image, module); i != -1 {
+ bootDexJars[i] = j
}
})
@@ -256,7 +318,8 @@
missingDeps = append(missingDeps, image.modules[i])
bootDexJars[i] = android.PathForOutput(ctx, "missing")
} else {
- ctx.Errorf("failed to find dex jar path for module %q",
+ ctx.Errorf("failed to find a dex jar path for module '%s'"+
+ ", note that some jars may be filtered out by module constraints",
image.modules[i])
}
}
@@ -275,10 +338,11 @@
profile := bootImageProfileRule(ctx, image, missingDeps)
bootFrameworkProfileRule(ctx, image, missingDeps)
+ updatableBcpPackagesRule(ctx, image, missingDeps)
var allFiles android.Paths
- for _, target := range image.targets {
- files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+ for _, variant := range image.variants {
+ files := buildBootImageVariant(ctx, variant, profile, missingDeps)
allFiles = append(allFiles, files.Paths()...)
}
@@ -296,15 +360,17 @@
return image
}
-func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage,
- arch android.ArchType, profile android.Path, missingDeps []string) android.WritablePaths {
+func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant,
+ profile android.Path, missingDeps []string) android.WritablePaths {
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
- symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
+ arch := image.target.Arch.ArchType
+ os := image.target.Os.String() // We need to distinguish host-x86 and device-x86.
+ symbolsDir := image.symbolsDir.Join(ctx, os, image.installSubdir, arch.String())
symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
- outputDir := image.dir.Join(ctx, image.installSubdir, arch.String())
+ outputDir := image.dir.Join(ctx, os, image.installSubdir, arch.String())
outputPath := outputDir.Join(ctx, image.stem+".oat")
oatLocation := dexpreopt.PathToLocation(outputPath, arch)
imagePath := outputPath.ReplaceExtension(ctx, "art")
@@ -350,8 +416,8 @@
cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path())
}
- if image.extension {
- artImage := image.primaryImages[arch]
+ if image.extends != nil {
+ artImage := image.primaryImages
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
@@ -372,12 +438,18 @@
FlagWithArg("--oat-location=", oatLocation).
FlagWithArg("--image=", imagePath.String()).
FlagWithArg("--instruction-set=", arch.String()).
- FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
- FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
FlagWithArg("--android-root=", global.EmptyDirectory).
FlagWithArg("--no-inline-from=", "core-oj.jar").
+ Flag("--force-determinism").
Flag("--abort-on-hard-verifier-error")
+ // Use the default variant/features for host builds.
+ // The map below contains only device CPU info (which might be x86 on some devices).
+ if image.target.Os == android.Android {
+ cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch])
+ cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
+ }
+
if global.BootFlags != "" {
cmd.Flag(global.BootFlags)
}
@@ -389,7 +461,6 @@
cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
installDir := filepath.Join("/", image.installSubdir, arch.String())
- vdexInstallDir := filepath.Join("/", image.installSubdir)
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
@@ -408,11 +479,10 @@
cmd.ImplicitOutput(vdex)
zipFiles = append(zipFiles, vdex)
- // The vdex files are identical between architectures, install them to a shared location. The Make rules will
- // only use the install rules for one architecture, and will create symlinks into the architecture-specific
- // directories.
+ // Note that the vdex files are identical between architectures.
+ // Make rules will create symlinks to share them between architectures.
vdexInstalls = append(vdexInstalls,
- android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())})
+ android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())})
}
for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") {
@@ -423,12 +493,12 @@
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
- rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String())
+ rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
- image.installs[arch] = rule.Installs()
- image.vdexInstalls[arch] = vdexInstalls
- image.unstrippedInstalls[arch] = unstrippedInstalls
+ image.installs = rule.Installs()
+ image.vdexInstalls = vdexInstalls
+ image.unstrippedInstalls = unstrippedInstalls
return zipFiles
}
@@ -437,7 +507,7 @@
It is likely that the boot classpath is inconsistent.
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 {
+func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
@@ -473,7 +543,7 @@
Tool(globalSoong.Profman).
FlagWithInput("--create-profile-from=", bootImageProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+ FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.prof")
@@ -492,7 +562,7 @@
var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
-func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, missingDeps []string) android.WritablePath {
+func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
@@ -524,7 +594,7 @@
Flag("--generate-boot-profile").
FlagWithInput("--create-profile-from=", bootFrameworkProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+ FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.bprof")
@@ -537,36 +607,91 @@
var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
-func dumpOatRules(ctx android.SingletonContext, image *bootImage) {
- var archs []android.ArchType
- for arch := range image.images {
- archs = append(archs, arch)
+func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+ if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+ return nil
}
- sort.Slice(archs, func(i, j int) bool { return archs[i].String() < archs[j].String() })
+ return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+
+ // Collect `permitted_packages` for updatable boot jars.
+ var updatablePackages []string
+ ctx.VisitAllModules(func(module android.Module) {
+ if j, ok := module.(*Library); ok {
+ name := ctx.ModuleName(module)
+ if i := android.IndexList(name, updatableModules); i != -1 {
+ pp := j.properties.Permitted_packages
+ if len(pp) > 0 {
+ updatablePackages = append(updatablePackages, pp...)
+ } else {
+ ctx.Errorf("Missing permitted_packages for %s", name)
+ }
+ // Do not match the same library repeatedly.
+ updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
+ }
+ }
+ })
+
+ // Sort updatable packages to ensure deterministic ordering.
+ sort.Strings(updatablePackages)
+
+ updatableBcpPackagesName := "updatable-bcp-packages.txt"
+ updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.WriteFile,
+ Output: updatableBcpPackages,
+ Args: map[string]string{
+ // WriteFile automatically adds the last end-of-line.
+ "content": strings.Join(updatablePackages, "\\n"),
+ },
+ })
+
+ rule := android.NewRuleBuilder()
+ rule.MissingDeps(missingDeps)
+ rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
+ // TODO: Rename `profileInstalls` to `extraInstalls`?
+ // Maybe even move the field out of the bootImageConfig into some higher level type?
+ image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+
+ return updatableBcpPackages
+ }).(android.WritablePath)
+}
+
+var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule")
+
+func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
var allPhonies android.Paths
- for _, arch := range archs {
+ for _, image := range image.variants {
+ arch := image.target.Arch.ArchType
+ suffix := arch.String()
+ // Host and target might both use x86 arch. We need to ensure the names are unique.
+ if image.target.Os.Class == android.Host {
+ suffix = "host-" + suffix
+ }
// Create a rule to call oatdump.
- output := android.PathForOutput(ctx, "boot."+arch.String()+".oatdump.txt")
+ output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
rule := android.NewRuleBuilder()
rule.Command().
// TODO: for now, use the debug version for better error reporting
BuiltTool(ctx, "oatdumpd").
FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps[arch].Paths()).
+ FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
- rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
// Create a phony rule that depends on the output file and prints the path.
- phony := android.PathForPhony(ctx, "dump-oat-boot-"+arch.String())
+ phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
rule = android.NewRuleBuilder()
rule.Command().
Implicit(output).
ImplicitOutput(phony).
Text("echo").FlagWithArg("Output in ", output.String())
- rule.Build(pctx, ctx, "phony-dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
allPhonies = append(allPhonies, phony)
}
@@ -604,28 +729,25 @@
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " "))
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " "))
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " "))
var imageNames []string
for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
- var arches []android.ArchType
- for arch, _ := range current.images {
- arches = append(arches, arch)
+ for _, variant := range current.variants {
+ suffix := ""
+ if variant.target.Os.Class == android.Host {
+ suffix = "_host"
+ }
+ sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String()
+ ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String())
+ ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String())
+ ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
+ ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
+ ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
}
-
- sort.Slice(arches, func(i, j int) bool { return arches[i].String() < arches[j].String() })
-
- for _, arch := range arches {
- sfx := current.name + "_" + arch.String()
- ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls[arch].String())
- ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images[arch].String())
- ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps[arch].Strings(), " "))
- ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs[arch].String())
- ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls[arch].String())
- }
-
- ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":"))
+ imageLocations := current.getAnyAndroidVariant().imageLocations()
+ ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":"))
ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
}
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index c3b2133..127c201 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -53,7 +53,7 @@
ctx := testContext()
- ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+ RegisterDexpreoptBootJarsComponents(ctx)
run(t, ctx, config)
@@ -62,7 +62,7 @@
bootArt := dexpreoptBootJars.Output("boot-foo.art")
expectedInputs := []string{
- "dex_artjars/apex/com.android.art/javalib/arm64/boot.art",
+ "dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
"dex_bootjars_input/foo.jar",
"dex_bootjars_input/bar.jar",
"dex_bootjars_input/baz.jar",
@@ -81,23 +81,23 @@
}
expectedOutputs := []string{
- "dex_bootjars/system/framework/arm64/boot.invocation",
+ "dex_bootjars/android/system/framework/arm64/boot.invocation",
- "dex_bootjars/system/framework/arm64/boot-foo.art",
- "dex_bootjars/system/framework/arm64/boot-bar.art",
- "dex_bootjars/system/framework/arm64/boot-baz.art",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.art",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.art",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.art",
- "dex_bootjars/system/framework/arm64/boot-foo.oat",
- "dex_bootjars/system/framework/arm64/boot-bar.oat",
- "dex_bootjars/system/framework/arm64/boot-baz.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.oat",
- "dex_bootjars/system/framework/arm64/boot-foo.vdex",
- "dex_bootjars/system/framework/arm64/boot-bar.vdex",
- "dex_bootjars/system/framework/arm64/boot-baz.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
- "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
}
for i := range expectedOutputs {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 28f56d2..066694c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -30,9 +30,9 @@
return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
global := dexpreopt.GetGlobalConfig(ctx)
var systemServerClasspathLocations []string
- var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
- // 1) The jars that are dexpreopted.
- for _, m := range dexpreoptJars {
+ nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
+ // 1) Non-updatable jars.
+ for _, m := range nonUpdatable {
systemServerClasspathLocations = append(systemServerClasspathLocations,
filepath.Join("/system/framework", m+".jar"))
}
@@ -41,13 +41,6 @@
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),
@@ -68,6 +61,10 @@
targets = append(targets, target)
}
}
+ // We may also need the images on host in order to run host-based tests.
+ for _, target := range ctx.Config().Targets[android.BuildOs] {
+ targets = append(targets, target)
+ }
return targets
}
@@ -82,6 +79,14 @@
return moduleName
}
+func getDexLocation(ctx android.PathContext, target android.Target, subdir string, name string) string {
+ if target.Os.Class == android.Host {
+ return filepath.Join(ctx.Config().Getenv("OUT_DIR"), "host", ctx.Config().PrebuiltOS(), subdir, name)
+ } else {
+ return filepath.Join("/", subdir, name)
+ }
+}
+
var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
artBootImageName = "art"
@@ -107,36 +112,23 @@
artSubdir := "apex/com.android.art/javalib"
frameworkSubdir := "system/framework"
- var artLocations, frameworkLocations []string
- for _, m := range artModules {
- artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar"))
- }
- for _, m := range frameworkModules {
- frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar"))
- }
-
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
- extension: false,
- name: artBootImageName,
- stem: "boot",
- installSubdir: artSubdir,
- modules: artModules,
- dexLocations: artLocations,
- dexLocationsDeps: artLocations,
+ name: artBootImageName,
+ stem: "boot",
+ installSubdir: artSubdir,
+ modules: artModules,
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
frameworkCfg := bootImageConfig{
- extension: true,
- name: frameworkBootImageName,
- stem: "boot",
- installSubdir: frameworkSubdir,
- modules: frameworkModules,
- dexLocations: frameworkLocations,
- dexLocationsDeps: append(artLocations, frameworkLocations...),
+ extends: &artCfg,
+ name: frameworkBootImageName,
+ stem: "boot",
+ installSubdir: frameworkSubdir,
+ modules: frameworkModules,
}
configs := map[string]*bootImageConfig{
@@ -146,16 +138,12 @@
// common to all configs
for _, c := range configs {
- c.targets = targets
-
c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
imageName := c.firstModuleNameOrStem() + ".art"
- c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()}
-
// The path to bootclasspath dex files needs to be known at module
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
// Set up known paths for them, the singleton rules will copy them there.
@@ -166,14 +154,21 @@
}
c.dexPathsDeps = c.dexPaths
- c.images = make(map[android.ArchType]android.OutputPath)
- c.imagesDeps = make(map[android.ArchType]android.OutputPaths)
-
+ // Create target-specific variants.
for _, target := range targets {
arch := target.Arch.ArchType
- imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
- c.images[arch] = imageDir.Join(ctx, imageName)
- c.imagesDeps[arch] = c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex")
+ imageDir := c.dir.Join(ctx, target.Os.String(), c.installSubdir, arch.String())
+ variant := &bootImageVariant{
+ bootImageConfig: c,
+ target: target,
+ images: imageDir.Join(ctx, imageName),
+ imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
+ }
+ for _, m := range c.modules {
+ variant.dexLocations = append(variant.dexLocations, getDexLocation(ctx, target, c.installSubdir, stemOf(m)+".jar"))
+ }
+ variant.dexLocationsDeps = variant.dexLocations
+ c.variants = append(c.variants, variant)
}
c.zip = c.dir.Join(ctx, c.name+".zip")
@@ -181,19 +176,21 @@
// specific to the framework config
frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
- frameworkCfg.primaryImages = artCfg.images
- frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
+ for i := range targets {
+ frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
+ frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
+ }
return configs
}).(map[string]*bootImageConfig)
}
-func artBootImageConfig(ctx android.PathContext) bootImageConfig {
- return *genBootImageConfigs(ctx)[artBootImageName]
+func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
+ return genBootImageConfigs(ctx)[artBootImageName]
}
-func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
- return *genBootImageConfigs(ctx)[frameworkBootImageName]
+func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
+ return genBootImageConfigs(ctx)[frameworkBootImageName]
}
func defaultBootclasspath(ctx android.PathContext) []string {
@@ -206,7 +203,7 @@
updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
}
- bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...)
+ bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
return bootclasspath
})
}
@@ -221,7 +218,7 @@
func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
- ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":"))
+ ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":"))
ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
diff --git a/java/droiddoc.go b/java/droiddoc.go
index fd4b90d..8df3c2d 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -177,37 +177,15 @@
// filegroup or genrule can be included within this property.
Knowntags []string `android:"path"`
- // the tag name used to distinguish if the API files belong to public/system/test.
- Api_tag_name *string
-
// the generated public API filename by Doclava.
Api_filename *string
- // the generated public Dex API filename by Doclava.
- Dex_api_filename *string
-
- // the generated private API filename by Doclava.
- Private_api_filename *string
-
- // the generated private Dex API filename by Doclava.
- Private_dex_api_filename *string
-
// the generated removed API filename by Doclava.
Removed_api_filename *string
// the generated removed Dex API filename by Doclava.
Removed_dex_api_filename *string
- // mapping of dex signatures to source file and line number. This is a temporary property and
- // will be deleted; you probably shouldn't be using it.
- Dex_mapping_filename *string
-
- // the generated exact API filename by Doclava.
- Exact_api_filename *string
-
- // the generated proguard filename by Doclava.
- Proguard_filename *string
-
// if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
Create_stubs *bool
@@ -229,37 +207,15 @@
}
type DroidstubsProperties struct {
- // the tag name used to distinguish if the API files belong to public/system/test.
- Api_tag_name *string
-
// the generated public API filename by Metalava.
Api_filename *string
- // the generated public Dex API filename by Metalava.
- Dex_api_filename *string
-
- // the generated private API filename by Metalava.
- Private_api_filename *string
-
- // the generated private Dex API filename by Metalava.
- Private_dex_api_filename *string
-
// the generated removed API filename by Metalava.
Removed_api_filename *string
// the generated removed Dex API filename by Metalava.
Removed_dex_api_filename *string
- // mapping of dex signatures to source file and line number. This is a temporary property and
- // will be deleted; you probably shouldn't be using it.
- Dex_mapping_filename *string
-
- // the generated exact API filename by Metalava.
- Exact_api_filename *string
-
- // the generated proguard filename by Metalava.
- Proguard_filename *string
-
Check_api struct {
Last_released ApiToCheck
@@ -301,6 +257,11 @@
// if set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
Create_doc_stubs *bool
+ // if set to false then do not write out stubs. Defaults to true.
+ //
+ // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
+ Generate_stubs *bool
+
// is set to true, Metalava will allow framework SDK to contain API levels annotations.
Api_levels_annotations_enabled *bool
@@ -370,10 +331,18 @@
apiToCheck.Removed_api_file = nil
}
+// Used by xsd_config
type ApiFilePath interface {
ApiFilePath() android.Path
}
+// Provider of information about API stubs, used by java_sdk_library.
+type ApiStubsProvider interface {
+ ApiFilePath
+ RemovedApiFilePath() android.Path
+ StubsSrcJar() android.Path
+}
+
//
// Javadoc
//
@@ -718,14 +687,9 @@
properties DroiddocProperties
apiFile android.WritablePath
- dexApiFile android.WritablePath
privateApiFile android.WritablePath
- privateDexApiFile android.WritablePath
removedApiFile android.WritablePath
removedDexApiFile android.WritablePath
- exactApiFile android.WritablePath
- apiMappingFile android.WritablePath
- proguardFile android.WritablePath
checkCurrentApiTimestamp android.WritablePath
updateCurrentApiTimestamp android.WritablePath
@@ -773,6 +737,7 @@
}
func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
+ buildNumberFile := ctx.Config().BuildNumberFile(ctx)
// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9
// sources, droiddoc will get sources produced by metalava which will have already stripped out the
// 1.9 language features.
@@ -782,7 +747,7 @@
Flag("-XDignore.symbol.file").
FlagWithArg("-doclet ", "com.google.doclava.Doclava").
FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
- FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()).
+ FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
if String(d.properties.Custom_template) == "" {
@@ -862,41 +827,11 @@
cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
}
- if String(d.properties.Private_api_filename) != "" {
- d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
- cmd.FlagWithOutput("-privateApi ", d.privateApiFile)
- }
-
- if String(d.properties.Dex_api_filename) != "" {
- d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
- cmd.FlagWithOutput("-dexApi ", d.dexApiFile)
- }
-
- if String(d.properties.Private_dex_api_filename) != "" {
- d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
- cmd.FlagWithOutput("-privateDexApi ", d.privateDexApiFile)
- }
-
if String(d.properties.Removed_dex_api_filename) != "" {
d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
}
- if String(d.properties.Exact_api_filename) != "" {
- d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
- cmd.FlagWithOutput("-exactApi ", d.exactApiFile)
- }
-
- if String(d.properties.Dex_mapping_filename) != "" {
- d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
- cmd.FlagWithOutput("-apiMapping ", d.apiMappingFile)
- }
-
- if String(d.properties.Proguard_filename) != "" {
- d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
- cmd.FlagWithOutput("-proguard ", d.proguardFile)
- }
-
if BoolDefault(d.properties.Create_stubs, true) {
cmd.FlagWithArg("-stubs ", stubsDir.String())
}
@@ -1196,14 +1131,9 @@
apiFile android.WritablePath
apiXmlFile android.WritablePath
lastReleasedApiXmlFile android.WritablePath
- dexApiFile android.WritablePath
privateApiFile android.WritablePath
- privateDexApiFile android.WritablePath
removedApiFile android.WritablePath
removedDexApiFile android.WritablePath
- apiMappingFile android.WritablePath
- exactApiFile android.WritablePath
- proguardFile android.WritablePath
nullabilityWarningsFile android.WritablePath
checkCurrentApiTimestamp android.WritablePath
@@ -1258,6 +1188,14 @@
return d.apiFilePath
}
+func (d *Droidstubs) RemovedApiFilePath() android.Path {
+ return d.removedApiFile
+}
+
+func (d *Droidstubs) StubsSrcJar() android.Path {
+ return d.stubsSrcJar
+}
+
func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
d.Javadoc.addDeps(ctx)
@@ -1284,7 +1222,7 @@
}
}
-func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
@@ -1300,50 +1238,23 @@
cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
}
- if String(d.properties.Private_api_filename) != "" {
- d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
- cmd.FlagWithOutput("--private-api ", d.privateApiFile)
- }
-
- if String(d.properties.Dex_api_filename) != "" {
- d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
- cmd.FlagWithOutput("--dex-api ", d.dexApiFile)
- }
-
- if String(d.properties.Private_dex_api_filename) != "" {
- d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
- cmd.FlagWithOutput("--private-dex-api ", d.privateDexApiFile)
- }
-
if String(d.properties.Removed_dex_api_filename) != "" {
d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile)
}
- if String(d.properties.Exact_api_filename) != "" {
- d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
- cmd.FlagWithOutput("--exact-api ", d.exactApiFile)
- }
-
- if String(d.properties.Dex_mapping_filename) != "" {
- d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
- cmd.FlagWithOutput("--dex-api-mapping ", d.apiMappingFile)
- }
-
- if String(d.properties.Proguard_filename) != "" {
- d.proguardFile = android.PathForModuleOut(ctx, String(d.properties.Proguard_filename))
- cmd.FlagWithOutput("--proguard ", d.proguardFile)
- }
-
if Bool(d.properties.Write_sdk_values) {
d.metadataDir = android.PathForModuleOut(ctx, "metadata")
cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
}
- if Bool(d.properties.Create_doc_stubs) {
- cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
- } else {
- cmd.FlagWithArg("--stubs ", stubsDir.String())
+ if stubsDir.Valid() {
+ if Bool(d.properties.Create_doc_stubs) {
+ cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
+ } else {
+ cmd.FlagWithArg("--stubs ", stubsDir.String())
+ cmd.Flag("--exclude-documentation-from-stubs")
+ }
}
}
@@ -1500,15 +1411,18 @@
// Create rule for metalava
- d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
- stubsDir := android.PathForModuleOut(ctx, "stubsDir")
rule := android.NewRuleBuilder()
- rule.Command().Text("rm -rf").Text(stubsDir.String())
- rule.Command().Text("mkdir -p").Text(stubsDir.String())
+ generateStubs := BoolDefault(d.properties.Generate_stubs, true)
+ var stubsDir android.OptionalPath
+ if generateStubs {
+ d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
+ stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "stubsDir"))
+ rule.Command().Text("rm -rf").Text(stubsDir.String())
+ rule.Command().Text("mkdir -p").Text(stubsDir.String())
+ }
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
@@ -1534,13 +1448,15 @@
cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
}
- rule.Command().
- BuiltTool(ctx, "soong_zip").
- Flag("-write_if_changed").
- Flag("-jar").
- FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
- FlagWithArg("-C ", stubsDir.String()).
- FlagWithArg("-D ", stubsDir.String())
+ if generateStubs {
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+ FlagWithArg("-C ", stubsDir.String()).
+ FlagWithArg("-D ", stubsDir.String())
+ }
if Bool(d.properties.Write_sdk_values) {
d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip")
@@ -2039,18 +1955,33 @@
return ok
}
-func (mt *droidStubsSdkMemberType) 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())
+func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
+}
+
+func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &droidStubsInfoProperties{}
+}
+
+type droidStubsInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ StubsSrcJar android.Path
+}
+
+func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ droidstubs := variant.(*Droidstubs)
+ p.StubsSrcJar = droidstubs.stubsSrcJar
+}
+
+func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if p.StubsSrcJar != nil {
+ builder := ctx.SnapshotBuilder()
+
+ snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
+
+ builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
+
+ propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
}
- variant := variants[0]
- d, _ := variant.(*Droidstubs)
- stubsSrcJar := d.stubsSrcJar
-
- snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
- builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
-
- pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
- pbm.AddProperty("srcs", []string{snapshotRelativeDir})
}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7e7e955..c7f7cbd 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -211,23 +211,30 @@
// the greylists.
func flagsRule(ctx android.SingletonContext) android.Path {
var flagsCSV android.Paths
-
- var greylistIgnoreConflicts android.Path
+ var greylistRemovedApis android.Paths
ctx.VisitAllModules(func(module android.Module) {
if h, ok := module.(hiddenAPIIntf); ok {
if csv := h.flagsCSV(); csv != nil {
flagsCSV = append(flagsCSV, csv)
}
- } else if ds, ok := module.(*Droidstubs); ok && ctx.ModuleName(module) == "hiddenapi-lists-docs" {
- greylistIgnoreConflicts = ds.removedDexApiFile
+ } else if ds, ok := module.(*Droidstubs); ok {
+ // Track @removed public and system APIs via corresponding droidstubs targets.
+ // These APIs are not present in the stubs, however, we have to keep allowing access
+ // to them at runtime.
+ if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" {
+ greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile)
+ }
}
})
- if greylistIgnoreConflicts == nil {
- ctx.Errorf("failed to find removed_dex_api_filename from hiddenapi-lists-docs module")
- return nil
- }
+ combinedRemovedApis := android.PathForOutput(ctx, "hiddenapi", "combined-removed-dex.txt")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cat,
+ Inputs: greylistRemovedApis,
+ Output: combinedRemovedApis,
+ Description: "Combine removed apis for " + combinedRemovedApis.String(),
+ })
rule := android.NewRuleBuilder()
@@ -242,8 +249,7 @@
Inputs(flagsCSV).
FlagWithInput("--greylist ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")).
- FlagWithInput("--greylist-ignore-conflicts ",
- greylistIgnoreConflicts).
+ FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis).
FlagWithInput("--greylist-max-q ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")).
FlagWithInput("--greylist-max-p ",
diff --git a/java/java.go b/java/java.go
index b3aca49..38f485e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,14 +23,12 @@
"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"
)
@@ -41,11 +39,17 @@
// Register sdk member types.
android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
- android.RegisterSdkMemberType(&implLibrarySdkMemberType{
- librarySdkMemberType{
- android.SdkMemberTypeBase{
- PropertyName: "java_libs",
- },
+ android.RegisterSdkMemberType(&librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_libs",
+ },
+ func(j *Library) android.Path {
+ implementationJars := j.ImplementationJars()
+ if len(implementationJars) != 1 {
+ panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ }
+
+ return implementationJars[0]
},
})
@@ -54,8 +58,6 @@
PropertyName: "java_tests",
},
})
-
- android.PostDepsMutators(RegisterPostDepsMutators)
}
func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
@@ -84,45 +86,7 @@
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) {
+func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
if j.SocSpecific() || j.DeviceSpecific() ||
(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
if sc, ok := ctx.Module().(sdkContext); ok {
@@ -132,6 +96,18 @@
}
}
}
+
+ ctx.VisitDirectDeps(func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ switch module.(type) {
+ // TODO(satayev): cover other types as well, e.g. imports
+ case *Library, *AndroidLibrary:
+ switch tag {
+ case bootClasspathTag, libTag, staticLibTag, java9LibTag:
+ checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag))
+ }
+ }
+ })
}
func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
@@ -361,6 +337,10 @@
UncompressDex bool `blueprint:"mutated"`
IsSDKLibrary bool `blueprint:"mutated"`
+
+ // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
+ // Defaults to false.
+ V4_signature *bool
}
func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
@@ -457,6 +437,8 @@
// list of the xref extraction files
kytheFiles android.Paths
+
+ distFile android.Path
}
func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -576,9 +558,10 @@
}
type jniLib struct {
- name string
- path android.Path
- target android.Target
+ name string
+ path android.Path
+ target android.Target
+ coverageFile android.OptionalPath
}
func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
@@ -705,11 +688,6 @@
} 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 {
@@ -841,7 +819,7 @@
return javaModule, true
case ver.kind == sdkModule:
return javaModule, false
- case name == "services-stubs":
+ case name == "android_system_server_stubs_current":
return javaSystemServer, true
case ver.kind == sdkSystemServer:
return javaSystemServer, false
@@ -932,15 +910,7 @@
// Handled by AndroidApp.collectAppDeps
return
}
- switch module.(type) {
- case *Library, *AndroidLibrary:
- if to, ok := module.(linkTypeContext); ok {
- switch tag {
- case bootClasspathTag, libTag, staticLibTag:
- checkLinkType(ctx, j, to, tag.(dependencyTag))
- }
- }
- }
+
switch dep := module.(type) {
case SdkLibraryDependency:
switch tag {
@@ -1164,7 +1134,8 @@
flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
- flags.processor = strings.Join(deps.processorClasses, ",")
+ flags.processors = append(flags.processors, deps.processorClasses...)
+ flags.processors = android.FirstUniqueStrings(flags.processors)
if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() {
@@ -1299,7 +1270,7 @@
srcJars = append(srcJars, kaptSrcJar)
// Disable annotation processing in javac, it's already been handled by kapt
flags.processorPath = nil
- flags.processor = ""
+ flags.processors = nil
}
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
@@ -1323,6 +1294,7 @@
j.compiledSrcJars = srcJars
enable_sharding := false
+ var headerJarFileWithoutJarjar android.Path
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enable_sharding = true
@@ -1332,7 +1304,8 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- j.headerJarFile = j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
+ headerJarFileWithoutJarjar, j.headerJarFile =
+ j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
if ctx.Failed() {
return
}
@@ -1351,7 +1324,7 @@
}
if enable_sharding {
- flags.classpath = append(flags.classpath, j.headerJarFile)
+ flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
@@ -1650,7 +1623,8 @@
}
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
- deps deps, flags javaBuilderFlags, jarName string, extraJars android.Paths) android.Path {
+ deps deps, flags javaBuilderFlags, jarName string,
+ extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1658,7 +1632,7 @@
turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
if ctx.Failed() {
- return nil
+ return nil, nil
}
jars = append(jars, turbineJar)
}
@@ -1667,7 +1641,6 @@
// Combine any static header libraries into classes-header.jar. If there is only
// one input jar this step will be skipped.
- var headerJar android.Path
jars = append(jars, deps.staticHeaderJars...)
// we cannot skip the combine step for now if there is only one jar
@@ -1676,18 +1649,19 @@
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
headerJar = combinedJar
+ jarjarHeaderJar = combinedJar
if j.expandJarjarRules != nil {
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
- headerJar = jarjarFile
+ jarjarHeaderJar = jarjarFile
if ctx.Failed() {
- return nil
+ return nil, nil
}
}
- return headerJar
+ return headerJar, jarjarHeaderJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1787,11 +1761,11 @@
}
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
- // 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()
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
+ return false
}
func (j *Module) Stem() string {
@@ -1810,9 +1784,18 @@
// Java libraries (.jar file)
//
+type LibraryProperties struct {
+ Dist struct {
+ // The tag of the output of this module that should be output.
+ Tag *string `android:"arch_variant"`
+ } `android:"arch_variant"`
+}
+
type Library struct {
Module
+ libraryProperties LibraryProperties
+
InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
}
@@ -1840,7 +1823,7 @@
}
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- j.checkSdkVersion(ctx)
+ j.checkSdkVersions(ctx)
j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
@@ -1856,6 +1839,15 @@
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
}
+
+ // Verify Dist.Tag is set to a supported output
+ if j.libraryProperties.Dist.Tag != nil {
+ distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag)
+ if err != nil {
+ ctx.PropertyErrorf("dist.tag", "%s", err.Error())
+ }
+ j.distFile = distFiles[0]
+ }
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1870,16 +1862,20 @@
)
// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(member android.SdkMember) string {
- return sdkSnapshotFilePathForMember(member, jarFileSuffix)
+func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+ return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
}
-func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
- return filepath.Join(javaDir, member.Name()+suffix)
+func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
+ return filepath.Join(javaDir, osPrefix, name+suffix)
}
type librarySdkMemberType struct {
android.SdkMemberTypeBase
+
+ // Function to retrieve the appropriate output jar (implementation or header) from
+ // the library.
+ jarToExportGetter func(j *Library) android.Path
}
func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
@@ -1891,75 +1887,67 @@
return ok
}
-func (mt *librarySdkMemberType) buildSnapshot(
- sdkModuleContext android.ModuleContext,
- builder android.SnapshotBuilder,
- member android.SdkMember,
- jarToExportGetter func(j *Library) android.Path) {
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
+}
- 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]
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &librarySdkMemberProperties{}
+}
+
+type librarySdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ JarToExport android.Path
+ AidlIncludeDirs android.Paths
+}
+
+func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
j := variant.(*Library)
- exportedJar := jarToExportGetter(j)
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+ p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
+ p.AidlIncludeDirs = j.AidlIncludeDirs()
+}
- for _, dir := range j.AidlIncludeDirs() {
- // TODO(jiyong): copy parcelable declarations only
- aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
- for _, file := range aidlFiles {
- builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
- }
+func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ builder := ctx.SnapshotBuilder()
+
+ exportedJar := p.JarToExport
+ if exportedJar != nil {
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
- module := builder.AddPrebuiltModule(member, "java_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ aidlIncludeDirs := p.AidlIncludeDirs
+ if len(aidlIncludeDirs) != 0 {
+ sdkModuleContext := ctx.SdkModuleContext()
+ for _, dir := range aidlIncludeDirs {
+ // TODO(jiyong): copy parcelable declarations only
+ aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+ for _, file := range aidlFiles {
+ builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+ }
+ }
+
+ // TODO(b/151933053) - add aidl include dirs property
+ }
}
-var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
- librarySdkMemberType{
- android.SdkMemberTypeBase{
- PropertyName: "java_header_libs",
- SupportsSdk: true,
- },
+var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_header_libs",
+ SupportsSdk: true,
},
-}
-
-type headerLibrarySdkMemberType struct {
- librarySdkMemberType
-}
-
-func (mt *headerLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
+ func(j *Library) android.Path {
headerJars := j.HeaderJars()
if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
}
return headerJars[0]
- })
-}
-
-type implLibrarySdkMemberType struct {
- librarySdkMemberType
-}
-
-func (mt *implLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
- mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
- implementationJars := j.ImplementationJars()
- if len(implementationJars) != 1 {
- panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
- }
-
- return implementationJars[0]
- })
+ },
}
// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
@@ -1980,7 +1968,8 @@
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.dexpreoptProperties,
- &module.Module.protoProperties)
+ &module.Module.protoProperties,
+ &module.libraryProperties)
android.InitApexModule(module)
android.InitSdkAwareModule(module)
@@ -2109,31 +2098,50 @@
return ok
}
-func (mt *testSdkMemberType) 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]
- j := variant.(*Test)
+func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
+}
- implementationJars := j.ImplementationJars()
+func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &testSdkMemberProperties{}
+}
+
+type testSdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ JarToExport android.Path
+ TestConfig android.Path
+}
+
+func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ test := variant.(*Test)
+
+ implementationJars := test.ImplementationJars()
if len(implementationJars) != 1 {
- panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
}
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
- builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
+ p.JarToExport = implementationJars[0]
+ p.TestConfig = test.testConfig
+}
- snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
- builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
+func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ builder := ctx.SnapshotBuilder()
- module := builder.AddPrebuiltModule(member, "java_test_import")
- module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
- module.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ exportedJar := p.JarToExport
+ if exportedJar != nil {
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+ propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+ }
+
+ testConfig := p.TestConfig
+ if testConfig != nil {
+ snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
+ builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
+ propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
+ }
}
// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@@ -2336,7 +2344,7 @@
//
type ImportProperties struct {
- Jars []string `android:"path"`
+ Jars []string `android:"path,arch_variant"`
Sdk_version *string
@@ -2356,6 +2364,12 @@
// set the name of the output
Stem *string
+
+ Aidl struct {
+ // directories that should be added as include directories for any aidl sources of modules
+ // that depend on this module, as well as to aidl for this module.
+ Export_include_dirs []string
+ }
}
type Import struct {
@@ -2369,6 +2383,7 @@
combinedClasspathFile android.Path
exportedSdkLibs []string
+ exportAidlIncludeDirs android.Paths
}
func (j *Import) sdkVersion() sdkSpec {
@@ -2442,6 +2457,8 @@
ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
jarName, outputFile)
}
+
+ j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
}
var _ Dependency = (*Import)(nil)
@@ -2476,7 +2493,7 @@
}
func (j *Import) AidlIncludeDirs() android.Paths {
- return nil
+ return j.exportAidlIncludeDirs
}
func (j *Import) ExportedSdkLibs() []string {
@@ -2492,11 +2509,11 @@
}
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()
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
+ return false
}
// Add compile time check for interface implementation
diff --git a/java/java_test.go b/java/java_test.go
index 6d972be..e8a1a7c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1491,3 +1491,27 @@
t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
}
}
+
+func TestAidlExportIncludeDirsFromImports(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ libs: ["bar"],
+ }
+
+ java_import {
+ name: "bar",
+ jars: ["a.jar"],
+ aidl: {
+ export_include_dirs: ["aidl/bar"],
+ },
+ }
+ `)
+
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "-Iaidl/bar"
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+}
diff --git a/java/kotlin.go b/java/kotlin.go
index cb7da20..9b160a0 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -136,8 +136,11 @@
kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
kaptProcessor := ""
- if flags.processor != "" {
- kaptProcessor = "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + flags.processor
+ for i, p := range flags.processors {
+ if i > 0 {
+ kaptProcessor += " "
+ }
+ kaptProcessor += "-P plugin:org.jetbrains.kotlin.kapt3:processors=" + p
}
encodedJavacFlags := kaptEncodeFlags([][2]string{
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 5c6d45f..60ca1c4 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -88,7 +88,7 @@
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
- plugins: ["bar"],
+ plugins: ["bar", "baz"],
}
java_plugin {
@@ -96,6 +96,12 @@
processor_class: "com.bar",
srcs: ["b.java"],
}
+
+ java_plugin {
+ name: "baz",
+ processor_class: "com.baz",
+ srcs: ["b.java"],
+ }
`)
buildOS := android.BuildOs.String()
@@ -105,6 +111,7 @@
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+ baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
// Test that the kotlin and java sources are passed to kapt and kotlinc
if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
@@ -136,11 +143,12 @@
}
// Test that the processors are passed to kapt
- expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar
+ expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+ " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
}
- expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar"
+ expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
if kapt.Args["kaptProcessor"] != expectedProcessor {
t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index cb17fee..86eddb1 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -28,10 +28,6 @@
func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("prebuilt_apis", PrebuiltApisFactory)
-
- ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
- })
}
type prebuiltApisProperties struct {
@@ -48,7 +44,7 @@
// no need to implement
}
-func parseJarPath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+func parseJarPath(path string) (module string, apiver string, scope string) {
elements := strings.Split(path, "/")
apiver = elements[0]
@@ -58,7 +54,7 @@
return
}
-func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+func parseApiFilePath(ctx android.LoadHookContext, path string) (module string, apiver string, scope string) {
elements := strings.Split(path, "/")
apiver = elements[0]
@@ -73,7 +69,7 @@
return
}
-func createImport(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
props := struct {
Name *string
Jars []string
@@ -89,7 +85,7 @@
mctx.CreateModule(ImportFactory, &props)
}
-func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+func createFilegroup(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
fgName := module + ".api." + scope + "." + apiver
filegroupProps := struct {
Name *string
@@ -100,7 +96,7 @@
mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
}
-func getPrebuiltFiles(mctx android.TopDownMutatorContext, name string) []string {
+func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string {
mydir := mctx.ModuleDir() + "/"
var files []string
for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
@@ -115,7 +111,7 @@
return files
}
-func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+func prebuiltSdkStubs(mctx android.LoadHookContext) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/<module>.jar
files := getPrebuiltFiles(mctx, "*.jar")
@@ -123,12 +119,12 @@
for _, f := range files {
// create a Import module for each jar file
localPath := strings.TrimPrefix(f, mydir)
- module, apiver, scope := parseJarPath(mctx, localPath)
+ module, apiver, scope := parseJarPath(localPath)
createImport(mctx, module, scope, apiver, localPath)
}
}
-func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
+func prebuiltApiFiles(mctx android.LoadHookContext) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
files := getPrebuiltFiles(mctx, "api/*.txt")
@@ -178,7 +174,7 @@
}
}
-func PrebuiltApisMutator(mctx android.TopDownMutatorContext) {
+func createPrebuiltApiModules(mctx android.LoadHookContext) {
if _, ok := mctx.Module().(*prebuiltApis); ok {
prebuiltApiFiles(mctx)
prebuiltSdkStubs(mctx)
@@ -191,9 +187,15 @@
// generates a filegroup module named <module>-api.<scope>.<ver>.
//
// It also creates <module>-api.<scope>.latest for the latest <ver>.
+//
+// Similarly, it generates a java_import for all API .jar files found under the
+// directory where the Android.bp is located. Specifically, an API file located
+// at ./<ver>/<scope>/api/<module>.jar generates a java_import module named
+// <prebuilt-api-module>.<scope>.<ver>.<module>.
func PrebuiltApisFactory() android.Module {
module := &prebuiltApis{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
+ android.AddLoadHook(module, createPrebuiltApiModules)
return module
}
diff --git a/java/sdk.go b/java/sdk.go
index 1e60d67..92076f4 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -50,9 +50,8 @@
targetSdkVersion() sdkSpec
}
-func UseApiFingerprint(ctx android.BaseModuleContext, v string) bool {
- if v == ctx.Config().PlatformSdkCodename() &&
- ctx.Config().UnbundledBuild() &&
+func UseApiFingerprint(ctx android.BaseModuleContext) bool {
+ if ctx.Config().UnbundledBuild() &&
!ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
return true
@@ -148,6 +147,10 @@
raw string
}
+func (s sdkSpec) String() string {
+ return fmt.Sprintf("%s_%s", s.kind, s.version)
+}
+
// 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 {
@@ -159,6 +162,23 @@
return s.valid() && s.kind != sdkPrivate
}
+// whether the API surface is managed and versioned, i.e. has .txt file that
+// get frozen on SDK freeze and changes get reviewed by API council.
+func (s sdkSpec) stable() bool {
+ if !s.specified() {
+ return false
+ }
+ switch s.kind {
+ case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer:
+ return true
+ case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate:
+ return false
+ default:
+ panic(fmt.Errorf("unknown sdkKind=%v", s.kind))
+ }
+ return false
+}
+
// prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK
// that can be used for unbundled builds.
func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool {
@@ -283,6 +303,28 @@
}
}
+func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool {
+ // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
+ // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
+ // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
+ if s.kind != sdkSystem || !s.version.isNumbered() {
+ return true
+ }
+ allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
+ if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
+ if len(systemSdkVersions) > 0 {
+ allowedVersions = systemSdkVersions
+ }
+ }
+ if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) {
+ ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
+ s.raw, allowedVersions)
+ return false
+ }
+ return true
+}
+
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep {
sdkVersion := sdkContext.sdkVersion()
if !sdkVersion.valid() {
@@ -293,6 +335,9 @@
if ctx.Config().IsPdkBuild() {
sdkVersion = sdkVersion.forPdkBuild(ctx)
}
+ if !sdkVersion.validateSystemSdk(ctx) {
+ return sdkDep{}
+ }
if sdkVersion.usePrebuilt(ctx) {
dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String())
@@ -340,21 +385,6 @@
}
}
- // 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 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(sdkVersion.version.String(), allowed_versions) {
- ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
- sdkVersion.raw, allowed_versions)
- }
- }
-
switch sdkVersion.kind {
case sdkPrivate:
return sdkDep{
@@ -397,7 +427,7 @@
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))
+ return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
default:
panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a8edf1d..51e680b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,18 +15,18 @@
package java
import (
- "android/soong/android"
-
"fmt"
- "io"
"path"
"path/filepath"
+ "reflect"
"sort"
"strings"
"sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
)
const (
@@ -67,6 +67,9 @@
// The name of the api scope, e.g. public, system, test
name string
+ // The name of the field in the dynamically created structure.
+ fieldName string
+
// The tag to use to depend on the stubs library module.
stubsTag scopeDependencyTag
@@ -87,11 +90,14 @@
// *current. Older stubs library built with a numbered SDK version is created from
// the prebuilt jar.
sdkVersion string
+
+ // Extra arguments to pass to droidstubs for this scope.
+ droidstubsArgs []string
}
// Initialize a scope, creating and adding appropriate dependency tags
func initApiScope(scope *apiScope) *apiScope {
- //apiScope := &scope
+ scope.fieldName = proptools.FieldNameForProperty(scope.name)
scope.stubsTag = scopeDependencyTag{
name: scope.name + "-stubs",
apiScope: scope,
@@ -132,6 +138,7 @@
moduleSuffix: sdkSystemApiSuffix,
apiFileMakeVariableSuffix: "_SYSTEM",
sdkVersion: "system_current",
+ droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi"},
})
apiScopeTest = initApiScope(&apiScope{
name: "test",
@@ -139,6 +146,7 @@
moduleSuffix: sdkTestApiSuffix,
apiFileMakeVariableSuffix: "_TEST",
sdkVersion: "test_current",
+ droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
})
allApiScopes = apiScopes{
apiScopePublic,
@@ -163,6 +171,14 @@
sort.Strings(*javaSdkLibraries)
ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " "))
})
+
+ // Register sdk member types.
+ android.RegisterSdkMemberType(&sdkLibrarySdkMemberType{
+ android.SdkMemberTypeBase{
+ PropertyName: "java_sdk_libs",
+ SupportsSdk: true,
+ },
+ })
}
func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -220,9 +236,11 @@
}
type scopePaths struct {
- stubsHeaderPath android.Paths
- stubsImplPath android.Paths
- apiFilePath android.Path
+ stubsHeaderPath android.Paths
+ stubsImplPath android.Paths
+ currentApiFilePath android.Path
+ removedApiFilePath android.Path
+ stubsSrcJar android.Path
}
// Common code between sdk library and sdk library import
@@ -309,11 +327,13 @@
scopePaths.stubsImplPath = lib.ImplementationJars()
}
}
- if doc, ok := to.(ApiFilePath); ok {
+ if doc, ok := to.(ApiStubsProvider); ok {
if scopeTag, ok := tag.(scopeDependencyTag); ok {
apiScope := scopeTag.apiScope
scopePaths := module.getScopePaths(apiScope)
- scopePaths.apiFilePath = doc.ApiFilePath()
+ scopePaths.currentApiFilePath = doc.ApiFilePath()
+ scopePaths.removedApiFilePath = doc.RemovedApiFilePath()
+ scopePaths.stubsSrcJar = doc.StubsSrcJar()
} else {
ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
}
@@ -328,41 +348,6 @@
entriesList := module.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.Required = append(entries.Required, module.xmlFileName())
-
- entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
- if !Bool(module.sdkLibraryProperties.No_dist) {
- // Create a phony module that installs the impl library, for the case when this lib is
- // in PRODUCT_PACKAGES.
- owner := module.ModuleBase.Owner()
- if owner == "" {
- if Bool(module.sdkLibraryProperties.Core_lib) {
- owner = "core"
- } else {
- owner = "android"
- }
- }
-
- // Create dist rules to install the stubs libs 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")+")")
- }
- }
- }
- }
- },
- }
return entriesList
}
@@ -386,6 +371,17 @@
return module.BaseModuleName() + sdkXmlFileSuffix
}
+// The dist path of the stub artifacts
+func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
+ if module.ModuleBase.Owner() != "" {
+ return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name)
+ } else if Bool(module.sdkLibraryProperties.Core_lib) {
+ return path.Join("apistubs", "core", apiScope.name)
+ } else {
+ return path.Join("apistubs", "android", apiScope.name)
+ }
+}
+
// Get the sdk version for use when compiling the stubs library.
func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -398,13 +394,6 @@
}
}
-// $(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 {
- return strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1) + apiScope.apiFileMakeVariableSuffix
-}
-
func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
}
@@ -438,6 +427,12 @@
Srcs []string
Javacflags []string
}
+ Dist struct {
+ Targets []string
+ Dest *string
+ Dir *string
+ Tag *string
+ }
}{}
props.Name = proptools.StringPtr(module.stubsName(apiScope))
@@ -466,11 +461,18 @@
} else if module.SystemExtSpecific() {
props.System_ext_specific = proptools.BoolPtr(true)
}
+ // Dist the class jar artifact for sdk builds.
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ props.Dist.Targets = []string{"sdk", "win_sdk"}
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.BaseModuleName()))
+ props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+ props.Dist.Tag = proptools.StringPtr(".jar")
+ }
mctx.CreateModule(LibraryFactory, &props)
}
-// Creates a droiddoc module that creates stubs source files from the given full source
+// Creates a droidstubs module that creates stubs source files from the given full source
// files
func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
props := struct {
@@ -482,9 +484,6 @@
Libs []string
Arg_files []string
Args *string
- Api_tag_name *string
- Api_filename *string
- Removed_api_filename *string
Java_version *string
Merge_annotations_dirs []string
Merge_inclusion_annotations_dirs []string
@@ -497,6 +496,11 @@
Include_dirs []string
Local_include_dirs []string
}
+ Dist struct {
+ Targets []string
+ Dest *string
+ Dir *string
+ }
}{}
sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -523,15 +527,15 @@
props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
- droiddocArgs := []string{}
+ droidstubsArgs := []string{}
if len(module.sdkLibraryProperties.Api_packages) != 0 {
- droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
+ droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
}
if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
- droiddocArgs = append(droiddocArgs,
+ droidstubsArgs = append(droidstubsArgs,
android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
}
- droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...)
+ droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
disabledWarnings := []string{
"MissingPermission",
"BroadcastBehavior",
@@ -543,16 +547,12 @@
"Todo",
"Typo",
}
- droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
+ droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
- switch apiScope {
- case apiScopeSystem:
- droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi")
- case apiScopeTest:
- droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi")
- }
+ // Add in scope specific arguments.
+ droidstubsArgs = append(droidstubsArgs, apiScope.droidstubsArgs...)
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
- props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " "))
+ props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
// 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
@@ -562,10 +562,6 @@
apiDir := module.getApiDir()
currentApiFileName = path.Join(apiDir, currentApiFileName)
removedApiFileName = path.Join(apiDir, removedApiFileName)
- // TODO(jiyong): remove these three props
- props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
- props.Api_filename = proptools.StringPtr(currentApiFileName)
- props.Removed_api_filename = proptools.StringPtr(removedApiFileName)
// check against the not-yet-release API
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
@@ -578,9 +574,24 @@
module.latestRemovedApiFilegroupName(apiScope))
props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+ // Dist the api txt artifact for sdk builds.
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ props.Dist.Targets = []string{"sdk", "win_sdk"}
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+ props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+ }
+
mctx.CreateModule(DroidstubsFactory, &props)
}
+func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
+ depTag := mctx.OtherModuleDependencyTag(dep)
+ if depTag == xmlPermissionsFileTag {
+ return true
+ }
+ return module.Library.DepIsInSameApex(mctx, dep)
+}
+
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
props := struct {
@@ -590,9 +601,11 @@
Device_specific *bool
Product_specific *bool
System_ext_specific *bool
+ Apex_available []string
}{
- Name: proptools.StringPtr(module.xmlFileName()),
- Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Name: proptools.StringPtr(module.xmlFileName()),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Apex_available: module.ApexProperties.Apex_available,
}
if module.SocSpecific() {
@@ -803,42 +816,89 @@
// List of shared java libs that this module has dependencies to
Libs []string
+
+ // The stub sources.
+ Stub_srcs []string `android:"path"`
+
+ // The current.txt
+ Current_api string `android:"path"`
+
+ // The removed.txt
+ Removed_api string `android:"path"`
}
type sdkLibraryImportProperties struct {
// List of shared java libs, common to all scopes, that this module has
// dependencies to
Libs []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 {
android.ModuleBase
android.DefaultableModuleBase
prebuilt android.Prebuilt
+ android.ApexModuleBase
+ android.SdkBase
properties sdkLibraryImportProperties
+ // Map from api scope to the scope specific property structure.
+ scopeProperties map[*apiScope]*sdkLibraryScopeProperties
+
commonToSdkLibraryAndImport
}
var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+// The type of a structure that contains a field of type sdkLibraryScopeProperties
+// for each apiscope in allApiScopes, e.g. something like:
+// struct {
+// Public sdkLibraryScopeProperties
+// System sdkLibraryScopeProperties
+// ...
+// }
+var allScopeStructType = createAllScopePropertiesStructType()
+
+// Dynamically create a structure type for each apiscope in allApiScopes.
+func createAllScopePropertiesStructType() reflect.Type {
+ var fields []reflect.StructField
+ for _, apiScope := range allApiScopes {
+ field := reflect.StructField{
+ Name: apiScope.fieldName,
+ Type: reflect.TypeOf(sdkLibraryScopeProperties{}),
+ }
+ fields = append(fields, field)
+ }
+
+ return reflect.StructOf(fields)
+}
+
+// Create an instance of the scope specific structure type and return a map
+// from apiscope to a pointer to each scope specific field.
+func createPropertiesInstance() (interface{}, map[*apiScope]*sdkLibraryScopeProperties) {
+ allScopePropertiesPtr := reflect.New(allScopeStructType)
+ allScopePropertiesStruct := allScopePropertiesPtr.Elem()
+ scopeProperties := make(map[*apiScope]*sdkLibraryScopeProperties)
+
+ for _, apiScope := range allApiScopes {
+ field := allScopePropertiesStruct.FieldByName(apiScope.fieldName)
+ scopeProperties[apiScope] = field.Addr().Interface().(*sdkLibraryScopeProperties)
+ }
+
+ return allScopePropertiesPtr.Interface(), scopeProperties
+}
+
// java_sdk_library_import imports a prebuilt java_sdk_library.
func sdkLibraryImportFactory() android.Module {
module := &sdkLibraryImport{}
- module.AddProperties(&module.properties)
+ allScopeProperties, scopeToProperties := createPropertiesInstance()
+ module.scopeProperties = scopeToProperties
+ module.AddProperties(&module.properties, allScopeProperties)
android.InitPrebuiltModule(module, &[]string{""})
+ android.InitApexModule(module)
+ android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
android.AddLoadHook(module, func(mctx android.LoadHookContext) { module.createInternalModules(mctx) })
@@ -860,48 +920,14 @@
module.prebuilt.ForcePrefer()
}
- for apiScope, scopeProperties := range module.scopeProperties() {
+ 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
- }{}
+ module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
- 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)
+ module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
}
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -910,16 +936,54 @@
*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) createJavaImportForStubs(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ // 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)
+}
+
+func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.LoadHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+ props := struct {
+ Name *string
+ Srcs []string
+ }{}
+ props.Name = proptools.StringPtr(apiScope.docsModuleName(module.BaseModuleName()))
+ props.Srcs = scopeProperties.Stub_srcs
+ mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
}
func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- for apiScope, scopeProperties := range module.scopeProperties() {
+ for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
}
@@ -1086,3 +1150,110 @@
},
}}
}
+
+type sdkLibrarySdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*SdkLibrary)
+ return ok
+}
+
+func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_sdk_library_import")
+}
+
+func (s *sdkLibrarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &sdkLibrarySdkMemberProperties{}
+}
+
+type sdkLibrarySdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ // Scope to per scope properties.
+ Scopes map[*apiScope]scopeProperties
+
+ // Additional libraries that the exported stubs libraries depend upon.
+ Libs []string
+
+ // The Java stubs source files.
+ Stub_srcs []string
+}
+
+type scopeProperties struct {
+ Jars android.Paths
+ StubsSrcJar android.Path
+ CurrentApiFile android.Path
+ RemovedApiFile android.Path
+ SdkVersion string
+}
+
+func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ sdk := variant.(*SdkLibrary)
+
+ s.Scopes = make(map[*apiScope]scopeProperties)
+ for _, apiScope := range allApiScopes {
+ paths := sdk.getScopePaths(apiScope)
+ jars := paths.stubsImplPath
+ if len(jars) > 0 {
+ properties := scopeProperties{}
+ properties.Jars = jars
+ properties.SdkVersion = apiScope.sdkVersion
+ properties.StubsSrcJar = paths.stubsSrcJar
+ properties.CurrentApiFile = paths.currentApiFilePath
+ properties.RemovedApiFile = paths.removedApiFilePath
+ s.Scopes[apiScope] = properties
+ }
+ }
+
+ s.Libs = sdk.properties.Libs
+}
+
+func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ for _, apiScope := range allApiScopes {
+ if properties, ok := s.Scopes[apiScope]; ok {
+ scopeSet := propertySet.AddPropertySet(apiScope.name)
+
+ scopeDir := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name)
+
+ var jars []string
+ for _, p := range properties.Jars {
+ dest := filepath.Join(scopeDir, ctx.Name()+"-stubs.jar")
+ ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
+ jars = append(jars, dest)
+ }
+ scopeSet.AddProperty("jars", jars)
+
+ // Merge the stubs source jar into the snapshot zip so that when it is unpacked
+ // the source files are also unpacked.
+ snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
+ ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
+ scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
+
+ if properties.CurrentApiFile != nil {
+ currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
+ ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
+ scopeSet.AddProperty("current_api", currentApiSnapshotPath)
+ }
+
+ if properties.RemovedApiFile != nil {
+ removedApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"-removed.txt")
+ ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, removedApiSnapshotPath)
+ scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
+ }
+
+ if properties.SdkVersion != "" {
+ scopeSet.AddProperty("sdk_version", properties.SdkVersion)
+ }
+ }
+ }
+
+ if len(s.Libs) > 0 {
+ propertySet.AddPropertyWithTag("libs", s.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(false))
+ }
+}
diff --git a/java/sdk_test.go b/java/sdk_test.go
index ea6733d..088db9e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -222,9 +222,9 @@
{
name: "system_server_current",
properties: `sdk_version: "system_server_current",`,
- bootclasspath: []string{"android_module_lib_stubs_current", "services-stubs", "core-lambda-stubs"},
+ bootclasspath: []string{"android_system_server_stubs_current", "core-lambda-stubs"},
system: "core-current-stubs-system-modules",
- java9classpath: []string{"android_module_lib_stubs_current", "services-stubs"},
+ java9classpath: []string{"android_system_server_stubs_current"},
aidl: "-p" + buildDir + "/framework.aidl",
},
}
diff --git a/java/system_modules.go b/java/system_modules.go
index 47de6e3..7394fd5 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -242,18 +242,28 @@
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)
+func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
+}
- 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())
+type systemModulesInfoProperties struct {
+ android.SdkMemberPropertiesBase
+
+ Libs []string
+}
+
+func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &systemModulesInfoProperties{}
+}
+
+func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ systemModule := variant.(*SystemModules)
+ p.Libs = systemModule.properties.Libs
+}
+
+func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if len(p.Libs) > 0 {
+ // Add the references to the libraries that form the system module.
+ propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+ }
}
diff --git a/java/testing.go b/java/testing.go
index 5b6a39b..6929bb7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -50,6 +50,8 @@
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
"framework/aidl/a.aidl": nil,
+ "aidl/foo/IFoo.aidl": nil,
+ "aidl/bar/IBar.aidl": nil,
"assets_a/a": nil,
"assets_b/b": nil,
@@ -148,7 +150,7 @@
"android_system_stubs_current",
"android_test_stubs_current",
"android_module_lib_stubs_current",
- "services-stubs",
+ "android_system_server_stubs_current",
"core.current.stubs",
"core.platform.api.stubs",
"kotlin-stdlib",
diff --git a/python/androidmk.go b/python/androidmk.go
index 8e8e8ef..d293d52 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -100,5 +100,6 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " "))
+ fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := false")
})
}
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
new file mode 100644
index 0000000..d43dc6c
--- /dev/null
+++ b/remoteexec/remoteexec.go
@@ -0,0 +1,155 @@
+// 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 remoteexec
+
+import (
+ "sort"
+ "strings"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+const (
+ // ContainerImageKey is the key identifying the container image in the platform spec.
+ ContainerImageKey = "container-image"
+
+ // PoolKey is the key identifying the pool to use for remote execution.
+ PoolKey = "Pool"
+
+ // DefaultImage is the default container image used for Android remote execution. The
+ // image was built with the Dockerfile at
+ // https://android.googlesource.com/platform/prebuilts/remoteexecution-client/+/refs/heads/master/docker/Dockerfile
+ DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62"
+
+ // DefaultWrapperPath is the default path to the remote execution wrapper.
+ DefaultWrapperPath = "prebuilts/remoteexecution-client/live/rewrapper"
+
+ // DefaultPool is the name of the pool to use for remote execution when none is specified.
+ DefaultPool = "default"
+
+ // LocalExecStrategy is the exec strategy to indicate that the action should be run locally.
+ LocalExecStrategy = "local"
+
+ // RemoteExecStrategy is the exec strategy to indicate that the action should be run
+ // remotely.
+ RemoteExecStrategy = "remote"
+
+ // RemoteLocalFallbackExecStrategy is the exec strategy to indicate that the action should
+ // be run remotely and fallback to local execution if remote fails.
+ RemoteLocalFallbackExecStrategy = "remote_local_fallback"
+)
+
+var (
+ defaultLabels = map[string]string{"type": "tool"}
+ defaultExecStrategy = LocalExecStrategy
+ pctx = android.NewPackageContext("android/soong/remoteexec")
+)
+
+// REParams holds information pertinent to the remote execution of a rule.
+type REParams struct {
+ // Platform is the key value pair used for remotely executing the action.
+ Platform map[string]string
+ // Labels is a map of labels that identify the rule.
+ Labels map[string]string
+ // ExecStrategy is the remote execution strategy: remote, local, or remote_local_fallback.
+ ExecStrategy string
+ // Inputs is a list of input paths or ninja variables.
+ Inputs []string
+ // RSPFile is the name of the ninja variable used by the rule as a placeholder for an rsp
+ // input.
+ RSPFile string
+ // OutputFiles is a list of output file paths or ninja variables as placeholders for rule
+ // outputs.
+ OutputFiles []string
+ // ToolchainInputs is a list of paths or ninja variables pointing to the location of
+ // toolchain binaries used by the rule.
+ ToolchainInputs []string
+}
+
+func init() {
+ pctx.VariableFunc("Wrapper", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RBE_WRAPPER"); override != "" {
+ return override
+ }
+ return DefaultWrapperPath
+ })
+}
+
+// Generate the remote execution wrapper template to be added as a prefix to the rule's command.
+func (r *REParams) Template() string {
+ template := "${remoteexec.Wrapper}"
+
+ var kvs []string
+ labels := r.Labels
+ if len(labels) == 0 {
+ labels = defaultLabels
+ }
+ for k, v := range labels {
+ kvs = append(kvs, k+"="+v)
+ }
+ sort.Strings(kvs)
+ template += " --labels=" + strings.Join(kvs, ",")
+
+ var platform []string
+ for k, v := range r.Platform {
+ if v == "" {
+ continue
+ }
+ platform = append(platform, k+"="+v)
+ }
+ if _, ok := r.Platform[ContainerImageKey]; !ok {
+ platform = append(platform, ContainerImageKey+"="+DefaultImage)
+ }
+ if platform != nil {
+ sort.Strings(platform)
+ template += " --platform=\"" + strings.Join(platform, ",") + "\""
+ }
+
+ strategy := r.ExecStrategy
+ if strategy == "" {
+ strategy = defaultExecStrategy
+ }
+ template += " --exec_strategy=" + strategy
+
+ if len(r.Inputs) > 0 {
+ template += " --inputs=" + strings.Join(r.Inputs, ",")
+ }
+
+ if r.RSPFile != "" {
+ template += " --input_list_paths=" + r.RSPFile
+ }
+
+ if len(r.OutputFiles) > 0 {
+ template += " --output_files=" + strings.Join(r.OutputFiles, ",")
+ }
+
+ if len(r.ToolchainInputs) > 0 {
+ template += " --toolchain_inputs=" + strings.Join(r.ToolchainInputs, ",")
+ }
+
+ return template + " -- "
+}
+
+// StaticRules returns a pair of rules based on the given RuleParams, where the first rule is a
+// locally executable rule and the second rule is a remotely executable rule.
+func StaticRules(ctx android.PackageContext, name string, ruleParams blueprint.RuleParams, reParams *REParams, commonArgs []string, reArgs []string) (blueprint.Rule, blueprint.Rule) {
+ ruleParamsRE := ruleParams
+ ruleParamsRE.Command = reParams.Template() + ruleParamsRE.Command
+
+ return ctx.AndroidStaticRule(name, ruleParams, commonArgs...),
+ ctx.AndroidRemoteStaticRule(name+"RE", android.RemoteRuleSupports{RBE: true}, ruleParamsRE, append(commonArgs, reArgs...)...)
+}
diff --git a/remoteexec/remoteexec_test.go b/remoteexec/remoteexec_test.go
new file mode 100644
index 0000000..30e891c
--- /dev/null
+++ b/remoteexec/remoteexec_test.go
@@ -0,0 +1,83 @@
+// 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 remoteexec
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestTemplate(t *testing.T) {
+ tests := []struct {
+ name string
+ params *REParams
+ want string
+ }{
+ {
+ name: "basic",
+ params: &REParams{
+ Labels: map[string]string{"type": "compile", "lang": "cpp", "compiler": "clang"},
+ Inputs: []string{"$in"},
+ OutputFiles: []string{"$out"},
+ Platform: map[string]string{
+ ContainerImageKey: DefaultImage,
+ PoolKey: "default",
+ },
+ },
+ want: fmt.Sprintf("${remoteexec.Wrapper} --labels=compiler=clang,lang=cpp,type=compile --platform=\"Pool=default,container-image=%s\" --exec_strategy=local --inputs=$in --output_files=$out -- ", DefaultImage),
+ },
+ {
+ name: "all params",
+ params: &REParams{
+ Labels: map[string]string{"type": "compile", "lang": "cpp", "compiler": "clang"},
+ Inputs: []string{"$in"},
+ OutputFiles: []string{"$out"},
+ ExecStrategy: "remote",
+ RSPFile: "$out.rsp",
+ ToolchainInputs: []string{"clang++"},
+ Platform: map[string]string{
+ ContainerImageKey: DefaultImage,
+ PoolKey: "default",
+ },
+ },
+ want: fmt.Sprintf("${remoteexec.Wrapper} --labels=compiler=clang,lang=cpp,type=compile --platform=\"Pool=default,container-image=%s\" --exec_strategy=remote --inputs=$in --input_list_paths=$out.rsp --output_files=$out --toolchain_inputs=clang++ -- ", DefaultImage),
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ if got := test.params.Template(); got != test.want {
+ t.Errorf("Template() returned\n%s\nwant\n%s", got, test.want)
+ }
+ })
+ }
+}
+
+func TestTemplateDeterminism(t *testing.T) {
+ r := &REParams{
+ Labels: map[string]string{"type": "compile", "lang": "cpp", "compiler": "clang"},
+ Inputs: []string{"$in"},
+ OutputFiles: []string{"$out"},
+ Platform: map[string]string{
+ ContainerImageKey: DefaultImage,
+ PoolKey: "default",
+ },
+ }
+ want := fmt.Sprintf("${remoteexec.Wrapper} --labels=compiler=clang,lang=cpp,type=compile --platform=\"Pool=default,container-image=%s\" --exec_strategy=local --inputs=$in --output_files=$out -- ", DefaultImage)
+ for i := 0; i < 1000; i++ {
+ if got := r.Template(); got != want {
+ t.Fatalf("Template() returned\n%s\nwant\n%s", got, want)
+ }
+ }
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index 4593165..81b258c 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -222,7 +222,10 @@
if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
dir = compiler.dir64
}
- if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
+ }
+ if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
return android.PathForModuleInstall(ctx, dir, compiler.subDir,
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 60796d8..180fd8b 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -27,7 +27,6 @@
"-Wl,--icf=safe",
"-Wl,-z,max-page-size=4096",
- "-Wl,--execute-only",
"-Wl,-z,separate-code",
}
diff --git a/rust/config/global.go b/rust/config/global.go
index 690d83e..c0bd0f2 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.40.0"
+ RustDefaultVersion = "1.42.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/library.go b/rust/library.go
index 0cf2dd0..bf863bb 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -318,6 +318,8 @@
if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
deps = library.baseCompiler.bionicDeps(ctx, deps)
+ deps.CrtBegin = "crtbegin_so"
+ deps.CrtEnd = "crtend_so"
}
return deps
diff --git a/rust/rust.go b/rust/rust.go
index de6512c..5cc8845 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -164,6 +164,10 @@
return false
}
+func (mod *Module) UseSdk() bool {
+ return false
+}
+
func (mod *Module) UseVndk() bool {
return false
}
@@ -184,6 +188,10 @@
return ""
}
+func (mod *Module) AlwaysSdk() bool {
+ return false
+}
+
func (mod *Module) ToolchainLibrary() bool {
return false
}
@@ -325,6 +333,10 @@
panic("SetStubsVersions not yet implemented for rust modules")
}
+func (mod *Module) StubsVersion() string {
+ panic("SetStubsVersions not yet implemented for rust modules")
+}
+
func (mod *Module) BuildStaticVariant() bool {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
@@ -723,13 +735,14 @@
deps := mod.deps(ctx)
commonDepVariations := []blueprint.Variation{}
- commonDepVariations = append(commonDepVariations,
- blueprint.Variation{Mutator: "version", Variation: ""})
+ if cc.VersionVariantAvailable(mod) {
+ commonDepVariations = append(commonDepVariations,
+ blueprint.Variation{Mutator: "version", Variation: ""})
+ }
if !mod.Host() {
commonDepVariations = append(commonDepVariations,
blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
}
-
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
{Mutator: "rust_libraries", Variation: "rlib"},
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 020581d..02b190f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -215,25 +215,6 @@
srcs: ["foo.rs"],
crate_name: "bar",
}
- // Make a dummy libstd to let resolution go through
- rust_library_dylib {
- name: "libstd",
- crate_name: "std",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
- rust_library_dylib {
- name: "libterm",
- crate_name: "term",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
- rust_library_dylib {
- name: "libtest",
- crate_name: "test",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
rust_proc_macro {
name: "libpm",
rlibs: ["libbar"],
diff --git a/rust/testing.go b/rust/testing.go
index f9adec8..c3a4625 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -22,51 +22,11 @@
func GatherRequiredDepsForTest() string {
bp := `
rust_prebuilt_dylib {
- name: "libarena_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libfmt_macros_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libgraphviz_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libserialize_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
name: "libstd_x86_64-unknown-linux-gnu",
srcs: [""],
host_supported: true,
}
rust_prebuilt_dylib {
- name: "libsyntax_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libsyntax_ext_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libsyntax_pos_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libterm_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
name: "libtest_x86_64-unknown-linux-gnu",
srcs: [""],
host_supported: true,
@@ -81,6 +41,31 @@
nocrt: true,
system_shared_libs: [],
}
+ rust_library_dylib {
+ name: "libstd",
+ crate_name: "std",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ }
+ rust_library_rlib {
+ name: "libstd.static",
+ crate_name: "std",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ }
+ rust_library_dylib {
+ name: "libtest",
+ crate_name: "test",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ }
+ rust_library_rlib {
+ name: "libtest.static",
+ crate_name: "test",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ }
+
` + cc.GatherRequiredDepsForTest(android.NoOsType)
return bp
}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 076b3f5..dd0966f 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1 +1,3 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
+per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index 7e3a82c..7408349 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -50,14 +50,20 @@
mkdir -p ${SOONG_OUT}
SOONG_VARS=${SOONG_OUT}/soong.variables
+# We enable bionic linux builds as ART also needs prebuilts for it.
+# Enabling bionic linux requires setting allow_missing_dependencies.
cat > ${SOONG_VARS}.new << EOF
{
"Platform_sdk_version": ${PLATFORM_SDK_VERSION},
"Platform_sdk_codename": "${PLATFORM_VERSION}",
"Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
+ "Allow_missing_dependencies": true,
"DeviceName": "generic_arm64",
"HostArch": "x86_64",
+ "HostSecondaryArch": "x86",
+ "CrossHost": "linux_bionic",
+ "CrossHostArch": "x86_64",
"Aml_abis": true,
"UseGoma": ${USE_GOMA}
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
new file mode 100755
index 0000000..fc91c3d
--- /dev/null
+++ b/scripts/build-mainline-modules.sh
@@ -0,0 +1,64 @@
+#!/bin/bash -ex
+
+# Non exhaustive list of modules where we want prebuilts. More can be added as
+# needed.
+MAINLINE_MODULES=(
+ com.android.art.debug
+ com.android.art.release
+ com.android.art.testing
+ com.android.conscrypt
+ com.android.runtime
+ com.android.tzdata
+ com.android.i18n
+)
+
+# List of SDKs and module exports we know of.
+MODULES_SDK_AND_EXPORTS=(
+ art-module-sdk
+ art-module-test-exports
+ conscrypt-module-sdk
+ conscrypt-module-test-exports
+ conscrypt-module-host-exports
+)
+
+# We want to create apex modules for all supported architectures.
+PRODUCTS=(
+ aosp_arm
+ aosp_arm64
+ aosp_x86
+ aosp_x86_64
+)
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the tree"
+ exit 1
+fi
+
+OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
+DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
+
+for product in "${PRODUCTS[@]}"; do
+ build/soong/soong_ui.bash --make-mode $@ \
+ TARGET_PRODUCT=${product} \
+ ${MAINLINE_MODULES[@]}
+
+ PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
+ TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
+ rm -rf ${DIST_DIR}/${TARGET_ARCH}/
+ mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
+ for module in "${MAINLINE_MODULES[@]}"; do
+ cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
+ done
+done
+
+
+# Create multi-archs SDKs in a different out directory. The multi-arch script
+# uses soong directly and therefore needs its own directory that doesn't clash
+# with make.
+export OUT_DIR=${OUT_DIR}/aml/
+for sdk in "${MODULES_SDK_AND_EXPORTS[@]}"; do
+ build/soong/scripts/build-aml-prebuilts.sh ${sdk}
+done
+
+rm -rf ${DIST_DIR}/mainline-sdks
+cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index 8021e55..82ba749 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -54,11 +54,13 @@
DefaultDeprecated
)
-var buildBrokenSettings = []struct {
+type Setting struct {
name string
behavior BuildBrokenBehavior
warnings []string
-}{
+}
+
+var buildBrokenSettings = []Setting{
{
name: "BUILD_BROKEN_DUP_RULES",
behavior: DefaultFalse,
@@ -68,6 +70,19 @@
name: "BUILD_BROKEN_USES_NETWORK",
behavior: DefaultDeprecated,
},
+ {
+ name: "BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
+ behavior: DefaultTrue,
+ warnings: []string{
+ "COPY_HEADERS has been deprecated",
+ "COPY_HEADERS is deprecated",
+ },
+ },
+}
+
+type Branch struct {
+ Settings []Setting
+ Logs []ProductLog
}
type ProductBranch struct {
@@ -82,35 +97,48 @@
}
type Log struct {
- BuildBroken []*bool
- HasBroken []bool
+ WarningModuleTypes []string
+ ErrorModuleTypes []string
+
+ BuildBroken map[string]*bool
+ HasBroken map[string]int
}
func Merge(l, l2 Log) Log {
- if len(l.BuildBroken) == 0 {
- l.BuildBroken = make([]*bool, len(buildBrokenSettings))
+ if l.BuildBroken == nil {
+ l.BuildBroken = map[string]*bool{}
}
- if len(l.HasBroken) == 0 {
- l.HasBroken = make([]bool, len(buildBrokenSettings))
+ if l.HasBroken == nil {
+ l.HasBroken = map[string]int{}
}
- if len(l.BuildBroken) != len(l2.BuildBroken) || len(l.HasBroken) != len(l2.HasBroken) {
- panic("mis-matched logs")
- }
-
- for i, v := range l.BuildBroken {
+ for n, v := range l.BuildBroken {
if v == nil {
- l.BuildBroken[i] = l2.BuildBroken[i]
+ l.BuildBroken[n] = l2.BuildBroken[n]
}
}
- for i := range l.HasBroken {
- l.HasBroken[i] = l.HasBroken[i] || l2.HasBroken[i]
+ for n, v := range l2.BuildBroken {
+ if _, ok := l.BuildBroken[n]; !ok {
+ l.BuildBroken[n] = v
+ }
+ }
+
+ for n := range l.HasBroken {
+ if l.HasBroken[n] < l2.HasBroken[n] {
+ l.HasBroken[n] = l2.HasBroken[n]
+ }
+ }
+ for n := range l2.HasBroken {
+ if _, ok := l.HasBroken[n]; !ok {
+ l.HasBroken[n] = l2.HasBroken[n]
+ }
}
return l
}
-func PrintResults(products []ProductLog) {
+func PrintResults(branch Branch) {
+ products := branch.Logs
devices := map[string]Log{}
deviceNames := []string{}
@@ -124,39 +152,48 @@
sort.Strings(deviceNames)
- for i, setting := range buildBrokenSettings {
+ for _, setting := range branch.Settings {
printed := false
+ n := setting.name
for _, device := range deviceNames {
log := devices[device]
if setting.behavior == DefaultTrue {
- if log.BuildBroken[i] == nil || *log.BuildBroken[i] == false {
- if log.HasBroken[i] {
+ if log.BuildBroken[n] == nil || *log.BuildBroken[n] == false {
+ if log.HasBroken[n] > 0 {
printed = true
- fmt.Printf(" %s needs to set %s := true\n", device, setting.name)
+ plural := ""
+ if log.HasBroken[n] > 1 {
+ plural = "s"
+ }
+ fmt.Printf(" %s needs to set %s := true (%d instance%s)\n", device, setting.name, log.HasBroken[n], plural)
}
- } else if !log.HasBroken[i] {
+ } else if log.HasBroken[n] == 0 {
printed = true
fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
}
} else if setting.behavior == DefaultFalse {
- if log.BuildBroken[i] == nil {
+ if log.BuildBroken[n] == nil {
// Nothing to be done
- } else if *log.BuildBroken[i] == false {
+ } else if *log.BuildBroken[n] == false {
printed = true
fmt.Printf(" %s sets %s := false, which is the default and can be removed\n", device, setting.name)
- } else if !log.HasBroken[i] {
+ } else if log.HasBroken[n] == 0 {
printed = true
fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
}
} else if setting.behavior == DefaultDeprecated {
- if log.BuildBroken[i] != nil {
+ if log.BuildBroken[n] != nil {
printed = true
- if log.HasBroken[i] {
- fmt.Printf(" %s sets %s := %v, which is deprecated, but has failures\n", device, setting.name, *log.BuildBroken[i])
+ if log.HasBroken[n] > 0 {
+ plural := ""
+ if log.HasBroken[n] > 1 {
+ plural = "s"
+ }
+ fmt.Printf(" %s sets %s := %v, which is deprecated, but has %d failure%s\n", device, setting.name, *log.BuildBroken[n], log.HasBroken[n], plural)
} else {
- fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[i])
+ fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[n])
}
}
}
@@ -168,17 +205,45 @@
}
}
-func ParseBranch(name string) []ProductLog {
+func ParseBranch(name string) Branch {
products, err := filepath.Glob(filepath.Join(name, "*"))
if err != nil {
log.Fatal(err)
}
- ret := []ProductLog{}
+ ret := Branch{Logs: []ProductLog{}}
for _, product := range products {
product = filepath.Base(product)
- ret = append(ret, ParseProduct(ProductBranch{Branch: name, Name: product}))
+ ret.Logs = append(ret.Logs, ParseProduct(ProductBranch{Branch: name, Name: product}))
+ }
+
+ ret.Settings = append(ret.Settings, buildBrokenSettings...)
+ if len(ret.Logs) > 0 {
+ for _, mtype := range ret.Logs[0].WarningModuleTypes {
+ if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
+ continue
+ }
+ ret.Settings = append(ret.Settings, Setting{
+ name: "BUILD_BROKEN_USES_" + mtype,
+ behavior: DefaultTrue,
+ warnings: []string{mtype + " has been deprecated"},
+ })
+ }
+ for _, mtype := range ret.Logs[0].ErrorModuleTypes {
+ if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
+ continue
+ }
+ ret.Settings = append(ret.Settings, Setting{
+ name: "BUILD_BROKEN_USES_" + mtype,
+ behavior: DefaultFalse,
+ warnings: []string{mtype + " has been deprecated"},
+ })
+ }
+ }
+
+ for _, productLog := range ret.Logs {
+ ScanProduct(ret.Settings, productLog)
}
return ret
}
@@ -192,15 +257,15 @@
ret := ProductLog{
ProductBranch: p,
Log: Log{
- BuildBroken: make([]*bool, len(buildBrokenSettings)),
- HasBroken: make([]bool, len(buildBrokenSettings)),
+ BuildBroken: map[string]*bool{},
+ HasBroken: map[string]int{},
},
}
lines := strings.Split(string(soongLog), "\n")
for _, line := range lines {
fields := strings.Split(line, " ")
- if len(fields) != 5 {
+ if len(fields) < 5 {
continue
}
@@ -208,30 +273,35 @@
ret.Device = fields[4]
}
+ if fields[3] == "DEFAULT_WARNING_BUILD_MODULE_TYPES" {
+ ret.WarningModuleTypes = fields[4:]
+ }
+ if fields[3] == "DEFAULT_ERROR_BUILD_MODULE_TYPES" {
+ ret.ErrorModuleTypes = fields[4:]
+ }
+
if strings.HasPrefix(fields[3], "BUILD_BROKEN_") {
- for i, setting := range buildBrokenSettings {
- if setting.name == fields[3] {
- ret.BuildBroken[i] = ParseBoolPtr(fields[4])
- }
- }
+ ret.BuildBroken[fields[3]] = ParseBoolPtr(fields[4])
}
}
- stdLog, err := ioutil.ReadFile(filepath.Join(p.Branch, p.Name, "std_full.log"))
+ return ret
+}
+
+func ScanProduct(settings []Setting, l ProductLog) {
+ stdLog, err := ioutil.ReadFile(filepath.Join(l.Branch, l.Name, "std_full.log"))
if err != nil {
log.Fatal(err)
}
stdStr := string(stdLog)
- for i, setting := range buildBrokenSettings {
+ for _, setting := range settings {
for _, warning := range setting.warnings {
if strings.Contains(stdStr, warning) {
- ret.HasBroken[i] = true
+ l.HasBroken[setting.name] += strings.Count(stdStr, warning)
}
}
}
-
- return ret
}
func ParseBoolPtr(str string) *bool {
diff --git a/scripts/generate-notice-files.py b/scripts/generate-notice-files.py
new file mode 100755
index 0000000..49011b2
--- /dev/null
+++ b/scripts/generate-notice-files.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2012 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.
+"""
+Usage: generate-notice-files --text-output [plain text output file] \
+ --html-output [html output file] \
+ --xml-output [xml output file] \
+ -t [file title] -s [directory of notices]
+
+Generate the Android notice files, including both text and html files.
+
+-h to display this usage message and exit.
+"""
+from collections import defaultdict
+import argparse
+import hashlib
+import itertools
+import os
+import os.path
+import re
+import sys
+
+MD5_BLOCKSIZE = 1024 * 1024
+HTML_ESCAPE_TABLE = {
+ "&": "&",
+ '"': """,
+ "'": "'",
+ ">": ">",
+ "<": "<",
+ }
+
+def hexify(s):
+ return ("%02x"*len(s)) % tuple(map(ord, s))
+
+def md5sum(filename):
+ """Calculate an MD5 of the file given by FILENAME,
+ and return hex digest as a string.
+ Output should be compatible with md5sum command"""
+
+ f = open(filename, "rb")
+ sum = hashlib.md5()
+ while 1:
+ block = f.read(MD5_BLOCKSIZE)
+ if not block:
+ break
+ sum.update(block)
+ f.close()
+ return hexify(sum.digest())
+
+
+def html_escape(text):
+ """Produce entities within text."""
+ return "".join(HTML_ESCAPE_TABLE.get(c,c) for c in text)
+
+HTML_OUTPUT_CSS="""
+<style type="text/css">
+body { padding: 0; font-family: sans-serif; }
+.same-license { background-color: #eeeeee; border-top: 20px solid white; padding: 10px; }
+.label { font-weight: bold; }
+.file-list { margin-left: 1em; color: blue; }
+</style>
+"""
+
+def combine_notice_files_html(file_hash, input_dir, output_filename):
+ """Combine notice files in FILE_HASH and output a HTML version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+
+ # Set up a filename to row id table (anchors inside tables don't work in
+ # most browsers, but href's to table row ids do)
+ id_table = {}
+ id_count = 0
+ for value in file_hash:
+ for filename in value:
+ id_table[filename] = id_count
+ id_count += 1
+
+ # Open the output file, and output the header pieces
+ output_file = open(output_filename, "wb")
+
+ print >> output_file, "<html><head>"
+ print >> output_file, HTML_OUTPUT_CSS
+ print >> output_file, '</head><body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">'
+
+ # Output our table of contents
+ print >> output_file, '<div class="toc">'
+ print >> output_file, "<ul>"
+
+ # Flatten the list of lists into a single list of filenames
+ sorted_filenames = sorted(itertools.chain.from_iterable(file_hash))
+
+ # Print out a nice table of contents
+ for filename in sorted_filenames:
+ stripped_filename = SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, '<li><a href="#id%d">%s</a></li>' % (id_table.get(filename), stripped_filename)
+
+ print >> output_file, "</ul>"
+ print >> output_file, "</div><!-- table of contents -->"
+ # Output the individual notice file lists
+ print >>output_file, '<table cellpadding="0" cellspacing="0" border="0">'
+ for value in file_hash:
+ print >> output_file, '<tr id="id%d"><td class="same-license">' % id_table.get(value[0])
+ print >> output_file, '<div class="label">Notices for file(s):</div>'
+ print >> output_file, '<div class="file-list">'
+ for filename in value:
+ print >> output_file, "%s <br/>" % (SRC_DIR_STRIP_RE.sub(r"\1", filename))
+ print >> output_file, "</div><!-- file-list -->"
+ print >> output_file
+ print >> output_file, '<pre class="license-text">'
+ print >> output_file, html_escape(open(value[0]).read())
+ print >> output_file, "</pre><!-- license-text -->"
+ print >> output_file, "</td></tr><!-- same-license -->"
+ print >> output_file
+ print >> output_file
+ print >> output_file
+
+ # Finish off the file output
+ print >> output_file, "</table>"
+ print >> output_file, "</body></html>"
+ output_file.close()
+
+def combine_notice_files_text(file_hash, input_dir, output_filename, file_title):
+ """Combine notice files in FILE_HASH and output a text version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+ output_file = open(output_filename, "wb")
+ print >> output_file, file_title
+ for value in file_hash:
+ print >> output_file, "============================================================"
+ print >> output_file, "Notices for file(s):"
+ for filename in value:
+ print >> output_file, SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, "------------------------------------------------------------"
+ print >> output_file, open(value[0]).read()
+ output_file.close()
+
+def combine_notice_files_xml(files_with_same_hash, input_dir, output_filename):
+ """Combine notice files in FILE_HASH and output a XML version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+
+ # Set up a filename to row id table (anchors inside tables don't work in
+ # most browsers, but href's to table row ids do)
+ id_table = {}
+ for file_key in files_with_same_hash.keys():
+ for filename in files_with_same_hash[file_key]:
+ id_table[filename] = file_key
+
+ # Open the output file, and output the header pieces
+ output_file = open(output_filename, "wb")
+
+ print >> output_file, '<?xml version="1.0" encoding="utf-8"?>'
+ print >> output_file, "<licenses>"
+
+ # Flatten the list of lists into a single list of filenames
+ sorted_filenames = sorted(id_table.keys())
+
+ # Print out a nice table of contents
+ for filename in sorted_filenames:
+ stripped_filename = SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, '<file-name contentId="%s">%s</file-name>' % (id_table.get(filename), stripped_filename)
+
+ print >> output_file
+ print >> output_file
+
+ processed_file_keys = []
+ # Output the individual notice file lists
+ for filename in sorted_filenames:
+ file_key = id_table.get(filename)
+ if file_key in processed_file_keys:
+ continue
+ processed_file_keys.append(file_key)
+
+ print >> output_file, '<file-content contentId="%s"><![CDATA[%s]]></file-content>' % (file_key, html_escape(open(filename).read()))
+ print >> output_file
+
+ # Finish off the file output
+ print >> output_file, "</licenses>"
+ output_file.close()
+
+def get_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--text-output', required=True,
+ help='The text output file path.')
+ parser.add_argument(
+ '--html-output',
+ help='The html output file path.')
+ parser.add_argument(
+ '--xml-output',
+ help='The xml output file path.')
+ parser.add_argument(
+ '-t', '--title', required=True,
+ help='The file title.')
+ parser.add_argument(
+ '-s', '--source-dir', required=True,
+ help='The directory containing notices.')
+ parser.add_argument(
+ '-i', '--included-subdirs', action='append',
+ help='The sub directories which should be included.')
+ parser.add_argument(
+ '-e', '--excluded-subdirs', action='append',
+ help='The sub directories which should be excluded.')
+ return parser.parse_args()
+
+def main(argv):
+ args = get_args()
+
+ txt_output_file = args.text_output
+ html_output_file = args.html_output
+ xml_output_file = args.xml_output
+ file_title = args.title
+ included_subdirs = []
+ excluded_subdirs = []
+ if args.included_subdirs is not None:
+ included_subdirs = args.included_subdirs
+ if args.excluded_subdirs is not None:
+ excluded_subdirs = args.excluded_subdirs
+
+ # Find all the notice files and md5 them
+ input_dir = os.path.normpath(args.source_dir)
+ files_with_same_hash = defaultdict(list)
+ for root, dir, files in os.walk(input_dir):
+ for file in files:
+ matched = True
+ if len(included_subdirs) > 0:
+ matched = False
+ for subdir in included_subdirs:
+ if (root == (input_dir + '/' + subdir) or
+ root.startswith(input_dir + '/' + subdir + '/')):
+ matched = True
+ break
+ elif len(excluded_subdirs) > 0:
+ for subdir in excluded_subdirs:
+ if (root == (input_dir + '/' + subdir) or
+ root.startswith(input_dir + '/' + subdir + '/')):
+ matched = False
+ break
+ if matched and file.endswith(".txt"):
+ filename = os.path.join(root, file)
+ file_md5sum = md5sum(filename)
+ files_with_same_hash[file_md5sum].append(filename)
+
+ filesets = [sorted(files_with_same_hash[md5]) for md5 in sorted(files_with_same_hash.keys())]
+
+ combine_notice_files_text(filesets, input_dir, txt_output_file, file_title)
+
+ if html_output_file is not None:
+ combine_notice_files_html(filesets, input_dir, html_output_file)
+
+ if xml_output_file is not None:
+ combine_notice_files_xml(files_with_same_hash, input_dir, xml_output_file)
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/scripts/mergenotice.py b/scripts/mergenotice.py
index 407ae8c..fe99073 100755
--- a/scripts/mergenotice.py
+++ b/scripts/mergenotice.py
@@ -16,7 +16,7 @@
#
"""
Merges input notice files to the output file while ignoring duplicated files
-This script shouldn't be confused with build/make/tools/generate-notice-files.py
+This script shouldn't be confused with build/soong/scripts/generate-notice-files.py
which is responsible for creating the final notice file for all artifacts
installed. This script has rather limited scope; it is meant to create a merged
notice file for a set of modules that are packaged together, e.g. in an APEX.
diff --git a/scripts/reverse-deps.sh b/scripts/reverse-deps.sh
new file mode 100755
index 0000000..02b7dcb
--- /dev/null
+++ b/scripts/reverse-deps.sh
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+set -eu
+
+# 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets depending on a given target.
+#
+# i.e. the list of things that could change after changing a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the reverse transitive closure of ninja targets depending on one or
+more targets.
+
+Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+#
+# only argument is the dependency depth indicator
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v depth="${1}" '
+ BEGIN {
+ inoutput = 0
+ }
+ $0 ~ /^\S\S*:$/ {
+ inoutput = 0
+ }
+ inoutput != 0 {
+ print gensub(/^\s*/, "", "g")" "depth
+ }
+ $1 == "outputs:" {
+ inoutput = 1
+ }
+ '
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+quiet=false # whether to suppress progress
+
+sep=" " # output separator between depth and target
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=*)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$';;
+ *)
+ die "Unknown flag ${1}"
+ ;;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target `target` is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))" "0
+ }
+ ' >"${newDeps}"
+else # start with no deps by clearing file
+ : >"${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ echo "${targets[${idx}]} 0" >>"${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u <"${newDeps}" >"${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ fi
+ depth=$(expr ${depth} + 1)
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ cut -d\ -f1 "${newDeps}" | getDeps "${depth}"
+ cat "${oldDeps}"
+ ) | sort -n | awk '
+ BEGIN {
+ prev = ""
+ }
+ {
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ if ($0 != prev) {
+ print gensub(/\s*$/, "", "g")" "depth
+ }
+ prev = $0
+ }
+ ' >"${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' \
+ --new-line-format='%L' --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+awk -v sep="${sep}" '{
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ print depth sep $0
+}' "${allDeps}" | sort -n
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
new file mode 100755
index 0000000..c6f8b76
--- /dev/null
+++ b/scripts/transitive-deps.sh
@@ -0,0 +1,491 @@
+#!/bin/bash
+
+set -eu
+
+# 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets a given target depends on.
+#
+# i.e. the list of things that, if changed, could cause a change to a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the transitive closure of files and ninja targets that one or more
+targets depend on.
+
+Dependency Options:
+
+ -(no)order_deps Whether to include order-only dependencies. (Default false)
+ -(no)implicit Whether to include implicit dependencies. (Default true)
+ -(no)explicit Whether to include regular / explicit deps. (Default true)
+
+ -nofollow Unanchored regular expression. Matching paths and targets
+ always get reported. Their dependencies do not get reported
+ unless first encountered in a 'container' file type.
+ Multiple allowed and combined using '|'.
+ e.g. -nofollow='*.so' not -nofollow='.so$'
+ -nofollow='*.so|*.dex' or -nofollow='*.so' -nofollow='.dex'
+ (Defaults to no matches)
+ -container Unanchored regular expression. Matching file extensions get
+ treated as 'container' files for -nofollow option.
+ Multiple allowed and combines using '|'
+ (Default 'apex|apk|zip|jar|tar|tgz')
+
+Output Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+ -directories=<f> Output directory names of dependencies to 'f'.
+ alias -d User '/dev/stdout' to send directories to stdout. Defaults
+ to no directory output.
+ -notices=<file> Output license and notice file paths to 'file'.
+ alias -n Use '/dev/stdout' to send notices to stdout. Defaults to no
+ license/notice output.
+ -projects=<file> Output git project names to 'file'. Use '/dev/stdout' to
+ alias -p send projects to stdout. Defaults to no project output.
+ -targets=<fils> Output target dependencies to 'file'. Use '/dev/stdout' to
+ alias -t send targets to stdout.
+ When no directory, notice, project or target output options
+ given, defaults to stdout. Otherwise, defaults to no target
+ output.
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 -r "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v include_order="${include_order_deps}" \
+ -v include_implicit="${include_implicit_deps}" \
+ -v include_explicit="${include_deps}" \
+ -v containers="${container_types}" \
+ '
+ BEGIN {
+ ininput = 0
+ isnotice = 0
+ currFileName = ""
+ currExt = ""
+ }
+ $1 == "outputs:" {
+ ininput = 0
+ }
+ ininput == 0 && $0 ~ /^\S\S*:$/ {
+ isnotice = ($0 ~ /.*NOTICE.*[.]txt:$/)
+ currFileName = gensub(/^.*[/]([^/]*)[:]$/, "\\1", "g")
+ currExt = gensub(/^.*[.]([^./]*)[:]$/, "\\1", "g")
+ }
+ ininput != 0 && $1 !~ /^[|][|]?/ {
+ if (include_explicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "|" {
+ if (include_implicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "||" {
+ if (include_order == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ $1 == "input:" {
+ ininput = 1
+ }
+ '
+}
+
+# Reads one input directory per line from stdin; outputs unique git projects.
+function getProjects() {
+ while read d; do
+ while [ "${d}" != '.' ] && [ "${d}" != '/' ]; do
+ if [ -d "${d}/.git/" ]; then
+ echo "${d}"
+ break
+ fi
+ d=$(dirname "${d}")
+ done
+ done | sort -u
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+readonly ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+readonly ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+include_order_deps=false # whether to trace through || "order dependencies"
+include_implicit_deps=true # whether to trace through | "implicit deps"
+include_deps=true # whether to trace through regular explicit deps
+quiet=false # whether to suppress progress
+
+projects_out='' # where to output the list of projects
+directories_out='' # where to output the list of directories
+targets_out='' # where to output the list of targets/source files
+notices_out='' # where to output the list of license/notice files
+
+sep=" " # separator between md5sum and notice filename
+
+nofollow='' # regularexp must fully match targets to skip
+
+container_types='' # regularexp must full match file extension
+ # defaults to 'apex|apk|zip|jar|tar|tgz' below.
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ order_deps)
+ include_order_deps=true;;
+ noorder_deps)
+ include_order_deps=false;;
+ implicit)
+ include_implicit_deps=true;;
+ noimplicit)
+ include_implicit_deps=false;;
+ explicit)
+ include_deps=true;;
+ noexplicit)
+ include_deps=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$');;
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ nofollow)
+ case "${nofollow}" in
+ '')
+ nofollow="${2?"${usage}"}";;
+ *)
+ nofollow="${nofollow}|${2?"${usage}"}";;
+ esac
+ shift
+ ;;
+ nofollow=*)
+ case "${nofollow}" in
+ '')
+ nofollow=$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ *)
+ nofollow="${nofollow}|"$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ esac
+ ;;
+ container)
+ container_types="${container_types}|${2?"${usage}"}";;
+ container=*)
+ container_types="${container_types}|"$(expr "${flag}" : '^container=\(.*\)$');;
+ p) ;&
+ projects)
+ projects_out="${2?"${usage}"}"; shift;;
+ p=*) ;&
+ projects=*)
+ projects_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ d) ;&
+ directores)
+ directories_out="${2?"${usage}"}"; shift;;
+ d=*) ;&
+ directories=*)
+ directories_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ t) ;&
+ targets)
+ targets_out="${2?"${usage}"}"; shift;;
+ t=*) ;&
+ targets=)
+ targets_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ n) ;&
+ notices)
+ notices_out="${2?"${usage}"}"; shift;;
+ n=*) ;&
+ notices=)
+ notices_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ *)
+ die "Unknown flag ${1}";;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+
+# fail fast if command-line arguments are invalid
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+if [ -z "${projects_out}" ] \
+ && [ -z "${directories_out}" ] \
+ && [ -z "${targets_out}" ] \
+ && [ -z "${notices_out}" ]
+then
+ targets_out='/dev/stdout'
+fi
+
+if [ -z "${container_types}" ]; then
+ container_types='apex|apk|zip|jar|tar|tgz'
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target 'target' is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print ( \
+ $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))
+ }
+ ' > "${newDeps}"
+else # start with no deps by clearing file
+ : > "${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ isnotice='0'
+ case "${targets[${idx}]}" in
+ *NOTICE*) ;&
+ *LICEN[CS]E*) ;&
+ *notice.txt) ;&
+ *licen[cs]e.txt)
+ isnotice='1';;
+ esac
+ echo "${isnotice} 1 ${targets[${idx}]}" >> "${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u < "${newDeps}" > "${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+# 1st iteration always unfiltered
+filter='cat'
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ depth=$(expr ${depth} + 1)
+ fi
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ set +e
+ sh -c "${filter}" < "${newDeps}" | cut -d\ -f3- | getDeps
+ set -e
+ cat "${oldDeps}"
+ ) | sort -u > "${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' --new-line-format='%L' \
+ --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # apply filters on subsequent iterations
+ case "${nofollow}" in
+ '')
+ filter='cat';;
+ *)
+ filter="egrep -v '^[01] 0 (${nofollow})$'"
+ ;;
+ esac
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+if [ -n "${targets_out}" ]; then
+ cut -d\ -f3- "${allDeps}" | sort -u > "${targets_out}"
+fi
+
+if [ -n "${directories_out}" ] \
+ || [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allDirs="${tmpFiles}/dirs"
+ (
+ cut -d\ -f3- "${allDeps}" | tr '\n' '\0' | xargs -0 dirname
+ ) | sort -u > "${allDirs}"
+ if ${showProgress}; then
+ echo $(wc -l < "${allDirs}")" directories" >&2
+ fi
+
+ case "${directories_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allDirs}" > "${directories_out}"
+ ;;
+ esac
+fi
+
+if [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allProj="${tmpFiles}/projects"
+ set +e
+ egrep -v '^out[/]' "${allDirs}" | getProjects > "${allProj}"
+ set -e
+ if ${showProgress}; then
+ echo $(wc -l < "${allProj}")" projects" >&2
+ fi
+
+ case "${projects_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allProj}" > "${projects_out}"
+ ;;
+ esac
+fi
+
+case "${notices_out}" in
+ '') : do nothing;;
+ *)
+ readonly allNotice="${tmpFiles}/notices"
+ set +e
+ egrep '^1' "${allDeps}" | cut -d\ -f3- | egrep -v '^out/' > "${allNotice}"
+ set -e
+ cat "${allProj}" | while read proj; do
+ for f in LICENSE LICENCE NOTICE license.txt notice.txt; do
+ if [ -f "${proj}/${f}" ]; then
+ echo "${proj}/${f}"
+ fi
+ done
+ done >> "${allNotice}"
+ if ${showProgress}; then
+ echo $(cat "${allNotice}" | sort -u | wc -l)" notice targets" >&2
+ fi
+ readonly hashedNotice="${tmpFiles}/hashednotices"
+ ( # md5sum outputs checksum space indicator(space or *) filename newline
+ set +e
+ sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null
+ set -e
+ # use sed to replace space and indicator with separator
+ ) > "${hashedNotice}"
+ if ${showProgress}; then
+ echo $(cut -d\ -f2- "${hashedNotice}" | sort -u | wc -l)" notice files" >&2
+ echo $(cut -d\ -f1 "${hashedNotice}" | sort -u | wc -l)" distinct notices" >&2
+ fi
+ sed 's/^\([^ ]*\) [* ]/\1'"${sep}"'/g' "${hashedNotice}" | sort > "${notices_out}"
+ ;;
+esac
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/sdk/bp.go b/sdk/bp.go
index c2a75e4..68fe7ab 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -35,7 +35,7 @@
func (s *bpPropertySet) AddProperty(name string, value interface{}) {
if s.properties[name] != nil {
- panic("Property %q already exists in property set")
+ panic(fmt.Sprintf("Property %q already exists in property set", name))
}
s.properties[name] = value
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index ecb1da0..780da9f 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -17,6 +17,7 @@
import (
"testing"
+ "android/soong/android"
"android/soong/cc"
)
@@ -24,11 +25,14 @@
t.Helper()
fs := map[string][]byte{
- "Test.cpp": nil,
- "include/Test.h": nil,
- "arm64/include/Arm64Test.h": nil,
- "libfoo.so": nil,
- "aidl/foo/bar/Test.aidl": nil,
+ "Test.cpp": nil,
+ "include/Test.h": nil,
+ "include-android/AndroidTest.h": nil,
+ "include-host/HostTest.h": nil,
+ "arm64/include/Arm64Test.h": nil,
+ "libfoo.so": nil,
+ "aidl/foo/bar/Test.aidl": nil,
+ "some/where/stubslib.map.txt": nil,
}
return testSdkWithFs(t, bp, fs)
}
@@ -45,7 +49,6 @@
cc_library_shared {
name: "sdkmember",
srcs: ["Test.cpp"],
- system_shared_libs: [],
stl: "none",
}
`)
@@ -54,7 +57,7 @@
arm64Output := result.Module("sdkmember", "android_arm64_armv8-a_shared").(*cc.Module).OutputFile()
var inputs []string
- buildParams := result.Module("mysdk", "android_common").BuildParamsForTests()
+ buildParams := result.Module("mysdk", android.CommonOS.Name).BuildParamsForTests()
for _, bp := range buildParams {
if bp.Input != nil {
inputs = append(inputs, bp.Input.String())
@@ -175,13 +178,11 @@
cc_library_host_shared {
name: "sdkshared",
- system_shared_libs: [],
stl: "none",
}
cc_library_host_static {
name: "sdkstatic",
- system_shared_libs: [],
stl: "none",
}
`)
@@ -198,30 +199,83 @@
cc_library_shared {
name: "sdkshared",
- system_shared_libs: [],
stl: "none",
}
cc_library_static {
name: "sdkstatic",
- system_shared_libs: [],
stl: "none",
}
cc_library {
name: "sdkboth1",
- system_shared_libs: [],
stl: "none",
}
cc_library {
name: "sdkboth2",
- system_shared_libs: [],
stl: "none",
}
`)
}
+func TestSnapshotWithObject(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_objects: ["crtobj"],
+ }
+
+ cc_object {
+ name: "crtobj",
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_object {
+ name: "mysdk_crtobj@current",
+ sdk_member_name: "crtobj",
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/crtobj.o"],
+ },
+ arm: {
+ srcs: ["arm/lib/crtobj.o"],
+ },
+ },
+}
+
+cc_prebuilt_object {
+ name: "crtobj",
+ prefer: false,
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/crtobj.o"],
+ },
+ arm: {
+ srcs: ["arm/lib/crtobj.o"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_objects: ["mysdk_crtobj@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/crtobj/android_arm64_armv8-a/crtobj.o -> arm64/lib/crtobj.o
+.intermediates/crtobj/android_arm_armv7-a-neon/crtobj.o -> arm/lib/crtobj.o
+`),
+ )
+}
+
func TestSnapshotWithCcDuplicateHeaders(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -235,7 +289,6 @@
"Test.cpp",
],
export_include_dirs: ["include"],
- system_shared_libs: [],
stl: "none",
}
@@ -245,12 +298,11 @@
"Test.cpp",
],
export_include_dirs: ["include"],
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAllCopyRules(`
include/Test.h -> include/include/Test.h
.intermediates/mynativelib1/android_arm64_armv8-a_shared/mynativelib1.so -> arm64/lib/mynativelib1.so
@@ -282,18 +334,19 @@
export_system_include_dirs: ["arm64/include"],
},
},
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_shared {
name: "mysdk_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -304,13 +357,12 @@
srcs: ["arm/lib/mynativelib.so"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
name: "mynativelib",
prefer: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -321,8 +373,6 @@
srcs: ["arm/lib/mynativelib.so"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -351,18 +401,18 @@
"Test.cpp",
],
compile_multilib: "both",
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mymodule_exports", "android_common", "",
+ result.CheckSnapshot("mymodule_exports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_binary {
name: "mymodule_exports_mynativebinary@current",
sdk_member_name: "mynativebinary",
+ installable: false,
compile_multilib: "both",
arch: {
arm64: {
@@ -400,6 +450,113 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["mynativebinary"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_binary {
+ name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ compile_multilib: "both",
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "myexports_mynativebinary@current",
+ sdk_member_name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "mynativebinary",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ target: {
+ linux_glibc: {
+ compile_multilib: "both",
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/bin/mynativebinary"],
+ },
+ windows: {
+ compile_multilib: "64",
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["myexports_mynativebinary@current"],
+ target: {
+ windows: {
+ compile_multilib: "64",
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativebinary/linux_glibc_x86_64/mynativebinary -> linux_glibc/x86_64/bin/mynativebinary
+.intermediates/mynativebinary/linux_glibc_x86/mynativebinary -> linux_glibc/x86/bin/mynativebinary
+.intermediates/mynativebinary/windows_x86_64/mynativebinary.exe -> windows/x86_64/bin/mynativebinary.exe
+`),
+ )
+}
+
func TestSnapshotWithCcSharedLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -413,22 +570,28 @@
"Test.cpp",
"aidl/foo/bar/Test.aidl",
],
+ apex_available: ["apex1", "apex2"],
export_include_dirs: ["include"],
aidl: {
export_aidl_headers: true,
},
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_shared {
name: "mysdk_mynativelib@current",
sdk_member_name: "mynativelib",
+ apex_available: [
+ "apex1",
+ "apex2",
+ ],
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -440,13 +603,16 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
name: "mynativelib",
prefer: false,
+ apex_available: [
+ "apex1",
+ "apex2",
+ ],
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -458,8 +624,6 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -481,6 +645,187 @@
)
}
+func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: [
+ "mynativelib",
+ "myothernativelib",
+ "mysystemnativelib",
+ ],
+ }
+
+ cc_library {
+ name: "mysystemnativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "myothernativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ system_shared_libs: [
+ // A reference to a library that is not an sdk member. Uses libm as that
+ // is in the default set of modules available to this test and so is available
+ // both here and also when the generated Android.bp file is tested in
+ // CheckSnapshot(). This ensures that the system_shared_libs property correctly
+ // handles references to modules that are not sdk members.
+ "libm",
+ ],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ shared_libs: [
+ // A reference to another sdk member.
+ "myothernativelib",
+ ],
+ target: {
+ android: {
+ shared: {
+ shared_libs: [
+ // A reference to a library that is not an sdk member. The libc library
+ // is used here to check that the shared_libs property is handled correctly
+ // in a similar way to how libm is used to check system_shared_libs above.
+ "libc",
+ ],
+ },
+ },
+ },
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
+ shared_libs: [
+ "mysdk_myothernativelib@current",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ stl: "none",
+ shared_libs: [
+ "myothernativelib",
+ "libc",
+ ],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_myothernativelib@current",
+ sdk_member_name: "myothernativelib",
+ installable: false,
+ stl: "none",
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "myothernativelib",
+ prefer: false,
+ stl: "none",
+ system_shared_libs: ["libm"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/myothernativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/myothernativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mysystemnativelib@current",
+ sdk_member_name: "mysystemnativelib",
+ installable: false,
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysystemnativelib",
+ prefer: false,
+ stl: "none",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mysystemnativelib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/mysystemnativelib.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: [
+ "mysdk_mynativelib@current",
+ "mysdk_myothernativelib@current",
+ "mysdk_mysystemnativelib@current",
+ ],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so
+.intermediates/myothernativelib/android_arm64_armv8-a_shared/myothernativelib.so -> arm64/lib/myothernativelib.so
+.intermediates/myothernativelib/android_arm_armv7-a-neon_shared/myothernativelib.so -> arm/lib/myothernativelib.so
+.intermediates/mysystemnativelib/android_arm64_armv8-a_shared/mysystemnativelib.so -> arm64/lib/mysystemnativelib.so
+.intermediates/mysystemnativelib/android_arm_armv7-a-neon_shared/mysystemnativelib.so -> arm/lib/mysystemnativelib.so
+`),
+ )
+}
+
func TestHostSnapshotWithCcSharedLibrary(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
@@ -505,12 +850,12 @@
aidl: {
export_aidl_headers: true,
},
- system_shared_libs: [],
stl: "none",
+ sdk_version: "minimum",
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -519,6 +864,9 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ sdk_version: "minimum",
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -530,8 +878,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_shared {
@@ -539,6 +885,8 @@
prefer: false,
device_supported: false,
host_supported: true,
+ sdk_version: "minimum",
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -550,8 +898,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
sdk_snapshot {
@@ -575,6 +921,102 @@
)
}
+func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mynativelib"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ ],
+ stl: "none",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+ },
+ windows_x86_64: {
+ srcs: ["windows/x86_64/lib/mynativelib.dll"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mysdk_mynativelib@current"],
+ target: {
+ windows: {
+ compile_multilib: "64",
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
+.intermediates/mynativelib/windows_x86_64_shared/mynativelib.dll -> windows/x86_64/lib/mynativelib.dll
+`),
+ )
+}
+
func TestSnapshotWithCcStaticLibrary(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {
@@ -592,18 +1034,19 @@
aidl: {
export_aidl_headers: true,
},
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_static {
name: "myexports_mynativelib@current",
sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -615,13 +1058,12 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
name: "mynativelib",
prefer: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -633,8 +1075,6 @@
export_include_dirs: ["arm/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -680,12 +1120,11 @@
aidl: {
export_aidl_headers: true,
},
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -694,6 +1133,8 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -705,8 +1146,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -714,6 +1153,7 @@
prefer: false,
device_supported: false,
host_supported: true,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -725,8 +1165,6 @@
export_include_dirs: ["x86/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
@@ -750,6 +1188,92 @@
)
}
+func TestSnapshotWithCcLibrary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "myexports",
+ native_libs: ["mynativelib"],
+ }
+
+ cc_library {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ ],
+ export_include_dirs: ["include"],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library {
+ name: "myexports_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ installable: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ static: {
+ srcs: ["arm64/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ },
+ arm: {
+ static: {
+ srcs: ["arm/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ },
+}
+
+cc_prebuilt_library {
+ name: "mynativelib",
+ prefer: false,
+ stl: "none",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ static: {
+ srcs: ["arm64/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ },
+ },
+ arm: {
+ static: {
+ srcs: ["arm/lib/mynativelib.a"],
+ },
+ shared: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ native_libs: ["myexports_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_static/mynativelib.a -> arm64/lib/mynativelib.a
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> arm/lib/mynativelib.a
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+ )
+}
+
func TestHostSnapshotWithMultiLib64(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
@@ -779,12 +1303,11 @@
aidl: {
export_aidl_headers: true,
},
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -793,6 +1316,8 @@
sdk_member_name: "mynativelib",
device_supported: false,
host_supported: true,
+ installable: false,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -800,8 +1325,6 @@
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
cc_prebuilt_library_static {
@@ -809,6 +1332,7 @@
prefer: false,
device_supported: false,
host_supported: true,
+ stl: "none",
export_include_dirs: ["include/include"],
arch: {
x86_64: {
@@ -816,20 +1340,18 @@
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
},
- stl: "none",
- system_shared_libs: [],
}
module_exports_snapshot {
name: "myexports@current",
device_supported: false,
host_supported: true,
+ native_static_libs: ["myexports_mynativelib@current"],
target: {
- host: {
+ linux_glibc: {
compile_multilib: "64",
},
},
- native_static_libs: ["myexports_mynativelib@current"],
}`),
checkAllCopyRules(`
include/Test.h -> include/include/Test.h
@@ -851,29 +1373,26 @@
cc_library_headers {
name: "mynativeheaders",
export_include_dirs: ["include"],
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library_headers {
name: "mysdk_mynativeheaders@current",
sdk_member_name: "mynativeheaders",
- export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
+ export_include_dirs: ["include/include"],
}
cc_prebuilt_library_headers {
name: "mynativeheaders",
prefer: false,
- export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
+ export_include_dirs: ["include/include"],
}
sdk_snapshot {
@@ -904,12 +1423,11 @@
device_supported: false,
host_supported: true,
export_include_dirs: ["include"],
- system_shared_libs: [],
stl: "none",
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -918,9 +1436,8 @@
sdk_member_name: "mynativeheaders",
device_supported: false,
host_supported: true,
- export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
+ export_include_dirs: ["include/include"],
}
cc_prebuilt_library_headers {
@@ -928,9 +1445,8 @@
prefer: false,
device_supported: false,
host_supported: true,
- export_include_dirs: ["include/include"],
stl: "none",
- system_shared_libs: [],
+ export_include_dirs: ["include/include"],
}
sdk_snapshot {
@@ -945,3 +1461,342 @@
`),
)
}
+
+func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_header_libs: ["mynativeheaders"],
+ }
+
+ cc_library_headers {
+ name: "mynativeheaders",
+ host_supported: true,
+ stl: "none",
+ export_system_include_dirs: ["include"],
+ target: {
+ android: {
+ export_include_dirs: ["include-android"],
+ },
+ host: {
+ export_include_dirs: ["include-host"],
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+ name: "mysdk_mynativeheaders@current",
+ sdk_member_name: "mynativeheaders",
+ host_supported: true,
+ stl: "none",
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+}
+
+cc_prebuilt_library_headers {
+ name: "mynativeheaders",
+ prefer: false,
+ host_supported: true,
+ stl: "none",
+ export_system_include_dirs: ["include/include"],
+ target: {
+ android: {
+ export_include_dirs: ["include/include-android"],
+ },
+ linux_glibc: {
+ export_include_dirs: ["include/include-host"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+include-android/AndroidTest.h -> include/include-android/AndroidTest.h
+include-host/HostTest.h -> include/include-host/HostTest.h
+`),
+ )
+}
+
+func TestSystemSharedLibPropagation(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["sslnil", "sslempty", "sslnonempty"],
+ }
+
+ cc_library {
+ name: "sslnil",
+ host_supported: true,
+ }
+
+ cc_library {
+ name: "sslempty",
+ system_shared_libs: [],
+ }
+
+ cc_library {
+ name: "sslnonempty",
+ system_shared_libs: ["sslnil"],
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_sslnil@current",
+ sdk_member_name: "sslnil",
+ installable: false,
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslnil.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslnil.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "sslnil",
+ prefer: false,
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslnil.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslnil.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_sslempty@current",
+ sdk_member_name: "sslempty",
+ installable: false,
+ system_shared_libs: [],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslempty.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "sslempty",
+ prefer: false,
+ system_shared_libs: [],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslempty.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mysdk_sslnonempty@current",
+ sdk_member_name: "sslnonempty",
+ installable: false,
+ system_shared_libs: ["mysdk_sslnil@current"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslnonempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslnonempty.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "sslnonempty",
+ prefer: false,
+ system_shared_libs: ["sslnil"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/sslnonempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/sslnonempty.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: [
+ "mysdk_sslnil@current",
+ "mysdk_sslempty@current",
+ "mysdk_sslnonempty@current",
+ ],
+}
+`))
+
+ result = testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_shared_libs: ["sslvariants"],
+ }
+
+ cc_library {
+ name: "sslvariants",
+ host_supported: true,
+ target: {
+ android: {
+ system_shared_libs: [],
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_sslvariants@current",
+ sdk_member_name: "sslvariants",
+ host_supported: true,
+ installable: false,
+ target: {
+ android: {
+ system_shared_libs: [],
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/sslvariants.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/sslvariants.so"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/sslvariants.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "sslvariants",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ system_shared_libs: [],
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/sslvariants.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/sslvariants.so"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/sslvariants.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_shared_libs: ["mysdk_sslvariants@current"],
+}
+`))
+}
+
+func TestStubsLibrary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["stubslib"],
+ }
+
+ cc_library {
+ name: "stubslib",
+ stubs: {
+ symbol_file: "some/where/stubslib.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_stubslib@current",
+ sdk_member_name: "stubslib",
+ installable: false,
+ stubs: {
+ versions: ["3"],
+ },
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/stubslib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/stubslib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "stubslib",
+ prefer: false,
+ stubs: {
+ versions: ["3"],
+ },
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/stubslib.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/stubslib.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: ["mysdk_stubslib@current"],
+}
+`))
+}
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index b905d71..20e2521 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -42,7 +42,7 @@
"package/Android.bp": []byte(packageBp),
})
- result.CheckSnapshot("myexports", "android_common", "package",
+ result.CheckSnapshot("myexports", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 0737e5e..c0ad35c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -24,7 +24,51 @@
fs := map[string][]byte{
"Test.java": nil,
"aidl/foo/bar/Test.aidl": nil,
+
+ // For java_sdk_library
+ "api/current.txt": nil,
+ "api/removed.txt": nil,
+ "api/system-current.txt": nil,
+ "api/system-removed.txt": nil,
+ "api/test-current.txt": nil,
+ "api/test-removed.txt": nil,
+ "build/soong/scripts/gen-java-current-api-files.sh": nil,
}
+
+ // for java_sdk_library tests
+ bp = `
+java_system_modules_import {
+ name: "core-current-stubs-system-modules",
+}
+java_system_modules_import {
+ name: "core-platform-api-stubs-system-modules",
+}
+java_import {
+ name: "core.platform.api.stubs",
+}
+java_sdk_library_import {
+ name: "android_stubs_current",
+}
+java_sdk_library_import {
+ name: "android_system_stubs_current",
+}
+java_sdk_library_import {
+ name: "android_test_stubs_current",
+}
+java_import {
+ name: "core-lambda-stubs",
+ sdk_version: "none",
+}
+java_import {
+ name: "ext",
+ sdk_version: "none",
+}
+java_import {
+ name: "framework",
+ sdk_version: "none",
+}
+` + bp
+
return testSdkWithFs(t, bp, fs)
}
@@ -53,30 +97,18 @@
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 {
@@ -141,7 +173,7 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -196,7 +228,7 @@
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -230,6 +262,72 @@
)
}
+func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
+
func TestSnapshotWithJavaImplLibrary(t *testing.T) {
result := testSdkWithJava(t, `
module_exports {
@@ -250,7 +348,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -305,7 +403,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -356,7 +454,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -409,7 +507,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -503,7 +601,7 @@
}
`)
- result.CheckSnapshot("myexports", "android_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -526,7 +624,7 @@
`),
checkAllCopyRules(""),
- checkMergeZip(".intermediates/myexports/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ checkMergeZips(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@@ -552,7 +650,7 @@
}
`)
- result.CheckSnapshot("myexports", "linux_glibc_common", "",
+ result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -580,7 +678,7 @@
}
`),
checkAllCopyRules(""),
- checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ checkMergeZips(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@@ -612,7 +710,7 @@
}
`)
- result.CheckSnapshot("mysdk", "android_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -702,7 +800,7 @@
}
`)
- result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -750,3 +848,222 @@
checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
)
}
+
+func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ module_exports {
+ name: "myexports",
+ host_supported: true,
+ java_libs: ["myjavalib"],
+ target: {
+ android: {
+ java_header_libs: ["androidjavalib"],
+ },
+ host: {
+ java_header_libs: ["hostjavalib"],
+ },
+ },
+ }
+
+ java_library {
+ name: "myjavalib",
+ host_supported: true,
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library {
+ name: "androidjavalib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_library_host {
+ name: "hostjavalib",
+ srcs: ["Test.java"],
+ }
+ `)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "myexports_hostjavalib@current",
+ sdk_member_name: "hostjavalib",
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "hostjavalib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/hostjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_androidjavalib@current",
+ sdk_member_name: "androidjavalib",
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "androidjavalib",
+ prefer: false,
+ jars: ["java/androidjavalib.jar"],
+}
+
+java_import {
+ name: "myexports_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ host_supported: true,
+ target: {
+ android: {
+ jars: ["java/android/myjavalib.jar"],
+ },
+ linux_glibc: {
+ jars: ["java/linux_glibc/myjavalib.jar"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ host_supported: true,
+ java_libs: ["myexports_myjavalib@current"],
+ target: {
+ android: {
+ java_header_libs: ["myexports_androidjavalib@current"],
+ },
+ linux_glibc: {
+ java_header_libs: ["myexports_hostjavalib@current"],
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
+.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+ )
+}
+
+func TestSnapshotWithJavaSdkLibrary(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_sdk_libs: ["myjavalib"],
+ }
+
+ java_sdk_library {
+ name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ srcs: ["Test.java"],
+ sdk_version: "current",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+ system: {
+ jars: ["sdk_library/system/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+ current_api: "sdk_library/system/myjavalib.txt",
+ removed_api: "sdk_library/system/myjavalib-removed.txt",
+ sdk_version: "system_current",
+ },
+ test: {
+ jars: ["sdk_library/test/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/test/myjavalib_stub_sources"],
+ current_api: "sdk_library/test/myjavalib.txt",
+ removed_api: "sdk_library/test/myjavalib-removed.txt",
+ sdk_version: "test_current",
+ },
+}
+
+java_sdk_library_import {
+ name: "myjavalib",
+ prefer: false,
+ apex_available: ["//apex_available:anyapex"],
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+ system: {
+ jars: ["sdk_library/system/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+ current_api: "sdk_library/system/myjavalib.txt",
+ removed_api: "sdk_library/system/myjavalib-removed.txt",
+ sdk_version: "system_current",
+ },
+ test: {
+ jars: ["sdk_library/test/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/test/myjavalib_stub_sources"],
+ current_api: "sdk_library/test/myjavalib.txt",
+ removed_api: "sdk_library/test/myjavalib-removed.txt",
+ sdk_version: "test_current",
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_sdk_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.test/android_common/javac/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.test/android_common/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib.txt
+.intermediates/myjavalib.stubs.source.test/android_common/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib-removed.txt
+`),
+ checkMergeZips(
+ ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+ ".intermediates/mysdk/common_os/tmp/sdk_library/system/myjavalib_stub_sources.zip",
+ ".intermediates/mysdk/common_os/tmp/sdk_library/test/myjavalib_stub_sources.zip"),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4976dc0..cb5a605 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -50,8 +50,17 @@
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
- // The set of exported members.
- exportedMembers map[string]struct{}
+ // Information about the OsType specific member variants associated with this variant.
+ //
+ // Set by OsType specific variants in the collectMembers() method and used by the
+ // CommonOS variant when building the snapshot. That work is all done on separate
+ // calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
+ // called for the OsType specific variants before the CommonOS variant (because
+ // the latter depends on the former).
+ memberRefs []sdkMemberRef
+
+ // The multilib variants that are used by this sdk variant.
+ multilibUsages multilibUsage
properties sdkProperties
@@ -143,6 +152,7 @@
fields = append(fields, reflect.StructField{
Name: proptools.FieldNameForProperty(p),
Type: reflect.TypeOf([]string{}),
+ Tag: `android:"arch_variant"`,
})
// Copy the field index for use in the getter func as using the loop variable directly will
@@ -201,7 +211,7 @@
// properties for the member type specific list properties.
s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties()
s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
- android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(s)
android.AddLoadHook(s, func(ctx android.LoadHookContext) {
type props struct {
@@ -225,26 +235,19 @@
}
func (s *sdk) getExportedMembers() map[string]struct{} {
- if s.exportedMembers == nil {
- // Collect all the exported members.
- s.exportedMembers = make(map[string]struct{})
+ // Collect all the exported members.
+ exportedMembers := make(map[string]struct{})
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
+ 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{}{}
- }
+ // Every member specified explicitly in the properties is exported by the sdk.
+ for _, name := range names {
+ exportedMembers[name] = struct{}{}
}
}
- return s.exportedMembers
-}
-
-func (s *sdk) isInternalMember(memberName string) bool {
- _, ok := s.getExportedMembers()[memberName]
- return !ok
+ return exportedMembers
}
func (s *sdk) snapshot() bool {
@@ -252,10 +255,31 @@
}
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if !s.snapshot() {
+ if s.snapshot() {
// We don't need to create a snapshot out of sdk_snapshot.
// That doesn't make sense. We need a snapshot to create sdk_snapshot.
- s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
+ return
+ }
+
+ // This method is guaranteed to be called on OsType specific variants before it is called
+ // on their corresponding CommonOS variant.
+ if !s.IsCommonOSVariant() {
+ // Update the OsType specific sdk variant with information about its members.
+ s.collectMembers(ctx)
+ } else {
+ // Get the OsType specific variants on which the CommonOS depends.
+ osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
+ var sdkVariants []*sdk
+ for _, m := range osSpecificVariants {
+ if sdkVariant, ok := m.(*sdk); ok {
+ sdkVariants = append(sdkVariants, sdkVariant)
+ }
+ }
+
+ // Generate the snapshot from the member info.
+ p := s.buildSnapshot(ctx, sdkVariants)
+ s.snapshotFile = android.OptionalPathForPath(p)
+ ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
}
}
@@ -288,7 +312,7 @@
ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
}
-// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// RegisterPostDepsMutators registers post-deps mutators to support modules implementing SdkAware
// interface and the sdk module type. This function has been made public to be called by tests
// outside of the sdk package
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -320,11 +344,14 @@
// Step 1: create dependencies from an SDK module to its members.
func memberMutator(mctx android.BottomUpMutatorContext) {
if s, ok := mctx.Module().(*sdk); ok {
- if s.Enabled() {
+ // Add dependencies from enabled and non CommonOS variants to the sdk member variants.
+ if s.Enabled() && !s.IsCommonOSVariant() {
for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- tag := memberListProperty.dependencyTag
- memberListProperty.memberType.AddDependencies(mctx, tag, names)
+ if len(names) > 0 {
+ tag := memberListProperty.dependencyTag
+ memberListProperty.memberType.AddDependencies(mctx, tag, names)
+ }
}
}
}
@@ -404,23 +431,31 @@
}
}
-// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs
+// Step 6: ensure that the dependencies outside of the APEX are all from the required SDKs
func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
if m, ok := mctx.Module().(interface {
- DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool
- RequiredSdks() android.SdkRefs
+ android.DepIsInSameApex
+ android.RequiredSdks
}); ok {
requiredSdks := m.RequiredSdks()
if len(requiredSdks) == 0 {
return
}
mctx.VisitDirectDeps(func(dep android.Module) {
- if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ if tag == android.DefaultsDepTag {
// dependency to defaults is always okay
return
}
- // If the dep is from outside of the APEX, but is not in any of the
+ // Ignore the dependency from the unversioned member to any versioned members as an
+ // apex that depends on the unversioned member will not also be depending on a versioned
+ // member.
+ if _, ok := tag.(sdkMemberVersionedDepTag); ok {
+ return
+ }
+
+ // If the dep is outside of the APEX, but is not in any of the
// required SDKs, we know that the dep is a violation.
if sa, ok := dep.(android.SdkAware); ok {
if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 934bdae..fde9230 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -16,6 +16,8 @@
import (
"testing"
+
+ "github.com/google/blueprint/proptools"
)
// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
@@ -58,6 +60,7 @@
sdk_version: "none",
compile_dex: true,
host_supported: true,
+ apex_available: ["myapex"],
}
// this lib is no in mysdk
@@ -113,7 +116,7 @@
java_defaults {
name: "java-defaults",
- visibility: ["//other/bar"],
+ visibility: ["//other/bar"],
}
java_library {
@@ -145,7 +148,7 @@
"package/Android.bp": []byte(packageBp),
})
- result.CheckSnapshot("mysdk", "android_common", "package",
+ result.CheckSnapshot("mysdk", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -205,3 +208,122 @@
}
`))
}
+
+func TestSDkInstall(t *testing.T) {
+ sdk := `
+ sdk {
+ name: "mysdk",
+ }
+ `
+ result := testSdkWithFs(t, ``,
+ map[string][]byte{
+ "Android.bp": []byte(sdk),
+ })
+
+ result.CheckSnapshot("mysdk", "",
+ checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
+ )
+}
+
+type EmbeddedPropertiesStruct struct {
+ S_Embedded_Common string
+ S_Embedded_Different string
+}
+
+type testPropertiesStruct struct {
+ private string
+ Public_Kept string `sdk:"keep"`
+ S_Common string
+ S_Different string
+ A_Common []string
+ A_Different []string
+ F_Common *bool
+ F_Different *bool
+ EmbeddedPropertiesStruct
+}
+
+func TestCommonValueOptimization(t *testing.T) {
+ common := &testPropertiesStruct{}
+ structs := []*testPropertiesStruct{
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "upper",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "beta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_upper",
+ },
+ },
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "common",
+ S_Different: "lower",
+ A_Common: []string{"first", "second"},
+ A_Different: []string{"alpha", "delta"},
+ F_Common: proptools.BoolPtr(false),
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "embedded_lower",
+ },
+ },
+ }
+
+ extractor := newCommonValueExtractor(common)
+ extractor.extractCommonProperties(common, structs)
+
+ h := TestHelper{t}
+ h.AssertDeepEquals("common properties not correct", common,
+ &testPropertiesStruct{
+ private: "",
+ Public_Kept: "",
+ S_Common: "common",
+ S_Different: "",
+ A_Common: []string{"first", "second"},
+ A_Different: []string(nil),
+ F_Common: proptools.BoolPtr(false),
+ F_Different: nil,
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "embedded_common",
+ S_Embedded_Different: "",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[0] not correct", structs[0],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "upper",
+ A_Common: nil,
+ A_Different: []string{"alpha", "beta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(false),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_upper",
+ },
+ })
+
+ h.AssertDeepEquals("updated properties[1] not correct", structs[1],
+ &testPropertiesStruct{
+ private: "common",
+ Public_Kept: "common",
+ S_Common: "",
+ S_Different: "lower",
+ A_Common: nil,
+ A_Different: []string{"alpha", "delta"},
+ F_Common: nil,
+ F_Different: proptools.BoolPtr(true),
+ EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
+ S_Embedded_Common: "",
+ S_Embedded_Different: "embedded_lower",
+ },
+ })
+}
diff --git a/sdk/testing.go b/sdk/testing.go
index ae0620d..9e27201 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -19,6 +19,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strings"
"testing"
@@ -40,7 +41,7 @@
name: "myapex.cert",
certificate: "myapex",
}
- ` + cc.GatherRequiredDepsForTest(android.Android)
+ ` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
mockFS := map[string][]byte{
"build/make/target/product/security": nil,
@@ -61,8 +62,24 @@
config := android.TestArchConfig(buildDir, nil, bp, mockFS)
+ // Add windows as a default disable OS to test behavior when some OS variants
+ // are disabled.
+ config.Targets[android.Windows] = []android.Target{
+ {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
+ }
+
ctx := android.NewTestArchContext()
+ // Enable androidmk support.
+ // * Register the singleton
+ // * Configure that we are inside make
+ // * Add CommonOS to ensure that androidmk processing works.
+ android.RegisterAndroidMkBuildComponents(ctx)
+ android.SetInMakeForTests(config)
+ config.Targets[android.CommonOS] = []android.Target{
+ {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""},
+ }
+
// from android package
android.RegisterPackageBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
@@ -73,6 +90,7 @@
// from java package
java.RegisterJavaBuildComponents(ctx)
java.RegisterAppBuildComponents(ctx)
+ java.RegisterSdkLibraryBuildComponents(ctx)
java.RegisterStubsBuildComponents(ctx)
java.RegisterSystemModulesBuildComponents(ctx)
@@ -160,6 +178,13 @@
h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
}
+func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
+ h.t.Helper()
+ if !reflect.DeepEqual(actual, expected) {
+ h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
+ }
+}
+
// Encapsulates result of processing an SDK definition. Provides support for
// checking the state of the build structures.
type testSdkResult struct {
@@ -182,15 +207,23 @@
buildParams := sdk.BuildParamsForTests()
copyRules := &strings.Builder{}
+ otherCopyRules := &strings.Builder{}
+ snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
for _, bp := range buildParams {
switch bp.Rule.String() {
case android.Cp.String():
- // Get source relative to build directory.
- src := android.NormalizePathForTesting(bp.Input)
+ output := bp.Output
// Get destination relative to the snapshot root
- dest := bp.Output.Rel()
- _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
- info.snapshotContents = append(info.snapshotContents, dest)
+ dest := output.Rel()
+ src := android.NormalizePathForTesting(bp.Input)
+ // We differentiate between copy rules for the snapshot, and copy rules for the install file.
+ if strings.HasPrefix(output.String(), snapshotDirPrefix) {
+ // Get source relative to build directory.
+ _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
+ info.snapshotContents = append(info.snapshotContents, dest)
+ } else {
+ _, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
+ }
case repackageZip.String():
// Add the destdir to the snapshot contents as that is effectively where
@@ -223,6 +256,7 @@
}
info.copyRules = copyRules.String()
+ info.otherCopyRules = otherCopyRules.String()
return info
}
@@ -240,9 +274,12 @@
// Takes a list of functions which check different facets of the snapshot build rules.
// Allows each test to customize what is checked without duplicating lots of code
// or proliferating check methods of different flavors.
-func (r *testSdkResult) CheckSnapshot(name string, variant string, dir string, checkers ...snapshotBuildInfoChecker) {
+func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) {
r.t.Helper()
+ // The sdk CommonOS variant is always responsible for generating the snapshot.
+ variant := android.CommonOS.Name
+
sdk := r.Module(name, variant).(*sdk)
snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
@@ -295,14 +332,22 @@
}
}
-// Check that the specified path is in the list of zips to merge with the intermediate zip.
-func checkMergeZip(expected string) snapshotBuildInfoChecker {
+func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.r.t.Helper()
+ info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
+ }
+}
+
+// Check that the specified paths match the list of zips to merge with the intermediate zip.
+func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
info.r.t.Helper()
if info.intermediateZip == "" {
info.r.t.Errorf("No intermediate zip file was created")
}
- ensureListContains(info.r.t, info.mergeZips, expected)
+
+ info.r.AssertDeepEquals("mismatching merge zip files", expected, info.mergeZips)
}
}
@@ -321,10 +366,14 @@
// snapshot.
snapshotContents []string
- // A formatted representation of the src/dest pairs, one pair per line, of the format
- // src -> dest
+ // A formatted representation of the src/dest pairs for a snapshot, one pair per line,
+ // of the format src -> dest
copyRules string
+ // A formatted representation of the src/dest pairs for files not in a snapshot, one pair
+ // per line, of the format src -> dest
+ otherCopyRules string
+
// The path to the intermediate zip, which is a zip created from the source files copied
// into the snapshot directory and which will be merged with other zips to form the final output.
// Is am empty string if there is no intermediate zip because there are no zips to merge in.
diff --git a/sdk/update.go b/sdk/update.go
index d211e80..e14347f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -17,8 +17,11 @@
import (
"fmt"
"reflect"
+ "sort"
"strings"
+ "android/soong/apex"
+ "android/soong/cc"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -104,18 +107,10 @@
// 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.SdkMemberTypesRegistry.
-// The names are in the order in which the dependencies were added.
-//
-// Returns the members as well as the multilib setting to use.
-func (s *sdk) collectMembers(ctx android.ModuleContext) ([]*sdkMember, string) {
- byType := make(map[android.SdkMemberType][]*sdkMember)
- byName := make(map[string]*sdkMember)
-
- lib32 := false // True if any of the members have 32 bit version.
- lib64 := false // True if any of the members have 64 bit version.
-
+// Returns a list containing type (extracted from the dependency tag) and the variant
+// plus the multilib usages.
+func (s *sdk) collectMembers(ctx android.ModuleContext) {
+ s.multilibUsages = multilibNone
ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
tag := ctx.OtherModuleDependencyTag(child)
if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -126,24 +121,10 @@
ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
}
- name := ctx.OtherModuleName(child)
- member := byName[name]
- if member == nil {
- member = &sdkMember{memberType: memberType, name: name}
- byName[name] = member
- byType[memberType] = append(byType[memberType], member)
- }
+ // Keep track of which multilib variants are used by the sdk.
+ s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
- multilib := child.Target().Arch.ArchType.Multilib
- if multilib == "lib32" {
- lib32 = true
- } else if multilib == "lib64" {
- lib64 = true
- }
-
- // 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))
+ s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
// If the member type supports transitive sdk members then recurse down into
// its dependencies, otherwise exit traversal.
@@ -152,6 +133,35 @@
return false
})
+}
+
+// Organize 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.SdkMemberTypesRegistry.
+// The names are in the order in which the dependencies were added.
+//
+// Returns the members as well as the multilib setting to use.
+func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
+ byType := make(map[android.SdkMemberType][]*sdkMember)
+ byName := make(map[string]*sdkMember)
+
+ for _, memberRef := range memberRefs {
+ memberType := memberRef.memberType
+ variant := memberRef.variant
+
+ name := ctx.OtherModuleName(variant)
+ member := byName[name]
+ if member == nil {
+ member = &sdkMember{memberType: memberType, name: name}
+ byName[name] = member
+ byType[memberType] = append(byType[memberType], member)
+ }
+
+ // 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, variant)
+ }
var members []*sdkMember
for _, memberListProperty := range s.memberListProperties() {
@@ -159,17 +169,7 @@
members = append(members, membersOfType...)
}
- // Compute the setting of multilib.
- var multilib string
- if lib32 && lib64 {
- multilib = "both"
- } else if lib32 {
- multilib = "32"
- } else if lib64 {
- multilib = "64"
- }
-
- return members, multilib
+ return members
}
func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
@@ -207,7 +207,26 @@
// buildSnapshot is the main function in this source file. It creates rules to copy
// the contents (header files, stub libraries, etc) into the zip file.
-func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
+func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+
+ allMembersByName := make(map[string]struct{})
+ exportedMembersByName := make(map[string]struct{})
+ var memberRefs []sdkMemberRef
+ for _, sdkVariant := range sdkVariants {
+ memberRefs = append(memberRefs, sdkVariant.memberRefs...)
+
+ // Record the names of all the members, both explicitly specified and implicitly
+ // included.
+ for _, memberRef := range sdkVariant.memberRefs {
+ allMembersByName[memberRef.variant.Name()] = struct{}{}
+ }
+
+ // Merge the exported member sets from all sdk variants.
+ for key, _ := range sdkVariant.getExportedMembers() {
+ exportedMembersByName[key] = struct{}{}
+ }
+ }
+
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
@@ -217,20 +236,27 @@
}
builder := &snapshotBuilder{
- ctx: ctx,
- sdk: s,
- version: "current",
- snapshotDir: snapshotDir.OutputPath,
- copies: make(map[string]string),
- filesToZip: []android.Path{bp.path},
- bpFile: bpFile,
- prebuiltModules: make(map[string]*bpModule),
+ ctx: ctx,
+ sdk: s,
+ version: "current",
+ snapshotDir: snapshotDir.OutputPath,
+ copies: make(map[string]string),
+ filesToZip: []android.Path{bp.path},
+ bpFile: bpFile,
+ prebuiltModules: make(map[string]*bpModule),
+ allMembersByName: allMembersByName,
+ exportedMembersByName: exportedMembersByName,
}
s.builderForTests = builder
- members, multilib := s.collectMembers(ctx)
+ members := s.organizeMembers(ctx, memberRefs)
for _, member := range members {
- member.memberType.BuildSnapshot(ctx, builder, member)
+ memberType := member.memberType
+
+ memberCtx := &memberContext{ctx, builder, memberType, member.name}
+
+ prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
+ s.createMemberSnapshot(memberCtx, member, prebuiltModule)
}
// Create a transformer that will transform an unversioned module into a versioned module.
@@ -273,23 +299,46 @@
snapshotModule.AddProperty("visibility", visibility)
}
- addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
+ addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
- // Compile_multilib defaults to both and must always be set to both on the
- // device and so only needs to be set when targeted at the host and is neither
- // unspecified or both.
- if s.HostSupported() && multilib != "" && multilib != "both" {
- targetSet := snapshotModule.AddPropertySet("target")
- hostSet := targetSet.AddPropertySet("host")
- hostSet.AddProperty("compile_multilib", multilib)
+ var dynamicMemberPropertiesList []interface{}
+ osTypeToMemberProperties := make(map[android.OsType]*sdk)
+ for _, sdkVariant := range sdkVariants {
+ properties := sdkVariant.dynamicMemberTypeListProperties
+ osTypeToMemberProperties[sdkVariant.Target().Os] = sdkVariant
+ dynamicMemberPropertiesList = append(dynamicMemberPropertiesList, properties)
}
- for _, memberListProperty := range s.memberListProperties() {
- names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
- if len(names) > 0 {
- snapshotModule.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names))
+ // Extract the common lists of members into a separate struct.
+ commonDynamicMemberProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+ extractor := newCommonValueExtractor(commonDynamicMemberProperties)
+ extractor.extractCommonProperties(commonDynamicMemberProperties, dynamicMemberPropertiesList)
+
+ // Add properties common to all os types.
+ s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
+
+ // Iterate over the os types in a fixed order.
+ targetPropertySet := snapshotModule.AddPropertySet("target")
+ for _, osType := range s.getPossibleOsTypes() {
+ if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
+ osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+
+ // Compile_multilib defaults to both and must always be set to both on the
+ // device and so only needs to be set when targeted at the host and is neither
+ // unspecified or both.
+ multilib := sdkVariant.multilibUsages
+ if (osType.Class == android.Host || osType.Class == android.HostCross) &&
+ multilib != multilibNone && multilib != multilibBoth {
+ osPropertySet.AddProperty("compile_multilib", multilib.String())
+ }
+
+ s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
}
}
+
+ // Prune any empty property sets.
+ snapshotModule.transform(pruneEmptySetTransformer{})
+
bpFile.AddModule(snapshotModule)
// generate Android.bp
@@ -340,11 +389,32 @@
return outputZipFile
}
+func (s *sdk) addMemberPropertiesToPropertySet(builder *snapshotBuilder, propertySet android.BpPropertySet, dynamicMemberTypeListProperties interface{}) {
+ for _, memberListProperty := range s.memberListProperties() {
+ names := memberListProperty.getter(dynamicMemberTypeListProperties)
+ if len(names) > 0 {
+ propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
+ }
+ }
+}
+
type propertyTag struct {
name string
}
-var sdkMemberReferencePropertyTag = propertyTag{"sdkMemberReferencePropertyTag"}
+// A BpPropertyTag to add to a property that contains references to other sdk members.
+//
+// This will cause the references to be rewritten to a versioned reference in the version
+// specific instance of a snapshot module.
+var requiredSdkMemberReferencePropertyTag = propertyTag{"requiredSdkMemberReferencePropertyTag"}
+var optionalSdkMemberReferencePropertyTag = propertyTag{"optionalSdkMemberReferencePropertyTag"}
+
+// A BpPropertyTag that indicates the property should only be present in the versioned
+// module.
+//
+// This will cause the property to be removed from the unversioned instance of a
+// snapshot module.
+var sdkVersionedOnlyPropertyTag = propertyTag{"sdkVersionedOnlyPropertyTag"}
type unversionedToVersionedTransformation struct {
identityTransformation
@@ -355,14 +425,15 @@
// 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.setProperty("name", t.builder.versionedSdkMemberName(name, true))
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
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.versionedSdkMemberNames(value.([]string), required), tag
} else {
return value, tag
}
@@ -376,7 +447,7 @@
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))
+ module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
// Set prefer: false - this is not strictly required as that is the default.
module.insertAfter("name", "prefer", false)
@@ -385,8 +456,12 @@
}
func (t unversionedTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
- if tag == sdkMemberReferencePropertyTag {
- return t.builder.unversionedSdkMemberNames(value.([]string)), tag
+ if tag == requiredSdkMemberReferencePropertyTag || tag == optionalSdkMemberReferencePropertyTag {
+ required := tag == requiredSdkMemberReferencePropertyTag
+ return t.builder.unversionedSdkMemberNames(value.([]string), required), tag
+ } else if tag == sdkVersionedOnlyPropertyTag {
+ // The property is not allowed in the unversioned module so remove it.
+ return nil, nil
} else {
return value, tag
}
@@ -418,41 +493,53 @@
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
contents.Indent()
+
+ // Output the properties first, followed by the nested sets. This ensures a
+ // consistent output irrespective of whether property sets are created before
+ // or after the properties. This simplifies the creation of the module.
for _, name := range set.order {
value := set.getValue(name)
- reflectedValue := reflect.ValueOf(value)
- t := reflectedValue.Type()
-
- kind := t.Kind()
- switch kind {
- case reflect.Slice:
- length := reflectedValue.Len()
+ switch v := value.(type) {
+ case []string:
+ length := len(v)
if length > 1 {
contents.Printfln("%s: [", name)
contents.Indent()
for i := 0; i < length; i = i + 1 {
- contents.Printfln("%q,", reflectedValue.Index(i).Interface())
+ contents.Printfln("%q,", v[i])
}
contents.Dedent()
contents.Printfln("],")
} else if length == 0 {
contents.Printfln("%s: [],", name)
} else {
- contents.Printfln("%s: [%q],", name, reflectedValue.Index(0).Interface())
+ contents.Printfln("%s: [%q],", name, v[0])
}
- case reflect.Bool:
- contents.Printfln("%s: %t,", name, reflectedValue.Bool())
- case reflect.Ptr:
- contents.Printfln("%s: {", name)
- outputPropertySet(contents, reflectedValue.Interface().(*bpPropertySet))
- contents.Printfln("},")
+ case bool:
+ contents.Printfln("%s: %t,", name, v)
+
+ case *bpPropertySet:
+ // Do not write property sets in the properties phase.
default:
contents.Printfln("%s: %q,", name, value)
}
}
+
+ for _, name := range set.order {
+ value := set.getValue(name)
+
+ // Only write property sets in the sets phase.
+ switch v := value.(type) {
+ case *bpPropertySet:
+ contents.Printfln("%s: {", name)
+ outputPropertySet(contents, v)
+ contents.Printfln("},")
+ }
+ }
+
contents.Dedent()
}
@@ -478,6 +565,12 @@
prebuiltModules map[string]*bpModule
prebuiltOrder []*bpModule
+
+ // The set of all members by name.
+ allMembersByName map[string]struct{}
+
+ // The set of exported members by name.
+ exportedMembersByName map[string]struct{}
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -529,69 +622,137 @@
m := s.bpFile.newModule(moduleType)
m.AddProperty("name", name)
- if s.sdk.isInternalMember(name) {
+ variant := member.Variants()[0]
+
+ if s.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])
+ visibility := android.EffectiveVisibilityRules(s.ctx, variant)
if len(visibility) != 0 {
m.AddProperty("visibility", visibility)
}
}
- addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
+ deviceSupported := false
+ hostSupported := false
+
+ for _, variant := range member.Variants() {
+ osClass := variant.Target().Os.Class
+ if osClass == android.Host || osClass == android.HostCross {
+ hostSupported = true
+ } else if osClass == android.Device {
+ deviceSupported = true
+ }
+ }
+
+ addHostDeviceSupportedProperties(deviceSupported, hostSupported, m)
+
+ // Where available copy apex_available properties from the member.
+ if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
+ apexAvailable := apexAware.ApexAvailable()
+
+ // Add in any white listed apex available settings.
+ apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...)
+
+ if len(apexAvailable) > 0 {
+ // Remove duplicates and sort.
+ apexAvailable = android.FirstUniqueStrings(apexAvailable)
+ sort.Strings(apexAvailable)
+
+ m.AddProperty("apex_available", apexAvailable)
+ }
+ }
+
+ // Disable installation in the versioned module of those modules that are ever installable.
+ if installable, ok := variant.(interface{ EverInstallable() bool }); ok {
+ if installable.EverInstallable() {
+ m.AddPropertyWithTag("installable", false, sdkVersionedOnlyPropertyTag)
+ }
+ }
s.prebuiltModules[name] = m
s.prebuiltOrder = append(s.prebuiltOrder, m)
return m
}
-func addHostDeviceSupportedProperties(module *android.ModuleBase, bpModule *bpModule) {
- if !module.DeviceSupported() {
+func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
+ if !deviceSupported {
bpModule.AddProperty("device_supported", false)
}
- if module.HostSupported() {
+ if hostSupported {
bpModule.AddProperty("host_supported", true)
}
}
-func (s *snapshotBuilder) SdkMemberReferencePropertyTag() android.BpPropertyTag {
- return sdkMemberReferencePropertyTag
+func (s *snapshotBuilder) SdkMemberReferencePropertyTag(required bool) android.BpPropertyTag {
+ if required {
+ return requiredSdkMemberReferencePropertyTag
+ } else {
+ return optionalSdkMemberReferencePropertyTag
+ }
+}
+
+func (s *snapshotBuilder) OptionalSdkMemberReferencePropertyTag() android.BpPropertyTag {
+ return optionalSdkMemberReferencePropertyTag
}
// Get a versioned name appropriate for the SDK snapshot version being taken.
-func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
+func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
}
-func (s *snapshotBuilder) versionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) versionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.versionedSdkMemberName(m))
+ references = append(references, s.versionedSdkMemberName(m, required))
}
return references
}
// Get an internal name unique to the sdk.
-func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string) string {
- if s.sdk.isInternalMember(unversionedName) {
+func (s *snapshotBuilder) unversionedSdkMemberName(unversionedName string, required bool) string {
+ if _, ok := s.allMembersByName[unversionedName]; !ok {
+ if required {
+ s.ctx.ModuleErrorf("Required member reference %s is not a member of the sdk", unversionedName)
+ }
+ return unversionedName
+ }
+
+ if s.isInternalMember(unversionedName) {
return s.ctx.ModuleName() + "_" + unversionedName
} else {
return unversionedName
}
}
-func (s *snapshotBuilder) unversionedSdkMemberNames(members []string) []string {
+func (s *snapshotBuilder) unversionedSdkMemberNames(members []string, required bool) []string {
var references []string = nil
for _, m := range members {
- references = append(references, s.unversionedSdkMemberName(m))
+ references = append(references, s.unversionedSdkMemberName(m, required))
}
return references
}
+func (s *snapshotBuilder) isInternalMember(memberName string) bool {
+ _, ok := s.exportedMembersByName[memberName]
+ return !ok
+}
+
+type sdkMemberRef struct {
+ memberType android.SdkMemberType
+ variant android.SdkAware
+}
+
var _ android.SdkMember = (*sdkMember)(nil)
type sdkMember struct {
@@ -607,3 +768,556 @@
func (m *sdkMember) Variants() []android.SdkAware {
return m.variants
}
+
+// Track usages of multilib variants.
+type multilibUsage int
+
+const (
+ multilibNone multilibUsage = 0
+ multilib32 multilibUsage = 1
+ multilib64 multilibUsage = 2
+ multilibBoth = multilib32 | multilib64
+)
+
+// Add the multilib that is used in the arch type.
+func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
+ multilib := archType.Multilib
+ switch multilib {
+ case "":
+ return m
+ case "lib32":
+ return m | multilib32
+ case "lib64":
+ return m | multilib64
+ default:
+ panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+ }
+}
+
+func (m multilibUsage) String() string {
+ switch m {
+ case multilibNone:
+ return ""
+ case multilib32:
+ return "32"
+ case multilib64:
+ return "64"
+ case multilibBoth:
+ return "both"
+ default:
+ panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+ m, multilibNone, multilib32, multilib64, multilibBoth))
+ }
+}
+
+type baseInfo struct {
+ Properties android.SdkMemberProperties
+}
+
+type osTypeSpecificInfo struct {
+ baseInfo
+
+ osType android.OsType
+
+ // The list of arch type specific info for this os type.
+ //
+ // Nil if there is one variant whose arch type is common
+ archInfos []*archTypeSpecificInfo
+}
+
+type variantPropertiesFactoryFunc func() android.SdkMemberProperties
+
+// Create a new osTypeSpecificInfo for the specified os type and its properties
+// structures populated with information from the variants.
+func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo {
+ osInfo := &osTypeSpecificInfo{
+ osType: osType,
+ }
+
+ osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
+ properties := variantPropertiesFactory()
+ properties.Base().Os = osType
+ return properties
+ }
+
+ // Create a structure into which properties common across the architectures in
+ // this os type will be stored.
+ osInfo.Properties = osSpecificVariantPropertiesFactory()
+
+ // Group the variants by arch type.
+ var variantsByArchName = make(map[string][]android.Module)
+ var archTypes []android.ArchType
+ for _, variant := range osTypeVariants {
+ archType := variant.Target().Arch.ArchType
+ archTypeName := archType.Name
+ if _, ok := variantsByArchName[archTypeName]; !ok {
+ archTypes = append(archTypes, archType)
+ }
+
+ variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
+ }
+
+ if commonVariants, ok := variantsByArchName["common"]; ok {
+ if len(osTypeVariants) != 1 {
+ panic("Expected to only have 1 variant when arch type is common but found " + string(len(osTypeVariants)))
+ }
+
+ // A common arch type only has one variant and its properties should be treated
+ // as common to the os type.
+ osInfo.Properties.PopulateFromVariant(ctx, commonVariants[0])
+ } else {
+ // Create an arch specific info for each supported architecture type.
+ for _, archType := range archTypes {
+ archTypeName := archType.Name
+
+ archVariants := variantsByArchName[archTypeName]
+ archInfo := newArchSpecificInfo(ctx, archType, osSpecificVariantPropertiesFactory, archVariants)
+
+ osInfo.archInfos = append(osInfo.archInfos, archInfo)
+ }
+ }
+
+ return osInfo
+}
+
+// Optimize the properties by extracting common properties from arch type specific
+// properties into os type specific properties.
+func (osInfo *osTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+ // Nothing to do if there is only a single common architecture.
+ if len(osInfo.archInfos) == 0 {
+ return
+ }
+
+ multilib := multilibNone
+ var archPropertiesList []android.SdkMemberProperties
+ for _, archInfo := range osInfo.archInfos {
+ multilib = multilib.addArchType(archInfo.archType)
+
+ // Optimize the arch properties first.
+ archInfo.optimizeProperties(commonValueExtractor)
+
+ archPropertiesList = append(archPropertiesList, archInfo.Properties)
+ }
+
+ commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+ // Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+ osInfo.Properties.Base().Compile_multilib = multilib.String()
+}
+
+// Add the properties for an os to a property set.
+//
+// Maps the properties related to the os variants through to an appropriate
+// module structure that will produce equivalent set of variants when it is
+// processed in a build.
+func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule android.BpModule, targetPropertySet android.BpPropertySet) {
+
+ var osPropertySet android.BpPropertySet
+ var archPropertySet android.BpPropertySet
+ var archOsPrefix string
+ if osInfo.Properties.Base().Os_count == 1 {
+ // There is only one os type present in the variants so don't bother
+ // with adding target specific properties.
+
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // <single os type specific properties>
+ //
+ // arch: {
+ // <arch specific sections>
+ // }
+ //
+ osPropertySet = bpModule
+ archPropertySet = osPropertySet.AddPropertySet("arch")
+
+ // Arch specific properties need to be added to an arch specific section
+ // within arch.
+ archOsPrefix = ""
+ } else {
+ // Create a structure that looks like:
+ // module_type {
+ // name: "...",
+ // ...
+ // <common properties>
+ // ...
+ // target: {
+ // <arch independent os specific sections, e.g. android>
+ // ...
+ // <arch and os specific sections, e.g. android_x86>
+ // }
+ //
+ osType := osInfo.osType
+ osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+ archPropertySet = targetPropertySet
+
+ // Arch specific properties need to be added to an os and arch specific
+ // section prefixed with <os>_.
+ archOsPrefix = osType.Name + "_"
+ }
+
+ // Add the os specific but arch independent properties to the module.
+ osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
+
+ // Add arch (and possibly os) specific sections for each set of arch (and possibly
+ // os) specific properties.
+ //
+ // The archInfos list will be empty if the os contains variants for the common
+ // architecture.
+ for _, archInfo := range osInfo.archInfos {
+ archInfo.addToPropertySet(ctx, archPropertySet, archOsPrefix)
+ }
+}
+
+type archTypeSpecificInfo struct {
+ baseInfo
+
+ archType android.ArchType
+
+ linkInfos []*linkTypeSpecificInfo
+}
+
+// Create a new archTypeSpecificInfo for the specified arch type and its properties
+// structures populated with information from the variants.
+func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo {
+
+ // Create an arch specific info into which the variant properties can be copied.
+ archInfo := &archTypeSpecificInfo{archType: archType}
+
+ // Create the properties into which the arch type specific properties will be
+ // added.
+ archInfo.Properties = variantPropertiesFactory()
+
+ if len(archVariants) == 1 {
+ archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
+ } else {
+ // There is more than one variant for this arch type which must be differentiated
+ // by link type.
+ for _, linkVariant := range archVariants {
+ linkType := getLinkType(linkVariant)
+ if linkType == "" {
+ panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
+ } else {
+ linkInfo := newLinkSpecificInfo(ctx, linkType, variantPropertiesFactory, linkVariant)
+
+ archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
+ }
+ }
+ }
+
+ return archInfo
+}
+
+// Get the link type of the variant
+//
+// If the variant is not differentiated by link type then it returns "",
+// otherwise it returns one of "static" or "shared".
+func getLinkType(variant android.Module) string {
+ linkType := ""
+ if linkable, ok := variant.(cc.LinkableInterface); ok {
+ if linkable.Shared() && linkable.Static() {
+ panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
+ } else if linkable.Shared() {
+ linkType = "shared"
+ } else if linkable.Static() {
+ linkType = "static"
+ } else {
+ panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
+ }
+ }
+ return linkType
+}
+
+// Optimize the properties by extracting common properties from link type specific
+// properties into arch type specific properties.
+func (archInfo *archTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+ if len(archInfo.linkInfos) == 0 {
+ return
+ }
+
+ var propertiesList []android.SdkMemberProperties
+ for _, linkInfo := range archInfo.linkInfos {
+ propertiesList = append(propertiesList, linkInfo.Properties)
+ }
+
+ commonValueExtractor.extractCommonProperties(archInfo.Properties, propertiesList)
+}
+
+// Add the properties for an arch type to a property set.
+func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
+ archTypeName := archInfo.archType.Name
+ archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+ archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+
+ for _, linkInfo := range archInfo.linkInfos {
+ linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
+ linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
+ }
+}
+
+type linkTypeSpecificInfo struct {
+ baseInfo
+
+ linkType string
+}
+
+// Create a new linkTypeSpecificInfo for the specified link type and its properties
+// structures populated with information from the variant.
+func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo {
+ linkInfo := &linkTypeSpecificInfo{
+ baseInfo: baseInfo{
+ // Create the properties into which the link type specific properties will be
+ // added.
+ Properties: variantPropertiesFactory(),
+ },
+ linkType: linkType,
+ }
+ linkInfo.Properties.PopulateFromVariant(ctx, linkVariant)
+ return linkInfo
+}
+
+type memberContext struct {
+ sdkMemberContext android.ModuleContext
+ builder *snapshotBuilder
+ memberType android.SdkMemberType
+ name string
+}
+
+func (m *memberContext) SdkModuleContext() android.ModuleContext {
+ return m.sdkMemberContext
+}
+
+func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
+ return m.builder
+}
+
+func (m *memberContext) MemberType() android.SdkMemberType {
+ return m.memberType
+}
+
+func (m *memberContext) Name() string {
+ return m.name
+}
+
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
+
+ memberType := member.memberType
+
+ // Group the variants by os type.
+ variantsByOsType := make(map[android.OsType][]android.Module)
+ variants := member.Variants()
+ for _, variant := range variants {
+ osType := variant.Target().Os
+ variantsByOsType[osType] = append(variantsByOsType[osType], variant)
+ }
+
+ osCount := len(variantsByOsType)
+ variantPropertiesFactory := func() android.SdkMemberProperties {
+ properties := memberType.CreateVariantPropertiesStruct()
+ base := properties.Base()
+ base.Os_count = osCount
+ return properties
+ }
+
+ osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
+
+ // The set of properties that are common across all architectures and os types.
+ commonProperties := variantPropertiesFactory()
+ commonProperties.Base().Os = android.CommonOS
+
+ // Create common value extractor that can be used to optimize the properties.
+ commonValueExtractor := newCommonValueExtractor(commonProperties)
+
+ // The list of property structures which are os type specific but common across
+ // architectures within that os type.
+ var osSpecificPropertiesList []android.SdkMemberProperties
+
+ for osType, osTypeVariants := range variantsByOsType {
+ osInfo := newOsTypeSpecificInfo(ctx, osType, variantPropertiesFactory, osTypeVariants)
+ osTypeToInfo[osType] = osInfo
+ // Add the os specific properties to a list of os type specific yet architecture
+ // independent properties structs.
+ osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
+
+ // Optimize the properties across all the variants for a specific os type.
+ osInfo.optimizeProperties(commonValueExtractor)
+ }
+
+ // Extract properties which are common across all architectures and os types.
+ commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
+
+ // Add the common properties to the module.
+ commonProperties.AddToPropertySet(ctx, bpModule)
+
+ // Create a target property set into which target specific properties can be
+ // added.
+ targetPropertySet := bpModule.AddPropertySet("target")
+
+ // Iterate over the os types in a fixed order.
+ for _, osType := range s.getPossibleOsTypes() {
+ osInfo := osTypeToInfo[osType]
+ if osInfo == nil {
+ continue
+ }
+
+ osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
+ }
+}
+
+// Compute the list of possible os types that this sdk could support.
+func (s *sdk) getPossibleOsTypes() []android.OsType {
+ var osTypes []android.OsType
+ for _, osType := range android.OsTypeList {
+ if s.DeviceSupported() {
+ if osType.Class == android.Device && osType != android.Fuchsia {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ if s.HostSupported() {
+ if osType.Class == android.Host || osType.Class == android.HostCross {
+ osTypes = append(osTypes, osType)
+ }
+ }
+ }
+ sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
+ return osTypes
+}
+
+// Given a struct value, access a field within that struct (or one of its embedded
+// structs).
+type fieldAccessorFunc func(structValue reflect.Value) reflect.Value
+
+// Supports extracting common values from a number of instances of a properties
+// structure into a separate common set of properties.
+type commonValueExtractor struct {
+ // The getters for every field from which common values can be extracted.
+ fieldGetters []fieldAccessorFunc
+}
+
+// Create a new common value extractor for the structure type for the supplied
+// properties struct.
+//
+// The returned extractor can be used on any properties structure of the same type
+// as the supplied set of properties.
+func newCommonValueExtractor(propertiesStruct interface{}) *commonValueExtractor {
+ structType := getStructValue(reflect.ValueOf(propertiesStruct)).Type()
+ extractor := &commonValueExtractor{}
+ extractor.gatherFields(structType, nil)
+ return extractor
+}
+
+// Gather the fields from the supplied structure type from which common values will
+// be extracted.
+//
+// This is recursive function. If it encounters an embedded field (no field name)
+// that is a struct then it will recurse into that struct passing in the accessor
+// for the field. That will then be used in the accessors for the fields in the
+// embedded struct.
+func (e *commonValueExtractor) gatherFields(structType reflect.Type, containingStructAccessor fieldAccessorFunc) {
+ for f := 0; f < structType.NumField(); f++ {
+ field := structType.Field(f)
+ if field.PkgPath != "" {
+ // Ignore unexported fields.
+ continue
+ }
+
+ // Ignore fields whose value should be kept.
+ if proptools.HasTag(field, "sdk", "keep") {
+ continue
+ }
+
+ // Save a copy of the field index for use in the function.
+ fieldIndex := f
+ fieldGetter := func(value reflect.Value) reflect.Value {
+ if containingStructAccessor != nil {
+ // This is an embedded structure so first access the field for the embedded
+ // structure.
+ value = containingStructAccessor(value)
+ }
+
+ // Skip through interface and pointer values to find the structure.
+ value = getStructValue(value)
+
+ // Return the field.
+ return value.Field(fieldIndex)
+ }
+
+ if field.Type.Kind() == reflect.Struct && field.Anonymous {
+ // Gather fields from the embedded structure.
+ e.gatherFields(field.Type, fieldGetter)
+ } else {
+ e.fieldGetters = append(e.fieldGetters, fieldGetter)
+ }
+ }
+}
+
+func getStructValue(value reflect.Value) reflect.Value {
+foundStruct:
+ for {
+ kind := value.Kind()
+ switch kind {
+ case reflect.Interface, reflect.Ptr:
+ value = value.Elem()
+ case reflect.Struct:
+ break foundStruct
+ default:
+ panic(fmt.Errorf("expecting struct, interface or pointer, found %v of kind %s", value, kind))
+ }
+ }
+ return value
+}
+
+// Extract common properties from a slice of property structures of the same type.
+//
+// All the property structures must be of the same type.
+// commonProperties - must be a pointer to the structure into which common properties will be added.
+// inputPropertiesSlice - must be a slice of input properties structures.
+//
+// Iterates over each exported field (capitalized name) and checks to see whether they
+// have the same value (using DeepEquals) across all the input properties. If it does not then no
+// change is made. Otherwise, the common value is stored in the field in the commonProperties
+// and the field in each of the input properties structure is set to its default value.
+func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
+ commonPropertiesValue := reflect.ValueOf(commonProperties)
+ commonStructValue := commonPropertiesValue.Elem()
+
+ for _, fieldGetter := range e.fieldGetters {
+ // Check to see if all the structures have the same value for the field. The commonValue
+ // is nil on entry to the loop and if it is nil on exit then there is no common value,
+ // otherwise it points to the common value.
+ var commonValue *reflect.Value
+ sliceValue := reflect.ValueOf(inputPropertiesSlice)
+
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+
+ if commonValue == nil {
+ // Use the first value as the commonProperties value.
+ commonValue = &fieldValue
+ } else {
+ // If the value does not match the current common value then there is
+ // no value in common so break out.
+ if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
+ commonValue = nil
+ break
+ }
+ }
+ }
+
+ // If the fields all have a common value then store it in the common struct field
+ // and set the input struct's field to the empty value.
+ if commonValue != nil {
+ emptyValue := reflect.Zero(commonValue.Type())
+ fieldGetter(commonStructValue).Set(*commonValue)
+ for i := 0; i < sliceValue.Len(); i++ {
+ itemValue := sliceValue.Index(i)
+ fieldValue := fieldGetter(itemValue)
+ fieldValue.Set(emptyValue)
+ }
+ }
+ }
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 65dbb22..0932873 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
"fmt"
"io"
"path"
+ "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -115,6 +116,7 @@
type syspropLibrary struct {
android.ModuleBase
+ android.ApexModuleBase
properties syspropLibraryProperties
@@ -149,13 +151,32 @@
// Whether public stub exists or not.
Public_stub *bool `blueprint:"mutated"`
+
+ Cpp struct {
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // Forwarded to cc_library.min_sdk_version
+ Min_sdk_version *string
+ }
}
var (
pctx = android.NewPackageContext("android/soong/sysprop")
syspropCcTag = dependencyTag{name: "syspropCc"}
+
+ syspropLibrariesKey = android.NewOnceKey("syspropLibraries")
+ syspropLibrariesLock sync.Mutex
)
+func syspropLibraries(config android.Config) *[]string {
+ return config.Once(syspropLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func SyspropLibraries(config android.Config) []string {
+ return append([]string{}, *syspropLibraries(config)...)
+}
+
func init() {
android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
}
@@ -195,6 +216,10 @@
return proptools.Bool(m.properties.Public_stub)
}
+func (m *syspropLibrary) CurrentSyspropApiFile() android.Path {
+ return m.currentApiFile
+}
+
func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
baseModuleName := m.BaseModuleName()
@@ -296,6 +321,7 @@
&m.properties,
)
android.InitAndroidModule(m)
+ android.InitApexModule(m)
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
return m
}
@@ -323,6 +349,8 @@
Recovery_available *bool
Vendor_available *bool
Host_supported *bool
+ Apex_available []string
+ Min_sdk_version *string
}
type javaLibraryProperties struct {
@@ -411,6 +439,8 @@
ccProps.Recovery_available = m.properties.Recovery_available
ccProps.Vendor_available = m.properties.Vendor_available
ccProps.Host_supported = m.properties.Host_supported
+ ccProps.Apex_available = m.ApexProperties.Apex_available
+ ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
ctx.CreateModule(cc.LibraryFactory, &ccProps)
scope := "internal"
@@ -463,6 +493,12 @@
Stem: proptools.StringPtr(m.BaseModuleName()),
})
}
+
+ syspropLibrariesLock.Lock()
+ defer syspropLibrariesLock.Unlock()
+
+ libraries := syspropLibraries(ctx.Config())
+ *libraries = append(*libraries, ctx.ModuleName())
}
func syspropDepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 51da222..8503386 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -15,6 +15,8 @@
package sysprop
import (
+ "reflect"
+
"android/soong/android"
"android/soong/cc"
"android/soong/java"
@@ -157,6 +159,7 @@
ctx := test(t, `
sysprop_library {
name: "sysprop-platform",
+ apex_available: ["//apex_available:platform"],
srcs: ["android/sysprop/PlatformProperties.sysprop"],
api_packages: ["android.sysprop"],
property_owner: "Platform",
@@ -305,7 +308,12 @@
"android_arm64_armv8-a_shared",
"android_arm64_armv8-a_static",
} {
- ctx.ModuleForTests("libsysprop-platform", variant)
+ library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
+ expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
+ if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) {
+ t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.",
+ expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
+ }
// core variant of vendor-owned sysprop_library is for product
ctx.ModuleForTests("libsysprop-vendor", variant)
diff --git a/ui/build/build.go b/ui/build/build.go
index f3feac2..1122733 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -53,7 +53,6 @@
{{end -}}
pool highmem_pool
depth = {{.HighmemParallel}}
-build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}}
{{end -}}
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 36d4f04..0bcdccb 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -99,6 +99,7 @@
hostOut("sdk_addon"),
hostOut("testcases"),
hostOut("vts"),
+ hostOut("vts10"),
hostOut("vts-core"),
productOut("*.img"),
productOut("*.zip"),
@@ -111,6 +112,9 @@
productOut("obj/PACKAGING"),
productOut("ramdisk"),
productOut("debug_ramdisk"),
+ productOut("vendor-ramdisk"),
+ productOut("vendor-ramdisk-debug.cpio.gz"),
+ productOut("vendor_debug_ramdisk"),
productOut("test_harness_ramdisk"),
productOut("recovery"),
productOut("root"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 5b9d10a..55e0d03 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -611,10 +611,6 @@
product = "aosp_arm"
case "arm64":
product = "aosm_arm64"
- case "mips":
- product = "aosp_mips"
- case "mips64":
- product = "aosp_mips64"
case "x86":
product = "aosp_x86"
case "x86_64":
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index ce8f968..a559330 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -190,6 +190,7 @@
// compiler wrappers set up by make
"CC_WRAPPER",
"CXX_WRAPPER",
+ "RBE_WRAPPER",
"JAVAC_WRAPPER",
"R8_WRAPPER",
"D8_WRAPPER",
@@ -228,8 +229,6 @@
"DEFAULT_ERROR_BUILD_MODULE_TYPES",
"BUILD_BROKEN_PREBUILT_ELF_FILES",
"BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW",
- "BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE",
- "BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY",
"BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
"BUILD_BROKEN_USES_BUILD_EXECUTABLE",
"BUILD_BROKEN_USES_BUILD_FUZZ_TEST",
@@ -237,17 +236,12 @@
"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_EXECUTABLE",
- "BUILD_BROKEN_USES_BUILD_HOST_FUZZ_TEST",
"BUILD_BROKEN_USES_BUILD_HOST_JAVA_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_NATIVE_TEST",
"BUILD_BROKEN_USES_BUILD_HOST_PREBUILT",
"BUILD_BROKEN_USES_BUILD_HOST_SHARED_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_STATIC_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_STATIC_TEST_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_TEST_CONFIG",
"BUILD_BROKEN_USES_BUILD_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_MULTI_PREBUILT",
- "BUILD_BROKEN_USES_BUILD_NATIVE_BENCHMARK",
"BUILD_BROKEN_USES_BUILD_NATIVE_TEST",
"BUILD_BROKEN_USES_BUILD_NOTICE_FILE",
"BUILD_BROKEN_USES_BUILD_PACKAGE",
@@ -257,8 +251,6 @@
"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_STATIC_TEST_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_TARGET_TEST_CONFIG",
}, exportEnvVars...), BannerVars...)
make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)
diff --git a/ui/build/exec.go b/ui/build/exec.go
index e435c53..053bbae 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -19,6 +19,8 @@
"io"
"os/exec"
"strings"
+ "syscall"
+ "time"
)
// Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
@@ -33,6 +35,8 @@
ctx Context
config Config
name string
+
+ started time.Time
}
func Command(ctx Context, config Config, name string, executable string, args ...string) *Cmd {
@@ -57,7 +61,20 @@
c.wrapSandbox()
}
- c.ctx.Verboseln(c.Path, c.Args)
+ c.ctx.Verbosef("%q executing %q %v\n", c.name, c.Path, c.Args)
+ c.started = time.Now()
+}
+
+func (c *Cmd) report() {
+ if c.Cmd.ProcessState != nil {
+ rusage := c.Cmd.ProcessState.SysUsage().(*syscall.Rusage)
+ c.ctx.Verbosef("%q finished with exit code %d (%s real, %s user, %s system, %dMB maxrss)",
+ c.name, c.Cmd.ProcessState.ExitCode(),
+ time.Since(c.started).Round(time.Millisecond),
+ c.Cmd.ProcessState.UserTime().Round(time.Millisecond),
+ c.Cmd.ProcessState.SystemTime().Round(time.Millisecond),
+ rusage.Maxrss/1024)
+ }
}
func (c *Cmd) Start() error {
@@ -68,21 +85,30 @@
func (c *Cmd) Run() error {
c.prepare()
err := c.Cmd.Run()
+ c.report()
return err
}
func (c *Cmd) Output() ([]byte, error) {
c.prepare()
bytes, err := c.Cmd.Output()
+ c.report()
return bytes, err
}
func (c *Cmd) CombinedOutput() ([]byte, error) {
c.prepare()
bytes, err := c.Cmd.CombinedOutput()
+ c.report()
return bytes, err
}
+func (c *Cmd) Wait() error {
+ err := c.Cmd.Wait()
+ c.report()
+ return err
+}
+
// StartOrFatal is equivalent to Start, but handles the error with a call to ctx.Fatal
func (c *Cmd) StartOrFatal() {
if err := c.Start(); err != nil {
diff --git a/ui/build/kati.go b/ui/build/kati.go
index a845c5b..2eb7850 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -67,6 +67,7 @@
"--ninja_dir=" + config.OutDir(),
"--ninja_suffix=" + config.KatiSuffix() + extraSuffix,
"--no_ninja_prelude",
+ "--use_ninja_phony_output",
"--regen",
"--ignore_optional_include=" + filepath.Join(config.OutDir(), "%.P"),
"--detect_android_echo",
@@ -104,17 +105,20 @@
envFunc(cmd.Environment)
if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
- u, err := user.Current()
- if err != nil {
- ctx.Println("Failed to get current user")
+ username := "unknown"
+ if u, err := user.Current(); err == nil {
+ username = u.Username
+ } else {
+ ctx.Println("Failed to get current user:", err)
}
- cmd.Environment.Set("BUILD_USERNAME", u.Username)
+ cmd.Environment.Set("BUILD_USERNAME", username)
}
if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
hostname, err := os.Hostname()
if err != nil {
- ctx.Println("Failed to read hostname")
+ ctx.Println("Failed to read hostname:", err)
+ hostname = "unknown"
}
cmd.Environment.Set("BUILD_HOSTNAME", hostname)
}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 0749fe3..1b13e5d 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -38,6 +38,7 @@
executable := config.PrebuiltBuildTool("ninja")
args := []string{
"-d", "keepdepfile",
+ "-d", "keeprsp",
"--frontend_file", fifo,
}
@@ -57,6 +58,7 @@
args = append(args, "-f", config.CombinedNinjaFile())
args = append(args,
+ "-o", "usesphonyoutputs=yes",
"-w", "dupbuild=err",
"-w", "missingdepfile=err")
@@ -127,6 +129,16 @@
"GOMA_USE_LOCAL",
// RBE client
+ "RBE_compare",
+ "RBE_exec_root",
+ "RBE_exec_strategy",
+ "RBE_invocation_id",
+ "RBE_log_dir",
+ "RBE_platform",
+ "RBE_remote_accept_cache",
+ "RBE_remote_update_cache",
+ "RBE_server_address",
+ // TODO: remove old FLAG_ variables.
"FLAG_compare",
"FLAG_exec_root",
"FLAG_exec_strategy",
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index bfe662d..5717401 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,28 +74,27 @@
}
var Configuration = map[string]PathConfig{
- "bash": Allowed,
- "dd": Allowed,
- "diff": Allowed,
- "dlv": Allowed,
- "expr": Allowed,
- "fuser": Allowed,
- "getopt": Allowed,
- "git": Allowed,
- "hexdump": Allowed,
- "jar": Allowed,
- "java": Allowed,
- "javap": Allowed,
- "lsof": Allowed,
- "openssl": Allowed,
- "patch": Allowed,
- "pstree": Allowed,
- "python3": Allowed,
- "rsync": Allowed,
- "sh": Allowed,
- "tr": Allowed,
- "unzip": Allowed,
- "zip": Allowed,
+ "bash": Allowed,
+ "dd": Allowed,
+ "diff": Allowed,
+ "dlv": Allowed,
+ "expr": Allowed,
+ "fuser": Allowed,
+ "getopt": Allowed,
+ "git": Allowed,
+ "hexdump": Allowed,
+ "jar": Allowed,
+ "java": Allowed,
+ "javap": Allowed,
+ "lsof": Allowed,
+ "openssl": Allowed,
+ "patch": Allowed,
+ "pstree": Allowed,
+ "rsync": Allowed,
+ "sh": Allowed,
+ "tr": Allowed,
+ "unzip": Allowed,
+ "zip": Allowed,
// Host toolchain is removed. In-tree toolchain should be used instead.
// GCC also can't find cc1 with this implementation.
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 11ff667..98eb028 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -19,6 +19,7 @@
"os"
"os/exec"
"os/user"
+ "path/filepath"
"strings"
"sync"
)
@@ -54,6 +55,9 @@
working bool
group string
+ srcDir string
+ outDir string
+ distDir string
}
func (c *Cmd) sandboxSupported() bool {
@@ -72,15 +76,45 @@
sandboxConfig.group = "nobody"
}
- cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
+ // These directories will be bind mounted
+ // so we need full non-symlink paths
+ sandboxConfig.srcDir = absPath(c.ctx, ".")
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
+ sandboxConfig.srcDir = absPath(c.ctx, derefPath)
+ }
+ sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
+ sandboxConfig.outDir = absPath(c.ctx, derefPath)
+ }
+ sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
+ sandboxConfig.distDir = absPath(c.ctx, derefPath)
+ }
+
+ sandboxArgs := []string{
"-H", "android-build",
"-e",
"-u", "nobody",
"-g", sandboxConfig.group,
- "-B", "/",
+ "-R", "/",
+ "-B", sandboxConfig.srcDir,
+ "-B", "/tmp",
+ "-B", sandboxConfig.outDir,
+ }
+
+ if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+ //Mount dist dir as read-write if it already exists
+ sandboxArgs = append(sandboxArgs, "-B",
+ sandboxConfig.distDir)
+ }
+
+ sandboxArgs = append(sandboxArgs,
"--disable_clone_newcgroup",
"--",
"/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
+
+ cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
+
cmd.Env = c.config.Environment().Environ()
c.ctx.Verboseln(cmd.Args)
@@ -90,10 +124,7 @@
return
}
- c.ctx.Println("Build sandboxing disabled due to nsjail error. This may become fatal in the future.")
- c.ctx.Println("Please let us know why nsjail doesn't work in your environment at:")
- c.ctx.Println(" https://groups.google.com/forum/#!forum/android-building")
- c.ctx.Println(" https://issuetracker.google.com/issues/new?component=381517")
+ c.ctx.Println("Build sandboxing disabled due to nsjail error.")
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
c.ctx.Verboseln(line)
@@ -147,8 +178,17 @@
"--rlimit_fsize", "soft",
"--rlimit_nofile", "soft",
- // For now, just map everything. Eventually we should limit this, especially to make most things readonly.
- "-B", "/",
+ // For now, just map everything. Make most things readonly.
+ "-R", "/",
+
+ // Mount source are read-write
+ "-B", sandboxConfig.srcDir,
+
+ //Mount out dir as read-write
+ "-B", sandboxConfig.outDir,
+
+ // Mount a writable tmp dir
+ "-B", "/tmp",
// Disable newcgroup for now, since it may require newer kernels
// TODO: try out cgroups
@@ -158,6 +198,11 @@
"-q",
}
+ if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+ //Mount dist dir as read-write if it already exists
+ sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+ }
+
if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
diff --git a/ui/build/soong.go b/ui/build/soong.go
index afbc073..2fbf381 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,11 +15,15 @@
package build
import (
+ "io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+
+ "github.com/golang/protobuf/proto"
"github.com/google/blueprint/microfactory"
"android/soong/ui/metrics"
@@ -115,7 +119,11 @@
cmd := Command(ctx, config, "soong "+name,
config.PrebuiltBuildTool("ninja"),
"-d", "keepdepfile",
+ "-o", "usesphonyoutputs=yes",
+ "-o", "preremoveoutputs=yes",
"-w", "dupbuild=err",
+ "-w", "outputdir=err",
+ "-w", "missingoutfile=err",
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
"-f", filepath.Join(config.SoongOutDir(), file))
@@ -126,4 +134,35 @@
ninja("minibootstrap", ".minibootstrap/build.ninja")
ninja("bootstrap", ".bootstrap/build.ninja")
+
+ soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
+ logSoongBuildMetrics(ctx, soongBuildMetrics)
+
+ if ctx.Metrics != nil {
+ ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
+ }
+}
+
+func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
+ soongBuildMetricsFile := filepath.Join(config.OutDir(), "soong", "soong_build_metrics.pb")
+ buf, err := ioutil.ReadFile(soongBuildMetricsFile)
+ if err != nil {
+ ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err)
+ }
+ soongBuildMetrics := &soong_metrics_proto.SoongBuildMetrics{}
+ err = proto.Unmarshal(buf, soongBuildMetrics)
+ if err != nil {
+ ctx.Fatalf("Failed to unmarshal %s: %s", soongBuildMetricsFile, err)
+ }
+ return soongBuildMetrics
+}
+
+func logSoongBuildMetrics(ctx Context, metrics *soong_metrics_proto.SoongBuildMetrics) {
+ ctx.Verbosef("soong_build metrics:")
+ ctx.Verbosef(" modules: %v", metrics.GetModules())
+ ctx.Verbosef(" variants: %v", metrics.GetVariants())
+ ctx.Verbosef(" max heap size: %v MB", metrics.GetMaxHeapSize()/1e6)
+ ctx.Verbosef(" total allocation count: %v", metrics.GetTotalAllocCount())
+ ctx.Verbosef(" total allocation size: %v MB", metrics.GetTotalAllocSize()/1e6)
+
}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 5109465..4ff9483 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -50,10 +50,10 @@
// Get a list of leaf nodes in the dependency graph from ninja
executable := config.PrebuiltBuildTool("ninja")
- args := []string{}
- args = append(args, config.NinjaArgs()...)
- args = append(args, "-f", config.CombinedNinjaFile())
- args = append(args, "-t", "targets", "rule")
+ common_args := []string{}
+ common_args = append(common_args, config.NinjaArgs()...)
+ common_args = append(common_args, "-f", config.CombinedNinjaFile())
+ args := append(common_args, "-t", "targets", "rule")
cmd := Command(ctx, config, "ninja", executable, args...)
stdout, err := cmd.StdoutPipe()
@@ -96,9 +96,31 @@
sb := &strings.Builder{}
title := "Dependencies in out found with no rule to create them:"
fmt.Fprintln(sb, title)
- for _, dep := range danglingRulesList {
- fmt.Fprintln(sb, " ", dep)
+
+ report_lines := 1
+ for i, dep := range danglingRulesList {
+ if report_lines > 20 {
+ fmt.Fprintf(sb, " ... and %d more\n", len(danglingRulesList)-i)
+ break
+ }
+ // It's helpful to see the reverse dependencies. ninja -t query is the
+ // best tool we got for that. Its output starts with the dependency
+ // itself.
+ query_cmd := Command(ctx, config, "ninja", executable,
+ append(common_args, "-t", "query", dep)...)
+ query_stdout, err := query_cmd.StdoutPipe()
+ if err != nil {
+ ctx.Fatal(err)
+ }
+ query_cmd.StartOrFatal()
+ scanner := bufio.NewScanner(query_stdout)
+ for scanner.Scan() {
+ report_lines++
+ fmt.Fprintln(sb, " ", scanner.Text())
+ }
+ query_cmd.WaitOrFatal()
}
+
ts.FinishAction(status.ActionResult{
Action: action,
Error: fmt.Errorf(title),
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 529639d..3596e10 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -17,6 +17,7 @@
pkgPath: "android/soong/ui/metrics",
deps: [
"golang-protobuf-proto",
+ "soong-ui-metrics_upload_proto",
"soong-ui-metrics_proto",
"soong-ui-tracer",
],
@@ -35,3 +36,11 @@
],
}
+bootstrap_go_package {
+ name: "soong-ui-metrics_upload_proto",
+ pkgPath: "android/soong/ui/metrics/upload_proto",
+ deps: ["golang-protobuf-proto"],
+ srcs: [
+ "upload_proto/upload.pb.go",
+ ],
+}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 8254e4a..3e76d37 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -145,6 +145,10 @@
return writeMessageToFile(&m.metrics, outputPath)
}
+func (m *Metrics) SetSoongBuildMetrics(metrics *soong_metrics_proto.SoongBuildMetrics) {
+ m.metrics.SoongBuildMetrics = metrics
+}
+
type CriticalUserJourneysMetrics struct {
cujs soong_metrics_proto.CriticalUserJourneysMetrics
}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 3986d0e..a39d1a8 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -197,10 +197,11 @@
// The metrics for calling Ninja.
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:"-"`
+ Total *PerfInfo `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
+ SoongBuildMetrics *SoongBuildMetrics `protobuf:"bytes,22,opt,name=soong_build_metrics,json=soongBuildMetrics" json:"soong_build_metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *MetricsBase) Reset() { *m = MetricsBase{} }
@@ -380,6 +381,13 @@
return nil
}
+func (m *MetricsBase) GetSoongBuildMetrics() *SoongBuildMetrics {
+ if m != nil {
+ return m.SoongBuildMetrics
+ }
+ 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"`
@@ -607,6 +615,82 @@
return nil
}
+type SoongBuildMetrics struct {
+ // The number of modules handled by soong_build.
+ Modules *uint32 `protobuf:"varint,1,opt,name=modules" json:"modules,omitempty"`
+ // The total number of variants handled by soong_build.
+ Variants *uint32 `protobuf:"varint,2,opt,name=variants" json:"variants,omitempty"`
+ // The total number of allocations in soong_build.
+ TotalAllocCount *uint64 `protobuf:"varint,3,opt,name=total_alloc_count,json=totalAllocCount" json:"total_alloc_count,omitempty"`
+ // The total size of allocations in soong_build in bytes.
+ TotalAllocSize *uint64 `protobuf:"varint,4,opt,name=total_alloc_size,json=totalAllocSize" json:"total_alloc_size,omitempty"`
+ // The approximate maximum size of the heap in soong_build in bytes.
+ MaxHeapSize *uint64 `protobuf:"varint,5,opt,name=max_heap_size,json=maxHeapSize" json:"max_heap_size,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SoongBuildMetrics) Reset() { *m = SoongBuildMetrics{} }
+func (m *SoongBuildMetrics) String() string { return proto.CompactTextString(m) }
+func (*SoongBuildMetrics) ProtoMessage() {}
+func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_6039342a2ba47b72, []int{5}
+}
+
+func (m *SoongBuildMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SoongBuildMetrics.Unmarshal(m, b)
+}
+func (m *SoongBuildMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SoongBuildMetrics.Marshal(b, m, deterministic)
+}
+func (m *SoongBuildMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SoongBuildMetrics.Merge(m, src)
+}
+func (m *SoongBuildMetrics) XXX_Size() int {
+ return xxx_messageInfo_SoongBuildMetrics.Size(m)
+}
+func (m *SoongBuildMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_SoongBuildMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SoongBuildMetrics proto.InternalMessageInfo
+
+func (m *SoongBuildMetrics) GetModules() uint32 {
+ if m != nil && m.Modules != nil {
+ return *m.Modules
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetVariants() uint32 {
+ if m != nil && m.Variants != nil {
+ return *m.Variants
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetTotalAllocCount() uint64 {
+ if m != nil && m.TotalAllocCount != nil {
+ return *m.TotalAllocCount
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetTotalAllocSize() uint64 {
+ if m != nil && m.TotalAllocSize != nil {
+ return *m.TotalAllocSize
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetMaxHeapSize() uint64 {
+ if m != nil && m.MaxHeapSize != nil {
+ return *m.MaxHeapSize
+ }
+ return 0
+}
+
func init() {
proto.RegisterEnum("soong_build_metrics.MetricsBase_BuildVariant", MetricsBase_BuildVariant_name, MetricsBase_BuildVariant_value)
proto.RegisterEnum("soong_build_metrics.MetricsBase_Arch", MetricsBase_Arch_name, MetricsBase_Arch_value)
@@ -616,63 +700,72 @@
proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo")
proto.RegisterType((*CriticalUserJourneyMetrics)(nil), "soong_build_metrics.CriticalUserJourneyMetrics")
proto.RegisterType((*CriticalUserJourneysMetrics)(nil), "soong_build_metrics.CriticalUserJourneysMetrics")
+ proto.RegisterType((*SoongBuildMetrics)(nil), "soong_build_metrics.SoongBuildMetrics")
}
func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
var fileDescriptor_6039342a2ba47b72 = []byte{
- // 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,
+ // 962 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x4e, 0xdc, 0x46,
+ 0x10, 0x8f, 0xe1, 0xe0, 0xce, 0x63, 0xee, 0x30, 0x0b, 0x69, 0x9c, 0x44, 0xa8, 0x27, 0xab, 0x89,
+ 0x50, 0xd5, 0x90, 0x88, 0x46, 0x28, 0x42, 0x51, 0x25, 0x38, 0x50, 0x9a, 0x22, 0xb8, 0xc8, 0xfc,
+ 0x69, 0xd4, 0x7e, 0x58, 0x2d, 0xf6, 0x12, 0x9c, 0xda, 0x5e, 0x6b, 0x77, 0x1d, 0x41, 0xde, 0xa1,
+ 0x0f, 0xd4, 0xcf, 0x7d, 0x96, 0xbe, 0x47, 0xb5, 0xb3, 0xf6, 0x61, 0xda, 0x8b, 0x40, 0xf9, 0x66,
+ 0xcf, 0xef, 0xcf, 0xce, 0xac, 0x67, 0xe6, 0x0e, 0xfa, 0x39, 0xd7, 0x32, 0x8d, 0xd5, 0x7a, 0x29,
+ 0x85, 0x16, 0x64, 0x59, 0x09, 0x51, 0x7c, 0xa0, 0x67, 0x55, 0x9a, 0x25, 0xb4, 0x86, 0xc2, 0xbf,
+ 0x00, 0xbc, 0x03, 0xfb, 0xbc, 0xc3, 0x14, 0x27, 0x2f, 0x60, 0xc5, 0x12, 0x12, 0xa6, 0x39, 0xd5,
+ 0x69, 0xce, 0x95, 0x66, 0x79, 0x19, 0x38, 0x43, 0x67, 0x6d, 0x36, 0x22, 0x88, 0xed, 0x32, 0xcd,
+ 0x8f, 0x1b, 0x84, 0x3c, 0x84, 0x9e, 0x55, 0xa4, 0x49, 0x30, 0x33, 0x74, 0xd6, 0xdc, 0xa8, 0x8b,
+ 0xef, 0x6f, 0x13, 0xb2, 0x05, 0x0f, 0xcb, 0x8c, 0xe9, 0x73, 0x21, 0x73, 0xfa, 0x89, 0x4b, 0x95,
+ 0x8a, 0x82, 0xc6, 0x22, 0xe1, 0x05, 0xcb, 0x79, 0x30, 0x8b, 0xdc, 0x07, 0x0d, 0xe1, 0xd4, 0xe2,
+ 0xa3, 0x1a, 0x26, 0x4f, 0x60, 0xa0, 0x99, 0xfc, 0xc0, 0x35, 0x2d, 0xa5, 0x48, 0xaa, 0x58, 0x07,
+ 0x1d, 0x14, 0xf4, 0x6d, 0xf4, 0x9d, 0x0d, 0x92, 0x04, 0x56, 0x6a, 0x9a, 0x4d, 0xe2, 0x13, 0x93,
+ 0x29, 0x2b, 0x74, 0x30, 0x37, 0x74, 0xd6, 0x06, 0x1b, 0xcf, 0xd6, 0xa7, 0xd4, 0xbc, 0xde, 0xaa,
+ 0x77, 0x7d, 0xc7, 0x20, 0xa7, 0x56, 0xb4, 0x35, 0xbb, 0x77, 0xf8, 0x26, 0x22, 0xd6, 0xaf, 0x0d,
+ 0x90, 0x31, 0x78, 0xf5, 0x29, 0x4c, 0xc6, 0x17, 0xc1, 0x3c, 0x9a, 0x3f, 0xb9, 0xd5, 0x7c, 0x5b,
+ 0xc6, 0x17, 0x5b, 0xdd, 0x93, 0xc3, 0xfd, 0xc3, 0xf1, 0xaf, 0x87, 0x11, 0x58, 0x0b, 0x13, 0x24,
+ 0xeb, 0xb0, 0xdc, 0x32, 0x9c, 0x64, 0xdd, 0xc5, 0x12, 0x97, 0xae, 0x89, 0x4d, 0x02, 0x3f, 0x40,
+ 0x9d, 0x16, 0x8d, 0xcb, 0x6a, 0x42, 0xef, 0x21, 0xdd, 0xb7, 0xc8, 0xa8, 0xac, 0x1a, 0xf6, 0x3e,
+ 0xb8, 0x17, 0x42, 0xd5, 0xc9, 0xba, 0x5f, 0x95, 0x6c, 0xcf, 0x18, 0x60, 0xaa, 0x11, 0xf4, 0xd1,
+ 0x6c, 0xa3, 0x48, 0xac, 0x21, 0x7c, 0x95, 0xa1, 0x67, 0x4c, 0x36, 0x8a, 0x04, 0x3d, 0x1f, 0x40,
+ 0x17, 0x3d, 0x85, 0x0a, 0x3c, 0xac, 0x61, 0xde, 0xbc, 0x8e, 0x15, 0x09, 0xeb, 0xc3, 0x84, 0xa2,
+ 0xfc, 0x52, 0x4b, 0x16, 0x2c, 0x20, 0xec, 0x59, 0x78, 0xcf, 0x84, 0x26, 0x9c, 0x58, 0x0a, 0xa5,
+ 0x8c, 0x45, 0xff, 0x9a, 0x33, 0x32, 0xb1, 0xb1, 0x22, 0x4f, 0x61, 0xb1, 0xc5, 0xc1, 0xb4, 0x07,
+ 0xb6, 0x7d, 0x26, 0x2c, 0x4c, 0xe4, 0x19, 0x2c, 0xb7, 0x78, 0x93, 0x12, 0x17, 0xed, 0xc5, 0x4e,
+ 0xb8, 0xad, 0xbc, 0x45, 0xa5, 0x69, 0x92, 0xca, 0xc0, 0xb7, 0x79, 0x8b, 0x4a, 0xef, 0xa6, 0x92,
+ 0xfc, 0x04, 0x9e, 0xe2, 0xba, 0x2a, 0xa9, 0x16, 0x22, 0x53, 0xc1, 0xd2, 0x70, 0x76, 0xcd, 0xdb,
+ 0x58, 0x9d, 0x7a, 0x45, 0xef, 0xb8, 0x3c, 0x7f, 0x5b, 0x9c, 0x8b, 0x08, 0x50, 0x71, 0x6c, 0x04,
+ 0x64, 0x0b, 0xdc, 0x3f, 0x98, 0x4e, 0xa9, 0xac, 0x0a, 0x15, 0x90, 0xbb, 0xa8, 0x7b, 0x86, 0x1f,
+ 0x55, 0x85, 0x22, 0xaf, 0x01, 0x2c, 0x13, 0xc5, 0xcb, 0x77, 0x11, 0xbb, 0x88, 0x36, 0xea, 0x22,
+ 0x2d, 0x3e, 0x32, 0xab, 0x5e, 0xb9, 0x93, 0x1a, 0x05, 0xa8, 0xfe, 0x11, 0xe6, 0xb4, 0xd0, 0x2c,
+ 0x0b, 0xee, 0x0f, 0x9d, 0xdb, 0x85, 0x96, 0x4b, 0x4e, 0x61, 0xda, 0x2a, 0x0a, 0xbe, 0x41, 0x8b,
+ 0xa7, 0x53, 0x2d, 0x8e, 0x4c, 0x0c, 0x47, 0xb2, 0xee, 0xb0, 0x68, 0x49, 0xfd, 0x37, 0x14, 0xbe,
+ 0x80, 0x85, 0x1b, 0x53, 0xdb, 0x83, 0xce, 0xc9, 0xd1, 0x5e, 0xe4, 0xdf, 0x23, 0x7d, 0x70, 0xcd,
+ 0xd3, 0xee, 0xde, 0xce, 0xc9, 0x1b, 0xdf, 0x21, 0x5d, 0x30, 0x93, 0xee, 0xcf, 0x84, 0xaf, 0xa1,
+ 0x83, 0xdf, 0xd5, 0x83, 0xa6, 0x4f, 0xfd, 0x7b, 0x06, 0xdd, 0x8e, 0x0e, 0x7c, 0x87, 0xb8, 0x30,
+ 0xb7, 0x1d, 0x1d, 0x6c, 0xbe, 0xf4, 0x67, 0x4c, 0xec, 0xfd, 0xab, 0x4d, 0x7f, 0x96, 0x00, 0xcc,
+ 0xbf, 0x7f, 0xb5, 0x49, 0x37, 0x5f, 0xfa, 0x9d, 0xf0, 0x4f, 0x07, 0x7a, 0x4d, 0x6d, 0x84, 0x40,
+ 0x27, 0xe1, 0x2a, 0xc6, 0x45, 0xe9, 0x46, 0xf8, 0x6c, 0x62, 0xb8, 0xea, 0xec, 0x5a, 0xc4, 0x67,
+ 0xb2, 0x0a, 0xa0, 0x34, 0x93, 0x1a, 0x77, 0x2b, 0x2e, 0xc1, 0x4e, 0xe4, 0x62, 0xc4, 0xac, 0x54,
+ 0xf2, 0x18, 0x5c, 0xc9, 0x59, 0x66, 0xd1, 0x0e, 0xa2, 0x3d, 0x13, 0x40, 0x70, 0x15, 0x20, 0xe7,
+ 0xb9, 0x90, 0x57, 0xb4, 0x52, 0x1c, 0x57, 0x5c, 0x27, 0x72, 0x6d, 0xe4, 0x44, 0xf1, 0xf0, 0x1f,
+ 0x07, 0x06, 0x07, 0x22, 0xa9, 0x32, 0x7e, 0x7c, 0x55, 0x72, 0xcc, 0xea, 0x77, 0x58, 0xb0, 0x17,
+ 0xa9, 0xae, 0x94, 0xe6, 0x39, 0x66, 0x37, 0xd8, 0x78, 0x3e, 0x7d, 0x76, 0x6f, 0x48, 0xed, 0x66,
+ 0x3c, 0x42, 0x59, 0x6b, 0x8a, 0xcf, 0xae, 0xa3, 0xe4, 0x5b, 0xf0, 0x72, 0xd4, 0x50, 0x7d, 0x55,
+ 0x36, 0x55, 0x42, 0x3e, 0xb1, 0x21, 0xdf, 0xc1, 0xa0, 0xa8, 0x72, 0x2a, 0xce, 0xa9, 0x0d, 0x2a,
+ 0xac, 0xb7, 0x1f, 0x2d, 0x14, 0x55, 0x3e, 0x3e, 0xb7, 0xe7, 0xa9, 0xf0, 0x39, 0x78, 0xad, 0xb3,
+ 0x6e, 0x7e, 0x0b, 0x17, 0xe6, 0x8e, 0xc6, 0xe3, 0x43, 0xf3, 0xd1, 0x7a, 0xd0, 0x39, 0xd8, 0xde,
+ 0xdf, 0xf3, 0x67, 0xc2, 0x0c, 0x1e, 0x8d, 0x64, 0xaa, 0xd3, 0x98, 0x65, 0x27, 0x8a, 0xcb, 0x5f,
+ 0x44, 0x25, 0x0b, 0x7e, 0x55, 0x77, 0xc1, 0xe4, 0xd2, 0x9d, 0xd6, 0xa5, 0x6f, 0x41, 0xb7, 0xe9,
+ 0xb2, 0x19, 0xec, 0xb2, 0xe1, 0x6d, 0xdb, 0x2b, 0x6a, 0x04, 0xe1, 0x19, 0x3c, 0x9e, 0x72, 0x9a,
+ 0x6a, 0x8e, 0x1b, 0x41, 0x27, 0xae, 0x3e, 0xaa, 0xc0, 0xc1, 0xc9, 0x99, 0x7e, 0xb3, 0x5f, 0xce,
+ 0x36, 0x42, 0x71, 0xf8, 0xb7, 0x03, 0x4b, 0xff, 0x6b, 0x71, 0x12, 0x40, 0xb7, 0xb9, 0x37, 0x07,
+ 0xef, 0xad, 0x79, 0x25, 0x8f, 0xa0, 0x57, 0xff, 0x06, 0xd8, 0x82, 0xfa, 0xd1, 0xe4, 0x9d, 0x7c,
+ 0x0f, 0x4b, 0x38, 0x66, 0x94, 0x65, 0x99, 0x88, 0x69, 0x2c, 0xaa, 0x42, 0xd7, 0x7d, 0xb6, 0x88,
+ 0xc0, 0xb6, 0x89, 0x8f, 0x4c, 0x98, 0xac, 0x81, 0xdf, 0xe6, 0xaa, 0xf4, 0x73, 0xd3, 0x74, 0x83,
+ 0x6b, 0xea, 0x51, 0xfa, 0x99, 0x9b, 0xa5, 0x9b, 0xb3, 0x4b, 0x7a, 0xc1, 0x59, 0x69, 0x69, 0xb6,
+ 0xfb, 0xbc, 0x9c, 0x5d, 0xfe, 0xcc, 0x59, 0x69, 0x38, 0x3b, 0xf7, 0x7f, 0xab, 0xe7, 0xba, 0xae,
+ 0x9b, 0xe2, 0xff, 0x8e, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x2a, 0x36, 0xe3, 0x87, 0x08,
+ 0x00, 0x00,
}
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 194aa6b..50810eb 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -92,6 +92,8 @@
// The metrics for the whole build
optional PerfInfo total = 21;
+
+ optional SoongBuildMetrics soong_build_metrics = 22;
}
message PerfInfo {
@@ -140,4 +142,21 @@
message CriticalUserJourneysMetrics {
// A set of metrics from a run of the critical user journey tests.
repeated CriticalUserJourneyMetrics cujs = 1;
+}
+
+message SoongBuildMetrics {
+ // The number of modules handled by soong_build.
+ optional uint32 modules = 1;
+
+ // The total number of variants handled by soong_build.
+ optional uint32 variants = 2;
+
+ // The total number of allocations in soong_build.
+ optional uint64 total_alloc_count = 3;
+
+ // The total size of allocations in soong_build in bytes.
+ optional uint64 total_alloc_size = 4;
+
+ // The approximate maximum size of the heap in soong_build in bytes.
+ optional uint64 max_heap_size = 5;
}
\ No newline at end of file
diff --git a/ui/metrics/upload_proto/regen.sh b/ui/metrics/upload_proto/regen.sh
new file mode 100755
index 0000000..4521df7
--- /dev/null
+++ b/ui/metrics/upload_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of upload.proto file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. upload.proto; then
+ die "build failed. ${error_msg}"
+fi
diff --git a/ui/metrics/upload_proto/upload.pb.go b/ui/metrics/upload_proto/upload.pb.go
new file mode 100644
index 0000000..1b1e5e8
--- /dev/null
+++ b/ui/metrics/upload_proto/upload.pb.go
@@ -0,0 +1,122 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: upload.proto
+
+package soong_metrics_upload_proto
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type Upload struct {
+ // The timestamp in milliseconds that the build was created.
+ CreationTimestampMs *uint64 `protobuf:"varint,1,opt,name=creation_timestamp_ms,json=creationTimestampMs" json:"creation_timestamp_ms,omitempty"`
+ // The timestamp in milliseconds when the build was completed.
+ CompletionTimestampMs *uint64 `protobuf:"varint,2,opt,name=completion_timestamp_ms,json=completionTimestampMs" json:"completion_timestamp_ms,omitempty"`
+ // The branch name.
+ BranchName *string `protobuf:"bytes,3,opt,name=branch_name,json=branchName" json:"branch_name,omitempty"`
+ // The target name.
+ TargetName *string `protobuf:"bytes,4,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+ // A list of metrics filepaths to upload.
+ MetricsFiles []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Upload) Reset() { *m = Upload{} }
+func (m *Upload) String() string { return proto.CompactTextString(m) }
+func (*Upload) ProtoMessage() {}
+func (*Upload) Descriptor() ([]byte, []int) {
+ return fileDescriptor_91b94b655bd2a7e5, []int{0}
+}
+
+func (m *Upload) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Upload.Unmarshal(m, b)
+}
+func (m *Upload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Upload.Marshal(b, m, deterministic)
+}
+func (m *Upload) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Upload.Merge(m, src)
+}
+func (m *Upload) XXX_Size() int {
+ return xxx_messageInfo_Upload.Size(m)
+}
+func (m *Upload) XXX_DiscardUnknown() {
+ xxx_messageInfo_Upload.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Upload proto.InternalMessageInfo
+
+func (m *Upload) GetCreationTimestampMs() uint64 {
+ if m != nil && m.CreationTimestampMs != nil {
+ return *m.CreationTimestampMs
+ }
+ return 0
+}
+
+func (m *Upload) GetCompletionTimestampMs() uint64 {
+ if m != nil && m.CompletionTimestampMs != nil {
+ return *m.CompletionTimestampMs
+ }
+ return 0
+}
+
+func (m *Upload) GetBranchName() string {
+ if m != nil && m.BranchName != nil {
+ return *m.BranchName
+ }
+ return ""
+}
+
+func (m *Upload) GetTargetName() string {
+ if m != nil && m.TargetName != nil {
+ return *m.TargetName
+ }
+ return ""
+}
+
+func (m *Upload) GetMetricsFiles() []string {
+ if m != nil {
+ return m.MetricsFiles
+ }
+ return nil
+}
+
+func init() {
+ proto.RegisterType((*Upload)(nil), "soong_metrics_upload.Upload")
+}
+
+func init() {
+ proto.RegisterFile("upload.proto", fileDescriptor_91b94b655bd2a7e5)
+}
+
+var fileDescriptor_91b94b655bd2a7e5 = []byte{
+ // 201 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x2d, 0xc8, 0xc9,
+ 0x4f, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f,
+ 0xcf, 0x4d, 0x2d, 0x29, 0xca, 0x4c, 0x2e, 0x8e, 0x87, 0xc8, 0x29, 0xdd, 0x66, 0xe4, 0x62, 0x0b,
+ 0x05, 0x33, 0x85, 0x8c, 0xb8, 0x44, 0x93, 0x8b, 0x52, 0x13, 0x4b, 0x32, 0xf3, 0xf3, 0xe2, 0x4b,
+ 0x32, 0x73, 0x53, 0x8b, 0x4b, 0x12, 0x73, 0x0b, 0xe2, 0x73, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35,
+ 0x58, 0x82, 0x84, 0x61, 0x92, 0x21, 0x30, 0x39, 0xdf, 0x62, 0x21, 0x33, 0x2e, 0xf1, 0xe4, 0xfc,
+ 0xdc, 0x82, 0x9c, 0x54, 0x4c, 0x5d, 0x4c, 0x60, 0x5d, 0xa2, 0x08, 0x69, 0x64, 0x7d, 0xf2, 0x5c,
+ 0xdc, 0x49, 0x45, 0x89, 0x79, 0xc9, 0x19, 0xf1, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0xcc, 0x0a, 0x8c,
+ 0x1a, 0x9c, 0x41, 0x5c, 0x10, 0x21, 0xbf, 0xc4, 0xdc, 0x54, 0x90, 0x82, 0x92, 0xc4, 0xa2, 0xf4,
+ 0xd4, 0x12, 0x88, 0x02, 0x16, 0x88, 0x02, 0x88, 0x10, 0x58, 0x81, 0x32, 0x17, 0x2f, 0xcc, 0x2b,
+ 0x69, 0x99, 0x39, 0xa9, 0xc5, 0x12, 0xac, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x3c, 0x50, 0x41, 0x37,
+ 0x90, 0x98, 0x93, 0x4c, 0x94, 0x14, 0x36, 0x5f, 0xc7, 0x83, 0x43, 0x04, 0x10, 0x00, 0x00, 0xff,
+ 0xff, 0xe2, 0x01, 0x74, 0x65, 0x20, 0x01, 0x00, 0x00,
+}
diff --git a/ui/metrics/upload_proto/upload.proto b/ui/metrics/upload_proto/upload.proto
new file mode 100644
index 0000000..7a9f080
--- /dev/null
+++ b/ui/metrics/upload_proto/upload.proto
@@ -0,0 +1,35 @@
+// 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.
+
+syntax = "proto2";
+
+package soong_metrics_upload;
+option go_package = "soong_metrics_upload_proto";
+
+message Upload {
+ // The timestamp in milliseconds that the build was created.
+ optional uint64 creation_timestamp_ms = 1;
+
+ // The timestamp in milliseconds when the build was completed.
+ optional uint64 completion_timestamp_ms = 2;
+
+ // The branch name.
+ optional string branch_name = 3;
+
+ // The target name.
+ optional string target_name = 4;
+
+ // A list of metrics filepaths to upload.
+ repeated string metrics_files = 5;
+}
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index ec929b3..19e5a2a 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -20,6 +20,7 @@
"soong-ui-logger",
"soong-ui-status-ninja_frontend",
"soong-ui-status-build_error_proto",
+ "soong-ui-status-build_progress_proto",
],
srcs: [
"critical_path.go",
@@ -53,3 +54,12 @@
"build_error_proto/build_error.pb.go",
],
}
+
+bootstrap_go_package {
+ name: "soong-ui-status-build_progress_proto",
+ pkgPath: "android/soong/ui/status/build_progress_proto",
+ deps: ["golang-protobuf-proto"],
+ srcs: [
+ "build_progress_proto/build_progress.pb.go",
+ ],
+}
diff --git a/ui/status/build_progress_proto/build_progress.pb.go b/ui/status/build_progress_proto/build_progress.pb.go
new file mode 100644
index 0000000..f63c157
--- /dev/null
+++ b/ui/status/build_progress_proto/build_progress.pb.go
@@ -0,0 +1,115 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_progress.proto
+
+package soong_build_progress_proto
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type BuildProgress struct {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ TotalActions *uint64 `protobuf:"varint,1,opt,name=total_actions,json=totalActions" json:"total_actions,omitempty"`
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ FinishedActions *uint64 `protobuf:"varint,2,opt,name=finished_actions,json=finishedActions" json:"finished_actions,omitempty"`
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ CurrentActions *uint64 `protobuf:"varint,3,opt,name=current_actions,json=currentActions" json:"current_actions,omitempty"`
+ // Total number of actions that reported as a failure.
+ FailedActions *uint64 `protobuf:"varint,4,opt,name=failed_actions,json=failedActions" json:"failed_actions,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *BuildProgress) Reset() { *m = BuildProgress{} }
+func (m *BuildProgress) String() string { return proto.CompactTextString(m) }
+func (*BuildProgress) ProtoMessage() {}
+func (*BuildProgress) Descriptor() ([]byte, []int) {
+ return fileDescriptor_a8a463f8e30dab2e, []int{0}
+}
+
+func (m *BuildProgress) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_BuildProgress.Unmarshal(m, b)
+}
+func (m *BuildProgress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_BuildProgress.Marshal(b, m, deterministic)
+}
+func (m *BuildProgress) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_BuildProgress.Merge(m, src)
+}
+func (m *BuildProgress) XXX_Size() int {
+ return xxx_messageInfo_BuildProgress.Size(m)
+}
+func (m *BuildProgress) XXX_DiscardUnknown() {
+ xxx_messageInfo_BuildProgress.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildProgress proto.InternalMessageInfo
+
+func (m *BuildProgress) GetTotalActions() uint64 {
+ if m != nil && m.TotalActions != nil {
+ return *m.TotalActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetFinishedActions() uint64 {
+ if m != nil && m.FinishedActions != nil {
+ return *m.FinishedActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetCurrentActions() uint64 {
+ if m != nil && m.CurrentActions != nil {
+ return *m.CurrentActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetFailedActions() uint64 {
+ if m != nil && m.FailedActions != nil {
+ return *m.FailedActions
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterType((*BuildProgress)(nil), "soong_build_progress.BuildProgress")
+}
+
+func init() { proto.RegisterFile("build_progress.proto", fileDescriptor_a8a463f8e30dab2e) }
+
+var fileDescriptor_a8a463f8e30dab2e = []byte{
+ // 165 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x49, 0x2a, 0xcd, 0xcc,
+ 0x49, 0x89, 0x2f, 0x28, 0xca, 0x4f, 0x2f, 0x4a, 0x2d, 0x2e, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
+ 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f, 0x47, 0x95, 0x53, 0x5a, 0xcf, 0xc8, 0xc5, 0xeb,
+ 0x04, 0x12, 0x0a, 0x80, 0x8a, 0x08, 0x29, 0x73, 0xf1, 0x96, 0xe4, 0x97, 0x24, 0xe6, 0xc4, 0x27,
+ 0x26, 0x97, 0x64, 0xe6, 0xe7, 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x04, 0xf1, 0x80, 0x05,
+ 0x1d, 0x21, 0x62, 0x42, 0x9a, 0x5c, 0x02, 0x69, 0x99, 0x79, 0x99, 0xc5, 0x19, 0xa9, 0x29, 0x70,
+ 0x75, 0x4c, 0x60, 0x75, 0xfc, 0x30, 0x71, 0x98, 0x52, 0x75, 0x2e, 0xfe, 0xe4, 0xd2, 0xa2, 0xa2,
+ 0xd4, 0xbc, 0x12, 0xb8, 0x4a, 0x66, 0xb0, 0x4a, 0x3e, 0xa8, 0x30, 0x4c, 0xa1, 0x2a, 0x17, 0x5f,
+ 0x5a, 0x62, 0x66, 0x0e, 0x92, 0x89, 0x2c, 0x60, 0x75, 0xbc, 0x10, 0x51, 0xa8, 0x32, 0x27, 0x99,
+ 0x28, 0x29, 0x6c, 0x3e, 0x89, 0x07, 0xfb, 0x12, 0x10, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x6e, 0xc1,
+ 0xef, 0xfc, 0x00, 0x00, 0x00,
+}
diff --git a/ui/status/build_progress_proto/build_progress.proto b/ui/status/build_progress_proto/build_progress.proto
new file mode 100644
index 0000000..d78060a
--- /dev/null
+++ b/ui/status/build_progress_proto/build_progress.proto
@@ -0,0 +1,38 @@
+// 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.
+
+syntax = "proto2";
+
+package soong_build_progress;
+option go_package = "soong_build_progress_proto";
+
+message BuildProgress {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ optional uint64 total_actions = 1;
+
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ optional uint64 finished_actions = 2;
+
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ optional uint64 current_actions = 3;
+
+ // Total number of actions that reported as a failure.
+ optional uint64 failed_actions = 4;
+}
diff --git a/ui/status/build_progress_proto/regen.sh b/ui/status/build_progress_proto/regen.sh
new file mode 100755
index 0000000..572785d
--- /dev/null
+++ b/ui/status/build_progress_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of build_completion.proto file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. build_progress.proto; then
+ die "build failed. ${error_msg}"
+fi
diff --git a/ui/status/log.go b/ui/status/log.go
index d407248..4a08acb 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -20,12 +20,14 @@
"fmt"
"io"
"io/ioutil"
+ "os"
"strings"
"github.com/golang/protobuf/proto"
"android/soong/ui/logger"
"android/soong/ui/status/build_error_proto"
+ "android/soong/ui/status/build_progress_proto"
)
type verboseLog struct {
@@ -154,6 +156,7 @@
}
func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
+ os.Remove(filename)
return &errorProtoLog{
errorProto: soong_build_error_proto.BuildError{},
filename: filename,
@@ -175,20 +178,17 @@
Artifacts: result.Outputs,
Error: proto.String(result.Error.Error()),
})
-}
-func (e *errorProtoLog) Flush() {
- data, err := proto.Marshal(&e.errorProto)
- if err != nil {
- e.log.Printf("Failed to marshal build status proto: %v\n", err)
- return
- }
- err = ioutil.WriteFile(e.filename, []byte(data), 0644)
+ err := writeToFile(&e.errorProto, e.filename)
if err != nil {
e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
}
}
+func (e *errorProtoLog) Flush() {
+ //Not required.
+}
+
func (e *errorProtoLog) Message(level MsgLevel, message string) {
if level > ErrorLvl {
e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
@@ -198,3 +198,75 @@
func (e *errorProtoLog) Write(p []byte) (int, error) {
return 0, errors.New("not supported")
}
+
+type buildProgressLog struct {
+ filename string
+ log logger.Logger
+ failedActions uint64
+}
+
+func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
+ return &buildProgressLog{
+ filename: filename,
+ log: log,
+ failedActions: 0,
+ }
+}
+
+func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
+ if result.Error != nil {
+ b.failedActions++
+ }
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) Flush() {
+ //Not required.
+}
+
+func (b *buildProgressLog) Message(level MsgLevel, message string) {
+ // Not required.
+}
+
+func (b *buildProgressLog) Write(p []byte) (int, error) {
+ return 0, errors.New("not supported")
+}
+
+func (b *buildProgressLog) updateCounters(counts Counts) {
+ err := writeToFile(
+ &soong_build_progress_proto.BuildProgress{
+ CurrentActions: proto.Uint64(uint64(counts.RunningActions)),
+ FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
+ TotalActions: proto.Uint64(uint64(counts.TotalActions)),
+ FailedActions: proto.Uint64(b.failedActions),
+ },
+ b.filename,
+ )
+ if err != nil {
+ b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
+ }
+}
+
+func writeToFile(pb proto.Message, outputPath string) (err error) {
+ data, err := proto.Marshal(pb)
+ if err != nil {
+ return err
+ }
+
+ tempPath := outputPath + ".tmp"
+ err = ioutil.WriteFile(tempPath, []byte(data), 0644)
+ if err != nil {
+ return err
+ }
+
+ err = os.Rename(tempPath, outputPath)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vnames.go.json b/vnames.go.json
index 5842097..7ce2d4b 100644
--- a/vnames.go.json
+++ b/vnames.go.json
@@ -3,7 +3,7 @@
"pattern": "(.*)",
"vname": {
"corpus": "android.googlesource.com/platform/superproject",
- "path": "build/soong/@1@"
+ "path": "@1@"
}
}
]