blob: bc0416a4714dc1508e0cc3934468d3cdca2f3816 [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"
Artur Satayev97259dc2021-04-07 15:17:14 +010022 "strings"
23
Artur Satayeveabf2c12021-04-07 15:45:02 +010024 "android/soong/android"
25)
26
27// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
28// config files based on build configuration to embed into /system and /apex on a device.
29//
30// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
31// on the device.
32
33type classpathType int
34
35const (
36 // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
37 BOOTCLASSPATH classpathType = iota
38 DEX2OATBOOTCLASSPATH
39 SYSTEMSERVERCLASSPATH
40)
41
42func (c classpathType) String() string {
43 return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
44}
45
46type classpathFragmentProperties struct {
47}
48
49// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
50// variables at runtime.
51type classpathFragment interface {
52 android.Module
53
Artur Satayev97259dc2021-04-07 15:17:14 +010054 classpathFragmentBase() *ClasspathFragmentBase
satayev013485b2021-05-06 23:38:10 +010055
56 // ClasspathFragmentToConfiguredJarList returns android.ConfiguredJarList representation of all
57 // the jars in this classpath fragment.
58 ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList
Artur Satayeveabf2c12021-04-07 15:45:02 +010059}
60
Artur Satayev97259dc2021-04-07 15:17:14 +010061// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
Artur Satayeveabf2c12021-04-07 15:45:02 +010062// such modules are expected to call initClasspathFragment().
Artur Satayev97259dc2021-04-07 15:17:14 +010063type ClasspathFragmentBase struct {
Artur Satayeveabf2c12021-04-07 15:45:02 +010064 properties classpathFragmentProperties
65
satayev95e9c5b2021-04-29 11:50:26 +010066 classpathType classpathType
67
Artur Satayeveabf2c12021-04-07 15:45:02 +010068 outputFilepath android.OutputPath
Artur Satayev97259dc2021-04-07 15:17:14 +010069 installDirPath android.InstallPath
Artur Satayeveabf2c12021-04-07 15:45:02 +010070}
71
Artur Satayev97259dc2021-04-07 15:17:14 +010072func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
73 return c
74}
75
76// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
satayev95e9c5b2021-04-29 11:50:26 +010077func initClasspathFragment(c classpathFragment, classpathType classpathType) {
Artur Satayeveabf2c12021-04-07 15:45:02 +010078 base := c.classpathFragmentBase()
satayev95e9c5b2021-04-29 11:50:26 +010079 base.classpathType = classpathType
Artur Satayeveabf2c12021-04-07 15:45:02 +010080 c.AddProperties(&base.properties)
81}
Artur Satayev97259dc2021-04-07 15:17:14 +010082
83// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
84type classpathJar struct {
85 path string
86 classpath classpathType
87 // TODO(satayev): propagate min/max sdk versions for the jars
88 minSdkVersion int32
89 maxSdkVersion int32
90}
91
satayev013485b2021-05-06 23:38:10 +010092// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
93func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
94 paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
95 jars := make([]classpathJar, 0, len(paths)*len(classpaths))
96 for i := 0; i < len(paths); i++ {
97 for _, classpathType := range classpaths {
98 jars = append(jars, classpathJar{
99 classpath: classpathType,
100 path: paths[i],
101 })
102 }
103 }
104 return jars
105}
106
107func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
Artur Satayev97259dc2021-04-07 15:17:14 +0100108 outputFilename := ctx.ModuleName() + ".pb"
109 c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
110 c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
111
Artur Satayev97259dc2021-04-07 15:17:14 +0100112 generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
113 writeClasspathsJson(ctx, generatedJson, jars)
114
115 rule := android.NewRuleBuilder(pctx, ctx)
116 rule.Command().
117 BuiltTool("conv_classpaths_proto").
118 Flag("encode").
119 Flag("--format=json").
120 FlagWithInput("--input=", generatedJson).
121 FlagWithOutput("--output=", c.outputFilepath)
122
123 rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
satayev14e49132021-05-17 21:03:07 +0100124
125 classpathProtoInfo := ClasspathFragmentProtoContentInfo{
126 ClasspathFragmentProtoInstallDir: c.installDirPath,
127 ClasspathFragmentProtoOutput: c.outputFilepath,
128 }
129 ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
Artur Satayev97259dc2021-04-07 15:17:14 +0100130}
131
132func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
133 var content strings.Builder
134 fmt.Fprintf(&content, "{\n")
135 fmt.Fprintf(&content, "\"jars\": [\n")
136 for idx, jar := range jars {
137 fmt.Fprintf(&content, "{\n")
138
satayev7d226572021-05-18 19:37:32 +0100139 fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
Artur Satayev97259dc2021-04-07 15:17:14 +0100140 fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
141
142 if idx < len(jars)-1 {
143 fmt.Fprintf(&content, "},\n")
144 } else {
145 fmt.Fprintf(&content, "}\n")
146 }
147 }
148 fmt.Fprintf(&content, "]\n")
149 fmt.Fprintf(&content, "}\n")
150 android.WriteFileRule(ctx, output, content.String())
151}
152
satayev3db35472021-05-06 23:59:58 +0100153// Returns AndroidMkEntries objects to install generated classpath.proto.
154// 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 +0100155func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
satayev013485b2021-05-06 23:38:10 +0100156 return []android.AndroidMkEntries{{
Artur Satayev97259dc2021-04-07 15:17:14 +0100157 Class: "ETC",
158 OutputFile: android.OptionalPathForPath(c.outputFilepath),
159 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
160 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
161 entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
162 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
163 },
164 },
165 }}
166}
satayev14e49132021-05-17 21:03:07 +0100167
168var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
169
170type ClasspathFragmentProtoContentInfo struct {
171 // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
172 //
173 // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
174 // for more details.
175 ClasspathFragmentProtoOutput android.OutputPath
176
177 // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
178 //
179 // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
180 // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
181 // use android.InstallPath#Rel().
182 //
183 // This is only relevant for APEX modules as they perform their own installation; while regular
184 // system files are installed via ClasspathFragmentBase#androidMkEntries().
185 ClasspathFragmentProtoInstallDir android.InstallPath
186}