bootimg.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright (C) 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 filesystem
  15. import (
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. "github.com/google/blueprint"
  20. "github.com/google/blueprint/proptools"
  21. "android/soong/android"
  22. )
  23. func init() {
  24. android.RegisterModuleType("bootimg", bootimgFactory)
  25. }
  26. type bootimg struct {
  27. android.ModuleBase
  28. properties bootimgProperties
  29. output android.OutputPath
  30. installDir android.InstallPath
  31. }
  32. type bootimgProperties struct {
  33. // Set the name of the output. Defaults to <module_name>.img.
  34. Stem *string
  35. // Path to the linux kernel prebuilt file
  36. Kernel_prebuilt *string `android:"arch_variant,path"`
  37. // Filesystem module that is used as ramdisk
  38. Ramdisk_module *string
  39. // Path to the device tree blob (DTB) prebuilt file to add to this boot image
  40. Dtb_prebuilt *string `android:"arch_variant,path"`
  41. // Header version number. Must be set to one of the version numbers that are currently
  42. // supported. Refer to
  43. // https://source.android.com/devices/bootloader/boot-image-header
  44. Header_version *string
  45. // Determines if this image is for the vendor_boot partition. Default is false. Refer to
  46. // https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
  47. Vendor_boot *bool
  48. // Optional kernel commandline arguments
  49. Cmdline []string `android:"arch_variant"`
  50. // File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
  51. // and `header_version` is greater than or equal to 4.
  52. Bootconfig *string `android:"arch_variant,path"`
  53. // When set to true, sign the image with avbtool. Default is false.
  54. Use_avb *bool
  55. // Name of the partition stored in vbmeta desc. Defaults to the name of this module.
  56. Partition_name *string
  57. // Path to the private key that avbtool will use to sign this filesystem image.
  58. // TODO(jiyong): allow apex_key to be specified here
  59. Avb_private_key *string `android:"path"`
  60. // Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
  61. Avb_algorithm *string
  62. }
  63. // bootimg is the image for the boot partition. It consists of header, kernel, ramdisk, and dtb.
  64. func bootimgFactory() android.Module {
  65. module := &bootimg{}
  66. module.AddProperties(&module.properties)
  67. android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
  68. return module
  69. }
  70. type bootimgDep struct {
  71. blueprint.BaseDependencyTag
  72. kind string
  73. }
  74. var bootimgRamdiskDep = bootimgDep{kind: "ramdisk"}
  75. func (b *bootimg) DepsMutator(ctx android.BottomUpMutatorContext) {
  76. ramdisk := proptools.String(b.properties.Ramdisk_module)
  77. if ramdisk != "" {
  78. ctx.AddDependency(ctx.Module(), bootimgRamdiskDep, ramdisk)
  79. }
  80. }
  81. func (b *bootimg) installFileName() string {
  82. return proptools.StringDefault(b.properties.Stem, b.BaseModuleName()+".img")
  83. }
  84. func (b *bootimg) partitionName() string {
  85. return proptools.StringDefault(b.properties.Partition_name, b.BaseModuleName())
  86. }
  87. func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  88. vendor := proptools.Bool(b.properties.Vendor_boot)
  89. unsignedOutput := b.buildBootImage(ctx, vendor)
  90. if proptools.Bool(b.properties.Use_avb) {
  91. b.output = b.signImage(ctx, unsignedOutput)
  92. } else {
  93. b.output = unsignedOutput
  94. }
  95. b.installDir = android.PathForModuleInstall(ctx, "etc")
  96. ctx.InstallFile(b.installDir, b.installFileName(), b.output)
  97. }
  98. func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.OutputPath {
  99. output := android.PathForModuleOut(ctx, "unsigned", b.installFileName()).OutputPath
  100. builder := android.NewRuleBuilder(pctx, ctx)
  101. cmd := builder.Command().BuiltTool("mkbootimg")
  102. kernel := proptools.String(b.properties.Kernel_prebuilt)
  103. if vendor && kernel != "" {
  104. ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
  105. return output
  106. }
  107. if !vendor && kernel == "" {
  108. ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
  109. return output
  110. }
  111. if kernel != "" {
  112. cmd.FlagWithInput("--kernel ", android.PathForModuleSrc(ctx, kernel))
  113. }
  114. dtbName := proptools.String(b.properties.Dtb_prebuilt)
  115. if dtbName != "" {
  116. dtb := android.PathForModuleSrc(ctx, dtbName)
  117. cmd.FlagWithInput("--dtb ", dtb)
  118. }
  119. cmdline := strings.Join(b.properties.Cmdline, " ")
  120. if cmdline != "" {
  121. flag := "--cmdline "
  122. if vendor {
  123. flag = "--vendor_cmdline "
  124. }
  125. cmd.FlagWithArg(flag, proptools.ShellEscapeIncludingSpaces(cmdline))
  126. }
  127. headerVersion := proptools.String(b.properties.Header_version)
  128. if headerVersion == "" {
  129. ctx.PropertyErrorf("header_version", "must be set")
  130. return output
  131. }
  132. verNum, err := strconv.Atoi(headerVersion)
  133. if err != nil {
  134. ctx.PropertyErrorf("header_version", "%q is not a number", headerVersion)
  135. return output
  136. }
  137. if verNum < 3 {
  138. ctx.PropertyErrorf("header_version", "must be 3 or higher for vendor_boot")
  139. return output
  140. }
  141. cmd.FlagWithArg("--header_version ", headerVersion)
  142. ramdiskName := proptools.String(b.properties.Ramdisk_module)
  143. if ramdiskName != "" {
  144. ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
  145. if filesystem, ok := ramdisk.(*filesystem); ok {
  146. flag := "--ramdisk "
  147. if vendor {
  148. flag = "--vendor_ramdisk "
  149. }
  150. cmd.FlagWithInput(flag, filesystem.OutputPath())
  151. } else {
  152. ctx.PropertyErrorf("ramdisk", "%q is not android_filesystem module", ramdisk.Name())
  153. return output
  154. }
  155. }
  156. bootconfig := proptools.String(b.properties.Bootconfig)
  157. if bootconfig != "" {
  158. if !vendor {
  159. ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
  160. return output
  161. }
  162. if verNum < 4 {
  163. ctx.PropertyErrorf("bootconfig", "requires header_version: 4 or later")
  164. return output
  165. }
  166. cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
  167. }
  168. flag := "--output "
  169. if vendor {
  170. flag = "--vendor_boot "
  171. }
  172. cmd.FlagWithOutput(flag, output)
  173. builder.Build("build_bootimg", fmt.Sprintf("Creating %s", b.BaseModuleName()))
  174. return output
  175. }
  176. func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
  177. propFile, toolDeps := b.buildPropFile(ctx)
  178. output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
  179. builder := android.NewRuleBuilder(pctx, ctx)
  180. builder.Command().Text("cp").Input(unsignedImage).Output(output)
  181. builder.Command().BuiltTool("verity_utils").
  182. Input(propFile).
  183. Implicits(toolDeps).
  184. Output(output)
  185. builder.Build("sign_bootimg", fmt.Sprintf("Signing %s", b.BaseModuleName()))
  186. return output
  187. }
  188. // Calculates avb_salt from some input for deterministic output.
  189. func (b *bootimg) salt() string {
  190. var input []string
  191. input = append(input, b.properties.Cmdline...)
  192. input = append(input, proptools.StringDefault(b.properties.Partition_name, b.Name()))
  193. input = append(input, proptools.String(b.properties.Header_version))
  194. return sha1sum(input)
  195. }
  196. func (b *bootimg) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
  197. var sb strings.Builder
  198. var deps android.Paths
  199. addStr := func(name string, value string) {
  200. fmt.Fprintf(&sb, "%s=%s\n", name, value)
  201. }
  202. addPath := func(name string, path android.Path) {
  203. addStr(name, path.String())
  204. deps = append(deps, path)
  205. }
  206. addStr("avb_hash_enable", "true")
  207. addPath("avb_avbtool", ctx.Config().HostToolPath(ctx, "avbtool"))
  208. algorithm := proptools.StringDefault(b.properties.Avb_algorithm, "SHA256_RSA4096")
  209. addStr("avb_algorithm", algorithm)
  210. key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
  211. addPath("avb_key_path", key)
  212. addStr("avb_add_hash_footer_args", "") // TODO(jiyong): add --rollback_index
  213. partitionName := proptools.StringDefault(b.properties.Partition_name, b.Name())
  214. addStr("partition_name", partitionName)
  215. addStr("avb_salt", b.salt())
  216. propFile = android.PathForModuleOut(ctx, "prop").OutputPath
  217. android.WriteFileRule(ctx, propFile, sb.String())
  218. return propFile, deps
  219. }
  220. var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
  221. // Implements android.AndroidMkEntriesProvider
  222. func (b *bootimg) AndroidMkEntries() []android.AndroidMkEntries {
  223. return []android.AndroidMkEntries{android.AndroidMkEntries{
  224. Class: "ETC",
  225. OutputFile: android.OptionalPathForPath(b.output),
  226. ExtraEntries: []android.AndroidMkExtraEntriesFunc{
  227. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  228. entries.SetString("LOCAL_MODULE_PATH", b.installDir.String())
  229. entries.SetString("LOCAL_INSTALLED_MODULE_STEM", b.installFileName())
  230. },
  231. },
  232. }}
  233. }
  234. var _ Filesystem = (*bootimg)(nil)
  235. func (b *bootimg) OutputPath() android.Path {
  236. return b.output
  237. }
  238. func (b *bootimg) SignedOutputPath() android.Path {
  239. if proptools.Bool(b.properties.Use_avb) {
  240. return b.OutputPath()
  241. }
  242. return nil
  243. }
  244. var _ android.OutputFileProducer = (*bootimg)(nil)
  245. // Implements android.OutputFileProducer
  246. func (b *bootimg) OutputFiles(tag string) (android.Paths, error) {
  247. if tag == "" {
  248. return []android.Path{b.output}, nil
  249. }
  250. return nil, fmt.Errorf("unsupported module reference tag %q", tag)
  251. }