xref: /aosp_15_r20/build/soong/java/classpath_fragment.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker/*
2*333d2b36SAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*333d2b36SAndroid Build Coastguard Worker *
4*333d2b36SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*333d2b36SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*333d2b36SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*333d2b36SAndroid Build Coastguard Worker *
8*333d2b36SAndroid Build Coastguard Worker *      http://www.apache.org/licenses/LICENSE-2.0
9*333d2b36SAndroid Build Coastguard Worker *
10*333d2b36SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*333d2b36SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*333d2b36SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*333d2b36SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*333d2b36SAndroid Build Coastguard Worker * limitations under the License.
15*333d2b36SAndroid Build Coastguard Worker */
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerpackage java
18*333d2b36SAndroid Build Coastguard Worker
19*333d2b36SAndroid Build Coastguard Workerimport (
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"strings"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
24*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
27*333d2b36SAndroid Build Coastguard Worker)
28*333d2b36SAndroid Build Coastguard Worker
29*333d2b36SAndroid Build Coastguard Worker// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
30*333d2b36SAndroid Build Coastguard Worker// config files based on build configuration to embed into /system and /apex on a device.
31*333d2b36SAndroid Build Coastguard Worker//
32*333d2b36SAndroid Build Coastguard Worker// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
33*333d2b36SAndroid Build Coastguard Worker// on the device.
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workertype classpathType int
36*333d2b36SAndroid Build Coastguard Worker
37*333d2b36SAndroid Build Coastguard Workerconst (
38*333d2b36SAndroid Build Coastguard Worker	// Matches definition in packages/modules/common/proto/classpaths.proto
39*333d2b36SAndroid Build Coastguard Worker	BOOTCLASSPATH classpathType = iota
40*333d2b36SAndroid Build Coastguard Worker	DEX2OATBOOTCLASSPATH
41*333d2b36SAndroid Build Coastguard Worker	SYSTEMSERVERCLASSPATH
42*333d2b36SAndroid Build Coastguard Worker	STANDALONE_SYSTEMSERVER_JARS
43*333d2b36SAndroid Build Coastguard Worker)
44*333d2b36SAndroid Build Coastguard Worker
45*333d2b36SAndroid Build Coastguard Workerfunc (c classpathType) String() string {
46*333d2b36SAndroid Build Coastguard Worker	return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
47*333d2b36SAndroid Build Coastguard Worker}
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard Workertype classpathFragmentProperties struct {
50*333d2b36SAndroid Build Coastguard Worker	// Whether to generated classpaths.proto config instance for the fragment. If the config is not
51*333d2b36SAndroid Build Coastguard Worker	// generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath
52*333d2b36SAndroid Build Coastguard Worker	// or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep
53*333d2b36SAndroid Build Coastguard Worker	// them as part of dexopt on device. Defaults to true.
54*333d2b36SAndroid Build Coastguard Worker	Generate_classpaths_proto *bool
55*333d2b36SAndroid Build Coastguard Worker}
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Worker// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
58*333d2b36SAndroid Build Coastguard Worker// variables at runtime.
59*333d2b36SAndroid Build Coastguard Workertype classpathFragment interface {
60*333d2b36SAndroid Build Coastguard Worker	android.Module
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Worker	classpathFragmentBase() *ClasspathFragmentBase
63*333d2b36SAndroid Build Coastguard Worker}
64*333d2b36SAndroid Build Coastguard Worker
65*333d2b36SAndroid Build Coastguard Worker// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
66*333d2b36SAndroid Build Coastguard Worker// such modules are expected to call initClasspathFragment().
67*333d2b36SAndroid Build Coastguard Workertype ClasspathFragmentBase struct {
68*333d2b36SAndroid Build Coastguard Worker	properties classpathFragmentProperties
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Worker	classpathType classpathType
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker	outputFilepath android.OutputPath
73*333d2b36SAndroid Build Coastguard Worker	installDirPath android.InstallPath
74*333d2b36SAndroid Build Coastguard Worker}
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
77*333d2b36SAndroid Build Coastguard Worker	return c
78*333d2b36SAndroid Build Coastguard Worker}
79*333d2b36SAndroid Build Coastguard Worker
80*333d2b36SAndroid Build Coastguard Worker// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
81*333d2b36SAndroid Build Coastguard Workerfunc initClasspathFragment(c classpathFragment, classpathType classpathType) {
82*333d2b36SAndroid Build Coastguard Worker	base := c.classpathFragmentBase()
83*333d2b36SAndroid Build Coastguard Worker	base.classpathType = classpathType
84*333d2b36SAndroid Build Coastguard Worker	c.AddProperties(&base.properties)
85*333d2b36SAndroid Build Coastguard Worker}
86*333d2b36SAndroid Build Coastguard Worker
87*333d2b36SAndroid Build Coastguard Worker// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
88*333d2b36SAndroid Build Coastguard Workertype classpathJar struct {
89*333d2b36SAndroid Build Coastguard Worker	path          string
90*333d2b36SAndroid Build Coastguard Worker	classpath     classpathType
91*333d2b36SAndroid Build Coastguard Worker	minSdkVersion string
92*333d2b36SAndroid Build Coastguard Worker	maxSdkVersion string
93*333d2b36SAndroid Build Coastguard Worker}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Worker// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
96*333d2b36SAndroid Build Coastguard Worker// supplied contents that may be in the apex boot jars.
97*333d2b36SAndroid Build Coastguard Worker//
98*333d2b36SAndroid Build Coastguard Worker// The module names are included because sometimes the stem is set to just change the name of
99*333d2b36SAndroid Build Coastguard Worker// the installed file and it expects the configuration to still use the actual module name.
100*333d2b36SAndroid Build Coastguard Worker//
101*333d2b36SAndroid Build Coastguard Worker// The stem names are included because sometimes the stem is set to change the effective name of the
102*333d2b36SAndroid Build Coastguard Worker// module that is used in the configuration as well,e .g. when a test library is overriding an
103*333d2b36SAndroid Build Coastguard Worker// actual boot jar
104*333d2b36SAndroid Build Coastguard Workerfunc gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
105*333d2b36SAndroid Build Coastguard Worker	set := map[string]struct{}{}
106*333d2b36SAndroid Build Coastguard Worker	for _, name := range contents {
107*333d2b36SAndroid Build Coastguard Worker		dep := ctx.GetDirectDepWithTag(name, tag)
108*333d2b36SAndroid Build Coastguard Worker		if dep == nil && ctx.Config().AllowMissingDependencies() {
109*333d2b36SAndroid Build Coastguard Worker			// Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed.
110*333d2b36SAndroid Build Coastguard Worker			continue
111*333d2b36SAndroid Build Coastguard Worker		}
112*333d2b36SAndroid Build Coastguard Worker		set[ModuleStemForDeapexing(dep)] = struct{}{}
113*333d2b36SAndroid Build Coastguard Worker		if m, ok := dep.(ModuleWithStem); ok {
114*333d2b36SAndroid Build Coastguard Worker			set[m.Stem()] = struct{}{}
115*333d2b36SAndroid Build Coastguard Worker		} else {
116*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
117*333d2b36SAndroid Build Coastguard Worker		}
118*333d2b36SAndroid Build Coastguard Worker	}
119*333d2b36SAndroid Build Coastguard Worker	return android.SortedKeys(set)
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Worker// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
123*333d2b36SAndroid Build Coastguard Workerfunc configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
124*333d2b36SAndroid Build Coastguard Worker	paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
125*333d2b36SAndroid Build Coastguard Worker	jars := make([]classpathJar, 0, len(paths)*len(classpaths))
126*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < len(paths); i++ {
127*333d2b36SAndroid Build Coastguard Worker		for _, classpathType := range classpaths {
128*333d2b36SAndroid Build Coastguard Worker			jar := classpathJar{
129*333d2b36SAndroid Build Coastguard Worker				classpath: classpathType,
130*333d2b36SAndroid Build Coastguard Worker				path:      paths[i],
131*333d2b36SAndroid Build Coastguard Worker			}
132*333d2b36SAndroid Build Coastguard Worker			ctx.VisitDirectDepsIf(func(m android.Module) bool {
133*333d2b36SAndroid Build Coastguard Worker				return m.Name() == configuredJars.Jar(i)
134*333d2b36SAndroid Build Coastguard Worker			}, func(m android.Module) {
135*333d2b36SAndroid Build Coastguard Worker				if s, ok := m.(*SdkLibrary); ok {
136*333d2b36SAndroid Build Coastguard Worker					minSdkVersion := s.MinSdkVersion(ctx)
137*333d2b36SAndroid Build Coastguard Worker					maxSdkVersion := s.MaxSdkVersion(ctx)
138*333d2b36SAndroid Build Coastguard Worker					// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
139*333d2b36SAndroid Build Coastguard Worker					if minSdkVersion.Specified() {
140*333d2b36SAndroid Build Coastguard Worker						if minSdkVersion.IsCurrent() {
141*333d2b36SAndroid Build Coastguard Worker							jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
142*333d2b36SAndroid Build Coastguard Worker						} else {
143*333d2b36SAndroid Build Coastguard Worker							jar.minSdkVersion = minSdkVersion.String()
144*333d2b36SAndroid Build Coastguard Worker						}
145*333d2b36SAndroid Build Coastguard Worker					}
146*333d2b36SAndroid Build Coastguard Worker					if maxSdkVersion.Specified() {
147*333d2b36SAndroid Build Coastguard Worker						if maxSdkVersion.IsCurrent() {
148*333d2b36SAndroid Build Coastguard Worker							jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
149*333d2b36SAndroid Build Coastguard Worker						} else {
150*333d2b36SAndroid Build Coastguard Worker							jar.maxSdkVersion = maxSdkVersion.String()
151*333d2b36SAndroid Build Coastguard Worker						}
152*333d2b36SAndroid Build Coastguard Worker					}
153*333d2b36SAndroid Build Coastguard Worker				}
154*333d2b36SAndroid Build Coastguard Worker			})
155*333d2b36SAndroid Build Coastguard Worker			jars = append(jars, jar)
156*333d2b36SAndroid Build Coastguard Worker		}
157*333d2b36SAndroid Build Coastguard Worker	}
158*333d2b36SAndroid Build Coastguard Worker	return jars
159*333d2b36SAndroid Build Coastguard Worker}
160*333d2b36SAndroid Build Coastguard Worker
161*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) outputFilename() string {
162*333d2b36SAndroid Build Coastguard Worker	return strings.ToLower(c.classpathType.String()) + ".pb"
163*333d2b36SAndroid Build Coastguard Worker}
164*333d2b36SAndroid Build Coastguard Worker
165*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) {
166*333d2b36SAndroid Build Coastguard Worker	generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
167*333d2b36SAndroid Build Coastguard Worker	if generateProto {
168*333d2b36SAndroid Build Coastguard Worker		outputFilename := c.outputFilename()
169*333d2b36SAndroid Build Coastguard Worker		c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
170*333d2b36SAndroid Build Coastguard Worker		c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Worker		generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
173*333d2b36SAndroid Build Coastguard Worker		writeClasspathsTextproto(ctx, generatedTextproto, jars)
174*333d2b36SAndroid Build Coastguard Worker
175*333d2b36SAndroid Build Coastguard Worker		rule := android.NewRuleBuilder(pctx, ctx)
176*333d2b36SAndroid Build Coastguard Worker		rule.Command().
177*333d2b36SAndroid Build Coastguard Worker			BuiltTool("conv_classpaths_proto").
178*333d2b36SAndroid Build Coastguard Worker			Flag("encode").
179*333d2b36SAndroid Build Coastguard Worker			Flag("--format=textproto").
180*333d2b36SAndroid Build Coastguard Worker			FlagWithInput("--input=", generatedTextproto).
181*333d2b36SAndroid Build Coastguard Worker			FlagWithOutput("--output=", c.outputFilepath)
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Worker		rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
184*333d2b36SAndroid Build Coastguard Worker	}
185*333d2b36SAndroid Build Coastguard Worker
186*333d2b36SAndroid Build Coastguard Worker	classpathProtoInfo := ClasspathFragmentProtoContentInfo{
187*333d2b36SAndroid Build Coastguard Worker		ClasspathFragmentProtoGenerated:  generateProto,
188*333d2b36SAndroid Build Coastguard Worker		ClasspathFragmentProtoContents:   configuredJars,
189*333d2b36SAndroid Build Coastguard Worker		ClasspathFragmentProtoInstallDir: c.installDirPath,
190*333d2b36SAndroid Build Coastguard Worker		ClasspathFragmentProtoOutput:     c.outputFilepath,
191*333d2b36SAndroid Build Coastguard Worker	}
192*333d2b36SAndroid Build Coastguard Worker	android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
193*333d2b36SAndroid Build Coastguard Worker}
194*333d2b36SAndroid Build Coastguard Worker
195*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) installClasspathProto(ctx android.ModuleContext) android.InstallPath {
196*333d2b36SAndroid Build Coastguard Worker	return ctx.InstallFile(c.installDirPath, c.outputFilename(), c.outputFilepath)
197*333d2b36SAndroid Build Coastguard Worker}
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Workerfunc writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
200*333d2b36SAndroid Build Coastguard Worker	var content strings.Builder
201*333d2b36SAndroid Build Coastguard Worker
202*333d2b36SAndroid Build Coastguard Worker	for _, jar := range jars {
203*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "jars {\n")
204*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
205*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
206*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
207*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
208*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(&content, "}\n")
209*333d2b36SAndroid Build Coastguard Worker	}
210*333d2b36SAndroid Build Coastguard Worker
211*333d2b36SAndroid Build Coastguard Worker	android.WriteFileRule(ctx, output, content.String())
212*333d2b36SAndroid Build Coastguard Worker}
213*333d2b36SAndroid Build Coastguard Worker
214*333d2b36SAndroid Build Coastguard Worker// Returns AndroidMkEntries objects to install generated classpath.proto.
215*333d2b36SAndroid Build Coastguard Worker// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
216*333d2b36SAndroid Build Coastguard Workerfunc (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
217*333d2b36SAndroid Build Coastguard Worker	return []android.AndroidMkEntries{{
218*333d2b36SAndroid Build Coastguard Worker		Class:      "ETC",
219*333d2b36SAndroid Build Coastguard Worker		OutputFile: android.OptionalPathForPath(c.outputFilepath),
220*333d2b36SAndroid Build Coastguard Worker		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
221*333d2b36SAndroid Build Coastguard Worker			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
222*333d2b36SAndroid Build Coastguard Worker				entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String())
223*333d2b36SAndroid Build Coastguard Worker				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
224*333d2b36SAndroid Build Coastguard Worker			},
225*333d2b36SAndroid Build Coastguard Worker		},
226*333d2b36SAndroid Build Coastguard Worker	}}
227*333d2b36SAndroid Build Coastguard Worker}
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Workervar ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]()
230*333d2b36SAndroid Build Coastguard Worker
231*333d2b36SAndroid Build Coastguard Workertype ClasspathFragmentProtoContentInfo struct {
232*333d2b36SAndroid Build Coastguard Worker	// Whether the classpaths.proto config is generated for the fragment.
233*333d2b36SAndroid Build Coastguard Worker	ClasspathFragmentProtoGenerated bool
234*333d2b36SAndroid Build Coastguard Worker
235*333d2b36SAndroid Build Coastguard Worker	// ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment.
236*333d2b36SAndroid Build Coastguard Worker	ClasspathFragmentProtoContents android.ConfiguredJarList
237*333d2b36SAndroid Build Coastguard Worker
238*333d2b36SAndroid Build Coastguard Worker	// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
239*333d2b36SAndroid Build Coastguard Worker	//
240*333d2b36SAndroid Build Coastguard Worker	// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
241*333d2b36SAndroid Build Coastguard Worker	// for more details.
242*333d2b36SAndroid Build Coastguard Worker	ClasspathFragmentProtoOutput android.OutputPath
243*333d2b36SAndroid Build Coastguard Worker
244*333d2b36SAndroid Build Coastguard Worker	// ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
245*333d2b36SAndroid Build Coastguard Worker	//
246*333d2b36SAndroid Build Coastguard Worker	// The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
247*333d2b36SAndroid Build Coastguard Worker	// for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
248*333d2b36SAndroid Build Coastguard Worker	// use android.InstallPath#Rel().
249*333d2b36SAndroid Build Coastguard Worker	//
250*333d2b36SAndroid Build Coastguard Worker	// This is only relevant for APEX modules as they perform their own installation; while regular
251*333d2b36SAndroid Build Coastguard Worker	// system files are installed via ClasspathFragmentBase#androidMkEntries().
252*333d2b36SAndroid Build Coastguard Worker	ClasspathFragmentProtoInstallDir android.InstallPath
253*333d2b36SAndroid Build Coastguard Worker}
254