Merge "Revert "Revert "Revert "Add integration test for testing generat...""
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 63495bc..17db472 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -218,6 +218,7 @@
 
 		"hardware/interfaces":                          Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl":               Bp2BuildDefaultTrue,
+		"hardware/interfaces/audio/aidl/common":        Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/aidl":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/fmq/aidl":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
diff --git a/android/config.go b/android/config.go
index b37d5c8..979f1ca 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1759,6 +1759,10 @@
 	return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
 }
 
+func (c *deviceConfig) BuildBrokenUsesSoongPython2Modules() bool {
+	return c.config.productVariables.BuildBrokenUsesSoongPython2Modules
+}
+
 func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
 	return c.config.productVariables.BuildDebugfsRestrictionsEnabled
 }
@@ -1837,3 +1841,14 @@
 		c.mixedBuildDisabledModules[moduleName] = struct{}{}
 	}
 }
+
+// ApiSurfaces directory returns the source path inside the api_surfaces repo
+// (relative to workspace root).
+func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
+	return filepath.Join(
+		"build",
+		"bazel",
+		"api_surfaces",
+		s.String(),
+		version)
+}
diff --git a/android/defaults.go b/android/defaults.go
index a821b28..31d6014 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"bytes"
-	"fmt"
 	"reflect"
 
 	"github.com/google/blueprint"
@@ -69,11 +67,9 @@
 	// Set the property structures into which defaults will be added.
 	setProperties(props []interface{}, variableProperties interface{})
 
-	// Apply defaults from the supplied DefaultsModule to the property structures supplied to
+	// Apply defaults from the supplied Defaults to the property structures supplied to
 	// setProperties(...).
-	applyDefaults(TopDownMutatorContext, []DefaultsModule)
-
-	applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
+	applyDefaults(TopDownMutatorContext, []Defaults)
 
 	// Set the hook to be called after any defaults have been applied.
 	//
@@ -119,23 +115,9 @@
 	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().
@@ -169,18 +151,6 @@
 	// 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{}
 
@@ -197,18 +167,6 @@
 	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
 }
@@ -232,10 +190,6 @@
 		&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)
@@ -263,58 +217,6 @@
 
 	// 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 = SortedKeys(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)
@@ -366,204 +268,35 @@
 	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 []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
-		}
-	}
+	defaultsList []Defaults) {
 
 	for _, defaults := range defaultsList {
 		if ctx.Config().BuildMode == Bp2build {
 			applyNamespacedVariableDefaults(defaults, ctx)
 		}
-
-		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))
+		for _, prop := range defaultable.defaultableProperties {
+			if prop == defaultable.defaultableVariableProperties {
+				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
 			} 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)
+				defaultable.applyDefaultProperties(ctx, defaults, prop)
 			}
 		}
 	}
 }
 
-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(defaults DefaultsModule,
-	defaultableProp interface{}, tracker defaultsTrackerFunc) error {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+	defaults Defaults, defaultableProp interface{}) {
 	if defaultableProp == nil {
-		return nil
+		return
 	}
 
 	defaultsProp := defaults.productVariableProperties()
 	if defaultsProp == nil {
-		return nil
+		return
 	}
 
 	dst := []interface{}{
@@ -573,26 +306,31 @@
 		proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
 	}
 
-	filter := filterForTracker(defaults, tracker)
-
-	return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
+	err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
+	if err != nil {
+		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+		} else {
+			panic(err)
+		}
+	}
 }
 
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
-	defaultableProp interface{}, checker defaultsTrackerFunc) error {
-
-	filter := filterForTracker(defaults, checker)
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+	defaults Defaults, defaultableProp interface{}) {
 
 	for _, def := range defaults.properties() {
 		if proptools.TypeEqual(defaultableProp, def) {
-			err := proptools.PrependProperties(defaultableProp, def, filter)
+			err := proptools.PrependProperties(defaultableProp, def, nil)
 			if err != nil {
-				return err
+				if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+					ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+				} else {
+					panic(err)
+				}
 			}
 		}
 	}
