blob: fdccd3a84290dfb31ed05d9589a5a92dafd604a3 [file] [log] [blame]
Artur Satayeveabf2c12021-04-07 15:45:02 +01001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package java
18
19import (
Artur Satayev97259dc2021-04-07 15:17:14 +010020 "fmt"
Yu Liud3228ac2024-11-08 23:11:47 +000021 "strings"
22
satayev14e49132021-05-17 21:03:07 +010023 "github.com/google/blueprint"
satayevb98371c2021-06-15 16:49:50 +010024 "github.com/google/blueprint/proptools"
Artur Satayev97259dc2021-04-07 15:17:14 +010025
Artur Satayeveabf2c12021-04-07 15:45:02 +010026 "android/soong/android"
27)
28
Jiakai Zhangcee9e192021-10-29 19:46:45 +000029// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
Artur Satayeveabf2c12021-04-07 15:45:02 +010030// config files based on build configuration to embed into /system and /apex on a device.
31//
32// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
33// on the device.
34
35type classpathType int
36
37const (
Jiakai Zhangcee9e192021-10-29 19:46:45 +000038 // Matches definition in packages/modules/common/proto/classpaths.proto
Artur Satayeveabf2c12021-04-07 15:45:02 +010039 BOOTCLASSPATH classpathType = iota
40 DEX2OATBOOTCLASSPATH
41 SYSTEMSERVERCLASSPATH
Jiakai Zhangcee9e192021-10-29 19:46:45 +000042 STANDALONE_SYSTEMSERVER_JARS
Artur Satayeveabf2c12021-04-07 15:45:02 +010043)
44
45func (c classpathType) String() string {
Jiakai Zhangcee9e192021-10-29 19:46:45 +000046 return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
Artur Satayeveabf2c12021-04-07 15:45:02 +010047}
48
49type classpathFragmentProperties struct {
satayevb98371c2021-06-15 16:49:50 +010050 // Whether to generated classpaths.proto config instance for the fragment. If the config is not
51 // generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath
52 // or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep
53 // them as part of dexopt on device. Defaults to true.
54 Generate_classpaths_proto *bool
Artur Satayeveabf2c12021-04-07 15:45:02 +010055}
56
57// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
58// variables at runtime.
59type classpathFragment interface {
60 android.Module
61
Artur Satayev97259dc2021-04-07 15:17:14 +010062 classpathFragmentBase() *ClasspathFragmentBase
Artur Satayeveabf2c12021-04-07 15:45:02 +010063}
64
Artur Satayev97259dc2021-04-07 15:17:14 +010065// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
Artur Satayeveabf2c12021-04-07 15:45:02 +010066// such modules are expected to call initClasspathFragment().
Artur Satayev97259dc2021-04-07 15:17:14 +010067type ClasspathFragmentBase struct {
Artur Satayeveabf2c12021-04-07 15:45:02 +010068 properties classpathFragmentProperties
69
satayev95e9c5b2021-04-29 11:50:26 +010070 classpathType classpathType
71
Artur Satayeveabf2c12021-04-07 15:45:02 +010072 outputFilepath android.OutputPath
Artur Satayev97259dc2021-04-07 15:17:14 +010073 installDirPath android.InstallPath
Artur Satayeveabf2c12021-04-07 15:45:02 +010074}
75
Artur Satayev97259dc2021-04-07 15:17:14 +010076func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
77 return c
78}
79
80// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
satayev95e9c5b2021-04-29 11:50:26 +010081func initClasspathFragment(c classpathFragment, classpathType classpathType) {
Artur Satayeveabf2c12021-04-07 15:45:02 +010082 base := c.classpathFragmentBase()
satayev95e9c5b2021-04-29 11:50:26 +010083 base.classpathType = classpathType
Artur Satayeveabf2c12021-04-07 15:45:02 +010084 c.AddProperties(&base.properties)
85}
Artur Satayev97259dc2021-04-07 15:17:14 +010086
87// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
88type classpathJar struct {
satayevcca4ab72021-11-30 12:33:55 +000089 path string
90 classpath classpathType
91 minSdkVersion string
92 maxSdkVersion string
Artur Satayev97259dc2021-04-07 15:17:14 +010093}
94
satayevd604b212021-07-21 14:23:52 +010095// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
96// supplied contents that may be in the apex boot jars.
Paul Duffin56c93e82021-06-29 20:04:45 +010097//
98// The module names are included because sometimes the stem is set to just change the name of
99// the installed file and it expects the configuration to still use the actual module name.
100//
101// The stem names are included because sometimes the stem is set to change the effective name of the
102// module that is used in the configuration as well,e .g. when a test library is overriding an
103// actual boot jar
satayevd604b212021-07-21 14:23:52 +0100104func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
Paul Duffin56c93e82021-06-29 20:04:45 +0100105 set := map[string]struct{}{}
106 for _, name := range contents {
Yu Liud3228ac2024-11-08 23:11:47 +0000107 dep := ctx.GetDirectDepWithTag(name, tag)
Spandan Das161e4682024-01-19 00:22:22 +0000108 set[ModuleStemForDeapexing(dep)] = struct{}{}
Paul Duffin56c93e82021-06-29 20:04:45 +0100109 if m, ok := dep.(ModuleWithStem); ok {
110 set[m.Stem()] = struct{}{}
111 } else {
112 ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
113 }
114 }
Cole Faust18994c72023-02-28 16:02:16 -0800115 return android.SortedKeys(set)
Paul Duffin56c93e82021-06-29 20:04:45 +0100116}
117
satayev013485b2021-05-06 23:38:10 +0100118// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
119func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
120 paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
121 jars := make([]classpathJar, 0, len(paths)*len(classpaths))
122 for i := 0; i < len(paths); i++ {
123 for _, classpathType := range classpaths {
satayevcca4ab72021-11-30 12:33:55 +0000124 jar := classpathJar{
satayev013485b2021-05-06 23:38:10 +0100125 classpath: classpathType,
126 path: paths[i],
satayevcca4ab72021-11-30 12:33:55 +0000127 }
128 ctx.VisitDirectDepsIf(func(m android.Module) bool {
129 return m.Name() == configuredJars.Jar(i)
130 }, func(m android.Module) {
131 if s, ok := m.(*SdkLibrary); ok {
Spandan Das306804f2024-06-12 17:02:40 +0000132 minSdkVersion := s.MinSdkVersion(ctx)
133 maxSdkVersion := s.MaxSdkVersion(ctx)
satayevcca4ab72021-11-30 12:33:55 +0000134 // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
Spandan Das306804f2024-06-12 17:02:40 +0000135 if minSdkVersion.Specified() {
136 if minSdkVersion.IsCurrent() {
Yurii Zubrytskyi16113342022-05-03 01:40:32 -0700137 jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
satayevcca4ab72021-11-30 12:33:55 +0000138 } else {
Spandan Das306804f2024-06-12 17:02:40 +0000139 jar.minSdkVersion = minSdkVersion.String()
satayevcca4ab72021-11-30 12:33:55 +0000140 }
141 }
Spandan Das306804f2024-06-12 17:02:40 +0000142 if maxSdkVersion.Specified() {
143 if maxSdkVersion.IsCurrent() {
Yurii Zubrytskyi16113342022-05-03 01:40:32 -0700144 jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
satayevcca4ab72021-11-30 12:33:55 +0000145 } else {
Spandan Das306804f2024-06-12 17:02:40 +0000146 jar.maxSdkVersion = maxSdkVersion.String()
satayevcca4ab72021-11-30 12:33:55 +0000147 }
148 }
149 }
satayev013485b2021-05-06 23:38:10 +0100150 })
satayevcca4ab72021-11-30 12:33:55 +0000151 jars = append(jars, jar)
satayev013485b2021-05-06 23:38:10 +0100152 }
153 }
154 return jars
155}
156
Inseob Kimdd532492024-04-30 17:22:58 +0900157func (c *ClasspathFragmentBase) outputFilename() string {
158 return strings.ToLower(c.classpathType.String()) + ".pb"
159}
160
satayevb3090502021-06-15 17:49:10 +0100161func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) {
satayevb98371c2021-06-15 16:49:50 +0100162 generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
163 if generateProto {
Inseob Kimdd532492024-04-30 17:22:58 +0900164 outputFilename := c.outputFilename()
satayevb98371c2021-06-15 16:49:50 +0100165 c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
166 c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
Artur Satayev97259dc2021-04-07 15:17:14 +0100167
satayev48dae672021-12-01 18:24:09 +0000168 generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
169 writeClasspathsTextproto(ctx, generatedTextproto, jars)
Artur Satayev97259dc2021-04-07 15:17:14 +0100170
satayevb98371c2021-06-15 16:49:50 +0100171 rule := android.NewRuleBuilder(pctx, ctx)
172 rule.Command().
173 BuiltTool("conv_classpaths_proto").
174 Flag("encode").
satayev48dae672021-12-01 18:24:09 +0000175 Flag("--format=textproto").
176 FlagWithInput("--input=", generatedTextproto).
satayevb98371c2021-06-15 16:49:50 +0100177 FlagWithOutput("--output=", c.outputFilepath)
Artur Satayev97259dc2021-04-07 15:17:14 +0100178
satayevb98371c2021-06-15 16:49:50 +0100179 rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
180 }
satayev14e49132021-05-17 21:03:07 +0100181
182 classpathProtoInfo := ClasspathFragmentProtoContentInfo{
satayevb98371c2021-06-15 16:49:50 +0100183 ClasspathFragmentProtoGenerated: generateProto,
satayevb3090502021-06-15 17:49:10 +0100184 ClasspathFragmentProtoContents: configuredJars,
satayev14e49132021-05-17 21:03:07 +0100185 ClasspathFragmentProtoInstallDir: c.installDirPath,
186 ClasspathFragmentProtoOutput: c.outputFilepath,
187 }
Colin Cross40213022023-12-13 15:19:49 -0800188 android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
Artur Satayev97259dc2021-04-07 15:17:14 +0100189}
190
Inseob Kimdd532492024-04-30 17:22:58 +0900191func (c *ClasspathFragmentBase) installClasspathProto(ctx android.ModuleContext) android.InstallPath {
192 return ctx.InstallFile(c.installDirPath, c.outputFilename(), c.outputFilepath)
193}
194
satayev48dae672021-12-01 18:24:09 +0000195func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
Artur Satayev97259dc2021-04-07 15:17:14 +0100196 var content strings.Builder
satayevcca4ab72021-11-30 12:33:55 +0000197
satayev48dae672021-12-01 18:24:09 +0000198 for _, jar := range jars {
199 fmt.Fprintf(&content, "jars {\n")
200 fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
201 fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
202 fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
203 fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
204 fmt.Fprintf(&content, "}\n")
Artur Satayev97259dc2021-04-07 15:17:14 +0100205 }
satayevcca4ab72021-11-30 12:33:55 +0000206
Artur Satayev97259dc2021-04-07 15:17:14 +0100207 android.WriteFileRule(ctx, output, content.String())
208}
209
satayev3db35472021-05-06 23:59:58 +0100210// Returns AndroidMkEntries objects to install generated classpath.proto.
211// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
satayev128ce2f2021-05-06 13:21:15 +0100212func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
satayev013485b2021-05-06 23:38:10 +0100213 return []android.AndroidMkEntries{{
Artur Satayev97259dc2021-04-07 15:17:14 +0100214 Class: "ETC",
215 OutputFile: android.OptionalPathForPath(c.outputFilepath),
216 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
217 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
Colin Crossc68db4b2021-11-11 18:59:15 -0800218 entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String())
Artur Satayev97259dc2021-04-07 15:17:14 +0100219 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
220 },
221 },
222 }}
223}
satayev14e49132021-05-17 21:03:07 +0100224
Colin Crossbc7d76c2023-12-12 16:39:03 -0800225var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]()
satayev14e49132021-05-17 21:03:07 +0100226
227type ClasspathFragmentProtoContentInfo struct {
satayevb98371c2021-06-15 16:49:50 +0100228 // Whether the classpaths.proto config is generated for the fragment.
229 ClasspathFragmentProtoGenerated bool
230
satayevb3090502021-06-15 17:49:10 +0100231 // ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment.
232 ClasspathFragmentProtoContents android.ConfiguredJarList
233
satayev14e49132021-05-17 21:03:07 +0100234 // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
235 //
236 // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
237 // for more details.
238 ClasspathFragmentProtoOutput android.OutputPath
239
240 // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
241 //
242 // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
243 // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
244 // use android.InstallPath#Rel().
245 //
246 // This is only relevant for APEX modules as they perform their own installation; while regular
247 // system files are installed via ClasspathFragmentBase#androidMkEntries().
248 ClasspathFragmentProtoInstallDir android.InstallPath
249}