host_snapshot.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2021 The Android Open Source Project
  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 snapshot
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "path/filepath"
  19. "sort"
  20. "github.com/google/blueprint"
  21. "github.com/google/blueprint/proptools"
  22. "android/soong/android"
  23. )
  24. //
  25. // The host_snapshot module creates a snapshot of the modules defined in
  26. // the deps property. The modules within the deps property (host tools)
  27. // are ones that return a valid path via HostToolPath() of the
  28. // HostToolProvider. The created snapshot contains the binaries and any
  29. // transitive PackagingSpecs of the included host tools, along with a JSON
  30. // meta file.
  31. //
  32. // The snapshot is installed into a source tree via
  33. // development/vendor_snapshot/update.py, the included modules are
  34. // provided as preferred prebuilts.
  35. //
  36. // To determine which tools to include in the host snapshot see
  37. // host_fake_snapshot.go.
  38. func init() {
  39. registerHostBuildComponents(android.InitRegistrationContext)
  40. }
  41. func registerHostBuildComponents(ctx android.RegistrationContext) {
  42. ctx.RegisterModuleType("host_snapshot", hostSnapshotFactory)
  43. }
  44. // Relative installation path
  45. type RelativeInstallPath interface {
  46. RelativeInstallPath() string
  47. }
  48. type hostSnapshot struct {
  49. android.ModuleBase
  50. android.PackagingBase
  51. zipFile android.OptionalPath
  52. installDir android.InstallPath
  53. }
  54. func hostSnapshotFactory() android.Module {
  55. module := &hostSnapshot{}
  56. initHostToolsModule(module)
  57. return module
  58. }
  59. func initHostToolsModule(module *hostSnapshot) {
  60. android.InitPackageModule(module)
  61. android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
  62. }
  63. var dependencyTag = struct {
  64. blueprint.BaseDependencyTag
  65. android.InstallAlwaysNeededDependencyTag
  66. android.PackagingItemAlwaysDepTag
  67. }{}
  68. func (f *hostSnapshot) DepsMutator(ctx android.BottomUpMutatorContext) {
  69. f.AddDeps(ctx, dependencyTag)
  70. }
  71. func (f *hostSnapshot) installFileName() string {
  72. return f.Name() + ".zip"
  73. }
  74. // Create zipfile with JSON description, notice files... for dependent modules
  75. func (f *hostSnapshot) CreateMetaData(ctx android.ModuleContext, fileName string) android.OutputPath {
  76. var jsonData []SnapshotJsonFlags
  77. var metaPaths android.Paths
  78. metaZipFile := android.PathForModuleOut(ctx, fileName).OutputPath
  79. // Create JSON file based on the direct dependencies
  80. ctx.VisitDirectDeps(func(dep android.Module) {
  81. desc := hostBinJsonDesc(dep)
  82. if desc != nil {
  83. jsonData = append(jsonData, *desc)
  84. }
  85. if len(dep.EffectiveLicenseFiles()) > 0 {
  86. noticeFile := android.PathForModuleOut(ctx, "NOTICE_FILES", dep.Name()+".txt").OutputPath
  87. android.CatFileRule(ctx, dep.EffectiveLicenseFiles(), noticeFile)
  88. metaPaths = append(metaPaths, noticeFile)
  89. }
  90. })
  91. // Sort notice paths and json data for repeatble build
  92. sort.Slice(jsonData, func(i, j int) bool {
  93. return (jsonData[i].ModuleName < jsonData[j].ModuleName)
  94. })
  95. sort.Slice(metaPaths, func(i, j int) bool {
  96. return (metaPaths[i].String() < metaPaths[j].String())
  97. })
  98. marsh, err := json.Marshal(jsonData)
  99. if err != nil {
  100. ctx.ModuleErrorf("host snapshot json marshal failure: %#v", err)
  101. return android.OutputPath{}
  102. }
  103. jsonZipFile := android.PathForModuleOut(ctx, "host_snapshot.json").OutputPath
  104. metaPaths = append(metaPaths, jsonZipFile)
  105. rspFile := android.PathForModuleOut(ctx, "host_snapshot.rsp").OutputPath
  106. android.WriteFileRule(ctx, jsonZipFile, string(marsh))
  107. builder := android.NewRuleBuilder(pctx, ctx)
  108. builder.Command().
  109. BuiltTool("soong_zip").
  110. FlagWithArg("-C ", android.PathForModuleOut(ctx).OutputPath.String()).
  111. FlagWithOutput("-o ", metaZipFile).
  112. FlagWithRspFileInputList("-r ", rspFile, metaPaths)
  113. builder.Build("zip_meta", fmt.Sprintf("zipping meta data for %s", ctx.ModuleName()))
  114. return metaZipFile
  115. }
  116. // Create the host tool zip file
  117. func (f *hostSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  118. // Create a zip file for the binaries, and a zip of the meta data, then merge zips
  119. depsZipFile := android.PathForModuleOut(ctx, f.Name()+"_deps.zip").OutputPath
  120. modsZipFile := android.PathForModuleOut(ctx, f.Name()+"_mods.zip").OutputPath
  121. outputFile := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
  122. f.installDir = android.PathForModuleInstall(ctx)
  123. f.CopyDepsToZip(ctx, depsZipFile)
  124. builder := android.NewRuleBuilder(pctx, ctx)
  125. builder.Command().
  126. BuiltTool("zip2zip").
  127. FlagWithInput("-i ", depsZipFile).
  128. FlagWithOutput("-o ", modsZipFile).
  129. Text("**/*:" + proptools.ShellEscape(f.installDir.String()))
  130. metaZipFile := f.CreateMetaData(ctx, f.Name()+"_meta.zip")
  131. builder.Command().
  132. BuiltTool("merge_zips").
  133. Output(outputFile).
  134. Input(metaZipFile).
  135. Input(modsZipFile)
  136. builder.Build("manifest", fmt.Sprintf("Adding manifest %s", f.installFileName()))
  137. zip := ctx.InstallFile(f.installDir, f.installFileName(), outputFile)
  138. f.zipFile = android.OptionalPathForPath(zip)
  139. }
  140. // Implements android.AndroidMkEntriesProvider
  141. func (f *hostSnapshot) AndroidMkEntries() []android.AndroidMkEntries {
  142. if !f.zipFile.Valid() {
  143. return []android.AndroidMkEntries{}
  144. }
  145. return []android.AndroidMkEntries{android.AndroidMkEntries{
  146. Class: "ETC",
  147. OutputFile: f.zipFile,
  148. DistFiles: android.MakeDefaultDistFiles(f.zipFile.Path()),
  149. ExtraEntries: []android.AndroidMkExtraEntriesFunc{
  150. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  151. entries.SetString("LOCAL_MODULE_PATH", f.installDir.String())
  152. entries.SetString("LOCAL_INSTALLED_MODULE_STEM", f.installFileName())
  153. },
  154. },
  155. }}
  156. }
  157. // Get host tools path and relative install string helpers
  158. func hostBinToolPath(m android.Module) android.OptionalPath {
  159. if provider, ok := m.(android.HostToolProvider); ok {
  160. return provider.HostToolPath()
  161. }
  162. return android.OptionalPath{}
  163. }
  164. func hostRelativePathString(m android.Module) string {
  165. var outString string
  166. if rel, ok := m.(RelativeInstallPath); ok {
  167. outString = rel.RelativeInstallPath()
  168. }
  169. return outString
  170. }
  171. // Create JSON description for given module, only create descriptions for binary modueles which
  172. // provide a valid HostToolPath
  173. func hostBinJsonDesc(m android.Module) *SnapshotJsonFlags {
  174. path := hostBinToolPath(m)
  175. relPath := hostRelativePathString(m)
  176. if path.Valid() && path.String() != "" {
  177. return &SnapshotJsonFlags{
  178. ModuleName: m.Name(),
  179. ModuleStemName: filepath.Base(path.String()),
  180. Filename: path.String(),
  181. Required: append(m.HostRequiredModuleNames(), m.RequiredModuleNames()...),
  182. RelativeInstallPath: relPath,
  183. }
  184. }
  185. return nil
  186. }