Add hook to be called after defaults have been applied

Previously, the only way for a module type to create modules (other
than defining its own mutator) was to register a LoadHook. However,
that is called before defaults are applied so any properties used in
that hook cannot take advantage of defaults, e.g. java_sdk_library
cannot use defaults to set its sdk_version property and have that
affect its child modules.

This change adds a new SetDefaultableHook() to DefaultableModule to
register a hook that is called after any defaults have been applied.

Also adds some tests to ensure that errors in the visibility property
introduced in a DefaultableHook are reported in the gather phase of
visibility processing.

A follow up change will switch java_sdk_library to use that instead
of the AddLoadHook() mechanism.

Bug: 155295806
Test: m checkapi
Change-Id: I13df3115f9e225f7324b6725eaeb16a78cc2538a
diff --git a/android/defaults.go b/android/defaults.go
index 6a908ea..81e340e 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -35,6 +35,9 @@
 	defaultsProperties            defaultsProperties
 	defaultableProperties         []interface{}
 	defaultableVariableProperties interface{}
+
+	// The optional hook to call after any defaults have been applied.
+	hook DefaultableHook
 }
 
 func (d *DefaultableModuleBase) defaults() *defaultsProperties {
@@ -46,6 +49,16 @@
 	d.defaultableVariableProperties = variableProperties
 }
 
+func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
+	d.hook = hook
+}
+
+func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
+	if d.hook != nil {
+		d.hook(ctx)
+	}
+}
+
 // Interface that must be supported by any module to which defaults can be applied.
 type Defaultable interface {
 	// Get a pointer to the struct containing the Defaults property.
@@ -57,6 +70,15 @@
 	// Apply defaults from the supplied Defaults to the property structures supplied to
 	// setProperties(...).
 	applyDefaults(TopDownMutatorContext, []Defaults)
+
+	// Set the hook to be called after any defaults have been applied.
+	//
+	// Should be used in preference to a AddLoadHook when the behavior of the load
+	// hook is dependent on properties supplied in the Android.bp file.
+	SetDefaultableHook(hook DefaultableHook)
+
+	// Call the hook if specified.
+	callHookIfAvailable(context DefaultableHookContext)
 }
 
 type DefaultableModule interface {
@@ -75,6 +97,15 @@
 	module.AddProperties(module.defaults())
 }
 
+// A restricted subset of context methods, similar to LoadHookContext.
+type DefaultableHookContext interface {
+	EarlyModuleContext
+
+	CreateModule(ModuleFactory, ...interface{}) Module
+}
+
+type DefaultableHook func(ctx DefaultableHookContext)
+
 // The Defaults_visibility property.
 type DefaultsVisibilityProperties struct {
 
@@ -268,25 +299,29 @@
 }
 
 func defaultsMutator(ctx TopDownMutatorContext) {
-	if defaultable, ok := ctx.Module().(Defaultable); ok && len(defaultable.defaults().Defaults) > 0 {
-		var defaultsList []Defaults
-		seen := make(map[Defaults]bool)
+	if defaultable, ok := ctx.Module().(Defaultable); ok {
+		if len(defaultable.defaults().Defaults) > 0 {
+			var defaultsList []Defaults
+			seen := make(map[Defaults]bool)
 
-		ctx.WalkDeps(func(module, parent Module) bool {
-			if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
-				if defaults, ok := module.(Defaults); ok {
-					if !seen[defaults] {
-						seen[defaults] = true
-						defaultsList = append(defaultsList, defaults)
-						return len(defaults.defaults().Defaults) > 0
+			ctx.WalkDeps(func(module, parent Module) bool {
+				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
+					if defaults, ok := module.(Defaults); ok {
+						if !seen[defaults] {
+							seen[defaults] = true
+							defaultsList = append(defaultsList, defaults)
+							return len(defaults.defaults().Defaults) > 0
+						}
+					} else {
+						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
+							ctx.OtherModuleName(module))
 					}
-				} else {
-					ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
-						ctx.OtherModuleName(module))
 				}
-			}
-			return false
-		})
-		defaultable.applyDefaults(ctx, defaultsList)
+				return false
+			})
+			defaultable.applyDefaults(ctx, defaultsList)
+		}
+
+		defaultable.callHookIfAvailable(ctx)
 	}
 }