Merge "Fix run_tool_with_logging_test in CI" into main
diff --git a/Android.bp b/Android.bp
index 682711d..0d1ff02 100644
--- a/Android.bp
+++ b/Android.bp
@@ -132,7 +132,7 @@
product_config: ":product_config",
// Currently, only microdroid can refer to buildinfo.prop
- visibility: ["//packages/modules/Virtualization/microdroid"],
+ visibility: ["//packages/modules/Virtualization/build/microdroid"],
}
// container for apex_contributions selected using build flags
diff --git a/aconfig/init.go b/aconfig/init.go
index 256b213..de155ab 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -47,7 +47,7 @@
// For create-device-config-sysprops: Generate aconfig flag value map text file
aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
blueprint.RuleParams{
- Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}'` +
+ Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}:{permission}={state:bool}'` +
` --cache ${in}` +
` --out ${out}.tmp` +
` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
diff --git a/android/Android.bp b/android/Android.bp
index 774d24a..ce27241 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -93,6 +93,7 @@
"register.go",
"rule_builder.go",
"sandbox.go",
+ "sbom.go",
"sdk.go",
"sdk_version.go",
"shared_properties.go",
diff --git a/android/arch.go b/android/arch.go
index e0c6908..6d896e5 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -19,6 +19,7 @@
"fmt"
"reflect"
"runtime"
+ "slices"
"strings"
"github.com/google/blueprint"
@@ -587,19 +588,21 @@
}
osTargets := mctx.Config().Targets[os]
+
image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported.
// Skip creating native bridge variants for non-core modules.
if os == Android && !(base.IsNativeBridgeSupported() && image == CoreVariation) {
+ osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
+ return bool(t.NativeBridge)
+ })
+ }
- var targets []Target
- for _, t := range osTargets {
- if !t.NativeBridge {
- targets = append(targets, t)
- }
- }
-
- osTargets = targets
+ // Filter HostCross targets if disabled.
+ if base.HostSupported() && !base.HostCrossSupported() {
+ osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
+ return t.HostCross
+ })
}
// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
diff --git a/android/arch_list.go b/android/arch_list.go
index 4233456..f1289a3 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -16,7 +16,6 @@
var archVariants = map[ArchType][]string{
Arm: {
- "armv7-a",
"armv7-a-neon",
"armv8-a",
"armv8-2a",
diff --git a/android/arch_test.go b/android/arch_test.go
index f0a58a9..6134a06 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -332,6 +332,12 @@
}
module {
+ name: "nohostcross",
+ host_supported: true,
+ host_cross_supported: false,
+ }
+
+ module {
name: "baz",
device_supported: false,
}
@@ -355,13 +361,14 @@
`
testCases := []struct {
- name string
- preparer FixturePreparer
- fooVariants []string
- barVariants []string
- bazVariants []string
- quxVariants []string
- firstVariants []string
+ name string
+ preparer FixturePreparer
+ fooVariants []string
+ barVariants []string
+ noHostCrossVariants []string
+ bazVariants []string
+ quxVariants []string
+ firstVariants []string
multiTargetVariants []string
multiTargetVariantsMap map[string][]string
@@ -373,6 +380,7 @@
preparer: nil,
fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
+ noHostCrossVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
bazVariants: nil,
quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
firstVariants: append(buildOS64Variants, "android_arm64_armv8-a"),
@@ -390,6 +398,7 @@
}),
fooVariants: nil,
barVariants: buildOSVariants,
+ noHostCrossVariants: buildOSVariants,
bazVariants: nil,
quxVariants: buildOS32Variants,
firstVariants: buildOS64Variants,
@@ -406,6 +415,7 @@
}),
fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
barVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+ noHostCrossVariants: []string{"linux_musl_x86_64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"},
bazVariants: nil,
quxVariants: []string{"linux_musl_x86", "android_arm_armv7-a-neon"},
firstVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "android_arm64_armv8-a"},
@@ -461,6 +471,10 @@
t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
}
+ if g, w := enabledVariants(ctx, "nohostcross"), tt.noHostCrossVariants; !reflect.DeepEqual(w, g) {
+ t.Errorf("want nohostcross variants:\n%q\ngot:\n%q\n", w, g)
+ }
+
if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
}
diff --git a/android/config.go b/android/config.go
index d16377d..cadc929 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1195,6 +1195,10 @@
return Bool(c.productVariables.UseGoma)
}
+func (c *config) UseABFS() bool {
+ return Bool(c.productVariables.UseABFS)
+}
+
func (c *config) UseRBE() bool {
return Bool(c.productVariables.UseRBE)
}
@@ -1356,10 +1360,6 @@
return ExistentPathForSource(ctx, "frameworks", "base", "Android.bp").Valid()
}
-func (c *config) VndkSnapshotBuildArtifacts() bool {
- return Bool(c.productVariables.VndkSnapshotBuildArtifacts)
-}
-
func (c *config) HasMultilibConflict(arch ArchType) bool {
return c.multilibConflicts[arch]
}
@@ -1423,10 +1423,6 @@
return "vendor"
}
-func (c *deviceConfig) RecoverySnapshotVersion() string {
- return String(c.config.productVariables.RecoverySnapshotVersion)
-}
-
func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
}
@@ -1804,22 +1800,6 @@
return c.SystemExtSepolicyPrebuiltApiDir() != "" || c.ProductSepolicyPrebuiltApiDir() != ""
}
-func (c *deviceConfig) DirectedVendorSnapshot() bool {
- return c.config.productVariables.DirectedVendorSnapshot
-}
-
-func (c *deviceConfig) VendorSnapshotModules() map[string]bool {
- return c.config.productVariables.VendorSnapshotModules
-}
-
-func (c *deviceConfig) DirectedRecoverySnapshot() bool {
- return c.config.productVariables.DirectedRecoverySnapshot
-}
-
-func (c *deviceConfig) RecoverySnapshotModules() map[string]bool {
- return c.config.productVariables.RecoverySnapshotModules
-}
-
func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) {
var ret = make(map[string]bool)
for _, dir := range dirs {
@@ -1846,40 +1826,6 @@
return dirMap.(map[string]bool)
}
-var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap")
-
-func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool {
- return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil,
- c.config.productVariables.VendorSnapshotDirsExcluded)
-}
-
-var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap")
-
-func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool {
- excludedMap := c.VendorSnapshotDirsExcludedMap()
- return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap,
- c.config.productVariables.VendorSnapshotDirsIncluded)
-}
-
-var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap")
-
-func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool {
- return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil,
- c.config.productVariables.RecoverySnapshotDirsExcluded)
-}
-
-var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap")
-
-func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool {
- excludedMap := c.RecoverySnapshotDirsExcludedMap()
- return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap,
- c.config.productVariables.RecoverySnapshotDirsIncluded)
-}
-
-func (c *deviceConfig) HostFakeSnapshotEnabled() bool {
- return c.config.productVariables.HostFakeSnapshotEnabled
-}
-
func (c *deviceConfig) ShippingApiLevel() ApiLevel {
if c.config.productVariables.Shipping_api_level == nil {
return NoneApiLevel
@@ -2127,3 +2073,11 @@
func (c *config) OemProperties() []string {
return c.productVariables.OemProperties
}
+
+func (c *config) UseDebugArt() bool {
+ if c.productVariables.ArtTargetIncludeDebugBuild != nil {
+ return Bool(c.productVariables.ArtTargetIncludeDebugBuild)
+ }
+
+ return Bool(c.productVariables.Eng)
+}
diff --git a/android/defaults.go b/android/defaults.go
index ff79002..c0a2fc6 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -28,7 +28,7 @@
var DefaultsDepTag defaultsDependencyTag
type defaultsProperties struct {
- Defaults []string
+ Defaults proptools.Configurable[[]string]
}
type DefaultableModuleBase struct {
@@ -278,13 +278,14 @@
func defaultsDepsMutator(ctx BottomUpMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
- ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
+ ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults.GetOrDefault(ctx, nil)...)
}
}
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
- if len(defaultable.defaults().Defaults) > 0 {
+ defaults := defaultable.defaults().Defaults.GetOrDefault(ctx, nil)
+ if len(defaults) > 0 {
var defaultsList []Defaults
seen := make(map[Defaults]bool)
@@ -294,7 +295,7 @@
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
- return len(defaults.defaults().Defaults) > 0
+ return len(defaults.defaults().Defaults.GetOrDefault(ctx, nil)) > 0
}
} else {
ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
diff --git a/android/module.go b/android/module.go
index dd56031..5c2b1e1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -389,7 +389,7 @@
Init_rc []string `android:"arch_variant,path"`
// VINTF manifest fragments to be installed if this module is installed
- Vintf_fragments []string `android:"path"`
+ Vintf_fragments proptools.Configurable[[]string] `android:"path"`
// names of other modules to install if this module is installed
Required proptools.Configurable[[]string] `android:"arch_variant"`
@@ -603,6 +603,11 @@
Device_supported *bool
}
+type hostCrossProperties struct {
+ // If set to true, build a variant of the module for the host cross. Defaults to true.
+ Host_cross_supported *bool
+}
+
type Multilib string
const (
@@ -718,6 +723,10 @@
m.AddProperties(&base.hostAndDeviceProperties)
}
+ if hod&hostCrossSupported != 0 {
+ m.AddProperties(&base.hostCrossProperties)
+ }
+
initArchModule(m)
}
@@ -803,6 +812,7 @@
distProperties distProperties
variableProperties interface{}
hostAndDeviceProperties hostAndDeviceProperties
+ hostCrossProperties hostCrossProperties
// Arch specific versions of structs in GetProperties() prior to
// initialization in InitAndroidArchModule, lets call it `generalProperties`.
@@ -1299,7 +1309,11 @@
// hostEnabled is true if the host_supported property is true or the HostOrDeviceSupported
// value has the hostDefault bit set.
hostEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Host_supported, hod&hostDefault != 0)
- return hod&hostCrossSupported != 0 && hostEnabled
+
+ // Default true for the Host_cross_supported property
+ hostCrossEnabled := proptools.BoolDefault(m.hostCrossProperties.Host_cross_supported, true)
+
+ return hod&hostCrossSupported != 0 && hostEnabled && hostCrossEnabled
}
func (m *ModuleBase) Platform() bool {
@@ -1839,7 +1853,7 @@
}
}
- m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+ m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil))
vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
for _, src := range m.vintfFragmentsPaths {
installedVintfFragment := vintfDir.Join(ctx, src.Base())
@@ -2199,6 +2213,9 @@
switch variable {
case "debuggable":
return proptools.ConfigurableValueBool(ctx.Config().Debuggable())
+ case "use_debug_art":
+ // TODO(b/234351700): Remove once ART does not have separated debug APEX
+ return proptools.ConfigurableValueBool(ctx.Config().UseDebugArt())
default:
// TODO(b/323382414): Might add these on a case-by-case basis
ctx.OtherModulePropertyErrorf(m, property, fmt.Sprintf("TODO(b/323382414): Product variable %q is not yet supported in selects", variable))
@@ -2504,8 +2521,9 @@
} else if cta, isCta := ctx.(*singletonContextAdaptor); isCta {
providerData, _ := cta.moduleProvider(module, OutputFilesProvider)
outputFiles, _ = providerData.(OutputFilesInfo)
+ } else {
+ return nil, fmt.Errorf("unsupported context %q in method outputFilesForModuleFromProvider", reflect.TypeOf(ctx))
}
- // TODO: Add a check for skipped context
if outputFiles.isEmpty() {
return nil, OutputFilesProviderNotSet
diff --git a/android/module_test.go b/android/module_test.go
index 922ea21..829c079 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -722,7 +722,6 @@
propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
propInfo{Name: "B", Type: "bool", Value: "true"},
propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
- propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
propInfo{Name: "Name", Type: "string", Value: "foo"},
propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
@@ -746,7 +745,6 @@
foo := result.ModuleForTests("foo", "").Module().base()
AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
-
})
}
}
diff --git a/android/neverallow.go b/android/neverallow.go
index ef4b8b8..0f363e7 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -212,7 +212,7 @@
func createCcStubsRule() Rule {
ccStubsImplementationInstallableProjectsAllowedList := []string{
- "packages/modules/Virtualization/vm_payload",
+ "packages/modules/Virtualization/libs/libvm_payload",
}
return NeverAllow().
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 85e29bd..8b03124 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -58,6 +58,7 @@
sboxInputs bool
sboxManifestPath WritablePath
missingDeps []string
+ args map[string]string
}
// NewRuleBuilder returns a newly created RuleBuilder.
@@ -78,6 +79,17 @@
return rb
}
+// Set the phony_output argument.
+// This causes the output files to be ignored.
+// If the output isn't created, it's not treated as an error.
+// The build rule is run every time whether or not the output is created.
+func (rb *RuleBuilder) SetPhonyOutput() {
+ if rb.args == nil {
+ rb.args = make(map[string]string)
+ }
+ rb.args["phony_output"] = "true"
+}
+
// RuleBuilderInstall is a tuple of install from and to locations.
type RuleBuilderInstall struct {
From Path
@@ -726,6 +738,12 @@
commandString = proptools.NinjaEscape(commandString)
}
+ args_vars := make([]string, len(r.args))
+ i := 0
+ for k, _ := range r.args {
+ args_vars[i] = k
+ i++
+ }
r.ctx.Build(r.pctx, BuildParams{
Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{
Command: commandString,
@@ -734,7 +752,7 @@
Rspfile: proptools.NinjaEscape(rspFile),
RspfileContent: rspFileContent,
Pool: pool,
- }),
+ }, args_vars...),
Inputs: rspFileInputs,
Implicits: inputs,
OrderOnly: r.OrderOnlys(),
@@ -744,6 +762,7 @@
Depfile: depFile,
Deps: depFormat,
Description: desc,
+ Args: r.args,
})
}
diff --git a/android/sbom.go b/android/sbom.go
new file mode 100644
index 0000000..dd2d2fa
--- /dev/null
+++ b/android/sbom.go
@@ -0,0 +1,100 @@
+// Copyright 2024 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"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint"
+)
+
+var (
+ // Command line tool to generate SBOM in Soong
+ genSbom = pctx.HostBinToolVariable("genSbom", "gen_sbom")
+
+ // Command to generate SBOM in Soong.
+ genSbomRule = pctx.AndroidStaticRule("genSbomRule", blueprint.RuleParams{
+ Command: "rm -rf $out && ${genSbom} --output_file ${out} --metadata ${in} --product_out ${productOut} --soong_out ${soongOut} --build_version \"$$(cat ${buildFingerprintFile})\" --product_mfr \"${productManufacturer}\" --json",
+ CommandDeps: []string{"${genSbom}"},
+ }, "productOut", "soongOut", "buildFingerprintFile", "productManufacturer")
+)
+
+func init() {
+ RegisterSbomSingleton(InitRegistrationContext)
+}
+
+func RegisterSbomSingleton(ctx RegistrationContext) {
+ ctx.RegisterParallelSingletonType("sbom_singleton", sbomSingletonFactory)
+}
+
+// sbomSingleton is used to generate build actions of generating SBOM of products.
+type sbomSingleton struct{}
+
+func sbomSingletonFactory() Singleton {
+ return &sbomSingleton{}
+}
+
+// Generates SBOM of products
+func (this *sbomSingleton) GenerateBuildActions(ctx SingletonContext) {
+ if !ctx.Config().HasDeviceProduct() {
+ return
+ }
+ // Get all METADATA files and add them as implicit input
+ metadataFileListFile := PathForArbitraryOutput(ctx, ".module_paths", "METADATA.list")
+ f, err := ctx.Config().fs.Open(metadataFileListFile.String())
+ if err != nil {
+ panic(err)
+ }
+ b, err := io.ReadAll(f)
+ if err != nil {
+ panic(err)
+ }
+ allMetadataFiles := strings.Split(string(b), "\n")
+ implicits := []Path{metadataFileListFile}
+ for _, path := range allMetadataFiles {
+ implicits = append(implicits, PathForSource(ctx, path))
+ }
+ prodVars := ctx.Config().productVariables
+ buildFingerprintFile := PathForArbitraryOutput(ctx, "target", "product", String(prodVars.DeviceName), "build_fingerprint.txt")
+ implicits = append(implicits, buildFingerprintFile)
+
+ // Add installed_files.stamp as implicit input, which depends on all installed files of the product.
+ installedFilesStamp := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "installed_files.stamp")
+ implicits = append(implicits, installedFilesStamp)
+
+ metadataDb := PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db")
+ sbomFile := PathForOutput(ctx, "sbom", ctx.Config().DeviceProduct(), "sbom.spdx.json")
+ ctx.Build(pctx, BuildParams{
+ Rule: genSbomRule,
+ Input: metadataDb,
+ Implicits: implicits,
+ Output: sbomFile,
+ Args: map[string]string{
+ "productOut": filepath.Join(ctx.Config().OutDir(), "target", "product", String(prodVars.DeviceName)),
+ "soongOut": ctx.Config().soongOutDir,
+ "buildFingerprintFile": buildFingerprintFile.String(),
+ "productManufacturer": ctx.Config().ProductVariables().ProductManufacturer,
+ },
+ })
+
+ // Phony rule "soong-sbom". "m soong-sbom" to generate product SBOM in Soong.
+ ctx.Build(pctx, BuildParams{
+ Rule: blueprint.Phony,
+ Inputs: []Path{sbomFile},
+ Output: PathForPhony(ctx, "soong-sbom"),
+ })
+}
diff --git a/android/variable.go b/android/variable.go
index 3b02bc7..df0e59c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -239,8 +239,6 @@
VendorApiLevel *string `json:",omitempty"`
- RecoverySnapshotVersion *string `json:",omitempty"`
-
DeviceSecondaryArch *string `json:",omitempty"`
DeviceSecondaryArchVariant *string `json:",omitempty"`
DeviceSecondaryCpuVariant *string `json:",omitempty"`
@@ -296,6 +294,7 @@
HostStaticBinaries *bool `json:",omitempty"`
Binder32bit *bool `json:",omitempty"`
UseGoma *bool `json:",omitempty"`
+ UseABFS *bool `json:",omitempty"`
UseRBE *bool `json:",omitempty"`
UseRBEJAVAC *bool `json:",omitempty"`
UseRBER8 *bool `json:",omitempty"`
@@ -373,20 +372,6 @@
PgoAdditionalProfileDirs []string `json:",omitempty"`
- VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
-
- DirectedVendorSnapshot bool `json:",omitempty"`
- VendorSnapshotModules map[string]bool `json:",omitempty"`
-
- DirectedRecoverySnapshot bool `json:",omitempty"`
- RecoverySnapshotModules map[string]bool `json:",omitempty"`
-
- VendorSnapshotDirsIncluded []string `json:",omitempty"`
- VendorSnapshotDirsExcluded []string `json:",omitempty"`
- RecoverySnapshotDirsExcluded []string `json:",omitempty"`
- RecoverySnapshotDirsIncluded []string `json:",omitempty"`
- HostFakeSnapshotEnabled bool `json:",omitempty"`
-
MultitreeUpdateMeta bool `json:",omitempty"`
BoardVendorSepolicyDirs []string `json:",omitempty"`
@@ -520,6 +505,8 @@
BoardUseVbmetaDigestInFingerprint *bool `json:",omitempty"`
OemProperties []string `json:",omitempty"`
+
+ ArtTargetIncludeDebugBuild *bool `json:",omitempty"`
}
type PartitionQualifiedVariablesType struct {
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index db3313d..fb03c23 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -86,20 +86,19 @@
},
{
name: "Blank line in rule's command",
- in: `all:
+ in: `all:
echo first line
echo second line`,
out: []Node{
&Rule{
- Target: SimpleMakeString("all", NoPos),
- RecipePos: NoPos,
- Recipe: "echo first line\necho second line",
+ Target: SimpleMakeString("all", NoPos),
+ RecipePos: NoPos,
+ Recipe: "echo first line\necho second line",
Prerequisites: SimpleMakeString("", NoPos),
},
},
},
-
}
func TestParse(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index f9b30d4..fc0500a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -86,7 +86,7 @@
// AndroidManifest.xml file used for the zip container of this APEX bundle. If unspecified,
// a default one is automatically generated.
- AndroidManifest *string `android:"path"`
+ AndroidManifest proptools.Configurable[string] `android:"path,replace_instead_of_append"`
// Determines the file contexts file for setting the security contexts to files in this APEX
// bundle. For platform APEXes, this should points to a file under /system/sepolicy Default:
@@ -104,7 +104,7 @@
// path_or_glob is a path or glob pattern for a file or set of files,
// uid/gid are numerial values of user ID and group ID, mode is octal value
// for the file mode, and cap is hexadecimal value for the capability.
- Canned_fs_config *string `android:"path"`
+ Canned_fs_config proptools.Configurable[string] `android:"path,replace_instead_of_append"`
ApexNativeDependencies
@@ -117,7 +117,8 @@
Bootclasspath_fragments []string
// List of systemserverclasspath fragments that are embedded inside this APEX bundle.
- Systemserverclasspath_fragments []string
+ Systemserverclasspath_fragments proptools.Configurable[[]string]
+ ResolvedSystemserverclasspathFragments []string `blueprint:"mutated"`
// List of java libraries that are embedded inside this APEX bundle.
Java_libs []string
@@ -221,7 +222,8 @@
Rust_dyn_libs []string
// List of native executables that are embedded inside this APEX.
- Binaries []string
+ Binaries proptools.Configurable[[]string]
+ ResolvedBinaries []string `blueprint:"mutated"`
// List of native tests that are embedded inside this APEX.
Tests []string
@@ -230,7 +232,8 @@
Filesystems []string
// List of prebuilt_etcs that are embedded inside this APEX bundle.
- Prebuilts []string
+ Prebuilts proptools.Configurable[[]string]
+ ResolvedPrebuilts []string `blueprint:"mutated"`
// List of native libraries to exclude from this APEX.
Exclude_native_shared_libs []string
@@ -255,14 +258,14 @@
}
// Merge combines another ApexNativeDependencies into this one
-func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) {
+func (a *ApexNativeDependencies) Merge(ctx android.BaseMutatorContext, b ApexNativeDependencies) {
a.Native_shared_libs = append(a.Native_shared_libs, b.Native_shared_libs...)
a.Jni_libs = append(a.Jni_libs, b.Jni_libs...)
a.Rust_dyn_libs = append(a.Rust_dyn_libs, b.Rust_dyn_libs...)
- a.Binaries = append(a.Binaries, b.Binaries...)
+ a.ResolvedBinaries = append(a.ResolvedBinaries, b.Binaries.GetOrDefault(ctx, nil)...)
a.Tests = append(a.Tests, b.Tests...)
a.Filesystems = append(a.Filesystems, b.Filesystems...)
- a.Prebuilts = append(a.Prebuilts, b.Prebuilts...)
+ a.ResolvedPrebuilts = append(a.ResolvedPrebuilts, b.Prebuilts.GetOrDefault(ctx, nil)...)
a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
@@ -338,10 +341,10 @@
// base apex.
type overridableProperties struct {
// List of APKs that are embedded inside this APEX.
- Apps []string
+ Apps proptools.Configurable[[]string]
// List of prebuilt files that are embedded inside this APEX bundle.
- Prebuilts []string
+ Prebuilts proptools.Configurable[[]string]
// List of BPF programs inside this APEX bundle.
Bpfs []string
@@ -703,7 +706,6 @@
rustLibVariations := append(
target.Variations(), []blueprint.Variation{
{Mutator: "rust_libraries", Variation: "dylib"},
- {Mutator: "link", Variation: ""},
}...,
)
@@ -716,7 +718,7 @@
// this module. This is required since arch variant of an APEX bundle is 'common' but it is
// 'arm' or 'arm64' for native shared libs.
ctx.AddFarVariationDependencies(binVariations, executableTag,
- android.RemoveListFromList(nativeModules.Binaries, nativeModules.Exclude_binaries)...)
+ android.RemoveListFromList(nativeModules.ResolvedBinaries, nativeModules.Exclude_binaries)...)
ctx.AddFarVariationDependencies(binVariations, testTag,
android.RemoveListFromList(nativeModules.Tests, nativeModules.Exclude_tests)...)
ctx.AddFarVariationDependencies(libVariations, jniLibTag,
@@ -728,7 +730,7 @@
ctx.AddFarVariationDependencies(target.Variations(), fsTag,
android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag,
- android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...)
+ android.RemoveListFromList(nativeModules.ResolvedPrebuilts, nativeModules.Exclude_prebuilts)...)
}
func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -783,20 +785,19 @@
// Add native modules targeting both ABIs. When multilib.* is omitted for
// native_shared_libs/jni_libs/tests, it implies multilib.both
- deps.Merge(a.properties.Multilib.Both)
- deps.Merge(ApexNativeDependencies{
+ deps.Merge(ctx, a.properties.Multilib.Both)
+ deps.Merge(ctx, ApexNativeDependencies{
Native_shared_libs: a.properties.Native_shared_libs,
Tests: a.properties.Tests,
Jni_libs: a.properties.Jni_libs,
- Binaries: nil,
})
// Add native modules targeting the first ABI When multilib.* is omitted for
// binaries, it implies multilib.first
isPrimaryAbi := i == 0
if isPrimaryAbi {
- deps.Merge(a.properties.Multilib.First)
- deps.Merge(ApexNativeDependencies{
+ deps.Merge(ctx, a.properties.Multilib.First)
+ deps.Merge(ctx, ApexNativeDependencies{
Native_shared_libs: nil,
Tests: nil,
Jni_libs: nil,
@@ -807,27 +808,27 @@
// Add native modules targeting either 32-bit or 64-bit ABI
switch target.Arch.ArchType.Multilib {
case "lib32":
- deps.Merge(a.properties.Multilib.Lib32)
- deps.Merge(a.properties.Multilib.Prefer32)
+ deps.Merge(ctx, a.properties.Multilib.Lib32)
+ deps.Merge(ctx, a.properties.Multilib.Prefer32)
case "lib64":
- deps.Merge(a.properties.Multilib.Lib64)
+ deps.Merge(ctx, a.properties.Multilib.Lib64)
if !has32BitTarget {
- deps.Merge(a.properties.Multilib.Prefer32)
+ deps.Merge(ctx, a.properties.Multilib.Prefer32)
}
}
// Add native modules targeting a specific arch variant
switch target.Arch.ArchType {
case android.Arm:
- deps.Merge(a.archProperties.Arch.Arm.ApexNativeDependencies)
+ deps.Merge(ctx, a.archProperties.Arch.Arm.ApexNativeDependencies)
case android.Arm64:
- deps.Merge(a.archProperties.Arch.Arm64.ApexNativeDependencies)
+ deps.Merge(ctx, a.archProperties.Arch.Arm64.ApexNativeDependencies)
case android.Riscv64:
- deps.Merge(a.archProperties.Arch.Riscv64.ApexNativeDependencies)
+ deps.Merge(ctx, a.archProperties.Arch.Riscv64.ApexNativeDependencies)
case android.X86:
- deps.Merge(a.archProperties.Arch.X86.ApexNativeDependencies)
+ deps.Merge(ctx, a.archProperties.Arch.X86.ApexNativeDependencies)
case android.X86_64:
- deps.Merge(a.archProperties.Arch.X86_64.ApexNativeDependencies)
+ deps.Merge(ctx, a.archProperties.Arch.X86_64.ApexNativeDependencies)
default:
panic(fmt.Errorf("unsupported arch %v\n", ctx.Arch().ArchType))
}
@@ -841,11 +842,13 @@
}
}
+ a.properties.ResolvedSystemserverclasspathFragments = a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)
+
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, rroTag, a.properties.Rros...)
ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
- ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
+ ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.ResolvedSystemserverclasspathFragments...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...)
@@ -858,9 +861,9 @@
}
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
- ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps...)
+ ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps.GetOrDefault(ctx, nil)...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs...)
- if prebuilts := a.overridableProperties.Prebuilts; len(prebuilts) > 0 {
+ if prebuilts := a.overridableProperties.Prebuilts.GetOrDefault(ctx, nil); len(prebuilts) > 0 {
// For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
// regardless of the TARGET_PREFER_* setting. See b/144532908
arches := ctx.DeviceConfig().Arches()
@@ -1493,7 +1496,6 @@
Native_shared_libs: []string{"libclang_rt.hwasan"},
Tests: nil,
Jni_libs: nil,
- Binaries: nil,
}, target, imageVariation)
break
}
@@ -2663,18 +2665,13 @@
})
}
-// TODO (b/221087384): Remove this allowlist
-var (
- updatableApexesWithCurrentMinSdkVersionAllowlist = []string{"com.android.profiling"}
-)
-
// checkUpdatable enforces APEX and its transitive dep properties to have desired values for updatable APEXes.
func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
if a.Updatable() {
if a.minSdkVersionValue(ctx) == "" {
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
}
- if a.minSdkVersion(ctx).IsCurrent() && !android.InList(ctx.ModuleName(), updatableApexesWithCurrentMinSdkVersionAllowlist) {
+ if a.minSdkVersion(ctx).IsCurrent() {
ctx.PropertyErrorf("updatable", "updatable APEXes should not set min_sdk_version to current. Please use a finalized API level or a recognized in-development codename")
}
if a.UsePlatformApis() {
@@ -2812,7 +2809,7 @@
func (a *apexBundle) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
- dpInfo.Deps = append(dpInfo.Deps, a.properties.Systemserverclasspath_fragments...)
+ dpInfo.Deps = append(dpInfo.Deps, a.properties.ResolvedSystemserverclasspathFragments...)
}
var (
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a2dbbfc..261d2ce 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5244,7 +5244,7 @@
myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
overrideNames := []string{
- "myapex",
+ "",
"myjavalib.myapex",
"libfoo.myapex",
"libbar.myapex",
@@ -11294,13 +11294,6 @@
// Test that product packaging installs the selected mainline module (either source or a specific prebuilt)
// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
- // check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES
- // Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either
- checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) {
- // Variations are created based on apex_name
- entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module())
- android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0])
- }
// for a mainline module family, check that only the flagged soong module is visible to make
checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) {
variation := func(moduleName string) string {
@@ -11355,7 +11348,7 @@
prebuilt_apex {
name: "com.google.android.foo.v2",
apex_name: "com.android.foo",
- source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file
+ source_apex_name: "com.google.android.foo",
src: "com.android.foo-arm.apex",
prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
}
@@ -11441,11 +11434,6 @@
}
ctx := testApex(t, bp, preparer)
- // Check that the LOCAL_MODULE of the two prebuilts is com.android.foo
- // This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions
- checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo")
- checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo")
-
// Check that
// 1. The contents of the selected apex_contributions are visible to make
// 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make
@@ -11738,3 +11726,121 @@
}
`)
}
+
+func TestPrebuiltStubNoinstall(t *testing.T) {
+ testFunc := func(t *testing.T, expectLibfooOnSystemLib bool, fs android.MockFS) {
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ android.PrepareForTestWithAndroidMk,
+ android.PrepareForTestWithMakevars,
+ android.FixtureMergeMockFs(fs),
+ ).RunTest(t)
+
+ ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld")
+ android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared/libfoo.so")
+
+ installRules := result.InstallMakeRulesForTesting(t)
+
+ var installedlibRule *android.InstallMakeRule
+ for i, rule := range installRules {
+ if rule.Target == "out/target/product/test_device/system/lib/installedlib.so" {
+ if installedlibRule != nil {
+ t.Errorf("Duplicate install rules for %s", rule.Target)
+ }
+ installedlibRule = &installRules[i]
+ }
+ }
+ if installedlibRule == nil {
+ t.Errorf("No install rule found for installedlib")
+ return
+ }
+
+ if expectLibfooOnSystemLib {
+ android.AssertStringListContains(t,
+ "installedlib doesn't have install dependency on libfoo impl",
+ installedlibRule.OrderOnlyDeps,
+ "out/target/product/test_device/system/lib/libfoo.so")
+ } else {
+ android.AssertStringListDoesNotContain(t,
+ "installedlib has install dependency on libfoo stub",
+ installedlibRule.Deps,
+ "out/target/product/test_device/system/lib/libfoo.so")
+ android.AssertStringListDoesNotContain(t,
+ "installedlib has order-only install dependency on libfoo stub",
+ installedlibRule.OrderOnlyDeps,
+ "out/target/product/test_device/system/lib/libfoo.so")
+ }
+ }
+
+ prebuiltLibfooBp := []byte(`
+ cc_prebuilt_library {
+ name: "libfoo",
+ prefer: true,
+ srcs: ["libfoo.so"],
+ stubs: {
+ versions: ["1"],
+ },
+ apex_available: ["apexfoo"],
+ }
+ `)
+
+ apexfooBp := []byte(`
+ apex {
+ name: "apexfoo",
+ key: "apexfoo.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ compile_multilib: "both",
+ }
+ apex_key {
+ name: "apexfoo.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ installedlibBp := []byte(`
+ cc_library {
+ name: "installedlib",
+ shared_libs: ["libfoo"],
+ }
+ `)
+
+ t.Run("prebuilt stub (without source): no install", func(t *testing.T) {
+ testFunc(
+ t,
+ /*expectLibfooOnSystemLib=*/ false,
+ android.MockFS{
+ "prebuilts/module_sdk/art/current/Android.bp": prebuiltLibfooBp,
+ "apexfoo/Android.bp": apexfooBp,
+ "system/sepolicy/apex/apexfoo-file_contexts": nil,
+ "Android.bp": installedlibBp,
+ },
+ )
+ })
+
+ disabledSourceLibfooBp := []byte(`
+ cc_library {
+ name: "libfoo",
+ enabled: false,
+ stubs: {
+ versions: ["1"],
+ },
+ apex_available: ["apexfoo"],
+ }
+ `)
+
+ t.Run("prebuilt stub (with disabled source): no install", func(t *testing.T) {
+ testFunc(
+ t,
+ /*expectLibfooOnSystemLib=*/ false,
+ android.MockFS{
+ "prebuilts/module_sdk/art/current/Android.bp": prebuiltLibfooBp,
+ "impl/Android.bp": disabledSourceLibfooBp,
+ "apexfoo/Android.bp": apexfooBp,
+ "system/sepolicy/apex/apexfoo-file_contexts": nil,
+ "Android.bp": installedlibBp,
+ },
+ )
+ })
+}
diff --git a/apex/builder.go b/apex/builder.go
index 763ce4d..bfe1692 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -704,8 +704,9 @@
optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
}
- if a.properties.AndroidManifest != nil {
- androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+ androidManifest := a.properties.AndroidManifest.GetOrDefault(ctx, "")
+ if androidManifest != "" {
+ androidManifestFile := android.PathForModuleSrc(ctx, androidManifest)
if a.testApex {
androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
@@ -1195,8 +1196,9 @@
}
// Custom fs_config is "appended" to the last so that entries from the file are preferred
// over default ones set above.
- if a.properties.Canned_fs_config != nil {
- cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config))
+ customFsConfig := a.properties.Canned_fs_config.GetOrDefault(ctx, "")
+ if customFsConfig != "" {
+ cmd.Text("cat").Input(android.PathForModuleSrc(ctx, customFsConfig))
}
cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 65c23d3..b9cc09b 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -246,7 +246,6 @@
OutputFile: android.OptionalPathForPath(p.outputApex),
Include: "$(BUILD_PREBUILT)",
Host_required: p.hostRequired,
- OverrideName: p.BaseModuleName(),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
diff --git a/bin/afind b/bin/afind
index 080f06a..f5b8319 100755
--- a/bin/afind
+++ b/bin/afind
@@ -14,6 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# prevent glob expansion in this script
+set -f
+
dir=${1:-.}
shift
diff --git a/bin/dirmods b/bin/dirmods
index 52d935a..a6d4de3 100755
--- a/bin/dirmods
+++ b/bin/dirmods
@@ -35,6 +35,14 @@
args = parser.parse_args()
d = os.path.normpath(args.path)
+ # Fix absolute path to be relative to build top
+ if os.path.isabs(d):
+ base = os.environ.get('ANDROID_BUILD_TOP')
+ if base:
+ base = os.path.normpath(base) + os.path.sep
+ if d.startswith(base):
+ d = d[len(base):]
+
prefix = d + '/'
module_info = modinfo.ReadModuleInfo()
diff --git a/bin/installmod b/bin/installmod
index 1d0d836..1ad5b84 100755
--- a/bin/installmod
+++ b/bin/installmod
@@ -28,7 +28,6 @@
return 1
fi
-local _path
_path=$(outmod ${@:$#:1})
if [ $? -ne 0 ]; then
return 1
@@ -39,7 +38,7 @@
echo "Module '$1' does not produce a file ending with .apk (try 'refreshmod' if there have been build changes?)" >&2
return 1
fi
-local serial_device=""
+serial_device=""
if [[ "$1" == "-s" ]]; then
if [[ $# -le 2 ]]; then
echo "-s requires an argument" >&2
@@ -48,7 +47,7 @@
serial_device="-s $2"
shift 2
fi
-local length=$(( $# - 1 ))
+length=$(( $# - 1 ))
echo adb $serial_device install ${@:1:$length} $_path
adb $serial_device install ${@:1:$length} $_path
diff --git a/cc/Android.bp b/cc/Android.bp
index 3bbcaa9..e68e4a3 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -73,7 +73,6 @@
"ndk_abi.go",
"ndk_headers.go",
"ndk_library.go",
- "ndk_prebuilt.go",
"ndk_sysroot.go",
"llndk_library.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 4134653..cecaae2 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -451,10 +451,6 @@
})
}
-func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
- entries.Class = "SHARED_LIBRARIES"
-}
-
func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
if p.properties.Check_elf_files != nil {
diff --git a/cc/cc.go b/cc/cc.go
index d307be6..3c276d2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -48,10 +48,10 @@
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("sdk", sdkMutator).Parallel()
+ ctx.Transition("sdk", &sdkTransitionMutator{})
ctx.BottomUp("llndk", llndkMutator).Parallel()
- ctx.BottomUp("link", LinkageMutator).Parallel()
- ctx.BottomUp("version", versionMutator).Parallel()
+ ctx.Transition("link", &linkageTransitionMutator{})
+ ctx.Transition("version", &versionTransitionMutator{})
ctx.BottomUp("begin", BeginMutator).Parallel()
})
@@ -1028,13 +1028,6 @@
return ""
}
-func (c *Module) NdkPrebuiltStl() bool {
- if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
- return true
- }
- return false
-}
-
func (c *Module) StubDecorator() bool {
if _, ok := c.linker.(*stubDecorator); ok {
return true
@@ -1088,16 +1081,6 @@
return false
}
-func (c *Module) IsNdkPrebuiltStl() bool {
- if c.linker == nil {
- return false
- }
- if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
- return true
- }
- return false
-}
-
func (c *Module) RlibStd() bool {
panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName()))
}
@@ -2754,10 +2737,6 @@
return
}
if c, ok := to.(*Module); ok {
- if c.NdkPrebuiltStl() {
- // These are allowed, but they don't set sdk_version
- return
- }
if c.StubDecorator() {
// These aren't real libraries, but are the stub shared libraries that are included in
// the NDK.
@@ -3927,7 +3906,6 @@
headerLibrary
testBin // testBinary already declared
ndkLibrary
- ndkPrebuiltStl
)
func (c *Module) typ() moduleType {
@@ -3966,8 +3944,6 @@
return sharedLibrary
} else if c.isNDKStubLibrary() {
return ndkLibrary
- } else if c.IsNdkPrebuiltStl() {
- return ndkPrebuiltStl
}
return unknownType
}
@@ -4079,6 +4055,13 @@
return c.ModuleBase.BaseModuleName()
}
+func (c *Module) stubsSymbolFilePath() android.Path {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return library.stubsSymbolFilePath
+ }
+ return android.OptionalPath{}.Path()
+}
+
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var BoolPtr = proptools.BoolPtr
diff --git a/cc/cc_test.go b/cc/cc_test.go
index ccdaae5..b1c0945 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2760,7 +2760,7 @@
"external/foo/libarm",
"external/foo/lib32",
"external/foo/libandroid_arm",
- "defaults/cc/common/ndk_libc++_shared",
+ "defaults/cc/common/ndk_libc++_shared_include_dirs",
}
conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index d30abba..469fe31 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -85,9 +85,8 @@
moduleDeps := ccDeps{}
moduleInfos := map[string]ccIdeInfo{}
- // Track which projects have already had CMakeLists.txt generated to keep the first
- // variant for each project.
- seenProjects := map[string]bool{}
+ // Track if best variant (device arch match) has been found.
+ bestVariantFound := map[string]bool{}
pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang)
@@ -96,7 +95,7 @@
ctx.VisitAllModules(func(module android.Module) {
if ccModule, ok := module.(*Module); ok {
if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
- generateCLionProjectData(ctx, compiledModule, ccModule, seenProjects, moduleInfos)
+ generateCLionProjectData(ctx, compiledModule, ccModule, bestVariantFound, moduleInfos)
}
}
})
@@ -180,26 +179,30 @@
}
func generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface,
- ccModule *Module, seenProjects map[string]bool, moduleInfos map[string]ccIdeInfo) {
+ ccModule *Module, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) {
+ moduleName := ccModule.ModuleBase.Name()
srcs := compiledModule.Srcs()
+
+ // Skip if best variant has already been found.
+ if bestVariantFound[moduleName] {
+ return
+ }
+
+ // Skip if sources are empty.
if len(srcs) == 0 {
return
}
- // Only keep the DeviceArch variant module.
- if ctx.DeviceConfig().DeviceArch() != ccModule.ModuleBase.Arch().ArchType.Name {
+ // Check if device arch matches, in which case this is the best variant and takes precedence.
+ if ccModule.Device() && ccModule.ModuleBase.Arch().ArchType.Name == ctx.DeviceConfig().DeviceArch() {
+ bestVariantFound[moduleName] = true
+ } else if _, ok := moduleInfos[moduleName]; ok {
+ // Skip because this isn't the best variant and a previous one has already been added.
+ // Heuristically, ones that appear first are likely to be more relevant.
return
}
- clionProjectLocation := getCMakeListsForModule(ccModule, ctx)
- if seenProjects[clionProjectLocation] {
- return
- }
-
- seenProjects[clionProjectLocation] = true
-
- name := ccModule.ModuleBase.Name()
- dpInfo := moduleInfos[name]
+ dpInfo := ccIdeInfo{}
dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule)))
dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...)
@@ -216,9 +219,9 @@
dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags)
dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags)
- dpInfo.Module_name = name
+ dpInfo.Module_name = moduleName
- moduleInfos[name] = dpInfo
+ moduleInfos[moduleName] = dpInfo
}
type Deal struct {
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index fb2924a..8f3ad96 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -347,8 +347,11 @@
if slices.Contains(ignoredSystemLibs, moduleName) {
return false // system libs built in-tree for Android
}
+ if dep.IsPrebuilt() {
+ return false // prebuilts are not supported
+ }
if dep.compiler == nil {
- return false // unsupported module type (e.g. prebuilt)
+ return false // unsupported module type
}
isAidlModule := dep.compiler.baseCompilerProps().AidlInterface.Lang != ""
diff --git a/cc/compiler.go b/cc/compiler.go
index 03f9899..ed10533 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -53,7 +53,7 @@
Cflags proptools.Configurable[[]string] `android:"arch_variant"`
// list of module-specific flags that will be used for C++ compiles
- Cppflags []string `android:"arch_variant"`
+ Cppflags proptools.Configurable[[]string] `android:"arch_variant"`
// list of module-specific flags that will be used for C compiles
Conlyflags []string `android:"arch_variant"`
@@ -367,8 +367,9 @@
compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
cflags := compiler.Properties.Cflags.GetOrDefault(ctx, nil)
+ cppflags := compiler.Properties.Cppflags.GetOrDefault(ctx, nil)
CheckBadCompilerFlags(ctx, "cflags", cflags)
- CheckBadCompilerFlags(ctx, "cppflags", compiler.Properties.Cppflags)
+ CheckBadCompilerFlags(ctx, "cppflags", cppflags)
CheckBadCompilerFlags(ctx, "conlyflags", compiler.Properties.Conlyflags)
CheckBadCompilerFlags(ctx, "asflags", compiler.Properties.Asflags)
CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
@@ -381,7 +382,7 @@
esc := proptools.NinjaAndShellEscapeList
flags.Local.CFlags = append(flags.Local.CFlags, esc(cflags)...)
- flags.Local.CppFlags = append(flags.Local.CppFlags, esc(compiler.Properties.Cppflags)...)
+ flags.Local.CppFlags = append(flags.Local.CppFlags, esc(cppflags)...)
flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Asflags)...)
flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
@@ -808,7 +809,7 @@
// list of c++ specific clang flags required to correctly interpret the headers.
// This is provided primarily to make sure cppflags defined in cc_defaults are pulled in.
- Cppflags []string `android:"arch_variant"`
+ Cppflags proptools.Configurable[[]string] `android:"arch_variant"`
// C standard version to use. Can be a specific version (such as "gnu11"),
// "experimental" (which will use draft versions like C1x when available),
diff --git a/cc/library.go b/cc/library.go
index 560b1ae..092b177 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -19,6 +19,7 @@
"io"
"path/filepath"
"regexp"
+ "slices"
"strconv"
"strings"
"sync"
@@ -63,7 +64,7 @@
Stubs struct {
// Relative path to the symbol map. The symbol map provides the list of
// symbols that are exported for stubs variant of this library.
- Symbol_file *string `android:"path"`
+ Symbol_file *string `android:"path,arch_variant"`
// List versions to generate stubs libs for. The version name "current" is always
// implicitly added.
@@ -74,7 +75,7 @@
// implementation is made available by some other means, e.g. in a Microdroid
// virtual machine.
Implementation_installable *bool
- }
+ } `android:"arch_variant"`
// set the name of the output
Stem *string `android:"arch_variant"`
@@ -117,7 +118,7 @@
// If this is an LLNDK library, properties to describe the LLNDK stubs. Will be copied from
// the module pointed to by llndk_stubs if it is set.
- Llndk llndkLibraryProperties
+ Llndk llndkLibraryProperties `android:"arch_variant"`
// If this is a vendor public library, properties to describe the vendor public library stubs.
Vendor_public_library vendorPublicLibraryProperties
@@ -427,6 +428,9 @@
*baseInstaller
apiListCoverageXmlPath android.ModuleOutPath
+
+ // Path to the file containing the APIs exported by this library
+ stubsSymbolFilePath android.Path
}
// linkerProps returns the list of properties structs relevant for this library. (For example, if
@@ -595,6 +599,7 @@
ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
return Objects{}
}
+ library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
// systemapi, respectively. The former is for symbols defined in platform libraries
// and the latter is for symbols defined in APEXes.
@@ -711,7 +716,7 @@
setStubsVersion(string)
stubsVersion() string
- stubsVersions(ctx android.BaseMutatorContext) []string
+ stubsVersions(ctx android.BaseModuleContext) []string
setAllStubsVersions([]string)
allStubsVersions() []string
@@ -1903,7 +1908,7 @@
return BoolDefault(library.Properties.Stubs.Implementation_installable, true)
}
-func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+func (library *libraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
if !library.hasStubsVariants() {
return nil
}
@@ -2064,26 +2069,26 @@
// connects a shared library to a static library in order to reuse its .o files to avoid
// compiling source files twice.
-func reuseStaticLibrary(mctx android.BottomUpMutatorContext, static, shared *Module) {
- if staticCompiler, ok := static.compiler.(*libraryDecorator); ok {
- sharedCompiler := shared.compiler.(*libraryDecorator)
+func reuseStaticLibrary(ctx android.BottomUpMutatorContext, shared *Module) {
+ if sharedCompiler, ok := shared.compiler.(*libraryDecorator); ok {
// Check libraries in addition to cflags, since libraries may be exporting different
// include directories.
- if len(staticCompiler.StaticProperties.Static.Cflags.GetOrDefault(mctx, nil)) == 0 &&
- len(sharedCompiler.SharedProperties.Shared.Cflags.GetOrDefault(mctx, nil)) == 0 &&
- len(staticCompiler.StaticProperties.Static.Whole_static_libs) == 0 &&
+ if len(sharedCompiler.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)) == 0 &&
+ len(sharedCompiler.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)) == 0 &&
+ len(sharedCompiler.StaticProperties.Static.Whole_static_libs) == 0 &&
len(sharedCompiler.SharedProperties.Shared.Whole_static_libs) == 0 &&
- len(staticCompiler.StaticProperties.Static.Static_libs) == 0 &&
+ len(sharedCompiler.StaticProperties.Static.Static_libs) == 0 &&
len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 &&
- len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 &&
+ len(sharedCompiler.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.StaticProperties.Static.System_shared_libs == nil &&
sharedCompiler.SharedProperties.Shared.System_shared_libs == nil {
- mctx.AddInterVariantDependency(reuseObjTag, shared, static)
+ // TODO: namespaces?
+ ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, reuseObjTag, ctx.ModuleName())
sharedCompiler.baseCompiler.Properties.OriginalSrcs =
sharedCompiler.baseCompiler.Properties.Srcs
sharedCompiler.baseCompiler.Properties.Srcs = nil
@@ -2091,19 +2096,21 @@
}
// This dep is just to reference static variant from shared variant
- mctx.AddInterVariantDependency(staticVariantTag, shared, static)
+ ctx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, staticVariantTag, ctx.ModuleName())
}
}
-// LinkageMutator adds "static" or "shared" variants for modules depending
+// linkageTransitionMutator adds "static" or "shared" variants for modules depending
// on whether the module can be built as a static library or a shared library.
-func LinkageMutator(mctx android.BottomUpMutatorContext) {
+type linkageTransitionMutator struct{}
+
+func (linkageTransitionMutator) Split(ctx android.BaseModuleContext) []string {
ccPrebuilt := false
- if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
+ if m, ok := ctx.Module().(*Module); ok && m.linker != nil {
_, ccPrebuilt = m.linker.(prebuiltLibraryInterface)
}
if ccPrebuilt {
- library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
+ library := ctx.Module().(*Module).linker.(prebuiltLibraryInterface)
// Differentiate between header only and building an actual static/shared library
buildStatic := library.buildStatic()
@@ -2112,75 +2119,118 @@
// Always create both the static and shared variants for prebuilt libraries, and then disable the one
// that is not being used. This allows them to share the name of a cc_library module, which requires that
// all the variants of the cc_library also exist on the prebuilt.
- modules := mctx.CreateLocalVariations("static", "shared")
- static := modules[0].(*Module)
- shared := modules[1].(*Module)
-
- static.linker.(prebuiltLibraryInterface).setStatic()
- shared.linker.(prebuiltLibraryInterface).setShared()
-
- if buildShared {
- mctx.AliasVariation("shared")
- } else if buildStatic {
- mctx.AliasVariation("static")
- }
-
- if !buildStatic {
- static.linker.(prebuiltLibraryInterface).disablePrebuilt()
- }
- if !buildShared {
- shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
- }
+ return []string{"static", "shared"}
} else {
// Header only
}
-
- } else if library, ok := mctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
+ } else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
// Non-cc.Modules may need an empty variant for their mutators.
variations := []string{}
if library.NonCcVariants() {
variations = append(variations, "")
}
isLLNDK := false
- if m, ok := mctx.Module().(*Module); ok {
+ if m, ok := ctx.Module().(*Module); ok {
isLLNDK = m.IsLlndk()
}
buildStatic := library.BuildStaticVariant() && !isLLNDK
buildShared := library.BuildSharedVariant()
if buildStatic && buildShared {
- variations := append([]string{"static", "shared"}, variations...)
-
- modules := mctx.CreateLocalVariations(variations...)
- static := modules[0].(LinkableInterface)
- shared := modules[1].(LinkableInterface)
- static.SetStatic()
- shared.SetShared()
-
- if _, ok := library.(*Module); ok {
- reuseStaticLibrary(mctx, static.(*Module), shared.(*Module))
- }
- mctx.AliasVariation("shared")
+ variations = append([]string{"static", "shared"}, variations...)
+ return variations
} else if buildStatic {
- variations := append([]string{"static"}, variations...)
-
- modules := mctx.CreateLocalVariations(variations...)
- modules[0].(LinkableInterface).SetStatic()
- mctx.AliasVariation("static")
+ variations = append([]string{"static"}, variations...)
} else if buildShared {
- variations := append([]string{"shared"}, variations...)
-
- modules := mctx.CreateLocalVariations(variations...)
- modules[0].(LinkableInterface).SetShared()
- mctx.AliasVariation("shared")
- } else if len(variations) > 0 {
- mctx.CreateLocalVariations(variations...)
- mctx.AliasVariation(variations[0])
+ variations = append([]string{"shared"}, variations...)
}
- if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic {
+
+ if len(variations) > 0 {
+ return variations
+ }
+ }
+ return []string{""}
+}
+
+func (linkageTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+}
+
+func (linkageTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ ccPrebuilt := false
+ if m, ok := ctx.Module().(*Module); ok && m.linker != nil {
+ _, ccPrebuilt = m.linker.(prebuiltLibraryInterface)
+ }
+ if ccPrebuilt {
+ if incomingVariation != "" {
+ return incomingVariation
+ }
+ library := ctx.Module().(*Module).linker.(prebuiltLibraryInterface)
+ if library.buildShared() {
+ return "shared"
+ } else if library.buildStatic() {
+ return "static"
+ }
+ return ""
+ } else if library, ok := ctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
+ isLLNDK := false
+ if m, ok := ctx.Module().(*Module); ok {
+ isLLNDK = m.IsLlndk()
+ }
+ buildStatic := library.BuildStaticVariant() && !isLLNDK
+ buildShared := library.BuildSharedVariant()
+ if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") {
// Rust modules do not build static libs, but rlibs are used as if they
// were via `static_libs`. Thus we need to alias the BuildRlibVariant
// to "static" for Rust FFI libraries.
- mctx.CreateAliasVariation("static", "")
+ return ""
+ }
+ if incomingVariation != "" {
+ return incomingVariation
+ }
+ if buildShared {
+ return "shared"
+ } else if buildStatic {
+ return "static"
+ }
+ return ""
+ }
+ return ""
+}
+
+func (linkageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ ccPrebuilt := false
+ if m, ok := ctx.Module().(*Module); ok && m.linker != nil {
+ _, ccPrebuilt = m.linker.(prebuiltLibraryInterface)
+ }
+ if ccPrebuilt {
+ library := ctx.Module().(*Module).linker.(prebuiltLibraryInterface)
+ if variation == "static" {
+ library.setStatic()
+ if !library.buildStatic() {
+ library.disablePrebuilt()
+ }
+ } else if variation == "shared" {
+ library.setShared()
+ if !library.buildShared() {
+ library.disablePrebuilt()
+ }
+ }
+ } else if library, ok := ctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
+ if variation == "static" {
+ library.SetStatic()
+ } else if variation == "shared" {
+ library.SetShared()
+ var isLLNDK bool
+ if m, ok := ctx.Module().(*Module); ok {
+ isLLNDK = m.IsLlndk()
+ }
+ buildStatic := library.BuildStaticVariant() && !isLLNDK
+ buildShared := library.BuildSharedVariant()
+ if buildStatic && buildShared {
+ if _, ok := library.(*Module); ok {
+ reuseStaticLibrary(ctx, library.(*Module))
+ }
+ }
}
}
}
@@ -2204,64 +2254,14 @@
}
}
-func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
- // "" is for the non-stubs (implementation) variant for system modules, or the LLNDK variant
- // for LLNDK modules.
- variants := append(android.CopyOf(versions), "")
-
- m := mctx.Module().(*Module)
- isLLNDK := m.IsLlndk()
- isVendorPublicLibrary := m.IsVendorPublicLibrary()
- isImportedApiLibrary := m.isImportedApiLibrary()
-
- modules := mctx.CreateLocalVariations(variants...)
- for i, m := range modules {
-
- if variants[i] != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
- // A stubs or LLNDK stubs variant.
- c := m.(*Module)
- if c.sanitize != nil {
- c.sanitize.Properties.ForceDisable = true
- }
- if c.stl != nil {
- c.stl.Properties.Stl = StringPtr("none")
- }
- c.Properties.PreventInstall = true
- lib := moduleLibraryInterface(m)
- isLatest := i == (len(versions) - 1)
- lib.setBuildStubs(isLatest)
-
- if variants[i] != "" {
- // A non-LLNDK stubs module is hidden from make and has a dependency from the
- // implementation module to the stubs module.
- c.Properties.HideFromMake = true
- lib.setStubsVersion(variants[i])
- mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
- }
- }
- }
- mctx.AliasVariation("")
- latestVersion := ""
- if len(versions) > 0 {
- latestVersion = versions[len(versions)-1]
- }
- mctx.CreateAliasVariation("latest", latestVersion)
-}
-
-func createPerApiVersionVariations(mctx android.BottomUpMutatorContext, minSdkVersion string) {
+func perApiVersionVariations(mctx android.BaseModuleContext, minSdkVersion string) []string {
from, err := nativeApiLevelFromUser(mctx, minSdkVersion)
if err != nil {
mctx.PropertyErrorf("min_sdk_version", err.Error())
- return
+ return []string{""}
}
- versionStrs := ndkLibraryVersions(mctx, from)
- modules := mctx.CreateLocalVariations(versionStrs...)
-
- for i, module := range modules {
- module.(*Module).Properties.Sdk_version = StringPtr(versionStrs[i])
- module.(*Module).Properties.Min_sdk_version = StringPtr(versionStrs[i])
- }
+ return ndkLibraryVersions(mctx, from)
}
func canBeOrLinkAgainstVersionVariants(module interface {
@@ -2291,7 +2291,7 @@
}
// setStubsVersions normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
-func setStubsVersions(mctx android.BottomUpMutatorContext, library libraryInterface, module *Module) {
+func setStubsVersions(mctx android.BaseModuleContext, library libraryInterface, module *Module) {
if !library.buildShared() || !canBeVersionVariant(module) {
return
}
@@ -2304,25 +2304,98 @@
library.setAllStubsVersions(versions)
}
-// versionMutator splits a module into the mandatory non-stubs variant
+// versionTransitionMutator splits a module into the mandatory non-stubs variant
// (which is unnamed) and zero or more stubs variants.
-func versionMutator(mctx android.BottomUpMutatorContext) {
- if mctx.Os() != android.Android {
- return
+type versionTransitionMutator struct{}
+
+func (versionTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ if ctx.Os() != android.Android {
+ return []string{""}
}
- m, ok := mctx.Module().(*Module)
- if library := moduleLibraryInterface(mctx.Module()); library != nil && canBeVersionVariant(m) {
- setStubsVersions(mctx, library, m)
+ m, ok := ctx.Module().(*Module)
+ if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+ setStubsVersions(ctx, library, m)
- createVersionVariations(mctx, library.allStubsVersions())
- return
+ return append(slices.Clone(library.allStubsVersions()), "")
+ } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
+ return perApiVersionVariations(ctx, m.MinSdkVersion())
}
- if ok {
- if m.SplitPerApiLevel() && m.IsSdkVariant() {
- createPerApiVersionVariations(mctx, m.MinSdkVersion())
+ return []string{""}
+}
+
+func (versionTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+}
+
+func (versionTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if ctx.Os() != android.Android {
+ return ""
+ }
+ m, ok := ctx.Module().(*Module)
+ if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+ if incomingVariation == "latest" {
+ latestVersion := ""
+ versions := library.allStubsVersions()
+ if len(versions) > 0 {
+ latestVersion = versions[len(versions)-1]
+ }
+ return latestVersion
}
+ return incomingVariation
+ } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
+ // If this module only has variants with versions and the incoming dependency doesn't specify which one
+ // is needed then assume the latest version.
+ if incomingVariation == "" {
+ return android.FutureApiLevel.String()
+ }
+ return incomingVariation
+ }
+
+ return ""
+}
+
+func (versionTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ // Optimization: return early if this module can't be affected.
+ if ctx.Os() != android.Android {
+ return
+ }
+
+ m, ok := ctx.Module().(*Module)
+ if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) {
+ isLLNDK := m.IsLlndk()
+ isVendorPublicLibrary := m.IsVendorPublicLibrary()
+ isImportedApiLibrary := m.isImportedApiLibrary()
+
+ if variation != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary {
+ // A stubs or LLNDK stubs variant.
+ if m.sanitize != nil {
+ m.sanitize.Properties.ForceDisable = true
+ }
+ if m.stl != nil {
+ m.stl.Properties.Stl = StringPtr("none")
+ }
+ m.Properties.PreventInstall = true
+ lib := moduleLibraryInterface(m)
+ allStubsVersions := library.allStubsVersions()
+ isLatest := len(allStubsVersions) > 0 && variation == allStubsVersions[len(allStubsVersions)-1]
+ lib.setBuildStubs(isLatest)
+ }
+ if variation != "" {
+ // A non-LLNDK stubs module is hidden from make
+ library.setStubsVersion(variation)
+ m.Properties.HideFromMake = true
+ } else {
+ // A non-LLNDK implementation module has a dependency to all stubs versions
+ for _, version := range library.allStubsVersions() {
+ ctx.AddVariationDependencies([]blueprint.Variation{{"version", version}},
+ stubImplDepTag, ctx.ModuleName())
+ }
+ }
+ } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() {
+ m.Properties.Sdk_version = StringPtr(variation)
+ m.Properties.Min_sdk_version = StringPtr(variation)
}
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 1f71c19..e8a9827 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -406,6 +406,9 @@
if len(libInfo.StubsVersions) > 0 {
stubsSet := outputProperties.AddPropertySet("stubs")
stubsSet.AddProperty("versions", libInfo.StubsVersions)
+ // The symbol file will be copied next to the Android.bp file
+ stubsSet.AddProperty("symbol_file", libInfo.StubsSymbolFilePath.Base())
+ builder.CopyToSnapshot(libInfo.StubsSymbolFilePath, libInfo.StubsSymbolFilePath.Base())
}
}
@@ -481,6 +484,9 @@
// is written to does not vary by arch so cannot be android specific.
StubsVersions []string `sdk:"ignored-on-host"`
+ // The symbol file containing the APIs exported by this library.
+ StubsSymbolFilePath android.Path `sdk:"ignored-on-host"`
+
// Value of SanitizeProperties.Sanitize. Several - but not all - of these
// affect the expanded variants. All are propagated to avoid entangling the
// sanitizer logic with the snapshot generation.
@@ -549,6 +555,11 @@
// the versioned stub libs are retained in the prebuilt tree; currently only
// the stub corresponding to ccModule.StubsVersion() is.
p.StubsVersions = lib.allStubsVersions()
+ if lib.buildStubs() && ccModule.stubsSymbolFilePath() == nil {
+ ctx.ModuleErrorf("Could not determine symbol_file")
+ } else {
+ p.StubsSymbolFilePath = ccModule.stubsSymbolFilePath()
+ }
}
}
p.SystemSharedLibs = specifiedDeps.systemSharedLibs
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 6f06333..6367825 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -303,7 +303,7 @@
return d.hasApexStubs()
}
-func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
m, ok := ctx.Module().(*Module)
if !ok {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 85c3edf..5ece78a 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -30,7 +30,7 @@
type llndkLibraryProperties struct {
// Relative path to the symbol map.
// An example file can be seen here: TODO(danalbert): Make an example.
- Symbol_file *string
+ Symbol_file *string `android:"path,arch_variant"`
// Whether to export any headers as -isystem instead of -I. Mainly for use by
// bionic/libc.
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f326068..b822e5c 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -133,7 +133,7 @@
return strings.TrimSuffix(name, ndkLibrarySuffix)
}
-func ndkLibraryVersions(ctx android.BaseMutatorContext, from android.ApiLevel) []string {
+func ndkLibraryVersions(ctx android.BaseModuleContext, from android.ApiLevel) []string {
var versions []android.ApiLevel
versionStrs := []string{}
for _, version := range ctx.Config().AllSupportedApiLevels() {
@@ -147,7 +147,7 @@
return versionStrs
}
-func (this *stubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
+func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string {
if !ctx.Module().Enabled(ctx) {
return nil
}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
deleted file mode 100644
index f503982..0000000
--- a/cc/ndk_prebuilt.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2016 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 (
- "strings"
-
- "android/soong/android"
-)
-
-func init() {
- android.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory)
- android.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
-}
-
-// NDK prebuilt libraries.
-//
-// These differ from regular prebuilts in that they aren't stripped and usually aren't installed
-// either (with the exception of the shared STLs, which are installed to the app's directory rather
-// than to the system image).
-
-type ndkPrebuiltStlLinker struct {
- *libraryDecorator
-}
-
-func (ndk *ndkPrebuiltStlLinker) linkerProps() []interface{} {
- return append(ndk.libraryDecorator.linkerProps(), &ndk.Properties, &ndk.flagExporter.Properties)
-}
-
-func (*ndkPrebuiltStlLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
- // NDK libraries can't have any dependencies
- 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
-// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.so.
-func NdkPrebuiltSharedStlFactory() android.Module {
- module, library := NewLibrary(android.DeviceSupported)
- library.BuildOnlyShared()
- module.compiler = nil
- module.linker = &ndkPrebuiltStlLinker{
- libraryDecorator: library,
- }
- module.installer = nil
- module.Properties.Sdk_version = StringPtr("minimum")
- module.Properties.AlwaysSdk = true
- module.stl.Properties.Stl = StringPtr("none")
- return module.Init()
-}
-
-// ndk_prebuilt_static_stl exports a precompiled ndk static standard template
-// library (stl) library for linking operation. The soong's module name format
-// is ndk_<NAME>.a where the library is located under
-// ./prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/$(HOST_ARCH)/<NAME>.a.
-func NdkPrebuiltStaticStlFactory() android.Module {
- module, library := NewLibrary(android.DeviceSupported)
- library.BuildOnlyStatic()
- module.compiler = nil
- module.linker = &ndkPrebuiltStlLinker{
- libraryDecorator: library,
- }
- module.installer = nil
- module.Properties.Sdk_version = StringPtr("minimum")
- module.Properties.HideFromMake = true
- module.Properties.AlwaysSdk = true
- module.Properties.Sdk_version = StringPtr("current")
- module.stl.Properties.Stl = StringPtr("none")
- return module.Init()
-}
-
-const (
- libDir = "current/sources/cxx-stl/llvm-libc++/libs"
-)
-
-func getNdkStlLibDir(ctx android.ModuleContext) android.SourcePath {
- return android.PathForSource(ctx, ctx.ModuleDir(), libDir).Join(ctx, ctx.Arch().Abi[0])
-}
-
-func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags,
- deps PathDeps, objs Objects) android.Path {
- // A null build step, but it sets up the output path.
- if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
- ctx.ModuleErrorf("NDK prebuilt libraries must have an ndk_lib prefixed name")
- }
-
- ndk.libraryDecorator.flagExporter.exportIncludesAsSystem(ctx)
-
- libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
- libExt := flags.Toolchain.ShlibSuffix()
- if ndk.static() {
- libExt = staticLibraryExtension
- }
-
- libDir := getNdkStlLibDir(ctx)
- lib := libDir.Join(ctx, libName+libExt)
-
- ndk.libraryDecorator.flagExporter.setProvider(ctx)
-
- if ndk.static() {
- depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build()
- android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
- StaticLibrary: lib,
-
- TransitiveStaticLibrariesForOrdering: depSet,
- })
- } else {
- android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
- SharedLibrary: lib,
- Target: ctx.Target(),
- })
- }
-
- return lib
-}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index e9f790f..e023a32 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -205,17 +205,6 @@
TableOfContents: p.tocFile,
})
- // TODO(b/220898484): Mainline module sdk prebuilts of stub libraries use a stub
- // library as their source and must not be installed, but other prebuilts like
- // libclang_rt.* libraries set `stubs` property because they are LLNDK libraries,
- // but use an implementation library as their source and need to be installed.
- // This discrepancy should be resolved without the prefix hack below.
- isModuleSdkPrebuilts := android.HasAnyPrefix(ctx.ModuleDir(), []string{
- "prebuilts/runtime/mainline/", "prebuilts/module_sdk/"})
- if p.hasStubsVariants() && !p.buildStubs() && !ctx.Host() && isModuleSdkPrebuilts {
- ctx.Module().MakeUninstallable()
- }
-
return outputFile
}
}
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 71b7e43..86e6af9 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -385,112 +385,6 @@
assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a")
}
-func TestPrebuiltStubNoinstall(t *testing.T) {
- testFunc := func(t *testing.T, expectLibfooOnSystemLib bool, fs android.MockFS) {
- result := android.GroupFixturePreparers(
- prepareForPrebuiltTest,
- android.PrepareForTestWithMakevars,
- android.FixtureMergeMockFs(fs),
- ).RunTest(t)
-
- ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld")
- android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared/libfoo.so")
-
- installRules := result.InstallMakeRulesForTesting(t)
- var installedlibRule *android.InstallMakeRule
- for i, rule := range installRules {
- if rule.Target == "out/target/product/test_device/system/lib/installedlib.so" {
- if installedlibRule != nil {
- t.Errorf("Duplicate install rules for %s", rule.Target)
- }
- installedlibRule = &installRules[i]
- }
- }
- if installedlibRule == nil {
- t.Errorf("No install rule found for installedlib")
- return
- }
-
- if expectLibfooOnSystemLib {
- android.AssertStringListContains(t,
- "installedlib doesn't have install dependency on libfoo impl",
- installedlibRule.OrderOnlyDeps,
- "out/target/product/test_device/system/lib/libfoo.so")
- } else {
- android.AssertStringListDoesNotContain(t,
- "installedlib has install dependency on libfoo stub",
- installedlibRule.Deps,
- "out/target/product/test_device/system/lib/libfoo.so")
- android.AssertStringListDoesNotContain(t,
- "installedlib has order-only install dependency on libfoo stub",
- installedlibRule.OrderOnlyDeps,
- "out/target/product/test_device/system/lib/libfoo.so")
- }
- }
-
- prebuiltLibfooBp := []byte(`
- cc_prebuilt_library {
- name: "libfoo",
- prefer: true,
- srcs: ["libfoo.so"],
- stubs: {
- versions: ["1"],
- },
- }
- `)
-
- installedlibBp := []byte(`
- cc_library {
- name: "installedlib",
- shared_libs: ["libfoo"],
- }
- `)
-
- t.Run("prebuilt stub (without source): no install", func(t *testing.T) {
- testFunc(
- t,
- /*expectLibfooOnSystemLib=*/ false,
- android.MockFS{
- "prebuilts/module_sdk/art/current/Android.bp": prebuiltLibfooBp,
- "Android.bp": installedlibBp,
- },
- )
- })
-
- disabledSourceLibfooBp := []byte(`
- cc_library {
- name: "libfoo",
- enabled: false,
- stubs: {
- versions: ["1"],
- },
- }
- `)
-
- t.Run("prebuilt stub (with disabled source): no install", func(t *testing.T) {
- testFunc(
- t,
- /*expectLibfooOnSystemLib=*/ false,
- android.MockFS{
- "prebuilts/module_sdk/art/current/Android.bp": prebuiltLibfooBp,
- "impl/Android.bp": disabledSourceLibfooBp,
- "Android.bp": installedlibBp,
- },
- )
- })
-
- t.Run("prebuilt impl (with `stubs` property set): install", func(t *testing.T) {
- testFunc(
- t,
- /*expectLibfooOnSystemLib=*/ true,
- android.MockFS{
- "impl/Android.bp": prebuiltLibfooBp,
- "Android.bp": installedlibBp,
- },
- )
- })
-}
-
func TestPrebuiltBinaryNoSrcsNoError(t *testing.T) {
const bp = `
cc_prebuilt_binary {
diff --git a/cc/proto.go b/cc/proto.go
index 4d72f26..93142b9 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -19,6 +19,8 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+
+ "strings"
)
const (
@@ -35,13 +37,21 @@
srcSuffix = ".c"
}
+ srcInfix := "pb"
+ for _, value := range flags.proto.Flags {
+ if strings.HasPrefix(value, "--plugin=") && strings.HasSuffix(value, "protoc-gen-grpc-cpp-plugin") {
+ srcInfix = "grpc.pb"
+ break
+ }
+ }
+
if flags.proto.CanonicalPathFromRoot {
- ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb"+srcSuffix)
- headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
+ ccFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+srcSuffix)
+ headerFile = android.GenPathWithExt(ctx, "proto", protoFile, srcInfix+".h")
} else {
rel := protoFile.Rel()
- ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb"+srcSuffix))
- headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h"))
+ ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+srcSuffix))
+ headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, srcInfix+".h"))
}
protoDeps := flags.proto.Deps
diff --git a/cc/proto_test.go b/cc/proto_test.go
index abcb273..a905ea8 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -68,4 +68,36 @@
}
})
+ t.Run("grpc-cpp-plugin", func(t *testing.T) {
+ ctx := testCc(t, `
+ cc_binary_host {
+ name: "protoc-gen-grpc-cpp-plugin",
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "libgrpc",
+ srcs: ["a.proto"],
+ proto: {
+ plugin: "grpc-cpp-plugin",
+ },
+ }`)
+
+ buildOS := ctx.Config().BuildOS.String()
+
+ proto := ctx.ModuleForTests("libgrpc", "android_arm_armv7-a-neon_shared").Output("proto/a.grpc.pb.cc")
+ grpcCppPlugin := ctx.ModuleForTests("protoc-gen-grpc-cpp-plugin", buildOS+"_x86_64")
+
+ cmd := proto.RuleParams.Command
+ if w := "--grpc-cpp-plugin_out="; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ grpcCppPluginPath := grpcCppPlugin.Module().(android.HostToolProvider).HostToolPath().RelativeToTop().String()
+
+ if w := "--plugin=protoc-gen-grpc-cpp-plugin=" + grpcCppPluginPath; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+ })
+
}
diff --git a/cc/sdk.go b/cc/sdk.go
index 4925ce1..dc1261d 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -19,12 +19,86 @@
"android/soong/genrule"
)
-// sdkMutator sets a creates a platform and an SDK variant for modules
+// sdkTransitionMutator 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) {
+type sdkTransitionMutator struct{}
+
+func (sdkTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ if ctx.Os() != android.Android {
+ return []string{""}
+ }
+
+ switch m := ctx.Module().(type) {
+ case LinkableInterface:
+ if m.AlwaysSdk() {
+ if !m.UseSdk() && !m.SplitPerApiLevel() {
+ ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
+ }
+ return []string{"sdk"}
+ } else if m.UseSdk() || m.SplitPerApiLevel() {
+ return []string{"", "sdk"}
+ } else {
+ return []string{""}
+ }
+ case *genrule.Module:
+ if p, ok := m.Extra.(*GenruleExtraProperties); ok {
+ if String(p.Sdk_version) != "" {
+ return []string{"", "sdk"}
+ } else {
+ return []string{""}
+ }
+ }
+ case *CcApiVariant:
+ ccApiVariant, _ := ctx.Module().(*CcApiVariant)
+ if String(ccApiVariant.properties.Variant) == "ndk" {
+ return []string{"sdk"}
+ } else {
+ return []string{""}
+ }
+ }
+
+ return []string{""}
+}
+
+func (sdkTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return sourceVariation
+}
+
+func (sdkTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if ctx.Os() != android.Android {
+ return ""
+ }
+ switch m := ctx.Module().(type) {
+ case LinkableInterface:
+ if m.AlwaysSdk() {
+ return "sdk"
+ } else if m.UseSdk() || m.SplitPerApiLevel() {
+ return incomingVariation
+ }
+ case *genrule.Module:
+ if p, ok := m.Extra.(*GenruleExtraProperties); ok {
+ if String(p.Sdk_version) != "" {
+ return incomingVariation
+ }
+ }
+ case *CcApiVariant:
+ ccApiVariant, _ := ctx.Module().(*CcApiVariant)
+ if String(ccApiVariant.properties.Variant) == "ndk" {
+ return "sdk"
+ }
+ }
+
+ if ctx.IsAddingDependency() {
+ return incomingVariation
+ } else {
+ return ""
+ }
+}
+
+func (sdkTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
if ctx.Os() != android.Android {
return
}
@@ -33,59 +107,45 @@
case LinkableInterface:
ccModule, isCcModule := ctx.Module().(*Module)
if m.AlwaysSdk() {
- if !m.UseSdk() && !m.SplitPerApiLevel() {
- ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
+ if variation != "sdk" {
+ ctx.ModuleErrorf("tried to create variation %q for module with AlwaysSdk set, expected \"sdk\"", variation)
}
- modules := ctx.CreateVariations("sdk")
- modules[0].(*Module).Properties.IsSdkVariant = true
+
+ ccModule.Properties.IsSdkVariant = true
} else if m.UseSdk() || m.SplitPerApiLevel() {
- modules := ctx.CreateVariations("", "sdk")
+ if variation == "" {
+ // Clear the sdk_version property for the platform (non-SDK) variant so later code
+ // doesn't get confused by it.
+ ccModule.Properties.Sdk_version = nil
+ } else {
+ // Mark the SDK variant.
+ ccModule.Properties.IsSdkVariant = true
- // Clear the sdk_version property for the platform (non-SDK) variant so later code
- // doesn't get confused by it.
- modules[0].(*Module).Properties.Sdk_version = nil
-
- // Mark the SDK variant.
- modules[1].(*Module).Properties.IsSdkVariant = true
+ // SDK variant never gets installed because the variant is to be embedded in
+ // APKs, not to be installed to the platform.
+ ccModule.Properties.PreventInstall = true
+ }
if ctx.Config().UnbundledBuildApps() {
- // For an unbundled apps build, hide the platform variant from Make
- // so that other Make modules don't link against it, but against the
- // SDK variant.
- modules[0].(*Module).Properties.HideFromMake = true
+ if variation == "" {
+ // For an unbundled apps build, hide the platform variant from Make
+ // so that other Make modules don't link against it, but against the
+ // SDK variant.
+ ccModule.Properties.HideFromMake = true
+ }
} else {
- // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
- // exposed to Make.
- modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+ if variation == "sdk" {
+ // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
+ // exposed to Make.
+ ccModule.Properties.SdkAndPlatformVariantVisibleToMake = true
+ }
}
- // SDK variant never gets installed because the variant is to be embedded in
- // APKs, not to be installed to the platform.
- modules[1].(*Module).Properties.PreventInstall = true
- ctx.AliasVariation("")
} else {
if isCcModule {
// Clear the sdk_version property for modules that don't have an SDK variant so
// later code doesn't get confused by it.
ccModule.Properties.Sdk_version = nil
}
- 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("")
- }
- case *CcApiVariant:
- ccApiVariant, _ := ctx.Module().(*CcApiVariant)
- if String(ccApiVariant.properties.Variant) == "ndk" {
- ctx.CreateVariations("sdk")
- } else {
- ctx.CreateVariations("")
}
}
}
diff --git a/cc/stl.go b/cc/stl.go
index de2066f..8c4ef0b 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -177,7 +177,7 @@
} else {
deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi")
}
- deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
+ deps.StaticLibs = append(deps.StaticLibs, "libunwind")
default:
panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
}
diff --git a/cc/testing.go b/cc/testing.go
index 02f9924..ed567af 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -38,8 +38,6 @@
ctx.RegisterModuleType("cc_cmake_snapshot", CmakeSnapshotFactory)
ctx.RegisterModuleType("cc_object", ObjectFactory)
ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
- ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
- ctx.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory)
ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
}
@@ -312,6 +310,25 @@
],
}
cc_library {
+ name: "ndk_libc++_shared",
+ export_include_dirs: ["ndk_libc++_shared_include_dirs"],
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ product_available: true,
+ recovery_available: true,
+ host_supported: false,
+ sdk_version: "minimum",
+ double_loadable: true,
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ }
+ cc_library {
name: "libc++demangle",
no_libcrt: true,
nocrt: true,
@@ -397,13 +414,6 @@
name: "libprotobuf-cpp-lite",
}
- cc_library {
- name: "ndk_libunwind",
- sdk_version: "minimum",
- stl: "none",
- system_shared_libs: [],
- }
-
ndk_library {
name: "libc",
first_version: "minimum",
@@ -422,11 +432,6 @@
symbol_file: "libdl.map.txt",
}
- ndk_prebuilt_shared_stl {
- name: "ndk_libc++_shared",
- export_include_dirs: ["ndk_libc++_shared"],
- }
-
cc_library_static {
name: "libgoogle-benchmark",
sdk_version: "current",
@@ -557,13 +562,6 @@
RegisterLlndkLibraryTxtType(ctx)
}),
-
- // Additional files needed in tests that disallow non-existent source files.
- // This includes files that are needed by all, or at least most, instances of a cc module type.
- android.MockFS{
- // Needed for ndk_prebuilt_(shared|static)_stl.
- "defaults/cc/common/current/sources/cxx-stl/llvm-libc++/libs": nil,
- }.AddToFixture(),
)
// Preparer that will define default cc modules, e.g. standard prebuilt modules.
@@ -572,17 +570,17 @@
// Additional files needed in tests that disallow non-existent source.
android.MockFS{
- "defaults/cc/common/libc.map.txt": nil,
- "defaults/cc/common/libdl.map.txt": nil,
- "defaults/cc/common/libft2.map.txt": nil,
- "defaults/cc/common/libm.map.txt": nil,
- "defaults/cc/common/ndk_libc++_shared": nil,
- "defaults/cc/common/crtbegin_so.c": nil,
- "defaults/cc/common/crtbegin.c": nil,
- "defaults/cc/common/crtend_so.c": nil,
- "defaults/cc/common/crtend.c": nil,
- "defaults/cc/common/crtbrand.c": nil,
- "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil,
+ "defaults/cc/common/libc.map.txt": nil,
+ "defaults/cc/common/libdl.map.txt": nil,
+ "defaults/cc/common/libft2.map.txt": nil,
+ "defaults/cc/common/libm.map.txt": nil,
+ "defaults/cc/common/ndk_libc++_shared_include_dirs": nil,
+ "defaults/cc/common/crtbegin_so.c": nil,
+ "defaults/cc/common/crtbegin.c": nil,
+ "defaults/cc/common/crtend_so.c": nil,
+ "defaults/cc/common/crtend.c": nil,
+ "defaults/cc/common/crtbrand.c": nil,
+ "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil,
"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil,
diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go
index 97d4d4c..22001bf 100644
--- a/cmd/release_config/release_config_lib/flag_declaration.go
+++ b/cmd/release_config/release_config_lib/flag_declaration.go
@@ -18,10 +18,21 @@
rc_proto "android/soong/cmd/release_config/release_config_proto"
)
+var (
+ // Allowlist: these flags may have duplicate (identical) declarations
+ // without generating an error. This will be removed once all such
+ // declarations have been fixed.
+ DuplicateDeclarationAllowlist = map[string]bool{}
+)
+
func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration) {
fd = &rc_proto.FlagDeclaration{}
if protoPath != "" {
LoadMessage(protoPath, fd)
}
+ // If the input didn't specify a value, create one (== UnspecifiedValue).
+ if fd.Value == nil {
+ fd.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}
+ }
return fd
}
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index a4c884c..97eb8f1 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -276,6 +276,20 @@
configs.Aliases[name] = alias.Target
}
var err error
+ // Temporarily allowlist duplicate flag declaration files to prevent
+ // more from entering the tree while we work to clean up the duplicates
+ // that already exist.
+ dupFlagFile := filepath.Join(dir, "duplicate_allowlist.txt")
+ data, err := os.ReadFile(dupFlagFile)
+ if err == nil {
+ for _, flag := range strings.Split(string(data), "\n") {
+ flag = strings.TrimSpace(flag)
+ if strings.HasPrefix(flag, "//") || strings.HasPrefix(flag, "#") {
+ continue
+ }
+ DuplicateDeclarationAllowlist[flag] = true
+ }
+ }
err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
flagDeclaration := FlagDeclarationFactory(path)
// Container must be specified.
@@ -289,14 +303,6 @@
}
}
- // TODO: once we have namespaces initialized, we can throw an error here.
- if flagDeclaration.Namespace == nil {
- flagDeclaration.Namespace = proto.String("android_UNKNOWN")
- }
- // If the input didn't specify a value, create one (== UnspecifiedValue).
- if flagDeclaration.Value == nil {
- flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}
- }
m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
name := *flagDeclaration.Name
if name == "RELEASE_ACONFIG_VALUE_SETS" {
@@ -304,8 +310,8 @@
}
if def, ok := configs.FlagArtifacts[name]; !ok {
configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
- } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
- return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
+ } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) || !DuplicateDeclarationAllowlist[name] {
+ return fmt.Errorf("Duplicate definition of %s in %s", *flagDeclaration.Name, path)
}
// Set the initial value in the flag artifact.
configs.FilesUsedMap[path] = true
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 201515f..5616483 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -244,6 +244,7 @@
}
odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex"))
+ odexSymbolsPath := odexPath.ReplaceExtension(ctx, "symbols.odex")
odexInstallPath := ToOdexPath(module.DexLocation, arch)
if odexOnSystemOther(module, global) {
odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath)
@@ -258,7 +259,8 @@
systemServerClasspathJars := global.AllSystemServerClasspathJars(ctx)
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
- rule.Command().FlagWithOutput("rm -f ", odexPath)
+ rule.Command().FlagWithOutput("rm -f ", odexPath).
+ FlagWithArg("rm -f ", odexSymbolsPath.String())
if jarIndex := systemServerJars.IndexOfJar(module.Name); jarIndex >= 0 {
// System server jars should be dexpreopted together: class loader context of each jar
@@ -386,7 +388,9 @@
FlagWithArg("--instruction-set=", arch.String()).
FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
- Flag("--no-generate-debug-info").
+ FlagWithOutput("--oat-symbols=", odexSymbolsPath).
+ Flag("--generate-debug-info").
+ Flag("--strip").
Flag("--generate-build-id").
Flag("--abort-on-hard-verifier-error").
Flag("--force-determinism").
@@ -532,7 +536,7 @@
}
for _, f := range global.PatternsOnSystemOther {
- if makefileMatch("/" + f, dexLocation) || makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
+ if makefileMatch("/"+f, dexLocation) || makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
return true
}
}
diff --git a/docs/resources.md b/docs/resources.md
new file mode 100644
index 0000000..c7cb0cf
--- /dev/null
+++ b/docs/resources.md
@@ -0,0 +1,89 @@
+## Soong Android Resource Compilation
+
+The Android build process involves several steps to compile resources into a format that the Android app can use
+efficiently in android_library, android_app and android_test modules. See the
+[resources documentation](https://developer.android.com/guide/topics/resources/providing-resources) for general
+information on resources (with a focus on building with Gradle).
+
+For all modules, AAPT2 compiles resources provided by directories listed in the resource_dirs directory (which is
+implicitly set to `["res"]` if unset, but can be overridden by setting the `resource_dirs` property).
+
+## android_library with resource processor
+For an android_library with resource processor enabled (currently by setting `use_resource_processor: true`, but will be
+enabled by default in the future):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_library module. `package-res.apk` files from transitive dependencies are passed to AAPT2 with the `-I` flag to
+resolve references to resources from dependencies.
+- AAPT2 generates an R.txt file that lists all the resources provided by the current android_library module.
+- ResourceProcessorBusyBox reads the `R.txt` file for the current android_library and produces an `R.jar` with an
+`R.class` in the package listed in the android_library's `AndroidManifest.xml` file that contains java fields for each
+resource ID. The resource IDs are non-final, as the final IDs will not be known until the resource table of the final
+android_app or android_test module is built.
+- The android_library's java and/or kotlin code is compiled with the generated `R.jar` in the classpath, along with the
+`R.jar` files from all transitive android_library dependencies.
+
+## android_app or android_test with resource processor
+For an android_app or android_test with resource processor enabled (currently by setting `use_resource_processor: true`,
+but will be enabled by default in the future):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_app or android_test, as well as all transitive android_library modules referenced via `static_libs`. The
+current module is overlaid on dependencies so that resources from the current module replace resources from dependencies
+in the case of conflicts.
+- AAPT2 generates an R.txt file that lists all the resources provided by the current android_app or android_test, as
+well as all transitive android_library modules referenced via `static_libs`. The R.txt file contains the final resource
+ID for each resource.
+- ResourceProcessorBusyBox reads the `R.txt` file for the current android_app or android_test, as well as all transitive
+android_library modules referenced via `static_libs`, and produces an `R.jar` with an `R.class` in the package listed in
+the android_app or android_test's `AndroidManifest.xml` file that contains java fields for all local or transitive
+resource IDs. In addition, it creates an `R.class` in the package listed in each android_library dependency's
+`AndroidManifest.xml` file that contains final resource IDs for the resources that were found in that library.
+- The android_app or android_test's java and/or kotlin code is compiled with the current module's `R.jar` in the
+classpath, but not the `R.jar` files from transitive android_library dependencies. The `R.jar` file is also merged into
+the program classes that are dexed and placed in the final APK.
+
+## android_app, android_test or android_library without resource processor
+For an android_app, android_test or android_library without resource processor enabled (current the default, or
+explicitly set with `use_resource_processor: false`):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_app, android_test or android_library module, as well as all transitive android_library modules referenced via
+`static_libs`. The current module is overlaid on dependencies so that resources from the current module replace
+resources from dependencies in the case of conflicts.
+- AAPT2 generates an `R.java` file in the package listed in each the current module's `AndroidManifest.xml` file that
+contains resource IDs for all resources from the current module as well as all transitive android_library modules
+referenced via `static_libs`. The same `R.java` containing all local and transitive resources is also duplicated into
+every package listed in an `AndroidManifest.xml` file in any static `android_library` dependency.
+- The module's java and/or kotlin code is compiled along with all the generated `R.java` files.
+
+
+## Downsides of legacy resource compilation without resource processor
+
+Compiling resources without using the resource processor results in a generated R.java source file for every transitive
+package that contains every transitive resource. For modules with large transitive dependency trees this can be tens of
+thousands of resource IDs duplicated in tens to a hundred java sources. These java sources all have to be compiled in
+every successive module in the dependency tree, and then the final R8 step has to drop hundreds of thousands of
+unreferenced fields. This results in significant build time and disk usage increases over building with resource
+processor.
+
+## Converting to compilation with resource processor
+
+### Reference resources using the package name of the module that includes them.
+Converting an android_library module to build with resource processor requires fixing any references to resources
+provided by android_library dependencies to reference the R classes using the package name found in the
+`AndroidManifest.xml` file of the dependency. For example, when referencing an androidx resource:
+```java
+View.inflate(mContext, R.layout.preference, null));
+```
+must be replaced with:
+```java
+View.inflate(mContext, androidx.preference.R.layout.preference, null));
+```
+
+### Use unique package names for each module in `AndroidManifest.xml`
+
+Each module will produce an `R.jar` containing an `R.class` in the package specified in it's `AndroidManifest.xml`.
+If multiple modules use the same package name they will produce conflicting `R.class` files, which can cause some
+resource IDs to appear to be missing.
+
+If existing code has multiple modules that contribute resources to the same package, one option is to move all the
+resources into a single resources-only `android_library` module with no code, and then depend on that from all the other
+modules.
\ No newline at end of file
diff --git a/elf/Android.bp b/elf/Android.bp
index 6450be1..6d3f4f0 100644
--- a/elf/Android.bp
+++ b/elf/Android.bp
@@ -20,6 +20,7 @@
name: "soong-elf",
pkgPath: "android/soong/elf",
srcs: [
+ "build_id_dir.go",
"elf.go",
],
testSrcs: [
diff --git a/elf/build_id_dir.go b/elf/build_id_dir.go
new file mode 100644
index 0000000..5fb7dda
--- /dev/null
+++ b/elf/build_id_dir.go
@@ -0,0 +1,172 @@
+// Copyright 2024 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 elf
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "time"
+)
+
+func UpdateBuildIdDir(path string) error {
+ path = filepath.Clean(path)
+ buildIdPath := path + "/.build-id"
+
+ // Collect the list of files and build-id symlinks. If the symlinks are
+ // up to date (newer than the symbol files), there is nothing to do.
+ var buildIdFiles, symbolFiles []string
+ var buildIdMtime, symbolsMtime time.Time
+ filepath.WalkDir(path, func(path string, entry fs.DirEntry, err error) error {
+ if entry == nil || entry.IsDir() {
+ return nil
+ }
+ info, err := entry.Info()
+ if err != nil {
+ return err
+ }
+ mtime := info.ModTime()
+ if strings.HasPrefix(path, buildIdPath) {
+ if buildIdMtime.Compare(mtime) < 0 {
+ buildIdMtime = mtime
+ }
+ buildIdFiles = append(buildIdFiles, path)
+ } else {
+ if symbolsMtime.Compare(mtime) < 0 {
+ symbolsMtime = mtime
+ }
+ symbolFiles = append(symbolFiles, path)
+ }
+ return nil
+ })
+ if symbolsMtime.Compare(buildIdMtime) < 0 {
+ return nil
+ }
+
+ // Collect build-id -> file mapping from ELF files in the symbols directory.
+ concurrency := 8
+ done := make(chan error)
+ buildIdToFile := make(map[string]string)
+ var mu sync.Mutex
+ for i := 0; i != concurrency; i++ {
+ go func(paths []string) {
+ for _, path := range paths {
+ id, err := Identifier(path, true)
+ if err != nil {
+ done <- err
+ return
+ }
+ if id == "" {
+ continue
+ }
+ mu.Lock()
+ oldPath := buildIdToFile[id]
+ if oldPath == "" || oldPath > path {
+ buildIdToFile[id] = path
+ }
+ mu.Unlock()
+ }
+ done <- nil
+ }(symbolFiles[len(symbolFiles)*i/concurrency : len(symbolFiles)*(i+1)/concurrency])
+ }
+
+ // Collect previously generated build-id -> file mapping from the .build-id directory.
+ // We will use this for incremental updates. If we see anything in the .build-id
+ // directory that we did not expect, we'll delete it and start over.
+ prevBuildIdToFile := make(map[string]string)
+out:
+ for _, buildIdFile := range buildIdFiles {
+ if !strings.HasSuffix(buildIdFile, ".debug") {
+ prevBuildIdToFile = nil
+ break
+ }
+ buildId := buildIdFile[len(buildIdPath)+1 : len(buildIdFile)-6]
+ for i, ch := range buildId {
+ if i == 2 {
+ if ch != '/' {
+ prevBuildIdToFile = nil
+ break out
+ }
+ } else {
+ if (ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') {
+ prevBuildIdToFile = nil
+ break out
+ }
+ }
+ }
+ target, err := os.Readlink(buildIdFile)
+ if err != nil || !strings.HasPrefix(target, "../../") {
+ prevBuildIdToFile = nil
+ break
+ }
+ prevBuildIdToFile[buildId[0:2]+buildId[3:]] = path + target[5:]
+ }
+ if prevBuildIdToFile == nil {
+ err := os.RemoveAll(buildIdPath)
+ if err != nil {
+ return err
+ }
+ prevBuildIdToFile = make(map[string]string)
+ }
+
+ // Wait for build-id collection from ELF files to finish.
+ for i := 0; i != concurrency; i++ {
+ err := <-done
+ if err != nil {
+ return err
+ }
+ }
+
+ // Delete old symlinks.
+ for id, _ := range prevBuildIdToFile {
+ if buildIdToFile[id] == "" {
+ symlinkDir := buildIdPath + "/" + id[:2]
+ symlinkPath := symlinkDir + "/" + id[2:] + ".debug"
+ if err := os.Remove(symlinkPath); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Add new symlinks and update changed symlinks.
+ for id, path := range buildIdToFile {
+ prevPath := prevBuildIdToFile[id]
+ if prevPath == path {
+ continue
+ }
+ symlinkDir := buildIdPath + "/" + id[:2]
+ symlinkPath := symlinkDir + "/" + id[2:] + ".debug"
+ if prevPath == "" {
+ if err := os.MkdirAll(symlinkDir, 0755); err != nil {
+ return err
+ }
+ } else {
+ if err := os.Remove(symlinkPath); err != nil {
+ return err
+ }
+ }
+
+ target, err := filepath.Rel(symlinkDir, path)
+ if err != nil {
+ return err
+ }
+ if err := os.Symlink(target, symlinkPath); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 0c6e7f4..3a9a64d 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -59,7 +59,7 @@
// List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
// have to be signed (use_avb: true).
- Partitions []string
+ Partitions proptools.Configurable[[]string]
// List of chained partitions that this vbmeta deletages the verification.
Chained_partitions []chainedPartitionProperties
@@ -110,7 +110,7 @@
var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
- ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions...)
+ ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
}
func (v *vbmeta) installFileName() string {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 5b40768..2557922 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -139,7 +139,8 @@
Export_include_dirs []string
// list of input files
- Srcs []string `android:"path,arch_variant"`
+ Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
+ ResolvedSrcs []string `blueprint:"mutated"`
// input files to exclude
Exclude_srcs []string `android:"path,arch_variant"`
@@ -382,7 +383,8 @@
}
return srcFiles
}
- srcFiles := addLabelsForInputs("srcs", g.properties.Srcs, g.properties.Exclude_srcs)
+ g.properties.ResolvedSrcs = g.properties.Srcs.GetOrDefault(ctx, nil)
+ srcFiles := addLabelsForInputs("srcs", g.properties.ResolvedSrcs, g.properties.Exclude_srcs)
android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
var copyFrom android.Paths
@@ -589,7 +591,7 @@
// Collect information for opening IDE project files in java/jdeps.go.
func (g *Module) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Srcs = append(dpInfo.Srcs, g.Srcs().Strings()...)
- for _, src := range g.properties.Srcs {
+ for _, src := range g.properties.ResolvedSrcs {
if strings.HasPrefix(src, ":") {
src = strings.Trim(src, ":")
dpInfo.Deps = append(dpInfo.Deps, src)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index fba9aec..444aedb 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -694,7 +694,7 @@
android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
expectedSrcs := []string{"in1"}
- android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.Srcs)
+ android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.ResolvedSrcs)
}
func TestGenruleAllowMissingDependencies(t *testing.T) {
diff --git a/java/Android.bp b/java/Android.bp
index a941754..9603815 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -101,6 +101,7 @@
"hiddenapi_singleton_test.go",
"jacoco_test.go",
"java_test.go",
+ "jarjar_test.go",
"jdeps_test.go",
"kotlin_test.go",
"lint_test.go",
diff --git a/java/aapt2.go b/java/aapt2.go
index f704fc6..61cf373 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -69,7 +69,7 @@
// aapt2Compile compiles resources and puts the results in the requested directory.
func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
- flags []string, productToFilter string) android.WritablePaths {
+ flags []string, productToFilter string, featureFlagsPaths android.Paths) android.WritablePaths {
if productToFilter != "" && productToFilter != "default" {
// --filter-product leaves only product-specific resources. Product-specific resources only exist
// in value resources (values/*.xml), so filter value resource files only. Ignore other types of
@@ -85,6 +85,10 @@
flags = append([]string{"--filter-product " + productToFilter}, flags...)
}
+ for _, featureFlagsPath := range android.SortedUniquePaths(featureFlagsPaths) {
+ flags = append(flags, "--feature-flags", "@"+featureFlagsPath.String())
+ }
+
// Shard the input paths so that they can be processed in parallel. If we shard them into too
// small chunks, the additional cost of spinning up aapt2 outweighs the performance gain. The
// current shard size, 100, seems to be a good balance between the added cost and the gain.
@@ -112,6 +116,7 @@
ctx.Build(pctx, android.BuildParams{
Rule: aapt2CompileRule,
Description: "aapt2 compile " + dir.String() + shardDesc,
+ Implicits: featureFlagsPaths,
Inputs: shard,
Outputs: outPaths,
Args: map[string]string{
diff --git a/java/aar.go b/java/aar.go
index 2f49a95..b69b7c2 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -440,7 +440,8 @@
var compiledResDirs []android.Paths
for _, dir := range resDirs {
a.resourceFiles = append(a.resourceFiles, dir.files...)
- compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths())
+ compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files,
+ compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths())
}
for i, zip := range resZips {
@@ -499,7 +500,8 @@
}
for _, dir := range overlayDirs {
- compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths()...)
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files,
+ compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
}
var splitPackages android.WritablePaths
diff --git a/java/app_import.go b/java/app_import.go
index fa87997..045a89a 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -431,6 +431,9 @@
var extraArgs []string
if a.Privileged() {
extraArgs = append(extraArgs, "--privileged")
+ if ctx.Config().UncompressPrivAppDex() {
+ extraArgs = append(extraArgs, "--uncompress-priv-app-dex")
+ }
}
if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks")
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 496fc13..54a5e75 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -777,30 +777,79 @@
}
func TestAndroidAppImport_Preprocessed(t *testing.T) {
- ctx, _ := testJava(t, `
- android_app_import {
- name: "foo",
- apk: "prebuilts/apk/app.apk",
- presigned: true,
- preprocessed: true,
- }
- `)
+ for _, dontUncompressPrivAppDexs := range []bool{false, true} {
+ name := fmt.Sprintf("dontUncompressPrivAppDexs:%t", dontUncompressPrivAppDexs)
+ t.Run(name, func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.UncompressPrivAppDex = proptools.BoolPtr(!dontUncompressPrivAppDexs)
+ }),
+ ).RunTestWithBp(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ preprocessed: true,
+ }
- apkName := "foo.apk"
- variant := ctx.ModuleForTests("foo", "android_common")
- outputBuildParams := variant.Output(apkName).BuildParams
- if outputBuildParams.Rule.String() != android.Cp.String() {
- t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
- }
+ android_app_import {
+ name: "bar",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ privileged: true,
+ preprocessed: true,
+ }
+ `)
- // Make sure compression and aligning were validated.
- if outputBuildParams.Validation == nil {
- t.Errorf("Expected validation rule, but was not found")
- }
+ // non-privileged app
+ apkName := "foo.apk"
+ variant := result.ModuleForTests("foo", "android_common")
+ outputBuildParams := variant.Output(apkName).BuildParams
+ if outputBuildParams.Rule.String() != android.Cp.String() {
+ t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+ }
- validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
- if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
- t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+ // Make sure compression and aligning were validated.
+ if outputBuildParams.Validation == nil {
+ t.Errorf("Expected validation rule, but was not found")
+ }
+
+ validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
+ if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
+ t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+ }
+
+ expectedScriptArgs := "--preprocessed"
+ actualScriptArgs := validationBuildParams.Args["extraArgs"]
+ android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs)
+
+ // privileged app
+ apkName = "bar.apk"
+ variant = result.ModuleForTests("bar", "android_common")
+ outputBuildParams = variant.Output(apkName).BuildParams
+ if outputBuildParams.Rule.String() != android.Cp.String() {
+ t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+ }
+
+ // Make sure compression and aligning were validated.
+ if outputBuildParams.Validation == nil {
+ t.Errorf("Expected validation rule, but was not found")
+ }
+
+ validationBuildParams = variant.Output("validated-prebuilt/check.stamp").BuildParams
+ if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
+ t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
+ }
+
+ expectedScriptArgs = "--privileged"
+ if !dontUncompressPrivAppDexs {
+ expectedScriptArgs += " --uncompress-priv-app-dex"
+ }
+ expectedScriptArgs += " --preprocessed"
+ actualScriptArgs = validationBuildParams.Args["extraArgs"]
+ android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs)
+ })
}
}
diff --git a/java/app_test.go b/java/app_test.go
index e878ccf..6b7d522 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -4364,7 +4364,16 @@
}
func TestAppFlagsPackages(t *testing.T) {
- ctx := testApp(t, `
+ ctx := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureMergeMockFs(
+ map[string][]byte{
+ "res/layout/layout.xml": nil,
+ "res/values/strings.xml": nil,
+ "res/values-en-rUS/strings.xml": nil,
+ },
+ ),
+ ).RunTestWithBp(t, `
android_app {
name: "foo",
srcs: ["a.java"],
@@ -4396,10 +4405,10 @@
// android_app module depends on aconfig_declarations listed in flags_packages
android.AssertBoolEquals(t, "foo expected to depend on bar", true,
- CheckModuleHasDependency(t, ctx, "foo", "android_common", "bar"))
+ CheckModuleHasDependency(t, ctx.TestContext, "foo", "android_common", "bar"))
android.AssertBoolEquals(t, "foo expected to depend on baz", true,
- CheckModuleHasDependency(t, ctx, "foo", "android_common", "baz"))
+ CheckModuleHasDependency(t, ctx.TestContext, "foo", "android_common", "baz"))
aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
linkInFlags := aapt2LinkRule.Args["inFlags"]
@@ -4408,6 +4417,14 @@
linkInFlags,
"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
)
+
+ aapt2CompileRule := foo.Rule("android/soong/java.aapt2Compile")
+ compileFlags := aapt2CompileRule.Args["cFlags"]
+ android.AssertStringDoesContain(t,
+ "aapt2 compile command expected to pass feature flags arguments",
+ compileFlags,
+ "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+ )
}
func TestAppFlagsPackagesPropagation(t *testing.T) {
diff --git a/java/base.go b/java/base.go
index 02dc3e3..02df147 100644
--- a/java/base.go
+++ b/java/base.go
@@ -91,6 +91,10 @@
// if not blank, run jarjar using the specified rules file
Jarjar_rules *string `android:"path,arch_variant"`
+ // java class names to rename with jarjar when a reverse dependency has a jarjar_prefix
+ // property.
+ Jarjar_rename []string
+
// if not blank, used as prefix to generate repackage rule
Jarjar_prefix *string
@@ -550,6 +554,10 @@
// java_aconfig_library or java_library modules that are statically linked
// to this module. Does not contain cache files from all transitive dependencies.
aconfigCacheFiles android.Paths
+
+ // List of soong module dependencies required to compile the current module.
+ // This information is printed out to `Dependencies` field in module_bp_java_deps.json
+ compileDepNames []string
}
var _ android.InstallableModule = (*Module)(nil)
@@ -2061,10 +2069,7 @@
}
func (j *Module) CompilerDeps() []string {
- jdeps := []string{}
- jdeps = append(jdeps, j.properties.Libs...)
- jdeps = append(jdeps, j.properties.Static_libs...)
- return jdeps
+ return j.compileDepNames
}
func (j *Module) hasCode(ctx android.ModuleContext) bool {
@@ -2408,6 +2413,11 @@
}
}
+ if android.InList(tag, compileDependencyTags) {
+ // Add the dependency name to compileDepNames so that it can be recorded in module_bp_java_deps.json
+ j.compileDepNames = append(j.compileDepNames, otherName)
+ }
+
addCLCFromDep(ctx, module, j.classLoaderContexts)
addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary)
})
@@ -2649,8 +2659,7 @@
// Gather repackage information from deps
result := collectDirectDepsProviders(ctx)
- // Update that with entries we've stored for ourself
- for orig, renamed := range module.jarjarRenameRules {
+ add := func(orig string, renamed string) {
if result == nil {
result = &JarJarProviderData{
Rename: make(map[string]string),
@@ -2659,12 +2668,22 @@
if renamed != "" {
if preexisting, exists := (*result).Rename[orig]; exists && preexisting != renamed {
ctx.ModuleErrorf("Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting)
- continue
+ return
}
}
(*result).Rename[orig] = renamed
}
+ // Update that with entries we've stored for ourself
+ for orig, renamed := range module.jarjarRenameRules {
+ add(orig, renamed)
+ }
+
+ // Update that with entries given in the jarjar_rename property.
+ for _, orig := range module.properties.Jarjar_rename {
+ add(orig, "")
+ }
+
// If there are no renamings, then jarjar_prefix does nothing, so skip the extra work.
if result == nil {
return nil
diff --git a/java/config/config.go b/java/config/config.go
index 2bb50f6..66e857c 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -47,6 +47,7 @@
"services",
"android.car",
"android.car7",
+ "android.car.builtin",
"conscrypt",
"core-icu4j",
"core-oj",
diff --git a/java/droidstubs.go b/java/droidstubs.go
index a8e0a22..d622903 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -197,6 +197,10 @@
// a list of aconfig_declarations module names that the stubs generated in this module
// depend on.
Aconfig_declarations []string
+
+ // List of hard coded filegroups containing Metalava config files that are passed to every
+ // Metalava invocation that this module performs. See addMetalavaConfigFilesToCmd.
+ ConfigFiles []string `android:"path" blueprint:"mutated"`
}
// Used by xsd_config
@@ -259,6 +263,7 @@
module.AddProperties(&module.properties,
&module.Javadoc.properties)
+ module.properties.ConfigFiles = getMetalavaConfigFilegroupReference()
module.initModuleAndImport(module)
InitDroiddocModule(module, android.HostAndDeviceSupported)
@@ -279,6 +284,7 @@
module.AddProperties(&module.properties,
&module.Javadoc.properties)
+ module.properties.ConfigFiles = getMetalavaConfigFilegroupReference()
InitDroiddocModule(module, android.HostSupported)
return module
}
@@ -694,7 +700,7 @@
}
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
- srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams) *android.RuleBuilderCommand {
+ srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams, configFiles android.Paths) *android.RuleBuilderCommand {
rule.Command().Text("rm -rf").Flag(homeDir.String())
rule.Command().Text("mkdir -p").Flag(homeDir.String())
@@ -738,9 +744,26 @@
cmd.Flag(config.MetalavaFlags)
+ addMetalavaConfigFilesToCmd(cmd, configFiles)
+
return cmd
}
+// MetalavaConfigFilegroup is the name of the filegroup in build/soong/java/metalava that lists
+// the configuration files to pass to Metalava.
+const MetalavaConfigFilegroup = "metalava-config-files"
+
+// Get a reference to the MetalavaConfigFilegroup suitable for use in a property.
+func getMetalavaConfigFilegroupReference() []string {
+ return []string{":" + MetalavaConfigFilegroup}
+}
+
+// addMetalavaConfigFilesToCmd adds --config-file options to use the config files list in the
+// MetalavaConfigFilegroup filegroup.
+func addMetalavaConfigFilesToCmd(cmd *android.RuleBuilderCommand, configFiles android.Paths) {
+ cmd.FlagForEachInput("--config-file ", configFiles)
+}
+
// Pass flagged apis related flags to metalava. When aconfig_declarations property is not
// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations
// property is defined, apply transformations and only revert the flagged apis that are not
@@ -812,7 +835,10 @@
srcJarList := zipSyncCmd(ctx, rule, params.srcJarDir, d.Javadoc.srcJars)
homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home")
- cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig)
+
+ configFiles := android.PathsForModuleSrc(ctx, d.properties.ConfigFiles)
+
+ cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig, configFiles)
cmd.Implicits(d.Javadoc.implicits)
d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi)
diff --git a/java/jarjar_test.go b/java/jarjar_test.go
new file mode 100644
index 0000000..82bfa2b
--- /dev/null
+++ b/java/jarjar_test.go
@@ -0,0 +1,85 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/android"
+)
+
+func AssertJarJarRename(t *testing.T, result *android.TestResult, libName, original, expectedRename string) {
+ module := result.ModuleForTests(libName, "android_common")
+
+ provider, found := android.OtherModuleProvider(result.OtherModuleProviderAdaptor(), module.Module(), JarJarProvider)
+ android.AssertBoolEquals(t, fmt.Sprintf("found provider (%s)", libName), true, found)
+
+ renamed, found := provider.Rename[original]
+ android.AssertBoolEquals(t, fmt.Sprintf("found rename (%s)", libName), true, found)
+ android.AssertStringEquals(t, fmt.Sprintf("renamed (%s)", libName), expectedRename, renamed)
+}
+
+func TestJarJarRenameDifferentModules(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "their_lib",
+ jarjar_rename: ["com.example.a"],
+ }
+
+ java_library {
+ name: "boundary_lib",
+ jarjar_prefix: "RENAME",
+ static_libs: ["their_lib"],
+ }
+
+ java_library {
+ name: "my_lib",
+ static_libs: ["boundary_lib"],
+ }
+ `)
+
+ original := "com.example.a"
+ renamed := "RENAME.com.example.a"
+ AssertJarJarRename(t, result, "their_lib", original, "")
+ AssertJarJarRename(t, result, "boundary_lib", original, renamed)
+ AssertJarJarRename(t, result, "my_lib", original, renamed)
+}
+
+func TestJarJarRenameSameModule(t *testing.T) {
+ t.Parallel()
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "their_lib",
+ jarjar_rename: ["com.example.a"],
+ jarjar_prefix: "RENAME",
+ }
+
+ java_library {
+ name: "my_lib",
+ static_libs: ["their_lib"],
+ }
+ `)
+
+ original := "com.example.a"
+ renamed := "RENAME.com.example.a"
+ AssertJarJarRename(t, result, "their_lib", original, renamed)
+ AssertJarJarRename(t, result, "my_lib", original, renamed)
+}
diff --git a/java/java.go b/java/java.go
index 88b31b5..b320732 100644
--- a/java/java.go
+++ b/java/java.go
@@ -269,7 +269,7 @@
ImplementationAndResourcesJars android.Paths
// ImplementationJars is a list of jars that contain the implementations of classes in the
- //module.
+ // module.
ImplementationJars android.Paths
// ResourceJars is a list of jars that contain the resources included in the module.
@@ -443,6 +443,30 @@
usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true)
)
+// A list of tags for deps used for compiling a module.
+// Any dependency tags that modifies the following properties of `deps` in `Module.collectDeps` should be
+// added to this list:
+// - bootClasspath
+// - classpath
+// - java9Classpath
+// - systemModules
+// - kotlin deps...
+var (
+ compileDependencyTags = []blueprint.DependencyTag{
+ sdkLibTag,
+ libTag,
+ staticLibTag,
+ bootClasspathTag,
+ systemModulesTag,
+ java9LibTag,
+ kotlinStdlibTag,
+ kotlinAnnotationsTag,
+ kotlinPluginTag,
+ syspropPublicStubDepTag,
+ instrumentationForTag,
+ }
+)
+
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
return depTag == libTag || depTag == sdkLibTag
}
@@ -2015,12 +2039,17 @@
// List of aconfig_declarations module names that the stubs generated in this module
// depend on.
Aconfig_declarations []string
+
+ // List of hard coded filegroups containing Metalava config files that are passed to every
+ // Metalava invocation that this module performs. See addMetalavaConfigFilesToCmd.
+ ConfigFiles []string `android:"path" blueprint:"mutated"`
}
func ApiLibraryFactory() android.Module {
module := &ApiLibrary{}
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
module.AddProperties(&module.properties)
+ module.properties.ConfigFiles = getMetalavaConfigFilegroupReference()
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
module.initModuleAndImport(module)
android.InitDefaultableModule(module)
return module
@@ -2036,7 +2065,7 @@
func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
srcs android.Paths, homeDir android.WritablePath,
- classpath android.Paths) *android.RuleBuilderCommand {
+ classpath android.Paths, configFiles android.Paths) *android.RuleBuilderCommand {
rule.Command().Text("rm -rf").Flag(homeDir.String())
rule.Command().Text("mkdir -p").Flag(homeDir.String())
@@ -2075,6 +2104,8 @@
FlagWithArg("--hide ", "InvalidNullabilityOverride").
FlagWithArg("--hide ", "ChangedDefault")
+ addMetalavaConfigFilesToCmd(cmd, configFiles)
+
if len(classpath) == 0 {
// The main purpose of the `--api-class-resolution api` option is to force metalava to ignore
// classes on the classpath when an API file contains missing classes. However, as this command
@@ -2286,7 +2317,9 @@
ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
}
- cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, systemModulesPaths)
+ configFiles := android.PathsForModuleSrc(ctx, al.properties.ConfigFiles)
+
+ cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, systemModulesPaths, configFiles)
al.stubsFlags(ctx, cmd, stubsDir)
@@ -2386,10 +2419,35 @@
return android.FutureApiLevel
}
+func (al *ApiLibrary) IDEInfo(i *android.IdeInfo) {
+ i.Deps = append(i.Deps, al.ideDeps()...)
+ i.Libs = append(i.Libs, al.properties.Libs...)
+ i.Static_libs = append(i.Static_libs, al.properties.Static_libs...)
+ i.SrcJars = append(i.SrcJars, al.stubsSrcJar.String())
+}
+
+// deps of java_api_library for module_bp_java_deps.json
+func (al *ApiLibrary) ideDeps() []string {
+ ret := []string{}
+ ret = append(ret, al.properties.Libs...)
+ ret = append(ret, al.properties.Static_libs...)
+ if al.properties.System_modules != nil {
+ ret = append(ret, proptools.String(al.properties.System_modules))
+ }
+ if al.properties.Full_api_surface_stub != nil {
+ ret = append(ret, proptools.String(al.properties.Full_api_surface_stub))
+ }
+ // Other non java_library dependencies like java_api_contribution are ignored for now.
+ return ret
+}
+
// implement the following interfaces for hiddenapi processing
var _ hiddenAPIModule = (*ApiLibrary)(nil)
var _ UsesLibraryDependency = (*ApiLibrary)(nil)
+// implement the following interface for IDE completion.
+var _ android.IDEInfo = (*ApiLibrary)(nil)
+
//
// Java prebuilts
//
diff --git a/java/jdeps_test.go b/java/jdeps_test.go
index 874d1d7..e180224 100644
--- a/java/jdeps_test.go
+++ b/java/jdeps_test.go
@@ -22,28 +22,46 @@
)
func TestCollectJavaLibraryPropertiesAddLibsDeps(t *testing.T) {
- expected := []string{"Foo", "Bar"}
- module := LibraryFactory().(*Library)
- module.properties.Libs = append(module.properties.Libs, expected...)
+ ctx, _ := testJava(t,
+ `
+ java_library {name: "Foo"}
+ java_library {name: "Bar"}
+ java_library {
+ name: "javalib",
+ libs: ["Foo", "Bar"],
+ }
+ `)
+ module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
dpInfo := &android.IdeInfo{}
module.IDEInfo(dpInfo)
- if !reflect.DeepEqual(dpInfo.Deps, expected) {
- t.Errorf("Library.IDEInfo() Deps = %v, want %v", dpInfo.Deps, expected)
+ for _, expected := range []string{"Foo", "Bar"} {
+ if !android.InList(expected, dpInfo.Deps) {
+ t.Errorf("Library.IDEInfo() Deps = %v, %v not found", dpInfo.Deps, expected)
+ }
}
}
func TestCollectJavaLibraryPropertiesAddStaticLibsDeps(t *testing.T) {
- expected := []string{"Foo", "Bar"}
- module := LibraryFactory().(*Library)
- module.properties.Static_libs = append(module.properties.Static_libs, expected...)
+ ctx, _ := testJava(t,
+ `
+ java_library {name: "Foo"}
+ java_library {name: "Bar"}
+ java_library {
+ name: "javalib",
+ static_libs: ["Foo", "Bar"],
+ }
+ `)
+ module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library)
dpInfo := &android.IdeInfo{}
module.IDEInfo(dpInfo)
- if !reflect.DeepEqual(dpInfo.Deps, expected) {
- t.Errorf("Library.IDEInfo() Deps = %v, want %v", dpInfo.Deps, expected)
+ for _, expected := range []string{"Foo", "Bar"} {
+ if !android.InList(expected, dpInfo.Deps) {
+ t.Errorf("Library.IDEInfo() Deps = %v, %v not found", dpInfo.Deps, expected)
+ }
}
}
diff --git a/java/metalava/Android.bp b/java/metalava/Android.bp
new file mode 100644
index 0000000..ccbd191
--- /dev/null
+++ b/java/metalava/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2024 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.
+
+filegroup {
+ name: "metalava-config-files",
+ srcs: ["*-config.xml"],
+}
diff --git a/java/metalava/OWNERS b/java/metalava/OWNERS
new file mode 100644
index 0000000..e8c438e
--- /dev/null
+++ b/java/metalava/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 463936
+
+file:platform/tools/metalava:/OWNERS
diff --git a/java/metalava/main-config.xml b/java/metalava/main-config.xml
new file mode 100644
index 0000000..c61196f
--- /dev/null
+++ b/java/metalava/main-config.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<config xmlns="http://www.google.com/tools/metalava/config"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd"/>
diff --git a/java/metalava/source-model-selection-config.xml b/java/metalava/source-model-selection-config.xml
new file mode 100644
index 0000000..c61196f
--- /dev/null
+++ b/java/metalava/source-model-selection-config.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<config xmlns="http://www.google.com/tools/metalava/config"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd"/>
diff --git a/java/ravenwood.go b/java/ravenwood.go
index 908619d..84c285c 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -33,6 +33,8 @@
var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"}
var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"}
var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"}
+var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"}
+var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"}
const ravenwoodUtilsName = "ravenwood-utils"
const ravenwoodRuntimeName = "ravenwood-runtime"
@@ -53,6 +55,13 @@
type ravenwoodTestProperties struct {
Jni_libs []string
+
+ // Specify another android_app module here to copy it to the test directory, so that
+ // the ravenwood test can access it.
+ // TODO: For now, we simply refer to another android_app module and copy it to the
+ // test directory. Eventually, android_ravenwood_test should support all the resource
+ // related properties and build resources from the `res/` directory.
+ Resource_apk *string
}
type ravenwoodTest struct {
@@ -114,6 +123,11 @@
for _, lib := range r.ravenwoodTestProperties.Jni_libs {
ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
}
+
+ // Resources APK
+ if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" {
+ ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk)
+ }
}
func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -175,6 +189,14 @@
installDeps = append(installDeps, installJni)
}
+ resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks")
+ if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 {
+ for _, installFile := range resApk[0].FilesToInstall() {
+ installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile)
+ installDeps = append(installDeps, installResApk)
+ }
+ }
+
// Install our JAR with all dependencies
ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
}
@@ -198,6 +220,9 @@
Libs []string
Jni_libs []string
+
+ // We use this to copy framework-res.apk to the ravenwood runtime directory.
+ Data []string
}
type ravenwoodLibgroup struct {
@@ -236,6 +261,9 @@
for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
}
+ for _, data := range r.ravenwoodLibgroupProperties.Data {
+ ctx.AddVariationDependencies(nil, ravenwoodDataTag, data)
+ }
}
func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -266,6 +294,13 @@
ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path)
}
+ dataInstallPath := installPath.Join(ctx, "ravenwood-data")
+ for _, data := range r.ravenwoodLibgroupProperties.Data {
+ libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag)
+ file := android.OutputFileForModule(ctx, libModule, "")
+ ctx.InstallFile(dataInstallPath, file.Base(), file)
+ }
+
// Normal build should perform install steps
ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
}
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index 5961264..d26db93 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -57,6 +57,14 @@
name: "framework-rules.ravenwood",
srcs: ["Rules.java"],
}
+ android_app {
+ name: "app1",
+ sdk_version: "current",
+ }
+ android_app {
+ name: "app2",
+ sdk_version: "current",
+ }
android_ravenwood_libgroup {
name: "ravenwood-runtime",
libs: [
@@ -67,6 +75,9 @@
"ravenwood-runtime-jni1",
"ravenwood-runtime-jni2",
],
+ data: [
+ "app1",
+ ],
}
android_ravenwood_libgroup {
name: "ravenwood-utils",
@@ -102,6 +113,7 @@
runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so")
runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
+ runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk")
utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
}
@@ -143,6 +155,7 @@
"jni-lib2",
"ravenwood-runtime-jni2",
],
+ resource_apk: "app2",
sdk_version: "test_current",
}
`)
@@ -169,6 +182,7 @@
module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so")
module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
+ module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk")
// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
for _, o := range module.AllOutputs() {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 1eb7ab8..3931456 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1516,6 +1516,13 @@
// Add other dependencies as normal.
func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // If the module does not create an implementation library or defaults to stubs,
+ // mark the top level sdk library as stubs module as the module will provide stubs via
+ // "magic" when listed as a dependency in the Android.bp files.
+ notCreateImplLib := proptools.Bool(module.sdkLibraryProperties.Api_only)
+ preferStubs := proptools.Bool(module.sdkLibraryProperties.Default_to_stubs)
+ module.properties.Is_stubs_module = proptools.BoolPtr(notCreateImplLib || preferStubs)
+
var missingApiModules []string
for _, apiScope := range module.getGeneratedApiScopes(ctx) {
if apiScope.unstable {
diff --git a/java/testing.go b/java/testing.go
index 5ae326d..7a42e4c 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -52,6 +52,8 @@
android.MockFS{
// Needed for linter used by java_library.
"build/soong/java/lint_defaults.txt": nil,
+ // Needed for java components that invoke Metalava.
+ "build/soong/java/metalava/Android.bp": []byte(`filegroup {name: "metalava-config-files"}`),
// Needed for apps that do not provide their own.
"build/make/target/product/security": nil,
// Required to generate Java used-by API coverage
diff --git a/phony/phony.go b/phony/phony.go
index b421176..807b95b 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -20,6 +20,8 @@
"strings"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -88,14 +90,15 @@
android.ModuleBase
android.DefaultableModuleBase
- properties PhonyProperties
+ phonyDepsModuleNames []string
+ properties PhonyProperties
}
type PhonyProperties struct {
// The Phony_deps is the set of all dependencies for this target,
// and it can function similarly to .PHONY in a makefile.
// Additionally, dependencies within it can even include genrule.
- Phony_deps []string
+ Phony_deps proptools.Configurable[[]string]
}
// The phony_rule provides functionality similar to the .PHONY in a makefile.
@@ -109,13 +112,14 @@
}
func (p *PhonyRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ p.phonyDepsModuleNames = p.properties.Phony_deps.GetOrDefault(ctx, nil)
}
func (p *PhonyRule) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- if len(p.properties.Phony_deps) > 0 {
- depModulesStr := strings.Join(p.properties.Phony_deps, " ")
+ if len(p.phonyDepsModuleNames) > 0 {
+ depModulesStr := strings.Join(p.phonyDepsModuleNames, " ")
fmt.Fprintln(w, ".PHONY:", name)
fmt.Fprintln(w, name, ":", depModulesStr)
}
diff --git a/python/python.go b/python/python.go
index 1ee533f..8726f02 100644
--- a/python/python.go
+++ b/python/python.go
@@ -38,7 +38,7 @@
// Exported to support other packages using Python modules in tests.
func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("python_version", versionSplitMutator()).Parallel()
+ ctx.Transition("python_version", &versionSplitTransitionMutator{})
}
// the version-specific properties that apply to python modules.
@@ -245,7 +245,6 @@
protoExt = ".proto"
pyVersion2 = "PY2"
pyVersion3 = "PY3"
- pyVersion2And3 = "PY2ANDPY3"
internalPath = "internal"
)
@@ -253,46 +252,68 @@
getBaseProperties() *BaseProperties
}
-// versionSplitMutator creates version variants for modules and appends the version-specific
-// properties for a given variant to the properties in the variant module
-func versionSplitMutator() func(android.BottomUpMutatorContext) {
- return func(mctx android.BottomUpMutatorContext) {
- if base, ok := mctx.Module().(basePropertiesProvider); ok {
- props := base.getBaseProperties()
- var versionNames []string
- // collect version specific properties, so that we can merge version-specific properties
- // into the module's overall properties
- var versionProps []VersionProperties
- // PY3 is first so that we alias the PY3 variant rather than PY2 if both
- // are available
- if proptools.BoolDefault(props.Version.Py3.Enabled, true) {
- versionNames = append(versionNames, pyVersion3)
- versionProps = append(versionProps, props.Version.Py3)
+type versionSplitTransitionMutator struct{}
+
+func (versionSplitTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ if base, ok := ctx.Module().(basePropertiesProvider); ok {
+ props := base.getBaseProperties()
+ var variants []string
+ // PY3 is first so that we alias the PY3 variant rather than PY2 if both
+ // are available
+ if proptools.BoolDefault(props.Version.Py3.Enabled, true) {
+ variants = append(variants, pyVersion3)
+ }
+ if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
+ if !ctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
+ ctx.ModuleName() != "py2-cmd" &&
+ ctx.ModuleName() != "py2-stdlib" {
+ ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
}
- if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
- if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
- mctx.ModuleName() != "py2-cmd" &&
- mctx.ModuleName() != "py2-stdlib" {
- mctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
- }
- versionNames = append(versionNames, pyVersion2)
- versionProps = append(versionProps, props.Version.Py2)
- }
- modules := mctx.CreateLocalVariations(versionNames...)
- // Alias module to the first variant
- if len(versionNames) > 0 {
- mctx.AliasVariation(versionNames[0])
- }
- for i, v := range versionNames {
- // set the actual version for Python module.
- newProps := modules[i].(basePropertiesProvider).getBaseProperties()
- newProps.Actual_version = v
- // append versioned properties for the Python module to the overall properties
- err := proptools.AppendMatchingProperties([]interface{}{newProps}, &versionProps[i], nil)
- if err != nil {
- panic(err)
- }
- }
+ variants = append(variants, pyVersion2)
+ }
+ return variants
+ }
+ return []string{""}
+}
+
+func (versionSplitTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+}
+
+func (versionSplitTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if incomingVariation != "" {
+ return incomingVariation
+ }
+ if base, ok := ctx.Module().(basePropertiesProvider); ok {
+ props := base.getBaseProperties()
+ if proptools.BoolDefault(props.Version.Py3.Enabled, true) {
+ return pyVersion3
+ } else {
+ return pyVersion2
+ }
+ }
+
+ return ""
+}
+
+func (versionSplitTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ if variation == "" {
+ return
+ }
+ if base, ok := ctx.Module().(basePropertiesProvider); ok {
+ props := base.getBaseProperties()
+ props.Actual_version = variation
+
+ var versionProps *VersionProperties
+ if variation == pyVersion3 {
+ versionProps = &props.Version.Py3
+ } else if variation == pyVersion2 {
+ versionProps = &props.Version.Py2
+ }
+
+ err := proptools.AppendMatchingProperties([]interface{}{props}, versionProps, nil)
+ if err != nil {
+ panic(err)
}
}
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index dbc3697..d412ea1 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r522817"
+ bindgenClangVersion = "clang-r530567"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -285,7 +285,7 @@
if isCpp {
cflags = append(cflags, "-x c++")
// Add any C++ only flags.
- cflags = append(cflags, esc(b.ClangProperties.Cppflags)...)
+ cflags = append(cflags, esc(b.ClangProperties.Cppflags.GetOrDefault(ctx, nil))...)
} else {
cflags = append(cflags, "-x c")
}
diff --git a/rust/coverage.go b/rust/coverage.go
index e0e919c..91a7806 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -47,7 +47,7 @@
// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
- ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}, rlibDepTag, ProfilerBuiltins)
+ ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, ProfilerBuiltins)
}
}
diff --git a/rust/library.go b/rust/library.go
index ba73f27..50d5a72 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -20,6 +20,8 @@
"regexp"
"strings"
+ "github.com/google/blueprint"
+
"android/soong/android"
"android/soong/cc"
)
@@ -692,31 +694,28 @@
}
}
-// LibraryMutator mutates the libraries into variants according to the
-// build{Rlib,Dylib} attributes.
-func LibraryMutator(mctx android.BottomUpMutatorContext) {
- // Only mutate on Rust libraries.
- m, ok := mctx.Module().(*Module)
+type libraryTransitionMutator struct{}
+
+func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ m, ok := ctx.Module().(*Module)
if !ok || m.compiler == nil {
- return
+ return []string{""}
}
library, ok := m.compiler.(libraryInterface)
if !ok {
- return
+ return []string{""}
}
// Don't produce rlib/dylib/source variants for shared or static variants
if library.shared() || library.static() {
- return
+ return []string{""}
}
var variants []string
// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
// depend on this variant. It must be the first variant to be declared.
- sourceVariant := false
if m.sourceProvider != nil {
- variants = append(variants, "source")
- sourceVariant = true
+ variants = append(variants, sourceVariation)
}
if library.buildRlib() {
variants = append(variants, rlibVariation)
@@ -726,92 +725,134 @@
}
if len(variants) == 0 {
- return
+ return []string{""}
}
- modules := mctx.CreateLocalVariations(variants...)
- // The order of the variations (modules) matches the variant names provided. Iterate
- // through the new variation modules and set their mutated properties.
- var emptyVariant = false
- var rlibVariant = false
- for i, v := range modules {
- switch variants[i] {
- case rlibVariation:
- v.(*Module).compiler.(libraryInterface).setRlib()
- rlibVariant = true
- case dylibVariation:
- v.(*Module).compiler.(libraryInterface).setDylib()
- if v.(*Module).ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
- // TODO(b/165791368)
- // Disable dylib Vendor Ramdisk variations until we support these.
- v.(*Module).Disable()
- }
+ return variants
+}
- case "source":
- v.(*Module).compiler.(libraryInterface).setSource()
- // The source variant does not produce any library.
- // Disable the compilation steps.
- v.(*Module).compiler.SetDisabled()
- case "":
- emptyVariant = true
+func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+}
+
+func (libraryTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ m, ok := ctx.Module().(*Module)
+ if !ok || m.compiler == nil {
+ return ""
+ }
+ library, ok := m.compiler.(libraryInterface)
+ if !ok {
+ return ""
+ }
+
+ if incomingVariation == "" {
+ if m.sourceProvider != nil {
+ return sourceVariation
+ }
+ if library.shared() {
+ return ""
+ }
+ if library.buildRlib() {
+ return rlibVariation
+ }
+ if library.buildDylib() {
+ return dylibVariation
}
}
+ return incomingVariation
+}
- if rlibVariant && library.isFFILibrary() {
- // If an rlib variant is set and this is an FFI library, make it the
- // default variant so CC can link against it appropriately.
- mctx.AliasVariation(rlibVariation)
- } else if emptyVariant {
- // If there's an empty variant, alias it so it is the default variant
- mctx.AliasVariation("")
+func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ m, ok := ctx.Module().(*Module)
+ if !ok || m.compiler == nil {
+ return
+ }
+ library, ok := m.compiler.(libraryInterface)
+ if !ok {
+ return
+ }
+
+ switch variation {
+ case rlibVariation:
+ library.setRlib()
+ case dylibVariation:
+ library.setDylib()
+ if m.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
+ // TODO(b/165791368)
+ // Disable dylib Vendor Ramdisk variations until we support these.
+ m.Disable()
+ }
+
+ case sourceVariation:
+ library.setSource()
+ // The source variant does not produce any library.
+ // Disable the compilation steps.
+ m.compiler.SetDisabled()
}
// If a source variant is created, add an inter-variant dependency
// between the other variants and the source variant.
- if sourceVariant {
- sv := modules[0]
- for _, v := range modules[1:] {
- if !v.Enabled(mctx) {
- continue
- }
- mctx.AddInterVariantDependency(sourceDepTag, v, sv)
- }
- // Alias the source variation so it can be named directly in "srcs" properties.
- mctx.AliasVariation("source")
+ if m.sourceProvider != nil && variation != sourceVariation {
+ ctx.AddVariationDependencies(
+ []blueprint.Variation{
+ {"rust_libraries", sourceVariation},
+ },
+ sourceDepTag, ctx.ModuleName())
}
}
-func LibstdMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
- switch library := m.compiler.(type) {
- case libraryInterface:
- // Only create a variant if a library is actually being built.
- if library.rlib() && !library.sysroot() {
- // If this is a rust_ffi variant it only needs rlib-std
- if library.isFFILibrary() {
- variants := []string{"rlib-std"}
- modules := mctx.CreateLocalVariations(variants...)
- rlib := modules[0].(*Module)
- rlib.compiler.(libraryInterface).setRlibStd()
- rlib.Properties.RustSubName += RlibStdlibSuffix
- mctx.AliasVariation("rlib-std")
- } else {
- variants := []string{"rlib-std", "dylib-std"}
- modules := mctx.CreateLocalVariations(variants...)
+type libstdTransitionMutator struct{}
- rlib := modules[0].(*Module)
- dylib := modules[1].(*Module)
- rlib.compiler.(libraryInterface).setRlibStd()
- dylib.compiler.(libraryInterface).setDylibStd()
- if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
- // TODO(b/165791368)
- // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
- // variants are properly supported.
- dylib.Disable()
- }
- rlib.Properties.RustSubName += RlibStdlibSuffix
+func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+ if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
+ // Only create a variant if a library is actually being built.
+ if library, ok := m.compiler.(libraryInterface); ok {
+ if library.rlib() && !library.sysroot() {
+ if library.isFFILibrary() {
+ return []string{"rlib-std"}
+ } else {
+ return []string{"rlib-std", "dylib-std"}
}
}
}
}
+ return []string{""}
+}
+
+func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ return ""
+}
+
+func (libstdTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if m, ok := ctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() {
+ if library, ok := m.compiler.(libraryInterface); ok {
+ if library.shared() {
+ return ""
+ }
+ if library.rlib() && !library.sysroot() {
+ if incomingVariation != "" {
+ return incomingVariation
+ }
+ return "rlib-std"
+ }
+ }
+ }
+ return ""
+}
+
+func (libstdTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+ if variation == "rlib-std" {
+ rlib := ctx.Module().(*Module)
+ rlib.compiler.(libraryInterface).setRlibStd()
+ rlib.Properties.RustSubName += RlibStdlibSuffix
+ } else if variation == "dylib-std" {
+ dylib := ctx.Module().(*Module)
+ dylib.compiler.(libraryInterface).setDylibStd()
+ if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
+ // TODO(b/165791368)
+ // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
+ // variants are properly supported.
+ dylib.Disable()
+ }
+ }
}
diff --git a/rust/rust.go b/rust/rust.go
index 9dae75e..3402adc 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -37,20 +37,24 @@
func init() {
android.RegisterModuleType("rust_defaults", defaultsFactory)
- android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
- ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
- ctx.BottomUp("rust_begin", BeginMutator).Parallel()
- })
- android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
- })
+ android.PreDepsMutators(registerPreDepsMutators)
+ android.PostDepsMutators(registerPostDepsMutators)
pctx.Import("android/soong/android")
pctx.Import("android/soong/rust/config")
pctx.ImportAs("cc_config", "android/soong/cc/config")
android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
}
+func registerPreDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.Transition("rust_libraries", &libraryTransitionMutator{})
+ ctx.Transition("rust_stdlinkage", &libstdTransitionMutator{})
+ ctx.BottomUp("rust_begin", BeginMutator).Parallel()
+}
+
+func registerPostDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+}
+
type Flags struct {
GlobalRustFlags []string // Flags that apply globally to rust
GlobalLinkFlags []string // Flags that apply globally to linker
@@ -1128,10 +1132,11 @@
}
var (
- rlibVariation = "rlib"
- dylibVariation = "dylib"
- rlibAutoDep = autoDep{variation: rlibVariation, depTag: rlibDepTag}
- dylibAutoDep = autoDep{variation: dylibVariation, depTag: dylibDepTag}
+ sourceVariation = "source"
+ rlibVariation = "rlib"
+ dylibVariation = "dylib"
+ rlibAutoDep = autoDep{variation: rlibVariation, depTag: rlibDepTag}
+ dylibAutoDep = autoDep{variation: dylibVariation, depTag: dylibDepTag}
)
type autoDeppable interface {
@@ -1613,7 +1618,6 @@
}
rlibDepVariations := commonDepVariations
- rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() {
rlibDepVariations = append(rlibDepVariations,
@@ -1629,7 +1633,6 @@
// dylibs
dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation})
- dylibDepVariations = append(dylibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
for _, lib := range deps.Dylibs {
actx.AddVariationDependencies(dylibDepVariations, dylibDepTag, lib)
@@ -1650,7 +1653,6 @@
// otherwise select the rlib variant.
autoDepVariations := append(commonDepVariations,
blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
- autoDepVariations = append(autoDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if actx.OtherModuleDependencyVariantExists(autoDepVariations, lib) {
actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib)
@@ -1664,8 +1666,7 @@
} else if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
for _, lib := range deps.Rustlibs {
srcProviderVariations := append(commonDepVariations,
- blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
- srcProviderVariations = append(srcProviderVariations, blueprint.Variation{Mutator: "link", Variation: ""})
+ blueprint.Variation{Mutator: "rust_libraries", Variation: sourceVariation})
// Only add rustlib dependencies if they're source providers themselves.
// This is used to track which crate names need to be added to the source generated
@@ -1681,7 +1682,7 @@
if deps.Stdlibs != nil {
if mod.compiler.stdLinkage(ctx) == RlibLinkage {
for _, lib := range deps.Stdlibs {
- actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}...),
+ actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
rlibDepTag, lib)
}
} else {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 0d005d0..eeedf3f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -60,6 +60,7 @@
// testRust returns a TestContext in which a basic environment has been setup.
// This environment contains a few mocked files. See rustMockedFiles for the list of these files.
func testRust(t *testing.T, bp string) *android.TestContext {
+ t.Helper()
skipTestIfOsNotSupported(t)
result := android.GroupFixturePreparers(
prepareForRustTest,
diff --git a/rust/testing.go b/rust/testing.go
index 6ee49a9..32cc823 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -200,15 +200,8 @@
ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- // rust mutators
- ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
- ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
- ctx.BottomUp("rust_begin", BeginMutator).Parallel()
- })
+ ctx.PreDepsMutators(registerPreDepsMutators)
ctx.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
ctx.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
- })
+ ctx.PostDepsMutators(registerPostDepsMutators)
}
diff --git a/scripts/buildinfo.py b/scripts/buildinfo.py
index db99209..8a24b63 100755
--- a/scripts/buildinfo.py
+++ b/scripts/buildinfo.py
@@ -132,7 +132,7 @@
# Dev. branches should have DISPLAY_BUILD_NUMBER set
if option.display_build_number:
- print(f"ro.build.display.id?={option.build_id} {build_number} {option.build_keys}")
+ print(f"ro.build.display.id?={option.build_id}.{build_number} {option.build_keys}")
else:
print(f"ro.build.display.id?={option.build_id} {option.build_keys}")
else:
diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py
index abedfb7..abab2e1 100755
--- a/scripts/check_prebuilt_presigned_apk.py
+++ b/scripts/check_prebuilt_presigned_apk.py
@@ -37,7 +37,7 @@
sys.exit(args.apk + ': Contains compressed JNI libraries')
return True
# It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
- if args.privileged:
+ if args.privileged and args.uncompress_priv_app_dex:
if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED:
if fail:
sys.exit(args.apk + ': Contains compressed dex files and is privileged')
@@ -52,6 +52,7 @@
parser.add_argument('--skip-preprocessed-apk-checks', action = 'store_true', help = "the value of the soong property with the same name")
parser.add_argument('--preprocessed', action = 'store_true', help = "the value of the soong property with the same name")
parser.add_argument('--privileged', action = 'store_true', help = "the value of the soong property with the same name")
+ parser.add_argument('--uncompress-priv-app-dex', action = 'store_true', help = "the value of the product variable with the same name")
parser.add_argument('apk', help = "the apk to check")
parser.add_argument('stampfile', help = "a file to touch if successful")
args = parser.parse_args()
diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py
index 799e00b..9ea56cb 100644
--- a/scripts/gen_build_prop.py
+++ b/scripts/gen_build_prop.py
@@ -188,7 +188,7 @@
# Dev. branches should have DISPLAY_BUILD_NUMBER set
if config["DisplayBuildNumber"]:
- print(f"ro.build.display.id?={config['BuildId']} {config['BuildNumber']} {config['BuildKeys']}")
+ print(f"ro.build.display.id?={config['BuildId']}.{config['BuildNumber']} {config['BuildKeys']}")
else:
print(f"ro.build.display.id?={config['BuildId']} {config['BuildKeys']}")
else:
diff --git a/scripts/run-ckati.sh b/scripts/run-ckati.sh
index b670c8a..70f5a7a 100755
--- a/scripts/run-ckati.sh
+++ b/scripts/run-ckati.sh
@@ -73,12 +73,12 @@
--writable out/ \
-f build/make/core/main.mk \
"${tracing[@]}" \
- ANDROID_JAVA_HOME=prebuilts/jdk/jdk17/linux-x86 \
+ ANDROID_JAVA_HOME=prebuilts/jdk/jdk21/linux-x86 \
ASAN_SYMBOLIZER_PATH=$PWD/prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-symbolizer \
BUILD_DATETIME_FILE="$timestamp_file" \
BUILD_HOSTNAME=$(hostname) \
BUILD_USERNAME="$USER" \
- JAVA_HOME=$PWD/prebuilts/jdk/jdk17/linux-x86 \
+ JAVA_HOME=$PWD/prebuilts/jdk/jdk21/linux-x86 \
KATI_PACKAGE_MK_DIR="{$out}/target/product/${target_device}/CONFIG/kati_packaging" \
OUT_DIR="$out" \
PATH="$PWD/prebuilts/build-tools/path/linux-x86:$PWD/${out}/.path" \
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 5d76930..25839b8 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -2205,6 +2205,7 @@
"3",
"current",
],
+ symbol_file: "stubslib.map.txt",
},
arch: {
arm64: {
@@ -2268,6 +2269,7 @@
"3",
"current",
],
+ symbol_file: "stubslib.map.txt",
},
target: {
host: {
diff --git a/snapshot/Android.bp b/snapshot/Android.bp
index 6cb318e..c384f8a 100644
--- a/snapshot/Android.bp
+++ b/snapshot/Android.bp
@@ -14,7 +14,6 @@
// Source file name convention is to include _snapshot as a
// file suffix for files that are generating snapshots.
srcs: [
- "host_fake_snapshot.go",
"host_snapshot.go",
"snapshot_base.go",
"util.go",
diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go
deleted file mode 100644
index 278247e..0000000
--- a/snapshot/host_fake_snapshot.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package snapshot
-
-import (
- "encoding/json"
- "path/filepath"
-
- "android/soong/android"
-)
-
-// The host_snapshot module creates a snapshot of host tools to be used
-// in a minimal source tree. In order to create the host_snapshot the
-// user must explicitly list the modules to be included. The
-// host-fake-snapshot, defined in this file, is a utility to help determine
-// which host modules are being used in the minimal source tree.
-//
-// The host-fake-snapshot is designed to run in a full source tree and
-// will result in a snapshot that contains an empty file for each host
-// tool found in the tree. The fake snapshot is only used to determine
-// the host modules that the minimal source tree depends on, hence the
-// snapshot uses an empty file for each module and saves on having to
-// actually build any tool to generate the snapshot. The fake snapshot
-// is compatible with an actual host_snapshot and is installed into a
-// minimal source tree via the development/vendor_snapshot/update.py
-// script.
-//
-// After generating the fake snapshot and installing into the minimal
-// source tree, the dependent modules are determined via the
-// development/vendor_snapshot/update.py script (see script for more
-// information). These modules are then used to define the actual
-// host_snapshot to be used. This is a similar process to the other
-// snapshots (vendor, recovery,...)
-//
-// Example
-//
-// Full source tree:
-// 1/ Generate fake host snapshot
-//
-// Minimal source tree:
-// 2/ Install the fake host snapshot
-// 3/ List the host modules used from the snapshot
-// 4/ Remove fake host snapshot
-//
-// Full source tree:
-// 4/ Create host_snapshot with modules identified in step 3
-//
-// Minimal source tree:
-// 5/ Install host snapshot
-// 6/ Build
-//
-// The host-fake-snapshot is a singleton module, that will be built
-// if HOST_FAKE_SNAPSHOT_ENABLE=true.
-
-func init() {
- registerHostSnapshotComponents(android.InitRegistrationContext)
-}
-
-// Add prebuilt information to snapshot data
-type hostSnapshotFakeJsonFlags struct {
- SnapshotJsonFlags
- Prebuilt bool `json:",omitempty"`
-}
-
-func registerHostSnapshotComponents(ctx android.RegistrationContext) {
- ctx.RegisterParallelSingletonType("host-fake-snapshot", HostToolsFakeAndroidSingleton)
-}
-
-type hostFakeSingleton struct {
- snapshotDir string
- zipFile android.OptionalPath
-}
-
-func (c *hostFakeSingleton) init() {
- c.snapshotDir = "host-fake-snapshot"
-
-}
-func HostToolsFakeAndroidSingleton() android.Singleton {
- singleton := &hostFakeSingleton{}
- singleton.init()
- return singleton
-}
-
-func (c *hostFakeSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.DeviceConfig().HostFakeSnapshotEnabled() {
- return
- }
- // Find all host binary modules add 'fake' versions to snapshot
- var outputs android.Paths
- seen := make(map[string]bool)
- var jsonData []hostSnapshotFakeJsonFlags
- prebuilts := make(map[string]bool)
-
- ctx.VisitAllModules(func(module android.Module) {
- if module.Target().Os != ctx.Config().BuildOSTarget.Os {
- return
- }
- if module.Target().Arch.ArchType != ctx.Config().BuildOSTarget.Arch.ArchType {
- return
- }
-
- if android.IsModulePrebuilt(module) {
- // Add non-prebuilt module name to map of prebuilts
- prebuilts[android.RemoveOptionalPrebuiltPrefix(module.Name())] = true
- return
- }
- if !module.Enabled(ctx) || module.IsHideFromMake() {
- return
- }
- apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
- if !apexInfo.IsForPlatform() {
- return
- }
- path := hostToolPath(module)
- if path.Valid() && path.String() != "" {
- outFile := filepath.Join(c.snapshotDir, path.String())
- if !seen[outFile] {
- seen[outFile] = true
- outputs = append(outputs, WriteStringToFileRule(ctx, "", outFile))
- jsonData = append(jsonData, hostSnapshotFakeJsonFlags{*hostJsonDesc(ctx, module), false})
- }
- }
- })
- // Update any module prebuilt information
- for idx := range jsonData {
- if _, ok := prebuilts[jsonData[idx].ModuleName]; ok {
- // Prebuilt exists for this module
- jsonData[idx].Prebuilt = true
- }
- }
- marsh, err := json.Marshal(jsonData)
- if err != nil {
- ctx.Errorf("host fake snapshot json marshal failure: %#v", err)
- return
- }
- outputs = append(outputs, WriteStringToFileRule(ctx, string(marsh), filepath.Join(c.snapshotDir, "host_snapshot.json")))
- c.zipFile = zipSnapshot(ctx, c.snapshotDir, c.snapshotDir, outputs)
-
-}
-func (c *hostFakeSingleton) MakeVars(ctx android.MakeVarsContext) {
- if !c.zipFile.Valid() {
- return
- }
- ctx.Phony(
- "host-fake-snapshot",
- c.zipFile.Path())
-
- ctx.DistForGoal(
- "host-fake-snapshot",
- c.zipFile.Path())
-
-}
diff --git a/snapshot/host_test.go b/snapshot/host_test.go
index ab9fedd..c68fdaf 100644
--- a/snapshot/host_test.go
+++ b/snapshot/host_test.go
@@ -107,17 +107,6 @@
var prepareForFakeHostTest = android.GroupFixturePreparers(
prepareForHostTest,
android.FixtureWithRootAndroidBp(hostTestBp),
- android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
- registerHostSnapshotComponents(ctx)
- }),
-)
-
-// Prepare for fake host snapshot test enabled
-var prepareForFakeHostTestEnabled = android.GroupFixturePreparers(
- prepareForFakeHostTest,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.HostFakeSnapshotEnabled = true
- }),
)
// Validate that a hostSnapshot object is created containing zip files and JSON file
@@ -140,31 +129,3 @@
}
}
-
-// Validate fake host snapshot contains binary modules as well as the JSON meta file
-func TestFakeHostSnapshotEnable(t *testing.T) {
- result := prepareForFakeHostTestEnabled.RunTest(t)
- t.Helper()
- bins := []string{"foo", "bar"}
- ctx := result.TestContext.SingletonForTests("host-fake-snapshot")
- if ctx.MaybeOutput(filepath.Join("host-fake-snapshot", "host_snapshot.json")).Rule == nil {
- t.Error("Manifest file not found")
- }
- for _, bin := range bins {
- if ctx.MaybeOutput(filepath.Join("host-fake-snapshot", hostTestBinOut(bin))).Rule == nil {
- t.Error("Binary file ", bin, "not found")
- }
-
- }
-}
-
-// Validate not fake host snapshot if HostFakeSnapshotEnabled has not been set to true
-func TestFakeHostSnapshotDisable(t *testing.T) {
- result := prepareForFakeHostTest.RunTest(t)
- t.Helper()
- ctx := result.TestContext.SingletonForTests("host-fake-snapshot")
- if len(ctx.AllOutputs()) != 0 {
- t.Error("Fake host snapshot not empty when disabled")
- }
-
-}
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 8dc1630..794003d 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -70,13 +70,14 @@
# m droid, build sbom later in case additional dependencies might be built and included in partition images.
run_soong "${out_dir}" "droid dump.erofs lz4"
+ soong_sbom_out=$out_dir/soong/sbom/$target_product
product_out=$out_dir/target/product/vsoc_x86_64
sbom_test=$product_out/sbom_test
mkdir -p $sbom_test
cp $product_out/*.img $sbom_test
- # m sbom
- run_soong "${out_dir}" sbom
+ # m sbom soong-sbom
+ run_soong "${out_dir}" "sbom soong-sbom"
# Generate installed file list from .img files in PRODUCT_OUT
dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
@@ -118,6 +119,7 @@
partition_name=$(basename $f | cut -d. -f1)
file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+ files_in_soong_spdx_file="${sbom_test}/soong-sbom-${partition_name}-files-in-spdx.txt"
rm "$file_list_file" > /dev/null 2>&1 || true
all_dirs="/"
while [ ! -z "$all_dirs" ]; do
@@ -145,6 +147,7 @@
done
sort -n -o "$file_list_file" "$file_list_file"
+ # Diff the file list from image and file list in SBOM created by Make
grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' > "$files_in_spdx_file"
if [ "$partition_name" = "system" ]; then
# system partition is mounted to /, so include FileName starts with /root/ too.
@@ -154,6 +157,17 @@
echo ============ Diffing files in $f and SBOM
diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
+
+ # Diff the file list from image and file list in SBOM created by Soong
+ grep "FileName: /${partition_name}/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: //' > "$files_in_soong_spdx_file"
+ if [ "$partition_name" = "system" ]; then
+ # system partition is mounted to /, so include FileName starts with /root/ too.
+ grep "FileName: /root/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: \/root//' >> "$files_in_soong_spdx_file"
+ fi
+ sort -n -o "$files_in_soong_spdx_file" "$files_in_soong_spdx_file"
+
+ echo ============ Diffing files in $f and SBOM created by Soong
+ diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" ""
done
RAMDISK_IMAGES="$product_out/ramdisk.img"
@@ -161,6 +175,7 @@
partition_name=$(basename $f | cut -d. -f1)
file_list_file="${sbom_test}/sbom-${partition_name}-files.txt"
files_in_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-spdx.txt"
+ files_in_soong_spdx_file="${sbom_test}/sbom-${partition_name}-files-in-soong-spdx.txt"
# lz4 decompress $f to stdout
# cpio list all entries like ls -l
# grep filter normal files and symlinks
@@ -170,11 +185,19 @@
grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
+ grep "FileName: /${partition_name}/" $soong_sbom_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_soong_spdx_file"
+
echo ============ Diffing files in $f and SBOM
diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
+
+ echo ============ Diffing files in $f and SBOM created by Soong
+ diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" ""
done
verify_package_verification_code "$product_out/sbom.spdx"
+ verify_package_verification_code "$soong_sbom_out/sbom.spdx"
+
+ verify_packages_licenses "$soong_sbom_out/sbom.spdx"
# Teardown
cleanup "${out_dir}"
@@ -213,6 +236,41 @@
fi
}
+function verify_packages_licenses {
+ local sbom_file="$1"; shift
+
+ num_of_packages=$(grep 'PackageName:' $sbom_file | wc -l)
+ num_of_declared_licenses=$(grep 'PackageLicenseDeclared:' $sbom_file | wc -l)
+ if [ "$num_of_packages" = "$num_of_declared_licenses" ]
+ then
+ echo "Number of packages with declared license is correct."
+ else
+ echo "Number of packages with declared license is WRONG."
+ exit 1
+ fi
+
+ # PRODUCT and 7 prebuilt packages have "PackageLicenseDeclared: NOASSERTION"
+ # All other packages have declared licenses
+ num_of_packages_with_noassertion_license=$(grep 'PackageLicenseDeclared: NOASSERTION' $sbom_file | wc -l)
+ if [ $num_of_packages_with_noassertion_license = 15 ]
+ then
+ echo "Number of packages with NOASSERTION license is correct."
+ else
+ echo "Number of packages with NOASSERTION license is WRONG."
+ exit 1
+ fi
+
+ num_of_files=$(grep 'FileName:' $sbom_file | wc -l)
+ num_of_concluded_licenses=$(grep 'LicenseConcluded:' $sbom_file | wc -l)
+ if [ "$num_of_files" = "$num_of_concluded_licenses" ]
+ then
+ echo "Number of files with concluded license is correct."
+ else
+ echo "Number of files with concluded license is WRONG."
+ exit 1
+ fi
+}
+
function test_sbom_unbundled_apex {
# Setup
out_dir="$(setup)"
@@ -274,7 +332,7 @@
target_product=aosp_cf_x86_64_phone
target_release=trunk_staging
-target_build_variant=userdebug
+target_build_variant=eng
for i in "$@"; do
case $i in
TARGET_PRODUCT=*)
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index ee286f6..fcf29c5 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,6 +36,7 @@
"blueprint-bootstrap",
"blueprint-microfactory",
"soong-android",
+ "soong-elf",
"soong-finder",
"soong-remoteexec",
"soong-shared",
diff --git a/ui/build/build.go b/ui/build/build.go
index 03d8392..49ac791 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -22,6 +22,7 @@
"sync"
"text/template"
+ "android/soong/elf"
"android/soong/ui/metrics"
)
@@ -210,9 +211,38 @@
}
}
+func abfsBuildStarted(ctx Context, config Config) {
+ abfsBox := config.PrebuiltBuildTool("abfsbox")
+ cmdArgs := []string{"build-started", "--"}
+ cmdArgs = append(cmdArgs, config.Arguments()...)
+ cmd := Command(ctx, config, "abfsbox", abfsBox, cmdArgs...)
+ cmd.Sandbox = noSandbox
+ cmd.RunAndPrintOrFatal()
+}
+
+func abfsBuildFinished(ctx Context, config Config, finished bool) {
+ var errMsg string
+ if !finished {
+ errMsg = "build was interrupted"
+ }
+ abfsBox := config.PrebuiltBuildTool("abfsbox")
+ cmdArgs := []string{"build-finished", "-e", errMsg, "--"}
+ cmdArgs = append(cmdArgs, config.Arguments()...)
+ cmd := Command(ctx, config, "abfsbox", abfsBox, cmdArgs...)
+ cmd.RunAndPrintOrFatal()
+}
+
// Build the tree. Various flags in `config` govern which components of
// the build to run.
func Build(ctx Context, config Config) {
+ done := false
+ if config.UseABFS() {
+ abfsBuildStarted(ctx, config)
+ defer func() {
+ abfsBuildFinished(ctx, config, done)
+ }()
+ }
+
ctx.Verboseln("Starting build with args:", config.Arguments())
ctx.Verboseln("Environment:", config.Environment().Environ())
@@ -344,11 +374,23 @@
installCleanIfNecessary(ctx, config)
}
runNinjaForBuild(ctx, config)
+ updateBuildIdDir(ctx, config)
}
if what&RunDistActions != 0 {
runDistActions(ctx, config)
}
+ done = true
+}
+
+func updateBuildIdDir(ctx Context, config Config) {
+ ctx.BeginTrace(metrics.RunShutdownTool, "update_build_id_dir")
+ defer ctx.EndTrace()
+
+ symbolsDir := filepath.Join(config.ProductOut(), "symbols")
+ if err := elf.UpdateBuildIdDir(symbolsDir); err != nil {
+ ctx.Printf("failed to update %s/.build-id: %v", symbolsDir, err)
+ }
}
func evaluateWhatToRun(config Config, verboseln func(v ...interface{})) int {
diff --git a/ui/build/config.go b/ui/build/config.go
index 2470f84..631b76f 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1270,9 +1270,25 @@
if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
return false
}
+ if c.UseABFS() {
+ return false
+ }
return true
}
+func (c *configImpl) UseABFS() bool {
+ if v, ok := c.environ.Get("NO_ABFS"); ok {
+ v = strings.ToLower(strings.TrimSpace(v))
+ if v == "true" || v == "1" {
+ return false
+ }
+ }
+
+ abfsBox := c.PrebuiltBuildTool("abfsbox")
+ err := exec.Command(abfsBox, "hash", srcDirFileCheck).Run()
+ return err == nil
+}
+
func (c *configImpl) UseRBE() bool {
// These alternate modes of running Soong do not use RBE / reclient.
if c.Queryview() || c.JsonModuleGraph() {
@@ -1585,6 +1601,23 @@
}
}
+func (c *configImpl) KatiBin() string {
+ binName := "ckati"
+ if c.UseABFS() {
+ binName = "ckati-wrap"
+ }
+
+ return c.PrebuiltBuildTool(binName)
+}
+
+func (c *configImpl) NinjaBin() string {
+ binName := "ninja"
+ if c.UseABFS() {
+ binName = "ninjago"
+ }
+ return c.PrebuiltBuildTool(binName)
+}
+
func (c *configImpl) PrebuiltBuildTool(name string) string {
if v, ok := c.environ.Get("SANITIZE_HOST"); ok {
if sanitize := strings.Fields(v); inList("address", sanitize) {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index b1222fe..b42edb0 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -22,6 +22,7 @@
"os"
"path/filepath"
"reflect"
+ "runtime"
"strings"
"testing"
@@ -1043,12 +1044,13 @@
},
},
{
+ // RBE is only supported on linux.
name: "use rbe",
environ: Environment{"USE_RBE=1"},
expectedBuildConfig: &smpb.BuildConfig{
ForceUseGoma: proto.Bool(false),
UseGoma: proto.Bool(false),
- UseRbe: proto.Bool(true),
+ UseRbe: proto.Bool(runtime.GOOS == "linux"),
NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
},
},
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index e77df44..5df3a95 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -93,7 +93,7 @@
defer tool.Finish()
cmd := Command(ctx, config, "dumpvars",
- config.PrebuiltBuildTool("ckati"),
+ config.KatiBin(),
"-f", "build/make/core/config.mk",
"--color_warnings",
"--kati_stats",
diff --git a/ui/build/kati.go b/ui/build/kati.go
index d599c99..a0efd2c 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -84,7 +84,7 @@
// arguments, and a custom function closure to mutate the environment Kati runs
// in.
func runKati(ctx Context, config Config, extraSuffix string, args []string, envFunc func(*Environment)) {
- executable := config.PrebuiltBuildTool("ckati")
+ executable := config.KatiBin()
// cKati arguments.
args = append([]string{
// Instead of executing commands directly, generate a Ninja file.
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 1935e72..b5e74b4 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -49,7 +49,7 @@
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()
- executable := config.PrebuiltBuildTool("ninja")
+ executable := config.NinjaBin()
args := []string{
"-d", "keepdepfile",
"-d", "keeprsp",
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 81c678d..6c9a1eb 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -86,28 +86,28 @@
// This list specifies whether a particular binary from $PATH is allowed to be
// run during the build. For more documentation, see path_interposer.go .
var Configuration = map[string]PathConfig{
- "bash": Allowed,
- "diff": Allowed,
- "dlv": Allowed,
- "expr": Allowed,
- "fuser": Allowed,
- "gcert": Allowed,
- "gcertstatus": Allowed,
- "gcloud": Allowed,
- "git": Allowed,
- "hexdump": Allowed,
- "jar": Allowed,
- "java": Allowed,
- "javap": Allowed,
- "lsof": Allowed,
- "openssl": Allowed,
- "pstree": Allowed,
- "rsync": Allowed,
- "sh": Allowed,
- "stubby": Allowed,
- "tr": Allowed,
- "unzip": Allowed,
- "zip": Allowed,
+ "bash": Allowed,
+ "diff": Allowed,
+ "dlv": Allowed,
+ "expr": Allowed,
+ "fuser": Allowed,
+ "gcert": Allowed,
+ "gcertstatus": Allowed,
+ "gcloud": Allowed,
+ "git": Allowed,
+ "hexdump": Allowed,
+ "jar": Allowed,
+ "java": Allowed,
+ "javap": Allowed,
+ "lsof": Allowed,
+ "openssl": Allowed,
+ "pstree": Allowed,
+ "rsync": Allowed,
+ "sh": Allowed,
+ "stubby": 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/rbe_test.go b/ui/build/rbe_test.go
index 266f76b..d1b8e26 100644
--- a/ui/build/rbe_test.go
+++ b/ui/build/rbe_test.go
@@ -19,6 +19,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "runtime"
"strings"
"testing"
@@ -26,6 +27,10 @@
)
func TestDumpRBEMetrics(t *testing.T) {
+ // RBE is only supported on linux.
+ if runtime.GOOS != "linux" {
+ t.Skip("RBE is only supported on linux")
+ }
ctx := testContext()
tests := []struct {
description string
@@ -82,6 +87,10 @@
}
func TestDumpRBEMetricsErrors(t *testing.T) {
+ // RBE is only supported on linux.
+ if runtime.GOOS != "linux" {
+ t.Skip("RBE is only supported on linux")
+ }
ctx := testContext()
tests := []struct {
description string
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index edb3b66..5c3fec1 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -200,6 +200,9 @@
// Only log important warnings / errors
"-q",
}
+ if c.config.UseABFS() {
+ sandboxArgs = append(sandboxArgs, "-B", "{ABFS_DIR}")
+ }
// Mount srcDir RW allowlists as Read-Write
if len(c.config.sandboxConfig.SrcDirRWAllowlist()) > 0 && !c.config.sandboxConfig.SrcDirIsRO() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index e18cc25..2ccdfec 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -661,7 +661,7 @@
}
ninjaArgs = append(ninjaArgs, targets...)
- ninjaCmd := config.PrebuiltBuildTool("ninja")
+ ninjaCmd := config.NinjaBin()
if config.useN2 {
ninjaCmd = config.PrebuiltBuildTool("n2")
}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 687ad6f..3faa94d 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -15,14 +15,16 @@
package build
import (
- "android/soong/ui/metrics"
- "android/soong/ui/status"
"bufio"
"fmt"
"path/filepath"
+ "regexp"
"runtime"
"sort"
"strings"
+
+ "android/soong/ui/metrics"
+ "android/soong/ui/status"
)
// Checks for files in the out directory that have a rule that depends on them but no rule to
@@ -84,6 +86,10 @@
// before running soong and ninja.
releaseConfigDir := filepath.Join(outDir, "soong", "release-config")
+ // out/target/product/<xxxxx>/build_fingerprint.txt is a source file created in sysprop.mk
+ // ^out/target/product/[^/]+/build_fingerprint.txt$
+ buildFingerPrintFilePattern := regexp.MustCompile("^" + filepath.Join(outDir, "target", "product") + "/[^/]+/build_fingerprint.txt$")
+
danglingRules := make(map[string]bool)
scanner := bufio.NewScanner(stdout)
@@ -100,7 +106,8 @@
line == dexpreoptConfigFilePath ||
line == buildDatetimeFilePath ||
line == bpglob ||
- strings.HasPrefix(line, releaseConfigDir) {
+ strings.HasPrefix(line, releaseConfigDir) ||
+ buildFingerPrintFilePattern.MatchString(line) {
// Leaf node is in one of Soong's bootstrap directories, which do not have
// full build rules in the primary build.ninja file.
continue
diff --git a/ui/terminal/format.go b/ui/terminal/format.go
index 241a1dd..01f8b0d 100644
--- a/ui/terminal/format.go
+++ b/ui/terminal/format.go
@@ -23,26 +23,28 @@
)
type formatter struct {
- format string
- quiet bool
- start time.Time
+ colorize bool
+ format string
+ quiet bool
+ start time.Time
}
// newFormatter returns a formatter for formatting output to
// the terminal in a format similar to Ninja.
// format takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func newFormatter(format string, quiet bool) formatter {
+func newFormatter(colorize bool, format string, quiet bool) formatter {
return formatter{
- format: format,
- quiet: quiet,
- start: time.Now(),
+ colorize: colorize,
+ format: format,
+ quiet: quiet,
+ start: time.Now(),
}
}
func (s formatter) message(level status.MsgLevel, message string) string {
if level >= status.ErrorLvl {
- return fmt.Sprintf("FAILED: %s", message)
+ return fmt.Sprintf("%s %s", s.failedString(), message)
} else if level > status.StatusLvl {
return fmt.Sprintf("%s%s", level.Prefix(), message)
} else if level == status.StatusLvl {
@@ -127,9 +129,9 @@
if result.Error != nil {
targets := strings.Join(result.Outputs, " ")
if s.quiet || result.Command == "" {
- ret = fmt.Sprintf("FAILED: %s\n%s", targets, result.Output)
+ ret = fmt.Sprintf("%s %s\n%s", s.failedString(), targets, result.Output)
} else {
- ret = fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output)
+ ret = fmt.Sprintf("%s %s\n%s\n%s", s.failedString(), targets, result.Command, result.Output)
}
} else if result.Output != "" {
ret = result.Output
@@ -141,3 +143,11 @@
return ret
}
+
+func (s formatter) failedString() string {
+ failed := "FAILED:"
+ if s.colorize {
+ failed = ansi.red() + ansi.bold() + failed + ansi.regular()
+ }
+ return failed
+}
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 2ad174f..92f2994 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -27,9 +27,10 @@
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput {
- formatter := newFormatter(statusFormat, quietBuild)
+ canUseSmartFormatting := !forceSimpleOutput && isSmartTerminal(w)
+ formatter := newFormatter(canUseSmartFormatting, statusFormat, quietBuild)
- if !forceSimpleOutput && isSmartTerminal(w) {
+ if canUseSmartFormatting {
return NewSmartStatusOutput(w, formatter)
} else {
return NewSimpleStatusOutput(w, formatter, forceKeepANSI)
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 8dd1809..991eca0 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -58,7 +58,7 @@
{
name: "action with error",
calls: actionsWithError,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
},
{
@@ -70,7 +70,7 @@
{
name: "messages",
calls: actionsWithMessages,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\n\x1b[31m\x1b[1mFAILED:\x1b[0m error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
},
{
@@ -362,7 +362,7 @@
stat.Flush()
- w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n"
+ w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n"
if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
@@ -407,7 +407,7 @@
stat.Flush()
- w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n"
+ w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n"
if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
@@ -445,7 +445,7 @@
stat.Flush()
- w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nFAILED: \nOutput2\n"
+ w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput2\n"
if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)