|  | // Copyright (C) 2018 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package apex | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "sort" | 
|  | "strings" | 
|  |  | 
|  | "android/soong/android" | 
|  | "android/soong/bazel" | 
|  |  | 
|  | "github.com/google/blueprint/proptools" | 
|  | ) | 
|  |  | 
|  | var String = proptools.String | 
|  |  | 
|  | func init() { | 
|  | registerApexKeyBuildComponents(android.InitRegistrationContext) | 
|  | } | 
|  |  | 
|  | func registerApexKeyBuildComponents(ctx android.RegistrationContext) { | 
|  | ctx.RegisterModuleType("apex_key", ApexKeyFactory) | 
|  | ctx.RegisterParallelSingletonType("apex_keys_text", apexKeysTextFactory) | 
|  | } | 
|  |  | 
|  | type apexKey struct { | 
|  | android.ModuleBase | 
|  | android.BazelModuleBase | 
|  |  | 
|  | properties apexKeyProperties | 
|  |  | 
|  | publicKeyFile  android.Path | 
|  | privateKeyFile android.Path | 
|  | } | 
|  |  | 
|  | type apexKeyProperties struct { | 
|  | // Path or module to the public key file in avbpubkey format. Installed to the device. | 
|  | // Base name of the file is used as the ID for the key. | 
|  | Public_key *string `android:"path"` | 
|  | // Path or module to the private key file in pem format. Used to sign APEXs. | 
|  | Private_key *string `android:"path"` | 
|  |  | 
|  | // Whether this key is installable to one of the partitions. Defualt: true. | 
|  | Installable *bool | 
|  | } | 
|  |  | 
|  | func ApexKeyFactory() android.Module { | 
|  | module := &apexKey{} | 
|  | module.AddProperties(&module.properties) | 
|  | android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) | 
|  | android.InitBazelModule(module) | 
|  | return module | 
|  | } | 
|  |  | 
|  | func (m *apexKey) installable() bool { | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) { | 
|  | // If the keys are from other modules (i.e. :module syntax) respect it. | 
|  | // Otherwise, try to locate the key files in the default cert dir or | 
|  | // in the local module dir | 
|  | if android.SrcIsModule(String(m.properties.Public_key)) != "" { | 
|  | m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) | 
|  | } else { | 
|  | m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key)) | 
|  | // If not found, fall back to the local key pairs | 
|  | if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() { | 
|  | m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) | 
|  | } | 
|  | } | 
|  |  | 
|  | if android.SrcIsModule(String(m.properties.Private_key)) != "" { | 
|  | m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) | 
|  | } else { | 
|  | m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key)) | 
|  | if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() { | 
|  | m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) | 
|  | } | 
|  | } | 
|  |  | 
|  | pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())] | 
|  | privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())] | 
|  |  | 
|  | if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName { | 
|  | ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname", | 
|  | m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName) | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | // ////////////////////////////////////////////////////////////////////// | 
|  | // apex_keys_text | 
|  | type apexKeysText struct { | 
|  | output android.OutputPath | 
|  | } | 
|  |  | 
|  | func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { | 
|  | s.output = android.PathForOutput(ctx, "apexkeys.txt") | 
|  | type apexKeyEntry struct { | 
|  | name                 string | 
|  | presigned            bool | 
|  | publicKey            string | 
|  | privateKey           string | 
|  | containerCertificate string | 
|  | containerPrivateKey  string | 
|  | partition            string | 
|  | signTool             string | 
|  | } | 
|  | toString := func(e apexKeyEntry) string { | 
|  | signTool := "" | 
|  | if e.signTool != "" { | 
|  | signTool = fmt.Sprintf(" sign_tool=%q", e.signTool) | 
|  | } | 
|  | format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n" | 
|  | if e.presigned { | 
|  | return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool) | 
|  | } else { | 
|  | return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool) | 
|  | } | 
|  | } | 
|  |  | 
|  | apexKeyMap := make(map[string]apexKeyEntry) | 
|  | ctx.VisitAllModules(func(module android.Module) { | 
|  | if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() { | 
|  | pem, key := m.getCertificateAndPrivateKey(ctx) | 
|  | apexKeyMap[m.Name()] = apexKeyEntry{ | 
|  | name:                 m.Name() + ".apex", | 
|  | presigned:            false, | 
|  | publicKey:            m.publicKeyFile.String(), | 
|  | privateKey:           m.privateKeyFile.String(), | 
|  | containerCertificate: pem.String(), | 
|  | containerPrivateKey:  key.String(), | 
|  | partition:            m.PartitionTag(ctx.DeviceConfig()), | 
|  | signTool:             proptools.String(m.properties.Custom_sign_tool), | 
|  | } | 
|  | } | 
|  | }) | 
|  |  | 
|  | // Find prebuilts and let them override apexBundle if they are preferred | 
|  | ctx.VisitAllModules(func(module android.Module) { | 
|  | if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() && | 
|  | m.Prebuilt().UsePrebuilt() { | 
|  | apexKeyMap[m.BaseModuleName()] = apexKeyEntry{ | 
|  | name:      m.InstallFilename(), | 
|  | presigned: true, | 
|  | partition: m.PartitionTag(ctx.DeviceConfig()), | 
|  | } | 
|  | } | 
|  | }) | 
|  |  | 
|  | // Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass | 
|  | // so that apex_set are not overridden by prebuilts. | 
|  | ctx.VisitAllModules(func(module android.Module) { | 
|  | if m, ok := module.(*ApexSet); ok && m.Enabled() { | 
|  | entry := apexKeyEntry{ | 
|  | name:      m.InstallFilename(), | 
|  | presigned: true, | 
|  | partition: m.PartitionTag(ctx.DeviceConfig()), | 
|  | } | 
|  | apexKeyMap[m.BaseModuleName()] = entry | 
|  | } | 
|  | }) | 
|  |  | 
|  | // iterating over map does not give consistent ordering in golang | 
|  | var moduleNames []string | 
|  | for key, _ := range apexKeyMap { | 
|  | moduleNames = append(moduleNames, key) | 
|  | } | 
|  | sort.Strings(moduleNames) | 
|  |  | 
|  | var filecontent strings.Builder | 
|  | for _, name := range moduleNames { | 
|  | filecontent.WriteString(toString(apexKeyMap[name])) | 
|  | } | 
|  | android.WriteFileRule(ctx, s.output, filecontent.String()) | 
|  | } | 
|  |  | 
|  | func apexKeysTextFactory() android.Singleton { | 
|  | return &apexKeysText{} | 
|  | } | 
|  |  | 
|  | func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) { | 
|  | ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String()) | 
|  | } | 
|  |  | 
|  | // For Bazel / bp2build | 
|  |  | 
|  | type bazelApexKeyAttributes struct { | 
|  | Public_key      bazel.LabelAttribute | 
|  | Public_key_name bazel.StringAttribute | 
|  |  | 
|  | Private_key      bazel.LabelAttribute | 
|  | Private_key_name bazel.StringAttribute | 
|  | } | 
|  |  | 
|  | // ConvertWithBp2build performs conversion apexKey for bp2build | 
|  | func (m *apexKey) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) { | 
|  | apexKeyBp2BuildInternal(ctx, m) | 
|  | } | 
|  |  | 
|  | func apexKeyBp2BuildInternal(ctx android.Bp2buildMutatorContext, module *apexKey) { | 
|  | privateKeyLabelAttribute, privateKeyNameAttribute := | 
|  | android.BazelStringOrLabelFromProp(ctx, module.properties.Private_key) | 
|  |  | 
|  | publicKeyLabelAttribute, publicKeyNameAttribute := | 
|  | android.BazelStringOrLabelFromProp(ctx, module.properties.Public_key) | 
|  |  | 
|  | attrs := &bazelApexKeyAttributes{ | 
|  | Private_key:      privateKeyLabelAttribute, | 
|  | Private_key_name: privateKeyNameAttribute, | 
|  |  | 
|  | Public_key:      publicKeyLabelAttribute, | 
|  | Public_key_name: publicKeyNameAttribute, | 
|  | } | 
|  |  | 
|  | props := bazel.BazelTargetModuleProperties{ | 
|  | Rule_class:        "apex_key", | 
|  | Bzl_load_location: "//build/bazel/rules/apex:apex_key.bzl", | 
|  | } | 
|  |  | 
|  | ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) | 
|  | } |