-
-	return nil
 }
 
 func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -609,12 +347,12 @@
 func defaultsMutator(ctx TopDownMutatorContext) {
 	if defaultable, ok := ctx.Module().(Defaultable); ok {
 		if len(defaultable.defaults().Defaults) > 0 {
-			var defaultsList []DefaultsModule
+			var defaultsList []Defaults
 			seen := make(map[Defaults]bool)
 
 			ctx.WalkDeps(func(module, parent Module) bool {
 				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
-					if defaults, ok := module.(DefaultsModule); ok {
+					if defaults, ok := module.(Defaults); ok {
 						if !seen[defaults] {
 							seen[defaults] = true
 							defaultsList = append(defaultsList, defaults)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index d80f40c..a7542ab 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,14 +19,7 @@
 )
 
 type defaultsTestProperties struct {
-	Foo    []string
-	Bar    []string
-	Nested struct {
-		Fizz *bool
-	}
-	Other struct {
-		Buzz *string
-	}
+	Foo []string
 }
 
 type defaultsTestModule struct {
@@ -137,167 +130,3 @@
 	// 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/filegroup.go b/android/filegroup.go
index 7d929bc..0f6e00e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -78,6 +78,12 @@
 	Strip_import_prefix *string
 }
 
+// api srcs can be contained in filegroups.
+// this should be generated in api_bp2build workspace as well.
+func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
+	fg.ConvertWithBp2build(ctx)
+}
+
 // ConvertWithBp2build performs bp2build conversion of filegroup
 func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
diff --git a/android/module.go b/android/module.go
index 58c5464..773d77b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1334,7 +1334,7 @@
 // Check product variables for `enabled: true` flag override.
 // Returns a list of the constraint_value targets who enable this override.
 func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
-	productVariableProps := ProductVariableProperties(ctx)
+	productVariableProps := ProductVariableProperties(ctx, ctx.Module())
 	productConfigEnablingTargets := []bazel.Label{}
 	const propName = "Enabled"
 	if productConfigProps, exists := productVariableProps[propName]; exists {
diff --git a/android/mutator.go b/android/mutator.go
index 4dacb8d..676f8a5 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -268,6 +268,11 @@
 	// platforms, as dictated by a given bool attribute: the target will not be buildable in
 	// any platform for which this bool attribute is false.
 	CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
+
+	// CreateBazelTargetAliasInDir creates an alias definition in `dir` directory.
+	// This function can be used to create alias definitions in a directory that is different
+	// from the directory of the visited Soong module.
+	CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
 }
 
 type topDownMutatorContext struct {
@@ -705,6 +710,34 @@
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
 }
 
+var (
+	bazelAliasModuleProperties = bazel.BazelTargetModuleProperties{
+		Rule_class: "alias",
+	}
+)
+
+type bazelAliasAttributes struct {
+	Actual *bazel.LabelAttribute
+}
+
+func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
+	dir string,
+	name string,
+	actual bazel.Label) {
+	mod := t.Module()
+	attrs := &bazelAliasAttributes{
+		Actual: bazel.MakeLabelAttribute(actual.Label),
+	}
+	info := bp2buildInfo{
+		Dir:             dir,
+		BazelProps:      bazelAliasModuleProperties,
+		CommonAttrs:     CommonAttributes{Name: name},
+		ConstraintAttrs: constraintAttributes{},
+		Attrs:           attrs,
+	}
+	mod.base().addBp2buildInfo(info)
+}
+
 // ApexAvailableTags converts the apex_available property value of an ApexModule
 // module and returns it as a list of keyed tags.
 func ApexAvailableTags(mod Module) bazel.StringListAttribute {
diff --git a/android/variable.go b/android/variable.go
index f7ac7d6..8c5c0bc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -442,6 +442,7 @@
 	BuildBrokenDepfile                 *bool    `json:",omitempty"`
 	BuildBrokenEnforceSyspropOwner     bool     `json:",omitempty"`
 	BuildBrokenTrebleSyspropNeverallow bool     `json:",omitempty"`
+	BuildBrokenUsesSoongPython2Modules bool     `json:",omitempty"`
 	BuildBrokenVendorPropertyNamespace bool     `json:",omitempty"`
 	BuildBrokenInputDirModules         []string `json:",omitempty"`
 
@@ -663,9 +664,8 @@
 type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
 
 // ProductVariableProperties returns a ProductConfigProperties containing only the properties which
-// have been set for the module in the given context.
-func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProperties {
-	module := ctx.Module()
+// have been set for the given module.
+func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductConfigProperties {
 	moduleBase := module.base()
 
 	productConfigProperties := ProductConfigProperties{}
diff --git a/apex/apex.go b/apex/apex.go
index 88eb72f..f506876 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -50,7 +50,7 @@
 	ctx.RegisterModuleType("apex", BundleFactory)
 	ctx.RegisterModuleType("apex_test", TestApexBundleFactory)
 	ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
-	ctx.RegisterModuleType("apex_defaults", defaultsFactory)
+	ctx.RegisterModuleType("apex_defaults", DefaultsFactory)
 	ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
 	ctx.RegisterModuleType("override_apex", OverrideApexFactory)
 	ctx.RegisterModuleType("apex_set", apexSetFactory)
@@ -2728,14 +2728,9 @@
 }
 
 // apex_defaults provides defaultable properties to other apex modules.
-func defaultsFactory() android.Module {
-	return DefaultsFactory()
-}
-
-func DefaultsFactory(props ...interface{}) android.Module {
+func DefaultsFactory() android.Module {
 	module := &Defaults{}
 
-	module.AddProperties(props...)
 	module.AddProperties(
 		&apexBundleProperties{},
 		&apexTargetBundleProperties{},
@@ -3538,7 +3533,7 @@
 		fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.File_contexts))
 	}
 
-	productVariableProps := android.ProductVariableProperties(ctx)
+	productVariableProps := android.ProductVariableProperties(ctx, a)
 	// TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but
 	// given it's coming via config, we probably don't want to put it in here.
 	var minSdkVersion bazel.StringAttribute
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 1c0e563..73c889f 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -61,7 +61,10 @@
 	ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("apex", apex.BundleFactory)
+	ctx.RegisterModuleType("apex_defaults", apex.DefaultsFactory)
 	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
+	ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
 }
 
 func TestApexBundleSimple(t *testing.T) {
@@ -1359,3 +1362,87 @@
 			}),
 		}})
 }
+
+func TestApexBundle_overridePlusProductVars(t *testing.T) {
+	// Reproduction of b/271424349
+	// Tests that overriding an apex that uses product variables correctly copies the product var
+	// selects over to the override.
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - overriding a module that uses product vars",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Blueprint: `
+soong_config_string_variable {
+    name: "library_linking_strategy",
+    values: [
+        "prefer_static",
+    ],
+}
+
+soong_config_module_type {
+    name: "library_linking_strategy_apex_defaults",
+    module_type: "apex_defaults",
+    config_namespace: "ANDROID",
+    variables: ["library_linking_strategy"],
+    properties: [
+        "manifest",
+        "min_sdk_version",
+    ],
+}
+
+library_linking_strategy_apex_defaults {
+    name: "higher_min_sdk_when_prefer_static",
+    soong_config_variables: {
+        library_linking_strategy: {
+            // Use the R min_sdk_version
+            prefer_static: {},
+            // Override the R min_sdk_version to min_sdk_version that supports dcla
+            conditions_default: {
+                min_sdk_version: "31",
+            },
+        },
+    },
+}
+
+filegroup {
+	name: "foo-file_contexts",
+	srcs: [
+		"com.android.apogee-file_contexts",
+	],
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "foo",
+	defaults: ["higher_min_sdk_when_prefer_static"],
+	min_sdk_version: "30",
+	package_name: "pkg_name",
+	file_contexts: ":foo-file_contexts",
+}
+override_apex {
+	name: "override_foo",
+	base: ":foo",
+	package_name: "override_pkg_name",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "foo", AttrNameToString{
+				"file_contexts": `":foo-file_contexts"`,
+				"manifest":      `"apex_manifest.json"`,
+				"min_sdk_version": `select({
+        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+        "//conditions:default": "31",
+    })`,
+				"package_name": `"pkg_name"`,
+			}), MakeBazelTarget("apex", "override_foo", AttrNameToString{
+				"base_apex_name": `"foo"`,
+				"file_contexts":  `":foo-file_contexts"`,
+				"manifest":       `"apex_manifest.json"`,
+				"min_sdk_version": `select({
+        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+        "//conditions:default": "31",
+    })`,
+				"package_name": `"override_pkg_name"`,
+			}),
+		}})
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index ced779c..fde9b69 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -60,6 +60,15 @@
 	}
 }
 
