1// Copyright (C) 2022 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 15package filesystem 16 17import ( 18 "fmt" 19 "strconv" 20 21 "github.com/google/blueprint/proptools" 22 23 "android/soong/android" 24) 25 26type avbAddHashFooter struct { 27 android.ModuleBase 28 29 properties avbAddHashFooterProperties 30 31 output android.OutputPath 32 installDir android.InstallPath 33} 34 35type avbProp struct { 36 // Name of a property 37 Name *string 38 39 // Value of a property. Can't be used together with `file`. 40 Value *string 41 42 // File from which the value of the prop is read from. Can't be used together with `value`. 43 File *string `android:"path,arch_variant"` 44} 45 46type avbAddHashFooterProperties struct { 47 // Source file of this image. Can reference a genrule type module with the ":module" syntax. 48 Src *string `android:"path,arch_variant"` 49 50 // Set the name of the output. Defaults to <module_name>.img. 51 Filename *string 52 53 // Name of the image partition. Defaults to the name of this module. 54 Partition_name *string 55 56 // Size of the partition. Defaults to dynamically calculating the size. 57 Partition_size *int64 58 59 // Path to the private key that avbtool will use to sign this image. 60 Private_key *string `android:"path"` 61 62 // Algorithm that avbtool will use to sign this image. Default is SHA256_RSA4096. 63 Algorithm *string 64 65 // The salt in hex. Required for reproducible builds. 66 Salt *string 67 68 // List of properties to add to the footer 69 Props []avbProp 70 71 // Include descriptors from images 72 Include_descriptors_from_images []string `android:"path,arch_variant"` 73} 74 75// The AVB footer adds verification information to the image. 76func avbAddHashFooterFactory() android.Module { 77 module := &avbAddHashFooter{} 78 module.AddProperties(&module.properties) 79 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) 80 return module 81} 82 83func (a *avbAddHashFooter) installFileName() string { 84 return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".img") 85} 86 87func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext) { 88 builder := android.NewRuleBuilder(pctx, ctx) 89 90 if a.properties.Src == nil { 91 ctx.PropertyErrorf("src", "missing source file") 92 return 93 } 94 input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src)) 95 a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath 96 builder.Command().Text("cp").Input(input).Output(a.output) 97 98 cmd := builder.Command().BuiltTool("avbtool").Text("add_hash_footer") 99 100 partition_name := proptools.StringDefault(a.properties.Partition_name, a.BaseModuleName()) 101 cmd.FlagWithArg("--partition_name ", partition_name) 102 103 if a.properties.Partition_size == nil { 104 cmd.Flag("--dynamic_partition_size") 105 } else { 106 partition_size := proptools.Int(a.properties.Partition_size) 107 cmd.FlagWithArg("--partition_size ", strconv.Itoa(partition_size)) 108 } 109 110 key := android.PathForModuleSrc(ctx, proptools.String(a.properties.Private_key)) 111 cmd.FlagWithInput("--key ", key) 112 113 algorithm := proptools.StringDefault(a.properties.Algorithm, "SHA256_RSA4096") 114 cmd.FlagWithArg("--algorithm ", algorithm) 115 116 if a.properties.Salt == nil { 117 ctx.PropertyErrorf("salt", "missing salt value") 118 return 119 } 120 cmd.FlagWithArg("--salt ", proptools.String(a.properties.Salt)) 121 122 imagePaths := android.PathsForModuleSrc(ctx, a.properties.Include_descriptors_from_images) 123 for _, imagePath := range imagePaths { 124 cmd.FlagWithInput("--include_descriptors_from_image ", imagePath) 125 } 126 127 for _, prop := range a.properties.Props { 128 addAvbProp(ctx, cmd, prop) 129 } 130 131 cmd.FlagWithOutput("--image ", a.output) 132 133 builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName())) 134 135 a.installDir = android.PathForModuleInstall(ctx, "etc") 136 ctx.InstallFile(a.installDir, a.installFileName(), a.output) 137} 138 139func addAvbProp(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, prop avbProp) { 140 name := proptools.String(prop.Name) 141 value := proptools.String(prop.Value) 142 file := proptools.String(prop.File) 143 if name == "" { 144 ctx.PropertyErrorf("name", "can't be empty") 145 return 146 } 147 if value == "" && file == "" { 148 ctx.PropertyErrorf("value", "either value or file should be set") 149 return 150 } 151 if value != "" && file != "" { 152 ctx.PropertyErrorf("value", "value and file can't be set at the same time") 153 return 154 } 155 156 if value != "" { 157 cmd.FlagWithArg("--prop ", proptools.ShellEscape(fmt.Sprintf("%s:%s", name, value))) 158 } else { 159 p := android.PathForModuleSrc(ctx, file) 160 cmd.Implicit(p) 161 cmd.FlagWithArg("--prop_from_file ", proptools.ShellEscape(fmt.Sprintf("%s:%s", name, cmd.PathForInput(p)))) 162 } 163} 164 165var _ android.AndroidMkEntriesProvider = (*avbAddHashFooter)(nil) 166 167// Implements android.AndroidMkEntriesProvider 168func (a *avbAddHashFooter) AndroidMkEntries() []android.AndroidMkEntries { 169 return []android.AndroidMkEntries{android.AndroidMkEntries{ 170 Class: "ETC", 171 OutputFile: android.OptionalPathForPath(a.output), 172 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 173 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 174 entries.SetString("LOCAL_MODULE_PATH", a.installDir.String()) 175 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", a.installFileName()) 176 }, 177 }, 178 }} 179} 180 181var _ Filesystem = (*avbAddHashFooter)(nil) 182 183func (a *avbAddHashFooter) OutputPath() android.Path { 184 return a.output 185} 186 187func (a *avbAddHashFooter) SignedOutputPath() android.Path { 188 return a.OutputPath() // always signed 189} 190 191// TODO(b/185115783): remove when not needed as input to a prebuilt_etc rule 192var _ android.SourceFileProducer = (*avbAddHashFooter)(nil) 193 194// Implements android.SourceFileProducer 195func (a *avbAddHashFooter) Srcs() android.Paths { 196 return append(android.Paths{}, a.output) 197} 198