Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6dd6a3c authored by Paul Duffin's avatar Paul Duffin Committed by Gerrit Code Review
Browse files

Merge changes I55dc71d2,I250ee4e1

* changes:
  Avoid separate call to module factory to create conditional properties
  Test using soong_config_module_type with singleton module type
parents 0c79abc9 e8b47681
Loading
Loading
Loading
Loading
+35 −3
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ package android
import (
	"fmt"
	"path/filepath"
	"reflect"
	"strings"
	"sync"
	"text/scanner"

	"github.com/google/blueprint"
@@ -422,13 +424,43 @@ func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[s
// configModuleFactory takes an existing soongConfigModuleFactory and a
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
	conditionalFactoryProps := soongconfig.CreateProperties(factory, moduleType)
	if !conditionalFactoryProps.IsValid() {
		return factory
	// Defer creation of conditional properties struct until the first call from the factory
	// method. That avoids having to make a special call to the factory to create the properties
	// structs from which the conditional properties struct is created. This is needed in order to
	// allow singleton modules to be customized by soong_config_module_type as the
	// SingletonModuleFactoryAdaptor factory registers a load hook for the singleton module
	// everytime that it is called. Calling the factory twice causes a build failure as the load
	// hook is called twice, the first time it updates the singleton module to indicate that it has
	// been registered as a module, and the second time it fails because it thinks it has been
	// registered again and a singleton module can only be registered once.
	//
	// This is an issue for singleton modules because:
	// * Load hooks are registered on the module object and are only called when the module object
	//   is created by Blueprint while processing the Android.bp file.
	// * The module factory for a singleton module returns the same module object each time it is
	//   called, and registers its load hook on that same module object.
	// * When the module factory is called by Blueprint it then calls all the load hooks that have
	//   been registered for every call to that module factory.
	//
	// It is not an issue for normal modules because they return a new module object each time the
	// factory is called and so any load hooks registered on module objects which are discarded will
	// not be run.
	once := &sync.Once{}
	conditionalFactoryProps := reflect.Value{}
	getConditionalFactoryProps := func(props []interface{}) reflect.Value {
		once.Do(func() {
			conditionalFactoryProps = soongconfig.CreateProperties(props, moduleType)
		})
		return conditionalFactoryProps
	}

	return func() (blueprint.Module, []interface{}) {
		module, props := factory()
		conditionalFactoryProps := getConditionalFactoryProps(props)
		if !conditionalFactoryProps.IsValid() {
			return module, props
		}

		conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
		props = append(props, conditionalProps.Interface())

+90 −7
Original line number Diff line number Diff line
@@ -15,12 +15,10 @@
package android

import (
	"fmt"
	"testing"
)

type soongConfigTestDefaultsModuleProperties struct {
}

type soongConfigTestDefaultsModule struct {
	ModuleBase
	DefaultsModuleBase
@@ -413,10 +411,95 @@ func TestDuplicateStringValueInSoongConfigStringVariable(t *testing.T) {
	})).RunTest(t)
}

func testConfigWithVendorVars(buildDir, bp string, fs map[string][]byte, vendorVars map[string]map[string]string) Config {
	config := TestConfig(buildDir, nil, bp, fs)
type soongConfigTestSingletonModule struct {
	SingletonModuleBase
	props soongConfigTestSingletonModuleProperties
}

type soongConfigTestSingletonModuleProperties struct {
	Fragments []struct {
		Apex   string
		Module string
	}
}

func soongConfigTestSingletonModuleFactory() SingletonModule {
	m := &soongConfigTestSingletonModule{}
	m.AddProperties(&m.props)
	InitAndroidModule(m)
	return m
}

func (t *soongConfigTestSingletonModule) GenerateAndroidBuildActions(ModuleContext) {}

func (t *soongConfigTestSingletonModule) GenerateSingletonBuildActions(SingletonContext) {}

var prepareForSoongConfigTestSingletonModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
	ctx.RegisterSingletonModuleType("test_singleton", soongConfigTestSingletonModuleFactory)
})

func TestSoongConfigModuleSingletonModule(t *testing.T) {
	bp := `
		soong_config_module_type {
			name: "acme_test_singleton",
			module_type: "test_singleton",
			config_namespace: "acme",
			bool_variables: ["coyote"],
			properties: ["fragments"],
		}

		acme_test_singleton {
			name: "wiley",
			fragments: [
				{
					apex: "com.android.acme",
					module: "road-runner",
				},
			],
			soong_config_variables: {
				coyote: {
					fragments: [
						{
							apex: "com.android.acme",
							module: "wiley",
						},
					],
				},
			},
		}
	`

	config.TestProductVariables.VendorVars = vendorVars
	for _, test := range []struct {
		coyote            bool
		expectedFragments string
	}{
		{
			coyote:            false,
			expectedFragments: "[{Apex:com.android.acme Module:road-runner}]",
		},
		{
			coyote:            true,
			expectedFragments: "[{Apex:com.android.acme Module:road-runner} {Apex:com.android.acme Module:wiley}]",
		},
	} {
		t.Run(fmt.Sprintf("coyote:%t", test.coyote), func(t *testing.T) {
			result := GroupFixturePreparers(
				PrepareForTestWithSoongConfigModuleBuildComponents,
				prepareForSoongConfigTestSingletonModule,
				FixtureWithRootAndroidBp(bp),
				FixtureModifyProductVariables(func(variables FixtureProductVariables) {
					variables.VendorVars = map[string]map[string]string{
						"acme": {
							"coyote": fmt.Sprintf("%t", test.coyote),
						},
					}
				}),
			).RunTest(t)

	return config
			// Make sure that the singleton was created.
			result.SingletonForTests("test_singleton")
			m := result.ModuleForTests("wiley", "").module.(*soongConfigTestSingletonModule)
			AssertStringEquals(t, "fragments", test.expectedFragments, fmt.Sprintf("%+v", m.props.Fragments))
		})
	}
}
+1 −3
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import (
	"strings"
	"sync"

	"github.com/google/blueprint"
	"github.com/google/blueprint/parser"
	"github.com/google/blueprint/proptools"

@@ -363,10 +362,9 @@ func (defs Bp2BuildSoongConfigDefinitions) String() string {
//	        },
//	    },
//	}
func CreateProperties(factory blueprint.ModuleFactory, moduleType *ModuleType) reflect.Value {
func CreateProperties(factoryProps []interface{}, moduleType *ModuleType) reflect.Value {
	var fields []reflect.StructField

	_, factoryProps := factory()
	affectablePropertiesType := createAffectablePropertiesType(moduleType.affectableProperties, factoryProps)
	if affectablePropertiesType == nil {
		return reflect.Value{}