• 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
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	android.InitBazelModule(module)
65	return module
66}
67
68func (m *apexKey) installable() bool {
69	return false
70}
71
72func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
73	// If the keys are from other modules (i.e. :module syntax) respect it.
74	// Otherwise, try to locate the key files in the default cert dir or
75	// in the local module dir
76	if android.SrcIsModule(String(m.properties.Public_key)) != "" {
77		m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
78	} else {
79		m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
80		// If not found, fall back to the local key pairs
81		if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() {
82			m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
83		}
84	}
85
86	if android.SrcIsModule(String(m.properties.Private_key)) != "" {
87		m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
88	} else {
89		m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
90		if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() {
91			m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
92		}
93	}
94
95	pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())]
96	privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())]
97
98	if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName {
99		ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname",
100			m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName)
101		return
102	}
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		signTool             string
122	}
123	toString := func(e apexKeyEntry) string {
124		signTool := ""
125		if e.signTool != "" {
126			signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
127		}
128		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
129		if e.presigned {
130			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
131		} else {
132			return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
133		}
134	}
135
136	apexKeyMap := make(map[string]apexKeyEntry)
137	ctx.VisitAllModules(func(module android.Module) {
138		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
139			pem, key := m.getCertificateAndPrivateKey(ctx)
140			apexKeyMap[m.Name()] = apexKeyEntry{
141				name:                 m.Name() + ".apex",
142				presigned:            false,
143				publicKey:            m.publicKeyFile.String(),
144				privateKey:           m.privateKeyFile.String(),
145				containerCertificate: pem.String(),
146				containerPrivateKey:  key.String(),
147				partition:            m.PartitionTag(ctx.DeviceConfig()),
148				signTool:             proptools.String(m.properties.Custom_sign_tool),
149			}
150		}
151	})
152
153	// Find prebuilts and let them override apexBundle if they are preferred
154	ctx.VisitAllModules(func(module android.Module) {
155		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
156			m.Prebuilt().UsePrebuilt() {
157			apexKeyMap[m.BaseModuleName()] = apexKeyEntry{
158				name:      m.InstallFilename(),
159				presigned: true,
160				partition: m.PartitionTag(ctx.DeviceConfig()),
161			}
162		}
163	})
164
165	// Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass
166	// so that apex_set are not overridden by prebuilts.
167	ctx.VisitAllModules(func(module android.Module) {
168		if m, ok := module.(*ApexSet); ok && m.Enabled() {
169			entry := apexKeyEntry{
170				name:      m.InstallFilename(),
171				presigned: true,
172				partition: m.PartitionTag(ctx.DeviceConfig()),
173			}
174			apexKeyMap[m.BaseModuleName()] = entry
175		}
176	})
177
178	// iterating over map does not give consistent ordering in golang
179	var moduleNames []string
180	for key, _ := range apexKeyMap {
181		moduleNames = append(moduleNames, key)
182	}
183	sort.Strings(moduleNames)
184
185	var filecontent strings.Builder
186	for _, name := range moduleNames {
187		filecontent.WriteString(toString(apexKeyMap[name]))
188	}
189	android.WriteFileRule(ctx, s.output, filecontent.String())
190}
191
192func apexKeysTextFactory() android.Singleton {
193	return &apexKeysText{}
194}
195
196func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) {
197	ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String())
198}
199
200// For Bazel / bp2build
201
202type bazelApexKeyAttributes struct {
203	Public_key      bazel.LabelAttribute
204	Public_key_name bazel.StringAttribute
205
206	Private_key      bazel.LabelAttribute
207	Private_key_name bazel.StringAttribute
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	privateKeyLabelAttribute, privateKeyNameAttribute :=
217		android.BazelStringOrLabelFromProp(ctx, module.properties.Private_key)
218
219	publicKeyLabelAttribute, publicKeyNameAttribute :=
220		android.BazelStringOrLabelFromProp(ctx, module.properties.Public_key)
221
222	attrs := &bazelApexKeyAttributes{
223		Private_key:      privateKeyLabelAttribute,
224		Private_key_name: privateKeyNameAttribute,
225
226		Public_key:      publicKeyLabelAttribute,
227		Public_key_name: publicKeyNameAttribute,
228	}
229
230	props := bazel.BazelTargetModuleProperties{
231		Rule_class:        "apex_key",
232		Bzl_load_location: "//build/bazel/rules/apex:apex_key.bzl",
233	}
234
235	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
236}
237