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