1// Copyright (C) 2018 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 apex 16 17import ( 18 "fmt" 19 "sort" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/bazel" 24 25 "github.com/google/blueprint/proptools" 26) 27 28var String = proptools.String 29 30func init() { 31 registerApexKeyBuildComponents(android.InitRegistrationContext) 32} 33 34func registerApexKeyBuildComponents(ctx android.RegistrationContext) { 35 ctx.RegisterModuleType("apex_key", ApexKeyFactory) 36 ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) 37} 38 39type apexKey struct { 40 android.ModuleBase 41 android.BazelModuleBase 42 43 properties apexKeyProperties 44 45 publicKeyFile android.Path 46 privateKeyFile android.Path 47 48 keyName string 49} 50 51type apexKeyProperties struct { 52 // Path or module to the public key file in avbpubkey format. Installed to the device. 53 // Base name of the file is used as the ID for the key. 54 Public_key *string `android:"path"` 55 // Path or module to the private key file in pem format. Used to sign APEXs. 56 Private_key *string `android:"path"` 57 58 // Whether this key is installable to one of the partitions. Defualt: true. 59 Installable *bool 60} 61 62func ApexKeyFactory() android.Module { 63 module := &apexKey{} 64 module.AddProperties(&module.properties) 65 android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon) 66 android.InitBazelModule(module) 67 return module 68} 69 70func (m *apexKey) installable() bool { 71 return false 72} 73 74func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) { 75 // If the keys are from other modules (i.e. :module syntax) respect it. 76 // Otherwise, try to locate the key files in the default cert dir or 77 // in the local module dir 78 if android.SrcIsModule(String(m.properties.Public_key)) != "" { 79 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 80 } else { 81 m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key)) 82 // If not found, fall back to the local key pairs 83 if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() { 84 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 85 } 86 } 87 88 if android.SrcIsModule(String(m.properties.Private_key)) != "" { 89 m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) 90 } else { 91 m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key)) 92 if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() { 93 m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) 94 } 95 } 96 97 pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())] 98 privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())] 99 100 if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName { 101 ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname", 102 m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName) 103 return 104 } 105 m.keyName = pubKeyName 106} 107 108//////////////////////////////////////////////////////////////////////// 109// apex_keys_text 110type apexKeysText struct { 111 output android.OutputPath 112} 113 114func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { 115 s.output = android.PathForOutput(ctx, "apexkeys.txt") 116 type apexKeyEntry struct { 117 name string 118 presigned bool 119 publicKey string 120 privateKey string 121 containerCertificate string 122 containerPrivateKey string 123 partition string 124 signTool string 125 } 126 toString := func(e apexKeyEntry) string { 127 signTool := "" 128 if e.signTool != "" { 129 signTool = fmt.Sprintf(" sign_tool=%q", e.signTool) 130 } 131 format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n" 132 if e.presigned { 133 return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool) 134 } else { 135 return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool) 136 } 137 } 138 139 apexKeyMap := make(map[string]apexKeyEntry) 140 ctx.VisitAllModules(func(module android.Module) { 141 if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() { 142 pem, key := m.getCertificateAndPrivateKey(ctx) 143 apexKeyMap[m.Name()] = apexKeyEntry{ 144 name: m.Name() + ".apex", 145 presigned: false, 146 publicKey: m.publicKeyFile.String(), 147 privateKey: m.privateKeyFile.String(), 148 containerCertificate: pem.String(), 149 containerPrivateKey: key.String(), 150 partition: m.PartitionTag(ctx.DeviceConfig()), 151 signTool: proptools.String(m.properties.Custom_sign_tool), 152 } 153 } 154 }) 155 156 // Find prebuilts and let them override apexBundle if they are preferred 157 ctx.VisitAllModules(func(module android.Module) { 158 if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() && 159 m.Prebuilt().UsePrebuilt() { 160 apexKeyMap[m.BaseModuleName()] = apexKeyEntry{ 161 name: m.InstallFilename(), 162 presigned: true, 163 partition: m.PartitionTag(ctx.DeviceConfig()), 164 } 165 } 166 }) 167 168 // Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass 169 // so that apex_set are not overridden by prebuilts. 170 ctx.VisitAllModules(func(module android.Module) { 171 if m, ok := module.(*ApexSet); ok && m.Enabled() { 172 entry := apexKeyEntry{ 173 name: m.InstallFilename(), 174 presigned: true, 175 partition: m.PartitionTag(ctx.DeviceConfig()), 176 } 177 apexKeyMap[m.BaseModuleName()] = entry 178 } 179 }) 180 181 // iterating over map does not give consistent ordering in golang 182 var moduleNames []string 183 for key, _ := range apexKeyMap { 184 moduleNames = append(moduleNames, key) 185 } 186 sort.Strings(moduleNames) 187 188 var filecontent strings.Builder 189 for _, name := range moduleNames { 190 filecontent.WriteString(toString(apexKeyMap[name])) 191 } 192 android.WriteFileRule(ctx, s.output, filecontent.String()) 193} 194 195func apexKeysTextFactory() android.Singleton { 196 return &apexKeysText{} 197} 198 199func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) { 200 ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String()) 201} 202 203// For Bazel / bp2build 204 205type bazelApexKeyAttributes struct { 206 Public_key bazel.LabelAttribute 207 Private_key bazel.LabelAttribute 208} 209 210// ConvertWithBp2build performs conversion apexKey for bp2build 211func (m *apexKey) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 212 apexKeyBp2BuildInternal(ctx, m) 213} 214 215func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) { 216 var privateKeyLabelAttribute bazel.LabelAttribute 217 if module.properties.Private_key != nil { 218 privateKeyLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Private_key)) 219 } 220 221 var publicKeyLabelAttribute bazel.LabelAttribute 222 if module.properties.Public_key != nil { 223 publicKeyLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Public_key)) 224 } 225 226 attrs := &bazelApexKeyAttributes{ 227 Private_key: privateKeyLabelAttribute, 228 Public_key: publicKeyLabelAttribute, 229 } 230 231 props := bazel.BazelTargetModuleProperties{ 232 Rule_class: "apex_key", 233 Bzl_load_location: "//build/bazel/rules:apex_key.bzl", 234 } 235 236 ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) 237} 238