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