• 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
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