Merge "Stop exporting systemserverclasspath_fragment when targeting S" into tm-dev am: 0147aca453
Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/19135262
Change-Id: I9039499819e938deb9d13557bdee26fc56bd6f4c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/android/defaults.go b/android/defaults.go
index 8b121f6..54f44bc 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "bytes"
+ "fmt"
"reflect"
"github.com/google/blueprint"
@@ -67,9 +69,11 @@
// Set the property structures into which defaults will be added.
setProperties(props []interface{}, variableProperties interface{})
- // Apply defaults from the supplied Defaults to the property structures supplied to
+ // Apply defaults from the supplied DefaultsModule to the property structures supplied to
// setProperties(...).
- applyDefaults(TopDownMutatorContext, []Defaults)
+ applyDefaults(TopDownMutatorContext, []DefaultsModule)
+
+ applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
// Set the hook to be called after any defaults have been applied.
//
@@ -115,9 +119,23 @@
Defaults_visibility []string
}
+// AdditionalDefaultsProperties contains properties of defaults modules which
+// can have other defaults applied.
+type AdditionalDefaultsProperties struct {
+
+ // The list of properties set by the default whose values must not be changed by any module that
+ // applies these defaults. It is an error if a property is not supported by the defaults module or
+ // has not been set to a non-zero value. If this contains "*" then that must be the only entry in
+ // which case all properties that are set on this defaults will be protected (except the
+ // protected_properties and visibility.
+ Protected_properties []string
+}
+
type DefaultsModuleBase struct {
DefaultableModuleBase
+ defaultsProperties AdditionalDefaultsProperties
+
// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
// target. This is primarily useful for modules that were architecture specific and instead are
// handled in Bazel as a select().
@@ -151,6 +169,18 @@
// DefaultsModuleBase will type-assert to the Defaults interface.
isDefaults() bool
+ // additionalDefaultableProperties returns additional properties provided by the defaults which
+ // can themselves have defaults applied.
+ additionalDefaultableProperties() []interface{}
+
+ // protectedProperties returns the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ protectedProperties() []string
+
+ // setProtectedProperties sets the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ setProtectedProperties(protectedProperties []string)
+
// Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
@@ -167,6 +197,18 @@
Bazelable
}
+func (d *DefaultsModuleBase) additionalDefaultableProperties() []interface{} {
+ return []interface{}{&d.defaultsProperties}
+}
+
+func (d *DefaultsModuleBase) protectedProperties() []string {
+ return d.defaultsProperties.Protected_properties
+}
+
+func (d *DefaultsModuleBase) setProtectedProperties(protectedProperties []string) {
+ d.defaultsProperties.Protected_properties = protectedProperties
+}
+
func (d *DefaultsModuleBase) properties() []interface{} {
return d.defaultableProperties
}
@@ -190,6 +232,10 @@
&ApexProperties{},
&distProperties{})
+ // Additional properties of defaults modules that can themselves have
+ // defaults applied.
+ module.AddProperties(module.additionalDefaultableProperties()...)
+
// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
InitBazelModule(module)
initAndroidModuleBase(module)
@@ -218,6 +264,57 @@
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
+ AddLoadHook(module, func(ctx LoadHookContext) {
+
+ protectedProperties := module.protectedProperties()
+ if len(protectedProperties) == 0 {
+ return
+ }
+
+ propertiesAvailable := map[string]struct{}{}
+ propertiesSet := map[string]struct{}{}
+
+ // A defaults tracker which will keep track of which properties have been set on this module.
+ collector := func(defaults DefaultsModule, property string, dstValue interface{}, srcValue interface{}) bool {
+ value := reflect.ValueOf(dstValue)
+ propertiesAvailable[property] = struct{}{}
+ if !value.IsZero() {
+ propertiesSet[property] = struct{}{}
+ }
+ // Skip all the properties so that there are no changes to the defaults.
+ return false
+ }
+
+ // Try and apply this module's defaults to itself, so that the properties can be collected but
+ // skip all the properties so it doesn't actually do anything.
+ module.applySingleDefaultsWithTracker(ctx, module, collector)
+
+ if InList("*", protectedProperties) {
+ if len(protectedProperties) != 1 {
+ ctx.PropertyErrorf("protected_properties", `if specified then "*" must be the only property listed`)
+ return
+ }
+
+ // Do not automatically protect the protected_properties property.
+ delete(propertiesSet, "protected_properties")
+
+ // Or the visibility property.
+ delete(propertiesSet, "visibility")
+
+ // Replace the "*" with the names of all the properties that have been set.
+ protectedProperties = SortedStringKeys(propertiesSet)
+ module.setProtectedProperties(protectedProperties)
+ } else {
+ for _, property := range protectedProperties {
+ if _, ok := propertiesAvailable[property]; !ok {
+ ctx.PropertyErrorf(property, "property is not supported by this module type %q",
+ ctx.ModuleType())
+ } else if _, ok := propertiesSet[property]; !ok {
+ ctx.PropertyErrorf(property, "is not set; protected properties must be explicitly set")
+ }
+ }
+ }
+ })
}
var _ Defaults = (*DefaultsModuleBase)(nil)
@@ -269,35 +366,204 @@
b.setNamespacedVariableProps(dst)
}
+// defaultValueInfo contains information about each default value that applies to a protected
+// property.
+type defaultValueInfo struct {
+ // The DefaultsModule providing the value, which may be defined on that module or applied as a
+ // default from other modules.
+ module Module
+
+ // The default value, as returned by getComparableValue
+ defaultValue reflect.Value
+}
+
+// protectedPropertyInfo contains information about each property that has to be protected when
+// applying defaults.
+type protectedPropertyInfo struct {
+ // True if the property was set on the module to which defaults are applied, this is an error.
+ propertySet bool
+
+ // The original value of the property on the module, as returned by getComparableValue.
+ originalValue reflect.Value
+
+ // A list of defaults for the property that are being applied.
+ defaultValues []defaultValueInfo
+}
+
+// getComparableValue takes a reflect.Value that may be a pointer to another value and returns a
+// reflect.Value to the underlying data or the original if was not a pointer or was nil. The
+// returned values can then be compared for equality.
+func getComparableValue(value reflect.Value) reflect.Value {
+ if value.IsZero() {
+ return value
+ }
+ for value.Kind() == reflect.Ptr {
+ value = value.Elem()
+ }
+ return value
+}
+
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
- defaultsList []Defaults) {
+ defaultsList []DefaultsModule) {
+
+ // Collate information on all the properties protected by each of the default modules applied
+ // to this module.
+ allProtectedProperties := map[string]*protectedPropertyInfo{}
+ for _, defaults := range defaultsList {
+ for _, property := range defaults.protectedProperties() {
+ info := allProtectedProperties[property]
+ if info == nil {
+ info = &protectedPropertyInfo{}
+ allProtectedProperties[property] = info
+ }
+ }
+ }
+
+ // If there are any protected properties then collate information about attempts to change them.
+ var protectedPropertyInfoCollector defaultsTrackerFunc
+ if len(allProtectedProperties) > 0 {
+ protectedPropertyInfoCollector = func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool {
+
+ // If the property is not protected then return immediately.
+ info := allProtectedProperties[property]
+ if info == nil {
+ return true
+ }
+
+ currentValue := reflect.ValueOf(dstValue)
+ if info.defaultValues == nil {
+ info.propertySet = !currentValue.IsZero()
+ info.originalValue = getComparableValue(currentValue)
+ }
+
+ defaultValue := reflect.ValueOf(srcValue)
+ if !defaultValue.IsZero() {
+ info.defaultValues = append(info.defaultValues,
+ defaultValueInfo{defaults, getComparableValue(defaultValue)})
+ }
+
+ return true
+ }
+ }
for _, defaults := range defaultsList {
if ctx.Config().runningAsBp2Build {
applyNamespacedVariableDefaults(defaults, ctx)
}
- for _, prop := range defaultable.defaultableProperties {
- if prop == defaultable.defaultableVariableProperties {
- defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
- } else {
- defaultable.applyDefaultProperties(ctx, defaults, prop)
+
+ defaultable.applySingleDefaultsWithTracker(ctx, defaults, protectedPropertyInfoCollector)
+ }
+
+ // Check the status of any protected properties.
+ for property, info := range allProtectedProperties {
+ if len(info.defaultValues) == 0 {
+ // No defaults were applied to the protected properties. Possibly because this module type
+ // does not support any of them.
+ continue
+ }
+
+ // Check to make sure that there are no conflicts between the defaults.
+ conflictingDefaults := false
+ previousDefaultValue := reflect.ValueOf(false)
+ for _, defaultInfo := range info.defaultValues {
+ defaultValue := defaultInfo.defaultValue
+ if previousDefaultValue.IsZero() {
+ previousDefaultValue = defaultValue
+ } else if !reflect.DeepEqual(previousDefaultValue.Interface(), defaultValue.Interface()) {
+ conflictingDefaults = true
+ break
}
}
+
+ if conflictingDefaults {
+ var buf bytes.Buffer
+ for _, defaultInfo := range info.defaultValues {
+ buf.WriteString(fmt.Sprintf("\n defaults module %q provides value %#v",
+ ctx.OtherModuleName(defaultInfo.module), defaultInfo.defaultValue))
+ }
+ result := buf.String()
+ ctx.ModuleErrorf("has conflicting default values for protected property %q:%s", property, result)
+ continue
+ }
+
+ // Now check to see whether there the current module tried to override/append to the defaults.
+ if info.propertySet {
+ originalValue := info.originalValue
+ // Just compare against the first defaults.
+ defaultValue := info.defaultValues[0].defaultValue
+ defaults := info.defaultValues[0].module
+
+ if originalValue.Kind() == reflect.Slice {
+ ctx.ModuleErrorf("attempts to append %q to protected property %q's value of %q defined in module %q",
+ originalValue,
+ property,
+ defaultValue,
+ ctx.OtherModuleName(defaults))
+ } else {
+ same := reflect.DeepEqual(originalValue.Interface(), defaultValue.Interface())
+ message := ""
+ if same {
+ message = fmt.Sprintf(" with a matching value (%#v) so this property can simply be removed.", originalValue)
+ } else {
+ message = fmt.Sprintf(" with a different value (override %#v with %#v) so removing the property may necessitate other changes.", defaultValue, originalValue)
+ }
+ ctx.ModuleErrorf("attempts to override protected property %q defined in module %q%s",
+ property,
+ ctx.OtherModuleName(defaults), message)
+ }
+ }
+ }
+}
+
+func (defaultable *DefaultableModuleBase) applySingleDefaultsWithTracker(ctx EarlyModuleContext, defaults DefaultsModule, tracker defaultsTrackerFunc) {
+ for _, prop := range defaultable.defaultableProperties {
+ var err error
+ if prop == defaultable.defaultableVariableProperties {
+ err = defaultable.applyDefaultVariableProperties(defaults, prop, tracker)
+ } else {
+ err = defaultable.applyDefaultProperties(defaults, prop, tracker)
+ }
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
+ }
+}
+
+// defaultsTrackerFunc is the type of a function that can be used to track how defaults are applied.
+type defaultsTrackerFunc func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool
+
+// filterForTracker wraps a defaultsTrackerFunc in a proptools.ExtendPropertyFilterFunc
+func filterForTracker(defaults DefaultsModule, tracker defaultsTrackerFunc) proptools.ExtendPropertyFilterFunc {
+ if tracker == nil {
+ return nil
+ }
+ return func(property string,
+ dstField, srcField reflect.StructField,
+ dstValue, srcValue interface{}) (bool, error) {
+
+ apply := tracker(defaults, property, dstValue, srcValue)
+ return apply, nil
}
}
// Product variable properties need special handling, the type of the filtered product variable
// property struct may not be identical between the defaults module and the defaultable module.
// Use PrependMatchingProperties to apply whichever properties match.
-func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
+ defaultableProp interface{}, tracker defaultsTrackerFunc) error {
if defaultableProp == nil {
- return
+ return nil
}
defaultsProp := defaults.productVariableProperties()
if defaultsProp == nil {
- return
+ return nil
}
dst := []interface{}{
@@ -307,31 +573,26 @@
proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
}
- err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
+ filter := filterForTracker(defaults, tracker)
+
+ return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
+ defaultableProp interface{}, checker defaultsTrackerFunc) error {
+
+ filter := filterForTracker(defaults, checker)
for _, def := range defaults.properties() {
if proptools.TypeEqual(defaultableProp, def) {
- err := proptools.PrependProperties(defaultableProp, def, nil)
+ err := proptools.PrependProperties(defaultableProp, def, filter)
if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
+ return err
}
}
}
+
+ return nil
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -348,12 +609,12 @@
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
if len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []Defaults
+ var defaultsList []DefaultsModule
seen := make(map[Defaults]bool)
ctx.WalkDeps(func(module, parent Module) bool {
if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(Defaults); ok {
+ if defaults, ok := module.(DefaultsModule); ok {
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index a7542ab..d80f40c 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,7 +19,14 @@
)
type defaultsTestProperties struct {
- Foo []string
+ Foo []string
+ Bar []string
+ Nested struct {
+ Fizz *bool
+ }
+ Other struct {
+ Buzz *string
+ }
}
type defaultsTestModule struct {
@@ -130,3 +137,167 @@
// TODO: missing transitive defaults is currently not handled
_ = missingTransitiveDefaults
}
+
+func TestProtectedProperties_ProtectedPropertyNotSet(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "module \"transitive\": foo: is not set; protected properties must be explicitly set")).
+ RunTest(t)
+}
+
+func TestProtectedProperties_ProtectedPropertyNotLeaf(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["nested"],
+ nested: {
+ fizz: true,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "transitive": nested: property is not supported by this module type "defaults"\E`)).
+ RunTest(t)
+}
+
+// TestProtectedProperties_ApplyDefaults makes sure that the protected_properties property has
+// defaults applied.
+func TestProtectedProperties_HasDefaultsApplied(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ foo: ["transitive"],
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ protected_properties: ["bar"],
+ bar: ["defaults"],
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"foo", "bar"}, defaults.protectedProperties())
+}
+
+// TestProtectedProperties_ProtectAllProperties makes sure that protected_properties: ["*"] protects
+// all properties.
+func TestProtectedProperties_ProtectAllProperties(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "transitive",
+ },
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ visibility: ["//visibility:private"],
+ protected_properties: ["*"],
+ foo: ["other"],
+ bar: ["defaults"],
+ nested: {
+ fizz: true,
+ }
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"other.buzz", "bar", "foo", "nested.fizz"},
+ defaults.protectedProperties())
+}
+
+func TestProtectedProperties_DetectedOverride(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults",
+ protected_properties: ["foo", "nested.fizz"],
+ foo: ["defaults"],
+ nested: {
+ fizz: true,
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults"],
+ foo: ["module"],
+ nested: {
+ fizz: false,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ `\Qmodule "foo": attempts to append ["module"] to protected property "foo"'s value of ["defaults"] defined in module "defaults"\E`,
+ `\Qmodule "foo": attempts to override protected property "nested.fizz" defined in module "defaults" with a different value (override true with false) so removing the property may necessitate other changes.\E`,
+ })).RunTest(t)
+}
+
+func TestProtectedProperties_DefaultsConflict(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults1",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "value",
+ },
+ }
+
+ defaults {
+ name: "defaults2",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "another",
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults1", "defaults2"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "foo": has conflicting default values for protected property "other.buzz":
+ defaults module "defaults1" provides value "value"
+ defaults module "defaults2" provides value "another"\E`,
+ )).RunTest(t)
+}
diff --git a/android/sdk.go b/android/sdk.go
index 1967a32..20ed794 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -974,3 +974,10 @@
}
var ExportedComponentsInfoProvider = blueprint.NewProvider(ExportedComponentsInfo{})
+
+// AdditionalSdkInfo contains additional properties to add to the generated SDK info file.
+type AdditionalSdkInfo struct {
+ Properties map[string]interface{}
+}
+
+var AdditionalSdkInfoProvider = blueprint.NewProvider(AdditionalSdkInfo{})
diff --git a/apex/Android.bp b/apex/Android.bp
index 41224ec..c4e6456 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -24,6 +24,7 @@
"apex.go",
"apex_singleton.go",
"builder.go",
+ "constants.go",
"deapexer.go",
"key.go",
"prebuilt.go",
diff --git a/apex/builder.go b/apex/builder.go
index a21fcb8..e3c4476 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -82,6 +82,11 @@
Description: "prepare ${out}",
}, "provideNativeLibs", "requireNativeLibs", "opt")
+ stripCommentsApexManifestRule = pctx.StaticRule("stripCommentsApexManifestRule", blueprint.RuleParams{
+ Command: `sed '/^\s*\/\//d' $in > $out`,
+ Description: "strip lines starting with // ${in}=>${out}",
+ })
+
stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
CommandDeps: []string{"${conv_apex_manifest}"},
@@ -107,6 +112,7 @@
`--canned_fs_config ${canned_fs_config} ` +
`--include_build_info ` +
`--payload_type image ` +
+ `--apex_version ${apex_version} ` +
`--key ${key} ${opt_flags} ${image_dir} ${out} `,
CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
"${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}",
@@ -114,7 +120,7 @@
Rspfile: "${out}.copy_commands",
RspfileContent: "${copy_commands}",
Description: "APEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
+ }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type", "apex_version")
zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -122,12 +128,13 @@
`APEXER_TOOL_PATH=${tool_path} ` +
`${apexer} --force --manifest ${manifest} ` +
`--payload_type zip ` +
+ `--apex_version ${apex_version} ` +
`${image_dir} ${out} `,
CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
Rspfile: "${out}.copy_commands",
RspfileContent: "${copy_commands}",
Description: "ZipAPEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "manifest")
+ }, "tool_path", "image_dir", "copy_commands", "manifest", "apex_version")
apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
blueprint.RuleParams{
@@ -205,10 +212,17 @@
optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
}
+ manifestJsonCommentsStripped := android.PathForModuleOut(ctx, "apex_manifest_comments_stripped.json")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: stripCommentsApexManifestRule,
+ Input: src,
+ Output: manifestJsonCommentsStripped,
+ })
+
manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
ctx.Build(pctx, android.BuildParams{
Rule: apexManifestRule,
- Input: src,
+ Input: manifestJsonCommentsStripped,
Output: manifestJsonFullOut,
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
@@ -670,6 +684,7 @@
"file_contexts": fileContexts.String(),
"canned_fs_config": cannedFsConfig.String(),
"key": a.privateKeyFile.String(),
+ "apex_version": defaultManifestVersion,
"opt_flags": strings.Join(optFlags, " "),
},
})
@@ -766,6 +781,7 @@
"image_dir": imageDir.String(),
"copy_commands": strings.Join(copyCommands, " && "),
"manifest": a.manifestPbOut.String(),
+ "apex_version": defaultManifestVersion,
},
})
}
diff --git a/apex/constants.go b/apex/constants.go
new file mode 100644
index 0000000..c68edb7
--- /dev/null
+++ b/apex/constants.go
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 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 apex
+
+// This file contains branch specific constants. They are stored in a separate
+// file to minimise the potential of merge conflicts between branches when
+// the code from the package is changed.
+
+// The default manifest version for all the modules on this branch.
+// This version code will be used only if there is no version field in the
+// module's apex_manifest.json. Release branches have their version injected
+// into apex_manifest.json by the tooling and will not use the version set
+// here. Developers can also set the version field locally in the
+// apex_manifest.json to build a module with a specific version.
+//
+// The value follows the schema from go/mainline-version-codes, and is chosen
+// based on the branch such that the builds from testing and development
+// branches will have a version higher than the prebuilts.
+// Versions per branch:
+// * x-dev - xx0090000 (where xx is the branch SDK level)
+// * AOSP - xx9990000
+// * x-mainline-prod - xx9990000
+// * master - 990090000
+const defaultManifestVersion = "339990000"
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 09cc352..893c52e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4076,7 +4076,7 @@
{
name: "assemble",
src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__"}, expectedIncludes, lastIncludes),
+ expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__", "-fdebug-default-version=4"}, expectedIncludes, lastIncludes),
},
}
diff --git a/cc/compiler.go b/cc/compiler.go
index eb5458f..383eed0 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -491,6 +491,10 @@
flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
+ // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
+ // end up in the dwarf data for crtend_so.S.
+ flags.Global.AsFlags = append(flags.Global.AsFlags, "-fdebug-default-version=4")
+
flags.Global.CppFlags = append(flags.Global.CppFlags, tc.Cppflags())
flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 4b3161b..3f8105c 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -183,8 +183,7 @@
touch(shared.JoinPath(topDir, queryviewMarker))
}
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler) {
- metricsDir := configuration.Getenv("LOG_DIR")
+func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
if len(metricsDir) < 1 {
fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
os.Exit(1)
@@ -238,7 +237,7 @@
// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
// or the actual Soong build for the build.ninja file. Returns the top level
// output file of the specific activity.
-func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
+func doChosenActivity(configuration android.Config, extraNinjaDeps []string, logDir string) string {
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateBazelWorkspace := bp2buildMarker != ""
generateQueryView := bazelQueryViewDir != ""
@@ -302,7 +301,7 @@
}
}
- writeMetrics(configuration, *ctx.EventHandler)
+ writeMetrics(configuration, *ctx.EventHandler, logDir)
return cmdlineArgs.OutFile
}
@@ -358,7 +357,11 @@
extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
}
- finalOutputFile := doChosenActivity(configuration, extraNinjaDeps)
+ // Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
+ // change between every CI build, so tracking it would require re-running Soong for every build.
+ logDir := availableEnv["LOG_DIR"]
+
+ finalOutputFile := doChosenActivity(configuration, extraNinjaDeps, logDir)
writeUsedEnvironmentFile(configuration, finalOutputFile)
}
diff --git a/java/base.go b/java/base.go
index 7aa2814..717c727 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1419,17 +1419,18 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
// Enable dex compilation for the APEX variants, unless it is disabled explicitly
+ compileDex := j.dexProperties.Compile_dex
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
- if j.dexProperties.Compile_dex == nil {
- j.dexProperties.Compile_dex = proptools.BoolPtr(true)
+ if compileDex == nil {
+ compileDex = proptools.BoolPtr(true)
}
if j.deviceProperties.Hostdex == nil {
j.deviceProperties.Hostdex = proptools.BoolPtr(true)
}
}
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) {
+ if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
if j.hasCode(ctx) {
if j.shouldInstrumentStatic(ctx) {
j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 3b1f7c0..20ea5ff 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -675,87 +675,16 @@
zipSyncCleanupCmd(rule, srcJarDir)
- rule.Build("metalava", "metalava merged")
-
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
+ d.generateCheckCurrentCheckedInApiIsUpToDateBuildRules(ctx)
- if len(d.Javadoc.properties.Out) > 0 {
- ctx.PropertyErrorf("out", "out property may not be combined with check_api")
- }
-
- apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
- removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
- baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
-
- if baselineFile.Valid() {
- ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
- }
-
- d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- // Diff command line.
- // -F matches the closest "opening" line, such as "package android {"
- // and " public class Intent {".
- diff := `diff -u -F '{ *$'`
-
- rule.Command().Text("( true")
- rule.Command().
- Text(diff).
- Input(apiFile).Input(d.apiFile)
-
- rule.Command().
- Text(diff).
- Input(removedApiFile).Input(d.removedApiFile)
-
- msg := fmt.Sprintf(`\n******************************\n`+
- `You have tried to change the API from what has been previously approved.\n\n`+
- `To make these errors go away, you have two choices:\n`+
- ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
- ` to the new methods, etc. shown in the above diff.\n\n`+
- ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
- ` m %s-update-current-api\n\n`+
- ` To submit the revised current.txt to the main Android repository,\n`+
- ` you will need approval.\n`+
- `******************************\n`, ctx.ModuleName())
-
- rule.Command().
- Text("touch").Output(d.checkCurrentApiTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build("metalavaCurrentApiCheck", "check current API")
-
- d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
-
- // update API rule
- rule = android.NewRuleBuilder(pctx, ctx)
-
- rule.Command().Text("( true")
-
- rule.Command().
- Text("cp").Flag("-f").
- Input(d.apiFile).Flag(apiFile.String())
-
- rule.Command().
- Text("cp").Flag("-f").
- Input(d.removedApiFile).Flag(removedApiFile.String())
-
- msg = "failed to update public API"
-
- rule.Command().
- Text("touch").Output(d.updateCurrentApiTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build("metalavaCurrentApiUpdate", "update current API")
+ // Make sure that whenever the API stubs are generated that the current checked in API files are
+ // checked to make sure that they are up-to-date.
+ cmd.Validation(d.checkCurrentApiTimestamp)
}
+ rule.Build("metalava", "metalava merged")
+
if String(d.properties.Check_nullability_warnings) != "" {
if d.nullabilityWarningsFile == nil {
ctx.PropertyErrorf("check_nullability_warnings",
@@ -792,6 +721,84 @@
}
}
+func (d *Droidstubs) generateCheckCurrentCheckedInApiIsUpToDateBuildRules(ctx android.ModuleContext) {
+ if len(d.Javadoc.properties.Out) > 0 {
+ ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+ }
+
+ apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+ removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
+ baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
+
+ if baselineFile.Valid() {
+ ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
+ }
+
+ d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+
+ // Diff command line.
+ // -F matches the closest "opening" line, such as "package android {"
+ // and " public class Intent {".
+ diff := `diff -u -F '{ *$'`
+
+ rule.Command().Text("( true")
+ rule.Command().
+ Text(diff).
+ Input(apiFile).Input(d.apiFile)
+
+ rule.Command().
+ Text(diff).
+ Input(removedApiFile).Input(d.removedApiFile)
+
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `You have tried to change the API from what has been previously approved.\n\n`+
+ `To make these errors go away, you have two choices:\n`+
+ ` 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
+ ` to the new methods, etc. shown in the above diff.\n\n`+
+ ` 2. You can update current.txt and/or removed.txt by executing the following command:\n`+
+ ` m %s-update-current-api\n\n`+
+ ` To submit the revised current.txt to the main Android repository,\n`+
+ ` you will need approval.\n`+
+ `******************************\n`, ctx.ModuleName())
+
+ rule.Command().
+ Text("touch").Output(d.checkCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build("metalavaCurrentApiCheck", "check current API")
+
+ d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
+
+ // update API rule
+ rule = android.NewRuleBuilder(pctx, ctx)
+
+ rule.Command().Text("( true")
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.apiFile).Flag(apiFile.String())
+
+ rule.Command().
+ Text("cp").Flag("-f").
+ Input(d.removedApiFile).Flag(removedApiFile.String())
+
+ msg = "failed to update public API"
+
+ rule.Command().
+ Text("touch").Output(d.updateCurrentApiTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build("metalavaCurrentApiUpdate", "update current API")
+}
+
func StubsDefaultsFactory() android.Module {
module := &DocDefaults{}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 44650a6..9449707 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -212,6 +212,10 @@
mctx.CreateModule(systemModulesImportFactory, &props)
}
+func PrebuiltApiModuleName(module, scope, version string) string {
+ return module + ".api." + scope + "." + version
+}
+
func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
// <apiver>/<scope>/api/<module>.txt
apiLevelFiles := globApiDirs(mctx, p, "api/*.txt")
@@ -220,12 +224,9 @@
}
// Create modules for all (<module>, <scope, <version>) triplets,
- apiModuleName := func(module, scope, version string) string {
- return module + ".api." + scope + "." + version
- }
for _, f := range apiLevelFiles {
module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
- createApiModule(mctx, apiModuleName(module, scope, strconv.Itoa(version)), f)
+ createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
}
// Figure out the latest version of each module/scope
@@ -266,7 +267,7 @@
// Sort the keys in order to make build.ninja stable
for _, k := range android.SortedStringKeys(latest) {
info := latest[k]
- name := apiModuleName(info.module, info.scope, "latest")
+ name := PrebuiltApiModuleName(info.module, info.scope, "latest")
createApiModule(mctx, name, info.path)
}
@@ -278,7 +279,7 @@
filename, _, scope := parsePrebuiltPath(mctx, f)
referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
- createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), f)
+ createApiModule(mctx, PrebuiltApiModuleName(referencedModule+"-incompatibilities", scope, "latest"), f)
incompatibilities[referencedModule+"."+scope] = true
}
@@ -286,7 +287,7 @@
// Create empty incompatibilities files for remaining modules
for _, k := range android.SortedStringKeys(latest) {
if _, ok := incompatibilities[k]; !ok {
- createEmptyFile(mctx, apiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
+ createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
}
}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 47ffc6a..591e90f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -97,6 +97,13 @@
// The tag to use to depend on the stubs source and API module.
stubsSourceAndApiTag scopeDependencyTag
+ // The tag to use to depend on the module that provides the latest version of the API .txt file.
+ latestApiModuleTag scopeDependencyTag
+
+ // The tag to use to depend on the module that provides the latest version of the API removed.txt
+ // file.
+ latestRemovedApiModuleTag scopeDependencyTag
+
// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
apiFilePrefix string
@@ -158,6 +165,16 @@
apiScope: scope,
depInfoExtractor: (*scopePaths).extractStubsSourceAndApiInfoFromApiStubsProvider,
}
+ scope.latestApiModuleTag = scopeDependencyTag{
+ name: name + "-latest-api",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractLatestApiPath,
+ }
+ scope.latestRemovedApiModuleTag = scopeDependencyTag{
+ name: name + "-latest-removed-api",
+ apiScope: scope,
+ depInfoExtractor: (*scopePaths).extractLatestRemovedApiPath,
+ }
// To get the args needed to generate the stubs source append all the args from
// this scope and all the scopes it extends as each set of args adds additional
@@ -203,6 +220,24 @@
return scope.name
}
+// snapshotRelativeDir returns the snapshot directory into which the files related to scopes will
+// be stored.
+func (scope *apiScope) snapshotRelativeDir() string {
+ return filepath.Join("sdk_library", scope.name)
+}
+
+// snapshotRelativeCurrentApiTxtPath returns the snapshot path to the API .txt file for the named
+// library.
+func (scope *apiScope) snapshotRelativeCurrentApiTxtPath(name string) string {
+ return filepath.Join(scope.snapshotRelativeDir(), name+".txt")
+}
+
+// snapshotRelativeRemovedApiTxtPath returns the snapshot path to the removed API .txt file for the
+// named library.
+func (scope *apiScope) snapshotRelativeRemovedApiTxtPath(name string) string {
+ return filepath.Join(scope.snapshotRelativeDir(), name+"-removed.txt")
+}
+
type apiScopes []*apiScope
func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
@@ -539,6 +574,12 @@
// Extracted annotations.
annotationsZip android.OptionalPath
+
+ // The path to the latest API file.
+ latestApiPath android.OptionalPath
+
+ // The path to the latest removed API file.
+ latestRemovedApiPath android.OptionalPath
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
@@ -602,6 +643,31 @@
})
}
+func extractSingleOptionalOutputPath(dep android.Module) (android.OptionalPath, error) {
+ var paths android.Paths
+ if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok {
+ paths = sourceFileProducer.Srcs()
+ } else {
+ return android.OptionalPath{}, fmt.Errorf("module %q does not produce source files", dep)
+ }
+ if len(paths) != 1 {
+ return android.OptionalPath{}, fmt.Errorf("expected one path from %q, got %q", dep, paths)
+ }
+ return android.OptionalPathForPath(paths[0]), nil
+}
+
+func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error {
+ outputPath, err := extractSingleOptionalOutputPath(dep)
+ paths.latestApiPath = outputPath
+ return err
+}
+
+func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error {
+ outputPath, err := extractSingleOptionalOutputPath(dep)
+ paths.latestRemovedApiPath = outputPath
+ return err
+}
+
type commonToSdkLibraryAndImportProperties struct {
// The naming scheme to use for the components that this module creates.
//
@@ -1174,6 +1240,16 @@
// Add a dependency on the stubs source in order to access both stubs source and api information.
ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
+
+ if module.compareAgainstLatestApi(apiScope) {
+ // Add dependencies on the latest finalized version of the API .txt file.
+ latestApiModuleName := module.latestApiModuleName(apiScope)
+ ctx.AddDependency(module, apiScope.latestApiModuleTag, latestApiModuleName)
+
+ // Add dependencies on the latest finalized version of the remove API .txt file.
+ latestRemovedApiModuleName := module.latestRemovedApiModuleName(apiScope)
+ ctx.AddDependency(module, apiScope.latestRemovedApiModuleTag, latestRemovedApiModuleName)
+ }
}
if module.requiresRuntimeImplementationLibrary() {
@@ -1194,13 +1270,13 @@
if apiScope.unstable {
continue
}
- if m := android.SrcIsModule(module.latestApiFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
- if m := android.SrcIsModule(module.latestRemovedApiFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestRemovedApiModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
- if m := android.SrcIsModule(module.latestIncompatibilitiesFilegroupName(apiScope)); !ctx.OtherModuleExists(m) {
+ if m := module.latestIncompatibilitiesModuleName(apiScope); !ctx.OtherModuleExists(m) {
missingApiModules = append(missingApiModules, m)
}
}
@@ -1274,6 +1350,26 @@
// Make the set of components exported by this module available for use elsewhere.
exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedStringKeys(exportedComponents)}
ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
+
+ // Provide additional information for inclusion in an sdk's generated .info file.
+ additionalSdkInfo := map[string]interface{}{}
+ additionalSdkInfo["dist_stem"] = module.distStem()
+ baseModuleName := module.BaseModuleName()
+ scopes := map[string]interface{}{}
+ additionalSdkInfo["scopes"] = scopes
+ for scope, scopePaths := range module.scopePaths {
+ scopeInfo := map[string]interface{}{}
+ scopes[scope.name] = scopeInfo
+ scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName)
+ scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName)
+ if p := scopePaths.latestApiPath; p.Valid() {
+ scopeInfo["latest_api"] = p.Path().String()
+ }
+ if p := scopePaths.latestRemovedApiPath; p.Valid() {
+ scopeInfo["latest_removed_api"] = p.Path().String()
+ }
+ }
+ ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -1319,16 +1415,32 @@
return proptools.StringDefault(module.sdkLibraryProperties.Dist_group, "unknown")
}
+func latestPrebuiltApiModuleName(name string, apiScope *apiScope) string {
+ return PrebuiltApiModuleName(name, apiScope.name, "latest")
+}
+
func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + ".api." + apiScope.name + ".latest"
+ return ":" + module.latestApiModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem(), apiScope)
}
func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + "-removed.api." + apiScope.name + ".latest"
+ return ":" + module.latestRemovedApiModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem()+"-removed", apiScope)
}
func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string {
- return ":" + module.distStem() + "-incompatibilities.api." + apiScope.name + ".latest"
+ return ":" + module.latestIncompatibilitiesModuleName(apiScope)
+}
+
+func (module *SdkLibrary) latestIncompatibilitiesModuleName(apiScope *apiScope) string {
+ return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope)
}
func childModuleVisibility(childVisibility []string) []string {
@@ -1557,7 +1669,7 @@
props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
- if !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api) {
+ if module.compareAgainstLatestApi(apiScope) {
// check against the latest released API
latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
props.Previous_api = latestApiFilegroupName
@@ -1609,6 +1721,10 @@
mctx.CreateModule(DroidstubsFactory, &props)
}
+func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
+ return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api)
+}
+
// Implements android.ApexModule
func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
depTag := mctx.OtherModuleDependencyTag(dep)
@@ -2906,7 +3022,7 @@
if properties, ok := s.Scopes[apiScope]; ok {
scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
- scopeDir := filepath.Join("sdk_library", s.OsPrefix(), apiScope.name)
+ scopeDir := apiScope.snapshotRelativeDir()
var jars []string
for _, p := range properties.Jars {
@@ -2930,13 +3046,13 @@
}
if properties.CurrentApiFile != nil {
- currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
+ currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(ctx.Name())
ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
scopeSet.AddProperty("current_api", currentApiSnapshotPath)
}
if properties.RemovedApiFile != nil {
- removedApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"-removed.txt")
+ removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(ctx.Name())
ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 3500c84..805bc22 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -126,6 +126,10 @@
exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
expectedFooExportedComponents := []string{
+ "foo-removed.api.public.latest",
+ "foo-removed.api.system.latest",
+ "foo.api.public.latest",
+ "foo.api.system.latest",
"foo.stubs",
"foo.stubs.source",
"foo.stubs.source.system",
@@ -529,6 +533,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
@@ -851,6 +857,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
@@ -894,6 +902,8 @@
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`prebuilt_sdklib`,
+ `sdklib-removed.api.public.latest`,
+ `sdklib.api.public.latest`,
`sdklib.impl`,
`sdklib.stubs`,
`sdklib.stubs.source`,
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a99fa1f..f33aa26 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -651,7 +651,19 @@
}
func TestSnapshotWithJavaSystemModules(t *testing.T) {
- result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJava,
+ java.PrepareForTestWithJavaDefaultModules,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithPrebuiltApisAndExtensions(map[string][]string{
+ "31": {"myjavalib"},
+ "32": {"myjavalib"},
+ "current": {"myjavalib"},
+ }, map[string][]string{
+ "1": {"myjavalib"},
+ "2": {"myjavalib"},
+ }),
+ ).RunTestWithBp(t, `
sdk {
name: "mysdk",
java_header_libs: ["exported-system-module"],
@@ -796,6 +808,53 @@
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
`),
+ checkInfoContents(result.Config, `
+[
+ {
+ "@type": "sdk",
+ "@name": "mysdk",
+ "java_header_libs": [
+ "exported-system-module",
+ "system-module"
+ ],
+ "java_sdk_libs": [
+ "myjavalib"
+ ],
+ "java_system_modules": [
+ "my-system-modules"
+ ]
+ },
+ {
+ "@type": "java_library",
+ "@name": "exported-system-module"
+ },
+ {
+ "@type": "java_system_modules",
+ "@name": "my-system-modules",
+ "@deps": [
+ "exported-system-module",
+ "system-module"
+ ]
+ },
+ {
+ "@type": "java_sdk_library",
+ "@name": "myjavalib",
+ "dist_stem": "myjavalib",
+ "scopes": {
+ "public": {
+ "current_api": "sdk_library/public/myjavalib.txt",
+ "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.public.latest/gen/myjavalib.api.public.latest",
+ "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.public.latest/gen/myjavalib-removed.api.public.latest",
+ "removed_api": "sdk_library/public/myjavalib-removed.txt"
+ }
+ }
+ },
+ {
+ "@type": "java_library",
+ "@name": "system-module"
+ }
+]
+`),
)
}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index c8c7b79..b37eaad 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -75,6 +75,8 @@
snapshotFile android.OptionalPath
+ infoFile android.OptionalPath
+
// The builder, preserved for testing.
builderForTests *snapshotBuilder
}
@@ -191,27 +193,32 @@
}
// Generate the snapshot from the member info.
- p := s.buildSnapshot(ctx, sdkVariants)
- zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p)
- s.snapshotFile = android.OptionalPathForPath(zip)
+ s.buildSnapshot(ctx, sdkVariants)
}
}
func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries {
- if !s.snapshotFile.Valid() {
+ if !s.snapshotFile.Valid() != !s.infoFile.Valid() {
+ panic("Snapshot (%q) and info file (%q) should both be set or neither should be set.")
+ } else if !s.snapshotFile.Valid() {
return []android.AndroidMkEntries{}
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "FAKE",
OutputFile: s.snapshotFile,
- DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()),
+ DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
Include: "$(BUILD_PHONY_PACKAGE)",
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {
// Allow the sdk to be built by simply passing its name on the command line.
fmt.Fprintln(w, ".PHONY:", s.Name())
fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String())
+
+ // Allow the sdk info to be built by simply passing its name on the command line.
+ infoTarget := s.Name() + ".info"
+ fmt.Fprintln(w, ".PHONY:", infoTarget)
+ fmt.Fprintln(w, infoTarget+":", s.infoFile.String())
},
},
}}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 40de150..ccbeb8d 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -263,7 +263,10 @@
result := testSdkWithFs(t, sdk, nil)
CheckSnapshot(t, result, "mysdk", "",
- checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`))
+ checkAllOtherCopyRules(`
+.intermediates/mysdk/common_os/mysdk-current.info -> mysdk-current.info
+.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip
+`))
}
type EmbeddedPropertiesStruct struct {
diff --git a/sdk/testing.go b/sdk/testing.go
index 062f200..72344de 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -142,6 +142,7 @@
androidBpContents: sdk.GetAndroidBpContentsForTests(),
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
+ infoContents: sdk.GetInfoContentsForTests(),
snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{},
targetBuildRelease: sdk.builderForTests.targetBuildRelease,
}
@@ -402,6 +403,17 @@
}
}
+// Check that the snapshot's info contents are ciorrect.
+//
+// Both the expected and actual string are both trimmed before comparing.
+func checkInfoContents(config android.Config, expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "info contents do not match",
+ expected, android.StringRelativeToTop(config, info.infoContents))
+ }
+}
+
type resultChecker func(t *testing.T, result *android.TestResult)
// snapshotTestPreparer registers a preparer that will be used to customize the specified
@@ -479,6 +491,9 @@
// The contents of the versioned Android.bp file
androidVersionedBpContents string
+ // The contents of the info file.
+ infoContents string
+
// The paths, relative to the snapshot root, of all files and directories copied into the
// snapshot.
snapshotContents []string
diff --git a/sdk/update.go b/sdk/update.go
index 740b23c..af2b247 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -15,6 +15,8 @@
package sdk
import (
+ "bytes"
+ "encoding/json"
"fmt"
"reflect"
"sort"
@@ -219,9 +221,19 @@
exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
}
+ var container android.SdkAware
+ if parent != ctx.Module() {
+ container = parent.(android.SdkAware)
+ }
+
export := memberTag.ExportMember()
s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
- s, memberType, child.(android.SdkAware), export, exportedComponentsInfo,
+ sdkVariant: s,
+ memberType: memberType,
+ variant: child.(android.SdkAware),
+ container: container,
+ export: export,
+ exportedComponentsInfo: exportedComponentsInfo,
})
// Recurse down into the member's dependencies as it may have dependencies that need to be
@@ -337,7 +349,7 @@
// buildSnapshot is the main function in this source file. It creates rules to copy
// the contents (header files, stub libraries, etc) into the zip file.
-func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
+func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
hasLicenses := false
@@ -396,9 +408,9 @@
// Unversioned modules are not required in that case because the numbered version will be a
// finalized version of the snapshot that is intended to be kept separate from the
generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
- snapshotZipFileSuffix := ""
+ snapshotFileSuffix := ""
if generateVersioned {
- snapshotZipFileSuffix = "-" + version
+ snapshotFileSuffix = "-" + version
}
currentBuildRelease := latestBuildRelease()
@@ -515,7 +527,7 @@
filesToZip := builder.filesToZip
// zip them all
- zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix)
outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
outputDesc := "Building snapshot for " + ctx.ModuleName()
@@ -528,7 +540,7 @@
zipFile = outputZipFile
desc = outputDesc
} else {
- intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotFileSuffix)
zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
desc = "Building intermediate snapshot for " + ctx.ModuleName()
}
@@ -553,7 +565,125 @@
})
}
- return outputZipFile
+ modules := s.generateInfoData(ctx, memberVariantDeps)
+
+ // Output the modules information as pretty printed JSON.
+ info := newGeneratedFile(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
+ output, err := json.MarshalIndent(modules, "", " ")
+ if err != nil {
+ ctx.ModuleErrorf("error generating %q: %s", info, err)
+ }
+ builder.infoContents = string(output)
+ info.generatedContents.UnindentedPrintf("%s", output)
+ info.build(pctx, ctx, nil)
+ infoPath := info.path
+ installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), infoPath.Base(), infoPath)
+ s.infoFile = android.OptionalPathForPath(installedInfo)
+
+ // Install the zip, making sure that the info file has been installed as well.
+ installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
+ s.snapshotFile = android.OptionalPathForPath(installedZip)
+}
+
+type moduleInfo struct {
+ // The type of the module, e.g. java_sdk_library
+ moduleType string
+ // The name of the module.
+ name string
+ // A list of additional dependencies of the module.
+ deps []string
+ // Additional member specific properties.
+ // These will be added into the generated JSON alongside the above properties.
+ memberSpecific map[string]interface{}
+}
+
+func (m *moduleInfo) MarshalJSON() ([]byte, error) {
+ buffer := bytes.Buffer{}
+
+ separator := ""
+ writeObjectPair := func(key string, value interface{}) {
+ buffer.WriteString(fmt.Sprintf("%s%q: ", separator, key))
+ b, err := json.Marshal(value)
+ if err != nil {
+ panic(err)
+ }
+ buffer.Write(b)
+ separator = ","
+ }
+
+ buffer.WriteString("{")
+ writeObjectPair("@type", m.moduleType)
+ writeObjectPair("@name", m.name)
+ if m.deps != nil {
+ writeObjectPair("@deps", m.deps)
+ }
+ for _, k := range android.SortedStringKeys(m.memberSpecific) {
+ v := m.memberSpecific[k]
+ writeObjectPair(k, v)
+ }
+ buffer.WriteString("}")
+ return buffer.Bytes(), nil
+}
+
+var _ json.Marshaler = (*moduleInfo)(nil)
+
+// generateInfoData creates a list of moduleInfo structures that will be marshalled into JSON.
+func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) interface{} {
+ modules := []*moduleInfo{}
+ sdkInfo := moduleInfo{
+ moduleType: "sdk",
+ name: ctx.ModuleName(),
+ memberSpecific: map[string]interface{}{},
+ }
+ modules = append(modules, &sdkInfo)
+
+ name2Info := map[string]*moduleInfo{}
+ getModuleInfo := func(module android.Module) *moduleInfo {
+ name := module.Name()
+ info := name2Info[name]
+ if info == nil {
+ moduleType := ctx.OtherModuleType(module)
+ // Remove any suffix added when creating modules dynamically.
+ moduleType = strings.Split(moduleType, "__")[0]
+ info = &moduleInfo{
+ moduleType: moduleType,
+ name: name,
+ }
+
+ additionalSdkInfo := ctx.OtherModuleProvider(module, android.AdditionalSdkInfoProvider).(android.AdditionalSdkInfo)
+ info.memberSpecific = additionalSdkInfo.Properties
+
+ name2Info[name] = info
+ }
+ return info
+ }
+
+ for _, memberVariantDep := range memberVariantDeps {
+ propertyName := memberVariantDep.memberType.SdkPropertyName()
+ var list []string
+ if v, ok := sdkInfo.memberSpecific[propertyName]; ok {
+ list = v.([]string)
+ }
+
+ memberName := memberVariantDep.variant.Name()
+ list = append(list, memberName)
+ sdkInfo.memberSpecific[propertyName] = android.SortedUniqueStrings(list)
+
+ if memberVariantDep.container != nil {
+ containerInfo := getModuleInfo(memberVariantDep.container)
+ containerInfo.deps = android.SortedUniqueStrings(append(containerInfo.deps, memberName))
+ }
+
+ // Make sure that the module info is created for each module.
+ getModuleInfo(memberVariantDep.variant)
+ }
+
+ for _, memberName := range android.SortedStringKeys(name2Info) {
+ info := name2Info[memberName]
+ modules = append(modules, info)
+ }
+
+ return modules
}
// filterOutComponents removes any item from the deps list that is a component of another item in
@@ -1062,6 +1192,10 @@
return contents.content.String()
}
+func (s *sdk) GetInfoContentsForTests() string {
+ return s.builderForTests.infoContents
+}
+
func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
@@ -1116,6 +1250,9 @@
// The target build release for which the snapshot is to be generated.
targetBuildRelease *buildRelease
+
+ // The contents of the .info file that describes the sdk contents.
+ infoContents string
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -1351,6 +1488,11 @@
// The variant that is added to the sdk.
variant android.SdkAware
+ // The optional container of this member, i.e. the module that is depended upon by the sdk
+ // (possibly transitively) and whose dependency on this module is why it was added to the sdk.
+ // Is nil if this a direct dependency of the sdk.
+ container android.SdkAware
+
// True if the member should be exported, i.e. accessible, from outside the sdk.
export bool
diff --git a/ui/build/build.go b/ui/build/build.go
index ec42b70..aadf4af 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -266,7 +266,6 @@
}
if config.StartRBE() {
- cleanupRBELogsDir(ctx, config)
startRBE(ctx, config)
defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 5765f21..e271bfc 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -19,14 +19,12 @@
"encoding/json"
"fmt"
"io/ioutil"
- "math/rand"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
- "syscall"
"time"
"android/soong/shared"
@@ -44,15 +42,6 @@
envConfigFetchTimeout = 10 * time.Second
)
-var (
- rbeRandPrefix int
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- rbeRandPrefix = rand.Intn(1000)
-}
-
type Config struct{ *configImpl }
type configImpl struct {
@@ -1155,25 +1144,34 @@
return true
}
-func (c *configImpl) rbeProxyLogsDir() string {
- for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
+func (c *configImpl) rbeLogDir() string {
+ for _, f := range []string{"RBE_log_dir", "FLAG_log_dir"} {
if v, ok := c.environ.Get(f); ok {
return v
}
}
- buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
- return filepath.Join(buildTmpDir, "rbe")
+ if c.Dist() {
+ return c.LogsDir()
+ }
+ return c.OutDir()
}
-func (c *configImpl) shouldCleanupRBELogsDir() bool {
- // Perform a log directory cleanup only when the log directory
- // is auto created by the build rather than user-specified.
- for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
- if _, ok := c.environ.Get(f); ok {
- return false
+func (c *configImpl) rbeStatsOutputDir() string {
+ for _, f := range []string{"RBE_output_dir", "FLAG_output_dir"} {
+ if v, ok := c.environ.Get(f); ok {
+ return v
}
}
- return true
+ return c.rbeLogDir()
+}
+
+func (c *configImpl) rbeLogPath() string {
+ for _, f := range []string{"RBE_log_path", "FLAG_log_path"} {
+ if v, ok := c.environ.Get(f); ok {
+ return v
+ }
+ }
+ return fmt.Sprintf("text://%v/reproxy_log.txt", c.rbeLogDir())
}
func (c *configImpl) rbeExecRoot() string {
@@ -1225,23 +1223,6 @@
return "RBE_use_application_default_credentials", "true"
}
-func (c *configImpl) rbeSockAddr(dir string) (string, error) {
- maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
- base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix)
-
- name := filepath.Join(dir, base)
- if len(name) < maxNameLen {
- return name, nil
- }
-
- name = filepath.Join("/tmp", base)
- if len(name) < maxNameLen {
- return name, nil
- }
-
- return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
-}
-
func (c *configImpl) UseRemoteBuild() bool {
return c.UseGoma() || c.UseRBE()
}
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 3e558f7..8f9a699 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -16,9 +16,12 @@
import (
"fmt"
+ "math/rand"
"os"
"path/filepath"
"runtime"
+ "syscall"
+ "time"
"android/soong/ui/metrics"
)
@@ -51,16 +54,34 @@
return cmdPath
}
+func sockAddr(dir string) (string, error) {
+ maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
+ rand.Seed(time.Now().UnixNano())
+ base := fmt.Sprintf("reproxy_%v.sock", rand.Intn(1000))
+
+ name := filepath.Join(dir, base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ name = filepath.Join("/tmp", base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
+}
+
func getRBEVars(ctx Context, config Config) map[string]string {
vars := map[string]string{
- "RBE_log_dir": config.rbeProxyLogsDir(),
+ "RBE_log_path": config.rbeLogPath(),
+ "RBE_log_dir": config.rbeLogDir(),
"RBE_re_proxy": config.rbeReproxy(),
"RBE_exec_root": config.rbeExecRoot(),
- "RBE_output_dir": config.rbeProxyLogsDir(),
- "RBE_proxy_log_dir": config.rbeProxyLogsDir(),
+ "RBE_output_dir": config.rbeStatsOutputDir(),
}
if config.StartRBE() {
- name, err := config.rbeSockAddr(absPath(ctx, config.TempDir()))
+ name, err := sockAddr(absPath(ctx, config.TempDir()))
if err != nil {
ctx.Fatalf("Error retrieving socket address: %v", err)
return nil
@@ -79,17 +100,6 @@
return vars
}
-func cleanupRBELogsDir(ctx Context, config Config) {
- if !config.shouldCleanupRBELogsDir() {
- return
- }
-
- rbeTmpDir := config.rbeProxyLogsDir()
- if err := os.RemoveAll(rbeTmpDir); err != nil {
- fmt.Fprintln(ctx.Writer, "\033[33mUnable to remove RBE log directory: ", err, "\033[0m")
- }
-}
-
func startRBE(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
defer ctx.EndTrace()
@@ -100,11 +110,6 @@
if n := ulimitOrFatal(ctx, config, "-n"); n < rbeLeastNFiles {
ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, rbeLeastNFiles)
}
- if _, err := os.Stat(config.rbeProxyLogsDir()); os.IsNotExist(err) {
- if err := os.MkdirAll(config.rbeProxyLogsDir(), 0744); err != nil {
- ctx.Fatalf("Unable to create logs dir (%v) for RBE: %v", config.rbeProxyLogsDir, err)
- }
- }
cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd))
@@ -146,7 +151,7 @@
return
}
- outputDir := config.rbeProxyLogsDir()
+ outputDir := config.rbeStatsOutputDir()
if outputDir == "" {
ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
}
diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go
index 266f76b..8ff96bc 100644
--- a/ui/build/rbe_test.go
+++ b/ui/build/rbe_test.go
@@ -56,8 +56,7 @@
env := Environment(tt.env)
env.Set("OUT_DIR", tmpDir)
env.Set("RBE_DIR", tmpDir)
- env.Set("RBE_output_dir", tmpDir)
- env.Set("RBE_proxy_log_dir", tmpDir)
+ env.Set("RBE_output_dir", t.TempDir())
config := Config{&configImpl{
environ: &env,
}}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index c7f22f9..8992b4f 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,7 +15,9 @@
package build
import (
+ "errors"
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -491,10 +493,14 @@
ninja("bootstrap", "bootstrap.ninja", targets...)
- var soongBuildMetrics *soong_metrics_proto.SoongBuildMetrics
if shouldCollectBuildSoongMetrics(config) {
soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
- logSoongBuildMetrics(ctx, soongBuildMetrics)
+ if soongBuildMetrics != nil {
+ logSoongBuildMetrics(ctx, soongBuildMetrics)
+ if ctx.Metrics != nil {
+ ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
+ }
+ }
}
distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
@@ -504,9 +510,6 @@
distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong")
}
- if shouldCollectBuildSoongMetrics(config) && ctx.Metrics != nil {
- ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
- }
if config.JsonModuleGraph() {
distGzipFile(ctx, config, config.ModuleGraphFile(), "soong")
}
@@ -538,8 +541,12 @@
func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
soongBuildMetricsFile := filepath.Join(config.LogsDir(), "soong_build_metrics.pb")
- buf, err := ioutil.ReadFile(soongBuildMetricsFile)
- if err != nil {
+ buf, err := os.ReadFile(soongBuildMetricsFile)
+ if errors.Is(err, fs.ErrNotExist) {
+ // Soong may not have run during this invocation
+ ctx.Verbosef("Failed to read metrics file, %s: %s", soongBuildMetricsFile, err)
+ return nil
+ } else if err != nil {
ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err)
}
soongBuildMetrics := &soong_metrics_proto.SoongBuildMetrics{}