hooks.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. package android
  15. import (
  16. "fmt"
  17. "path"
  18. "reflect"
  19. "runtime"
  20. "github.com/google/blueprint"
  21. "github.com/google/blueprint/proptools"
  22. )
  23. // This file implements hooks that external module types can use to inject logic into existing
  24. // module types. Each hook takes an interface as a parameter so that new methods can be added
  25. // to the interface without breaking existing module types.
  26. // Load hooks are run after the module's properties have been filled from the blueprint file, but
  27. // before the module has been split into architecture variants, and before defaults modules have
  28. // been applied.
  29. type LoadHookContext interface {
  30. EarlyModuleContext
  31. AppendProperties(...interface{})
  32. PrependProperties(...interface{})
  33. CreateModule(ModuleFactory, ...interface{}) Module
  34. registerScopedModuleType(name string, factory blueprint.ModuleFactory)
  35. moduleFactories() map[string]blueprint.ModuleFactory
  36. }
  37. // Add a hook that will be called once the module has been loaded, i.e. its
  38. // properties have been initialized from the Android.bp file.
  39. //
  40. // Consider using SetDefaultableHook to register a hook for any module that implements
  41. // DefaultableModule as the hook is called after any defaults have been applied to the
  42. // module which could reduce duplication and make it easier to use.
  43. func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
  44. blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) {
  45. actx := &loadHookContext{
  46. earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx),
  47. bp: ctx,
  48. }
  49. hook(actx)
  50. })
  51. }
  52. type loadHookContext struct {
  53. earlyModuleContext
  54. bp blueprint.LoadHookContext
  55. module Module
  56. }
  57. func (l *loadHookContext) moduleFactories() map[string]blueprint.ModuleFactory {
  58. return l.bp.ModuleFactories()
  59. }
  60. func (l *loadHookContext) appendPrependHelper(props []interface{},
  61. extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) {
  62. for _, p := range props {
  63. err := extendFn(l.Module().base().GetProperties(), p, nil)
  64. if err != nil {
  65. if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
  66. l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
  67. } else {
  68. panic(err)
  69. }
  70. }
  71. }
  72. }
  73. func (l *loadHookContext) AppendProperties(props ...interface{}) {
  74. l.appendPrependHelper(props, proptools.AppendMatchingProperties)
  75. }
  76. func (l *loadHookContext) PrependProperties(props ...interface{}) {
  77. l.appendPrependHelper(props, proptools.PrependMatchingProperties)
  78. }
  79. func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module {
  80. return l.bp.CreateModule(factory, name, props...)
  81. }
  82. type createModuleContext interface {
  83. Module() Module
  84. createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module
  85. }
  86. func createModule(ctx createModuleContext, factory ModuleFactory, ext string, props ...interface{}) Module {
  87. inherited := []interface{}{&ctx.Module().base().commonProperties}
  88. var typeName string
  89. if typeNameLookup, ok := ModuleTypeByFactory()[reflect.ValueOf(factory)]; ok {
  90. typeName = typeNameLookup
  91. } else {
  92. factoryPtr := reflect.ValueOf(factory).Pointer()
  93. factoryFunc := runtime.FuncForPC(factoryPtr)
  94. filePath, _ := factoryFunc.FileLine(factoryPtr)
  95. typeName = fmt.Sprintf("%s_%s", path.Base(filePath), factoryFunc.Name())
  96. }
  97. typeName = typeName + "_" + ext
  98. module := ctx.createModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
  99. if ctx.Module().base().variableProperties != nil && module.base().variableProperties != nil {
  100. src := ctx.Module().base().variableProperties
  101. dst := []interface{}{
  102. module.base().variableProperties,
  103. // Put an empty copy of the src properties into dst so that properties in src that are not in dst
  104. // don't cause a "failed to find property to extend" error.
  105. proptools.CloneEmptyProperties(reflect.ValueOf(src)).Interface(),
  106. }
  107. err := proptools.AppendMatchingProperties(dst, src, nil)
  108. if err != nil {
  109. panic(err)
  110. }
  111. }
  112. return module
  113. }
  114. func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
  115. return createModule(l, factory, "_loadHookModule", props...)
  116. }
  117. func (l *loadHookContext) registerScopedModuleType(name string, factory blueprint.ModuleFactory) {
  118. l.bp.RegisterScopedModuleType(name, factory)
  119. }
  120. type InstallHookContext interface {
  121. ModuleContext
  122. SrcPath() Path
  123. Path() InstallPath
  124. Symlink() bool
  125. }
  126. // Install hooks are run after a module creates a rule to install a file or symlink.
  127. // The installed path is available from InstallHookContext.Path(), and
  128. // InstallHookContext.Symlink() will be true if it was a symlink.
  129. func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) {
  130. h := &m.(Module).base().hooks
  131. h.install = append(h.install, hook)
  132. }
  133. type installHookContext struct {
  134. ModuleContext
  135. srcPath Path
  136. path InstallPath
  137. symlink bool
  138. }
  139. var _ InstallHookContext = &installHookContext{}
  140. func (x *installHookContext) SrcPath() Path {
  141. return x.srcPath
  142. }
  143. func (x *installHookContext) Path() InstallPath {
  144. return x.path
  145. }
  146. func (x *installHookContext) Symlink() bool {
  147. return x.symlink
  148. }
  149. func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) {
  150. if len(x.install) > 0 {
  151. mctx := &installHookContext{
  152. ModuleContext: ctx,
  153. srcPath: srcPath,
  154. path: path,
  155. symlink: symlink,
  156. }
  157. for _, x := range x.install {
  158. x(mctx)
  159. if mctx.Failed() {
  160. return
  161. }
  162. }
  163. }
  164. }
  165. type hooks struct {
  166. install []func(InstallHookContext)
  167. }