1// Copyright 2016 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "reflect" 19 20 "github.com/google/blueprint" 21 "github.com/google/blueprint/proptools" 22) 23 24// This file implements hooks that external module types can use to inject logic into existing 25// module types. Each hook takes an interface as a parameter so that new methods can be added 26// to the interface without breaking existing module types. 27 28// Load hooks are run after the module's properties have been filled from the blueprint file, but 29// before the module has been split into architecture variants, and before defaults modules have 30// been applied. 31type LoadHookContext interface { 32 EarlyModuleContext 33 34 AppendProperties(...interface{}) 35 PrependProperties(...interface{}) 36 CreateModule(ModuleFactory, ...interface{}) Module 37 38 registerScopedModuleType(name string, factory blueprint.ModuleFactory) 39 moduleFactories() map[string]blueprint.ModuleFactory 40} 41 42// Add a hook that will be called once the module has been loaded, i.e. its 43// properties have been initialized from the Android.bp file. 44// 45// Consider using SetDefaultableHook to register a hook for any module that implements 46// DefaultableModule as the hook is called after any defaults have been applied to the 47// module which could reduce duplication and make it easier to use. 48func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { 49 blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) { 50 actx := &loadHookContext{ 51 earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), 52 bp: ctx, 53 } 54 hook(actx) 55 }) 56} 57 58type loadHookContext struct { 59 earlyModuleContext 60 bp blueprint.LoadHookContext 61 module Module 62} 63 64func (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory { 65 return l.bp.ModuleFactories() 66} 67 68func (l *loadHookContext) AppendProperties(props ...interface{}) { 69 for _, p := range props { 70 err := proptools.AppendMatchingProperties(l.Module().base().customizableProperties, 71 p, nil) 72 if err != nil { 73 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 74 l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 75 } else { 76 panic(err) 77 } 78 } 79 } 80} 81 82func (l *loadHookContext) PrependProperties(props ...interface{}) { 83 for _, p := range props { 84 err := proptools.PrependMatchingProperties(l.Module().base().customizableProperties, 85 p, nil) 86 if err != nil { 87 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 88 l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 89 } else { 90 panic(err) 91 } 92 } 93 } 94} 95 96func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { 97 inherited := []interface{}{&l.Module().base().commonProperties} 98 module := l.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module) 99 100 if l.Module().base().variableProperties != nil && module.base().variableProperties != nil { 101 src := l.Module().base().variableProperties 102 dst := []interface{}{ 103 module.base().variableProperties, 104 // Put an empty copy of the src properties into dst so that properties in src that are not in dst 105 // don't cause a "failed to find property to extend" error. 106 proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(), 107 } 108 err := proptools.AppendMatchingProperties(dst, src, nil) 109 if err != nil { 110 panic(err) 111 } 112 } 113 114 return module 115} 116 117func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) { 118 l.bp.RegisterScopedModuleType(name, factory) 119} 120 121type InstallHookContext interface { 122 ModuleContext 123 Path() InstallPath 124 Symlink() bool 125} 126 127// Install hooks are run after a module creates a rule to install a file or symlink. 128// The installed path is available from InstallHookContext.Path(), and 129// InstallHookContext.Symlink() will be true if it was a symlink. 130func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { 131 h := &m.(Module).base().hooks 132 h.install = append(h.install, hook) 133} 134 135type installHookContext struct { 136 ModuleContext 137 path InstallPath 138 symlink bool 139} 140 141func (x *installHookContext) Path() InstallPath { 142 return x.path 143} 144 145func (x *installHookContext) Symlink() bool { 146 return x.symlink 147} 148 149func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) { 150 if len(x.install) > 0 { 151 mctx := &installHookContext{ 152 ModuleContext: ctx, 153 path: path, 154 symlink: symlink, 155 } 156 for _, x := range x.install { 157 x(mctx) 158 if mctx.Failed() { 159 return 160 } 161 } 162 } 163} 164 165type hooks struct { 166 install []func(InstallHookContext) 167} 168