+// PackageName returns the package of the Bazel target.
+// Defaults to root of tree.
+func (t BazelTarget) PackageName() string {
+	if t.packageName == "" {
+		return "."
+	}
+	return t.packageName
+}
+
 // BazelTargets is a typedef for a slice of BazelTarget objects.
 type BazelTargets []BazelTarget
 
@@ -337,7 +346,10 @@
 			return
 		}
 
-		buildFileToTargets[dir] = append(buildFileToTargets[dir], targets...)
+		for _, target := range targets {
+			targetDir := target.PackageName()
+			buildFileToTargets[targetDir] = append(buildFileToTargets[targetDir], target)
+		}
 	})
 
 	if len(errs) > 0 {
@@ -454,7 +466,8 @@
 
 	targetName := targetNameWithVariant(ctx, m)
 	return BazelTarget{
-		name: targetName,
+		name:        targetName,
+		packageName: ctx.ModuleDir(m),
 		content: fmt.Sprintf(
 			soongModuleTargetTemplate,
 			targetName,
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 0784f4b..f1d6398 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -755,3 +755,29 @@
 		},
 	})
 }
+
+func TestJavaLibraryArchVariantSrcsWithExcludes(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Description: "java_library with arch variant libs",
+		Blueprint: `java_library {
+    name: "java-lib-1",
+    srcs: ["a.java", "b.java"],
+    target: {
+        android: {
+            exclude_srcs: ["a.java"],
+        },
+    },
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+				"srcs": `["b.java"] + select({
+        "//build/bazel/platforms/os:android": [],
+        "//conditions:default": ["a.java"],
+    })`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+		},
+	})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 43baf98..a737ea1 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -21,6 +21,7 @@
 
 import (
 	"fmt"
+	"sort"
 	"strings"
 	"testing"
 
@@ -263,6 +264,12 @@
 		t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
 			description, expectedCount, expectedContents, actualCount, actualTargets)
 	} else {
+		sort.SliceStable(actualTargets, func(i, j int) bool {
+			return actualTargets[i].name < actualTargets[j].name
+		})
+		sort.SliceStable(expectedContents, func(i, j int) bool {
+			return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
+		})
 		for i, actualTarget := range actualTargets {
 			if w, g := expectedContents[i], actualTarget.content; w != g {
 				t.Errorf(
@@ -454,7 +461,7 @@
 			}
 		}
 	}
-	productVariableProps := android.ProductVariableProperties(ctx)
+	productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
 	if props, ok := productVariableProps["String_literal_prop"]; ok {
 		for c, p := range props {
 			if val, ok := p.(*string); ok {
@@ -637,3 +644,13 @@
 		"exports":   `[":` + name + `"]`,
 	})
 }
+
+func getTargetName(targetContent string) string {
+	data := strings.Split(targetContent, "name = \"")
+	if len(data) < 2 {
+		return ""
+	} else {
+		endIndex := strings.Index(data[1], "\"")
+		return data[1][:endIndex]
+	}
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 1ea8bda..8644bf6 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -766,7 +766,7 @@
 		nativeCoverage = BoolPtr(false)
 	}
 
-	productVariableProps := android.ProductVariableProperties(ctx)
+	productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
 
 	(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
 	(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
diff --git a/cc/config/global.go b/cc/config/global.go
index 05dc773..488af45 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -193,6 +193,7 @@
 
 	noOverrideGlobalCflags = []string{
 		"-Werror=bool-operation",
+		"-Werror=format-insufficient-args",
 		"-Werror=implicit-int-float-conversion",
 		"-Werror=int-in-bool-context",
 		"-Werror=int-to-pointer-cast",
@@ -247,6 +248,8 @@
 	noOverride64GlobalCflags = []string{}
 
 	noOverrideExternalGlobalCflags = []string{
+		// http://b/191699019
+		"-Wno-format-insufficient-args",
 		"-Wno-sizeof-array-div",
 		"-Wno-unused-but-set-variable",
 		"-Wno-unused-but-set-parameter",
@@ -284,9 +287,6 @@
 
 		// http://b/239661264
 		"-Wno-deprecated-non-prototype",
-
-		// http://b/191699019
-		"-Wno-format-insufficient-args",
 	}
 
 	llvmNextExtraCommonGlobalCflags = []string{
diff --git a/cc/library.go b/cc/library.go
index e73af81..27f0623 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -464,6 +464,21 @@
 		ctx.CreateBazelTargetModule(stubSuitesProps,
 			android.CommonAttributes{Name: m.Name() + "_stub_libs"},
 			stubSuitesAttrs)
+
+		// Add alias for the stub shared_library in @api_surfaces repository
+		currentModuleLibApiDir := ctx.Config().ApiSurfacesDir(android.ModuleLibApi, "current")
+		actualLabelInMainWorkspace := bazel.Label{
+			Label: fmt.Sprintf("@//%s:%s_stub_libs_current", ctx.ModuleDir(), m.Name()),
+		}
+		ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, m.Name(), actualLabelInMainWorkspace)
+
+		// Add alias for headers exported by the stub library
+		headerLabelInMainWorkspace := bazel.Label{
+			// This label is generated from cc_stub_suite macro
+			Label: fmt.Sprintf("@//%s:%s_stub_libs_%s_headers", ctx.ModuleDir(), m.Name(), android.ModuleLibApi.String()),
+		}
+		headerAlias := m.Name() + "_headers"
+		ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, headerAlias, headerLabelInMainWorkspace)
 	}
 }
 
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 5c187f6..9b51160 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -136,7 +136,7 @@
 	ctx.EventHandler.Begin("queryview")
 	defer ctx.EventHandler.End("queryview")
 	codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.QueryView, topDir)
-	err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir))
+	err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir), false)
 	maybeQuit(err, "")
 	touch(shared.JoinPath(topDir, queryviewMarker))
 }
@@ -174,7 +174,28 @@
 	// Run codegen to generate BUILD files
 	codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build, topDir)
 	absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir)
-	err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir)
+	// Always generate bp2build_all_srcs filegroups in api_bp2build.
+	// This is necessary to force each Android.bp file to create an equivalent BUILD file
+	// and prevent package boundray issues.
+	// e.g.
+	// Source
+	// f/b/Android.bp
+	// java_library{
+	//   name: "foo",
+	//   api: "api/current.txt",
+	// }
+	//
+	// f/b/api/Android.bp <- will cause package boundary issues
+	//
+	// Gen
+	// f/b/BUILD
+	// java_contribution{
+	//   name: "foo.contribution",
+	//   api: "//f/b/api:current.txt",
+	// }
+	//
+	// If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable.
+	err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
 	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 35ae009..ce32184 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -25,11 +25,11 @@
 )
 
 // A helper function to generate a Read-only Bazel workspace in outDir
-func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string) error {
+func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string, generateFilegroups bool) error {
 	os.RemoveAll(outDir)
 	ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
 
-	res, err := bp2build.GenerateBazelTargets(ctx, false)
+	res, err := bp2build.GenerateBazelTargets(ctx, generateFilegroups)
 	if err != nil {
 		panic(err)
 	}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index b0660df..dcd7fdc 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -717,7 +717,7 @@
 			}
 		}
 
-		for propName, productConfigProps := range android.ProductVariableProperties(ctx) {
+		for propName, productConfigProps := range android.ProductVariableProperties(ctx, ctx.Module()) {
 			for configProp, propVal := range productConfigProps {
 				if propName == "Src" {
 					props, ok := propVal.(*string)
diff --git a/java/java.go b/java/java.go
index 63c4416..e8f78ba 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2660,6 +2660,7 @@
 			}
 		}
 	}
+	srcs.ResolveExcludes()
 
 	javaSrcPartition := "java"
 	protoSrcPartition := "proto"
@@ -2843,12 +2844,12 @@
 	if !bp2BuildInfo.hasKotlin {
 		props = bazel.BazelTargetModuleProperties{
 			Rule_class:        "java_library",
-			Bzl_load_location: "//build/bazel/rules/java:library.bzl",
+			Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
 		}
 	} else {
 		props = bazel.BazelTargetModuleProperties{
 			Rule_class:        "kt_jvm_library",
-			Bzl_load_location: "//build/bazel/rules/kotlin:kt_jvm_library.bzl",
+			Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
 		}
 	}
 
@@ -2928,7 +2929,8 @@
 	}
 
 	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "java_binary",
+		Rule_class:        "java_binary",
+		Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
 	}
 	attrs := &javaBinaryHostAttributes{
 		Runtime_deps: runtimeDeps,
@@ -2943,7 +2945,7 @@
 		ktName := m.Name() + "_kt"
 		ktProps := bazel.BazelTargetModuleProperties{
 			Rule_class:        "kt_jvm_library",
-			Bzl_load_location: "//build/bazel/rules/kotlin:kt_jvm_library.bzl",
+			Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
 		}
 
 		ktAttrs := &javaLibraryAttributes{
@@ -2980,7 +2982,10 @@
 	attrs := &bazelJavaImportAttributes{
 		Jars: jars,
 	}
-	props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "java_import",
+		Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+	}
 
 	name := android.RemoveOptionalPrebuiltPrefix(i.Name())
 
@@ -2991,7 +2996,13 @@
 		Neverlink: bazel.BoolAttribute{Value: &neverlink},
 		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
 	}
-	ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{Rule_class: "java_library"}, android.CommonAttributes{Name: name + "-neverlink"}, neverlinkAttrs)
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "java_library",
+			Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+		},
+		android.CommonAttributes{Name: name + "-neverlink"},
+		neverlinkAttrs)
 
 }
 
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 061f4d0..1bb4996 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -40,6 +40,13 @@
 # NewApi checks will continue to be enforced for apex deps since
 # lint.strict_updatability_linting will be true for those Soong modules
 --disable_check NewApi
+# Disable ChromeOS specific checks
+--disable_check PermissionImpliesUnsupportedChromeOsHardware
+# Disable UnsafeImplicitIntentLaunch until it can avoid false positives/crash
+# TODO(265425607)
+--disable_check UnsafeImplicitIntentLaunch
+# InvalidId will give errors on ids defined like android:id="@androidprv:id/contentPanel"
+--disable_check InvalidId
 
 # Downgrade existing errors to warnings
 --warning_check AppCompatResource                  # 55 occurences in 10 modules
diff --git a/python/python.go b/python/python.go
index 0ae7b36..c7c523d 100644
--- a/python/python.go
+++ b/python/python.go
@@ -263,6 +263,12 @@
 				versionProps = append(versionProps, props.Version.Py3)
 			}
 			if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
+				if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
+					mctx.ModuleName() != "par_test" &&
+					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)
 			}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 5dd45cd..ddbba74 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -191,6 +191,17 @@
     ],
 }
 
+python_test_host {
+    name: "conv_linker_config_test",
+    main: "conv_linker_config_test.py",
+    srcs: [
+        "conv_linker_config_test.py",
+        "conv_linker_config.py",
+    ],
+    libs: ["linker_config_proto"],
+    test_suites: ["general-tests"],
+}
+
 python_binary_host {
     name: "get_clang_version",
     main: "get_clang_version.py",
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 2ce0ee2..3ac1b7e 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -19,6 +19,7 @@
 import collections
 import json
 import os
+import sys
 
 import linker_config_pb2 #pylint: disable=import-error
 from google.protobuf.descriptor import FieldDescriptor
@@ -26,17 +27,41 @@
 from google.protobuf.text_format import MessageToString
 
 
+def LoadJsonMessage(path):
+    """
+    Loads a message from a .json file with `//` comments strippedfor convenience.
+    """
+    json_content = ''
+    with open(path) as f:
+        for line in f:
+            if not line.lstrip().startswith('//'):
+                json_content += line
+    obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
+    return ParseDict(obj, linker_config_pb2.LinkerConfig())
+
+
 def Proto(args):
+    """
+    Merges input json files (--source) into a protobuf message (--output).
+    Fails if the output file exists. Set --force or --append to deal with the existing
+    output file.
+    --force to overwrite the output file with the input (.json files).
+    --append to append the input to the output file.
+    """
     pb = linker_config_pb2.LinkerConfig()
+    if os.path.isfile(args.output):
+        if args.force:
+            pass
+        elif args.append:
+            with open(args.output, 'rb') as f:
+                pb.ParseFromString(f.read())
+        else:
+            sys.stderr.write(f'Error: {args.output} exists. Use --force or --append.\n')
+            sys.exit(1)
+
     if args.source:
         for input in args.source.split(':'):
-            json_content = ''
-            with open(input) as f:
-                for line in f:
-                    if not line.lstrip().startswith('//'):
-                        json_content += line
-            obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
-            ParseDict(obj, pb)
+            pb.MergeFrom(LoadJsonMessage(input))
     with open(args.output, 'wb') as f:
         f.write(pb.SerializeToString())
 
@@ -114,6 +139,17 @@
         required=True,
         type=str,
         help='Target path to create protobuf file.')
+    option_for_existing_output = parser_proto.add_mutually_exclusive_group()
+    option_for_existing_output.add_argument(
+        '-f',
+        '--force',
+        action='store_true',
+        help='Overwrite if the output file exists.')
+    option_for_existing_output.add_argument(
+        '-a',
+        '--append',
+        action='store_true',
+        help='Append the input to the output file if the output file exists.')
     parser_proto.set_defaults(func=Proto)
 
     print_proto = subparsers.add_parser(
@@ -195,8 +231,12 @@
 
 
 def main():
-    args = GetArgParser().parse_args()
-    args.func(args)
+    parser = GetArgParser()
+    args = parser.parse_args()
+    if 'func' in args:
+        args.func(args)
+    else:
+        parser.print_help()
 
 
 if __name__ == '__main__':
diff --git a/scripts/conv_linker_config_test.py b/scripts/conv_linker_config_test.py
new file mode 100644
index 0000000..d19a47b
--- /dev/null
+++ b/scripts/conv_linker_config_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Unit tests for conv_linker_config.py."""
+
+import io
+import os
+import shutil
+import tempfile
+import unittest
+
+import conv_linker_config
+from contextlib import redirect_stderr
+from linker_config_pb2 import LinkerConfig
+
+class FileArgs:
+  def __init__(self, files, sep = ':'):
+    self.files = files
+    self.sep = sep
+
+
+class FileArg:
+  def __init__(self, file):
+    self.file = file
+
+
+class TempDirTest(unittest.TestCase):
+
+  def setUp(self):
+    self.tempdir = tempfile.mkdtemp()
+
+
+  def tearDown(self):
+    shutil.rmtree(self.tempdir)
+
+
+  def write(self, name, contents):
+    with open(os.path.join(self.tempdir, name), 'wb') as f:
+      f.write(contents)
+
+
+  def read(self, name):
+    with open(os.path.join(self.tempdir, name), 'rb') as f:
+      return f.read()
+
+
+  def resolve_paths(self, args):
+    for i in range(len(args)):
+      if isinstance(args[i], FileArgs):
+        args[i] = args[i].sep.join(os.path.join(self.tempdir, f.file) for f in args[i].files)
+      elif isinstance(args[i], FileArg):
+        args[i] = os.path.join(self.tempdir, args[i].file)
+    return args
+
+
+class ConvLinkerConfigTest(TempDirTest):
+  """Unit tests for conv_linker_config."""
+
+
+  def test_Proto_empty_input(self):
+    self.command(['proto', '-s', '-o', FileArg('out.pb')])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertEqual(pb, LinkerConfig())
+
+
+  def test_Proto_single_input(self):
+    self.write('foo.json', b'{ "provideLibs": ["libfoo.so"]}')
+    self.command(['proto', '-s', FileArg('foo.json'), '-o', FileArg('out.pb')])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertSequenceEqual(pb.provideLibs, ['libfoo.so'])
+
+
+  def test_Proto_with_multiple_input(self):
+    self.write('foo.json', b'{ "provideLibs": ["libfoo.so"]}')
+    self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+    self.command(['proto', '-s', FileArgs([FileArg('foo.json'), FileArg('bar.json')]), '-o', FileArg('out.pb')])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertSetEqual(set(pb.provideLibs), set(['libfoo.so', 'libbar.so']))
+
+
+  def test_Proto_with_existing_output(self):
+    self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+    buf = io.StringIO()
+    with self.assertRaises(SystemExit) as err:
+      with redirect_stderr(buf):
+        self.command(['proto', '-o', FileArg('out.pb')])
+    self.assertEqual(err.exception.code, 1)
+    self.assertRegex(buf.getvalue(), r'.*out\.pb exists')
+
+
+  def test_Proto_with_append(self):
+    self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+    self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+    self.command(['proto', '-s', FileArg('bar.json'), '-o', FileArg('out.pb'), '-a'])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertSetEqual(set(pb.provideLibs), set(['libfoo.so', 'libbar.so']))
+
+
+  def test_Proto_with_force(self):
+    self.write('out.pb', LinkerConfig(provideLibs=['libfoo.so']).SerializeToString())
+    self.write('bar.json', b'{ "provideLibs": ["libbar.so"]}')
+    self.command(['proto', '-s', FileArg('bar.json'), '-o', FileArg('out.pb'), '-f'])
+    pb = LinkerConfig()
+    pb.ParseFromString(self.read('out.pb'))
+    self.assertSetEqual(set(pb.provideLibs), set(['libbar.so']))
+
+
+  def command(self, args):
+    parser = conv_linker_config.GetArgParser()
+    parsed_args = parser.parse_args(self.resolve_paths(args))
+    parsed_args.func(parsed_args)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 1ff1b5b..68d7f8d 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -343,4 +343,29 @@
   run_bazel build --config=android --config=api_bp2build //:empty
 }
 
