blob: 18a5dae6c7c0feb94bb4c59d6d62963f2f5ae56e [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"
satayev14e49132021-05-17 21:03:07 +010021 "github.com/google/blueprint"
satayevb98371c2021-06-15 16:49:50 +010022 "github.com/google/blueprint/proptools"
Artur Satayev97259dc2021-04-07 15:17:14 +010023 "strings"
24
Artur Satayeveabf2c12021-04-07 15:45:02 +010025 "android/soong/android"
26)
27
Jiakai Zhangcee9e192021-10-29 19:46:45 +000028// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
Artur Satayeveabf2c12021-04-07 15:45:02 +010029// config files based on build configuration to embed into /system and /apex on a device.
30//
31// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
32// on the device.
33
34type classpathType int
35
36const (
Jiakai Zhangcee9e192021-10-29 19:46:45 +000037 // Matches definition in packages/modules/common/proto/classpaths.proto
Artur Satayeveabf2c12021-04-07 15:45:02 +010038 BOOTCLASSPATH classpathType = iota
39 DEX2OATBOOTCLASSPATH
40 SYSTEMSERVERCLASSPATH
Jiakai Zhangcee9e192021-10-29 19:46:45 +000041 STANDALONE_SYSTEMSERVER_JARS
Artur Satayeveabf2c12021-04-07 15:45:02 +010042)
43
44func (c classpathType) String() string {
Jiakai Zhangcee9e192021-10-29 19:46:45 +000045 return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
Artur Satayeveabf2c12021-04-07 15:45:02 +010046}
47
48type classpathFragmentProperties struct {
satayevb98371c2021-06-15 16:49:50 +010049 // Whether to generated classpaths.proto config instance for the fragment. If the config is not
50 // generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath
51 // or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep
52 // them as part of dexopt on device. Defaults to true.
53 Generate_classpaths_proto *bool
Artur Satayeveabf2c12021-04-07 15:45:02 +010054}
55
56// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
57// variables at runtime.
58type classpathFragment interface {
59 android.Module
60
Artur Satayev97259dc2021-04-07 15:17:14 +010061 classpathFragmentBase() *ClasspathFragmentBase
Artur Satayeveabf2c12021-04-07 15:45:02 +010062}
63
Artur Satayev97259dc2021-04-07 15:17:14 +010064// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
Artur Satayeveabf2c12021-04-07 15:45:02 +010065// such modules are expected to call initClasspathFragment().
Artur Satayev97259dc2021-04-07 15:17:14 +010066type ClasspathFragmentBase struct {
Artur Satayeveabf2c12021-04-07 15:45:02 +010067 properties classpathFragmentProperties
68
satayev95e9c5b2021-04-29 11:50:26 +010069 classpathType classpathType
70
Artur Satayeveabf2c12021-04-07 15:45:02 +010071 outputFilepath android.OutputPath
Artur Satayev97259dc2021-04-07 15:17:14 +010072 installDirPath android.InstallPath
Artur Satayeveabf2c12021-04-07 15:45:02 +010073}
74
Artur Satayev97259dc2021-04-07 15:17:14 +010075func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
76 return c
77}
78
79// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
satayev95e9c5b2021-04-29 11:50:26 +010080func initClasspathFragment(c classpathFragment, classpathType classpathType) {
Artur Satayeveabf2c12021-04-07 15:45:02 +010081 base := c.classpathFragmentBase()
satayev95e9c5b2021-04-29 11:50:26 +010082 base.classpathType = classpathType
Artur Satayeveabf2c12021-04-07 15:45:02 +010083 c.AddProperties(&base.properties)
84}
Artur Satayev97259dc2021-04-07 15:17:14 +010085
86// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
87type classpathJar struct {
satayevcca4ab72021-11-30 12:33:55 +000088 path string
89 classpath classpathType
90 minSdkVersion string
91 maxSdkVersion string
Artur Satayev97259dc2021-04-07 15:17:14 +010092}
93
satayevd604b212021-07-21 14:23:52 +010094// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
95// supplied contents that may be in the apex boot jars.
Paul Duffin56c93e82021-06-29 20:04:45 +010096//
97// The module names are included because sometimes the stem is set to just change the name of
98// the installed file and it expects the configuration to still use the actual module name.
99//
100// The stem names are included because sometimes the stem is set to change the effective name of the
101// module that is used in the configuration as well,e .g. when a test library is overriding an
102// actual boot jar
satayevd604b212021-07-21 14:23:52 +0100103func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
Paul Duffin56c93e82021-06-29 20:04:45 +0100104 set := map[string]struct{}{}
105 for _, name := range contents {
Spandan Das161e4682024-01-19 00:22:22 +0000106 dep, _ := ctx.GetDirectDepWithTag(name, tag).(android.Module)
107 set[ModuleStemForDeapexing(dep)] = struct{}{}
Paul Duffin56c93e82021-06-29 20:04:45 +0100108 if m, ok := dep.(ModuleWithStem); ok {
109 set[m.Stem()] = struct{}{}
110 } else {
111 ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
112 }
113 }
Cole Faust18994c72023-02-28 16:02:16 -0800114 return android.SortedKeys(set)
Paul Duffin56c93e82021-06-29 20:04:45 +0100115}
116
satayev013485b2021-05-06 23:38:10 +0100117// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
118func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
119 paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
120 jars := make([]classpathJar, 0, len(paths)*len(classpaths))
121 for i := 0; i < len(paths); i++ {
122 for _, classpathType := range classpaths {
satayevcca4ab72021-11-30 12:33:55 +0000123 jar := classpathJar{
satayev013485b2021-05-06 23:38:10 +0100124 classpath: classpathType,
125 path: paths[i],
satayevcca4ab72021-11-30 12:33:55 +0000126 }
127 ctx.VisitDirectDepsIf(func(m android.Module) bool {
128 return m.Name() == configuredJars.Jar(i)
129 }, func(m android.Module) {
130 if s, ok := m.(*SdkLibrary); ok {
Spandan Das306804f2024-06-12 17:02:40 +0000131 minSdkVersion := s.MinSdkVersion(ctx)
132 maxSdkVersion := s.MaxSdkVersion(ctx)
satayevcca4ab72021-11-30 12:33:55 +0000133 // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
Spandan Das306804f2024-06-12 17:02:40 +0000134 if minSdkVersion.Specified() {
135 if minSdkVersion.IsCurrent() {
Yurii Zubrytskyi16113342022-05-03 01:40:32 -0700136 jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
satayevcca4ab72021-11-30 12:33:55 +0000137 } else {
Spandan Das306804f2024-06-12 17:02:40 +0000138 jar.minSdkVersion = minSdkVersion.String()
satayevcca4ab72021-11-30 12:33:55 +0000139 }
140 }
Spandan Das306804f2024-06-12 17:02:40 +0000141 if maxSdkVersion.Specified() {
142 if maxSdkVersion.IsCurrent() {
Yurii Zubrytskyi16113342022-05-03 01:40:32 -0700143 jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
satayevcca4ab72021-11-30 12:33:55 +0000144 } else {
Spandan Das306804f2024-06-12 17:02:40 +0000145 jar.maxSdkVersion = maxSdkVersion.String()
satayevcca4ab72021-11-30 12:33:55 +0000146 }
147 }
148 }
satayev013485b2021-05-06 23:38:10 +0100149 })
satayevcca4ab72021-11-30 12:33:55 +0000150 jars = append(jars, jar)
satayev013485b2021-05-06 23:38:10 +0100151 }
152 }
153 return jars
154}
155
Inseob Kimdd532492024-04-30 17:22:58 +0900156func (c *ClasspathFragmentBase) outputFilename() string {
157 return strings.ToLower(c.classpathType.String()) + ".pb"
158}
159
satayevb3090502021-06-15 17:49:10 +0100160func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) {
satayevb98371c2021-06-15 16:49:50 +0100161 generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
162 if generateProto {
Inseob Kimdd532492024-04-30 17:22:58 +0900163 outputFilename := c.outputFilename()
satayevb98371c2021-06-15 16:49:50 +0100164 c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
165 c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
Artur Satayev97259dc2021-04-07 15:17:14 +0100166
satayev48dae672021-12-01 18:24:09 +0000167 generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
168 writeClasspathsTextproto(ctx, generatedTextproto, jars)
Artur Satayev97259dc2021-04-07 15:17:14 +0100169
satayevb98371c2021-06-15 16:49:50 +0100170 rule := android.NewRuleBuilder(pctx, ctx)
171 rule.Command().
172 BuiltTool("conv_classpaths_proto").
173 Flag("encode").
satayev48dae672021-12-01 18:24:09 +0000174 Flag("--format=textproto").
175 FlagWithInput("--input=", generatedTextproto).
satayevb98371c2021-06-15 16:49:50 +0100176 FlagWithOutput("--output=", c.outputFilepath)
Artur Satayev97259dc2021-04-07 15:17:14 +0100177
satayevb98371c2021-06-15 16:49:50 +0100178 rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
179 }
satayev14e49132021-05-17 21:03:07 +0100180
181 classpathProtoInfo := ClasspathFragmentProtoContentInfo{
satayevb98371c2021-06-15 16:49:50 +0100182 ClasspathFragmentProtoGenerated: generateProto,
satayevb3090502021-06-15 17:49:10 +0100183 ClasspathFragmentProtoContents: configuredJars,
satayev14e49132021-05-17 21:03:07 +0100184 ClasspathFragmentProtoInstallDir: c.installDirPath,
185 ClasspathFragmentProtoOutput: c.outputFilepath,
186 }
Colin Cross40213022023-12-13 15:19:49 -0800187 android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
Artur Satayev97259dc2021-04-07 15:17:14 +0100188}
189
Inseob Kimdd532492024-04-30 17:22:58 +0900190func (c *ClasspathFragmentBase) installClasspathProto(ctx android.ModuleContext) android.InstallPath {
191 return ctx.InstallFile(c.installDirPath, c.outputFilename(), c.outputFilepath)
192}
193
satayev48dae672021-12-01 18:24:09 +0000194func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
Artur Satayev97259dc2021-04-07 15:17:14 +0100195 var content strings.Builder
satayevcca4ab72021-11-30 12:33:55 +0000196
satayev48dae672021-12-01 18:24:09 +0000197 for _, jar := range jars {
198 fmt.Fprintf(&content, "jars {\n")
199 fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
200 fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
201 fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
202 fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
203 fmt.Fprintf(&content, "}\n")
Artur Satayev97259dc2021-04-07 15:17:14 +0100204 }
satayevcca4ab72021-11-30 12:33:55 +0000205
Artur Satayev97259dc2021-04-07 15:17:14 +0100206 android.WriteFileRule(ctx, output, content.String())
207}
208
satayev3db35472021-05-06 23:59:58 +0100209// Returns AndroidMkEntries objects to install generated classpath.proto.
210// 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 +0100211func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
satayev013485b2021-05-06 23:38:10 +0100212 return []android.AndroidMkEntries{{
Artur Satayev97259dc2021-04-07 15:17:14 +0100213 Class: "ETC",
214 OutputFile: android.OptionalPathForPath(c.outputFilepath),
215 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
216 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
Colin Crossc68db4b2021-11-11 18:59:15 -0800217 entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String())
Artur Satayev97259dc2021-04-07 15:17:14 +0100218 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
219 },
220 },
221 }}
222}
satayev14e49132021-05-17 21:03:07 +0100223
Colin Crossbc7d76c2023-12-12 16:39:03 -0800224var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]()
satayev14e49132021-05-17 21:03:07 +0100225
226type ClasspathFragmentProtoContentInfo struct {
satayevb98371c2021-06-15 16:49:50 +0100227 // Whether the classpaths.proto config is generated for the fragment.
228 ClasspathFragmentProtoGenerated bool
229
satayevb3090502021-06-15 17:49:10 +0100230 // ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment.
231 ClasspathFragmentProtoContents android.ConfiguredJarList
232
satayev14e49132021-05-17 21:03:07 +0100233 // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
234 //
235 // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
236 // for more details.
237 ClasspathFragmentProtoOutput android.OutputPath
238
239 // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
240 //
241 // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
242 // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
243 // use android.InstallPath#Rel().
244 //
245 // This is only relevant for APEX modules as they perform their own installation; while regular
246 // system files are installed via ClasspathFragmentBase#androidMkEntries().
247 ClasspathFragmentProtoInstallDir android.InstallPath
248}