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 // This module is device-only 60 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 61 return module 62} 63 64func (m *apexKey) installable() bool { 65 return false 66} 67 68func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) { 69 // If the keys are from other modules (i.e. :module syntax) respect it. 70 // Otherwise, try to locate the key files in the default cert dir or 71 // in the local module dir 72 if android.SrcIsModule(String(m.properties.Public_key)) != "" { 73 m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 74 } else { 75 m.public_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key)) 76 // If not found, fall back to the local key pairs 77 if !android.ExistentPathForSource(ctx, m.public_key_file.String()).Valid() { 78 m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 79 } 80 } 81 82 if android.SrcIsModule(String(m.properties.Private_key)) != "" { 83 m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) 84 } else { 85 m.private_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key)) 86 if !android.ExistentPathForSource(ctx, m.private_key_file.String()).Valid() { 87 m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) 88 } 89 } 90 91 pubKeyName := m.public_key_file.Base()[0 : len(m.public_key_file.Base())-len(m.public_key_file.Ext())] 92 privKeyName := m.private_key_file.Base()[0 : len(m.private_key_file.Base())-len(m.private_key_file.Ext())] 93 94 if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName { 95 ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname", 96 m.public_key_file.String(), pubKeyName, m.private_key_file, privKeyName) 97 return 98 } 99 m.keyName = pubKeyName 100} 101 102//////////////////////////////////////////////////////////////////////// 103// apex_keys_text 104type apexKeysText struct { 105 output android.OutputPath 106} 107 108func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { 109 s.output = android.PathForOutput(ctx, "apexkeys.txt") 110 apexModulesMap := make(map[string]android.Module) 111 ctx.VisitAllModules(func(module android.Module) { 112 if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() { 113 apexModulesMap[m.Name()] = m 114 } 115 }) 116 117 // Find prebuilts and let them override apexBundle if they are preferred 118 ctx.VisitAllModules(func(module android.Module) { 119 if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() && 120 m.Prebuilt().UsePrebuilt() { 121 apexModulesMap[m.BaseModuleName()] = m 122 } 123 }) 124 125 // iterating over map does not give consistent ordering in golang 126 var moduleNames []string 127 for key, _ := range apexModulesMap { 128 moduleNames = append(moduleNames, key) 129 } 130 sort.Strings(moduleNames) 131 132 var filecontent strings.Builder 133 for _, key := range moduleNames { 134 module := apexModulesMap[key] 135 if m, ok := module.(*apexBundle); ok { 136 fmt.Fprintf(&filecontent, 137 "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n", 138 m.Name()+".apex", 139 m.public_key_file.String(), 140 m.private_key_file.String(), 141 m.container_certificate_file.String(), 142 m.container_private_key_file.String()) 143 } else if m, ok := module.(*Prebuilt); ok { 144 fmt.Fprintf(&filecontent, 145 "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n", 146 m.InstallFilename(), 147 "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED") 148 } 149 } 150 151 ctx.Build(pctx, android.BuildParams{ 152 Rule: android.WriteFile, 153 Description: "apexkeys.txt", 154 Output: s.output, 155 Args: map[string]string{ 156 "content": filecontent.String(), 157 }, 158 }) 159} 160 161func apexKeysTextFactory() android.Singleton { 162 return &apexKeysText{} 163} 164 165func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) { 166 ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String()) 167} 168