+# Verify that an *_api_contribution target can refer to an api file from
+# another Bazel package.
+function test_api_export_from_another_bazel_package() {
+  setup
+  # Parent dir Android.bp
+  mkdir -p foo
+  cat > foo/Android.bp << 'EOF'
+cc_library {
+  name: "libfoo",
+  stubs: {
+    symbol_file: "api/libfoo.map.txt",
+  },
+}
+EOF
+  # Child dir Android.bp
+  mkdir -p foo/api
+  cat > foo/api/Android.bp << 'EOF'
+package{}
+EOF
+  touch foo/api/libfoo.map.txt
+  # Run test
+  run_soong api_bp2build
+  run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
+}
+
 scan_and_run_tests
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index b3a027e..cbdeb27 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -135,8 +135,8 @@
 	e := t.peek()
 	e.procResInfo = append(e.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
 		Name:             proto.String(name),
-		UserTimeMicros:   proto.Uint64(uint64(rusage.Utime.Usec)),
-		SystemTimeMicros: proto.Uint64(uint64(rusage.Stime.Usec)),
+		UserTimeMicros:   proto.Uint64(uint64(state.UserTime().Microseconds())),
+		SystemTimeMicros: proto.Uint64(uint64(state.SystemTime().Microseconds())),
 		MinorPageFaults:  proto.Uint64(uint64(rusage.Minflt)),
 		MajorPageFaults:  proto.Uint64(uint64(rusage.Majflt)),
 		// ru_inblock and ru_oublock are measured in blocks of 512 bytes.