• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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