blob: 7422fa2d52a6fa79c1783cceeb8604a5d1cdbf1e [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"
21 "strings"
22
Artur Satayeveabf2c12021-04-07 15:45:02 +010023 "android/soong/android"
24)
25
26// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
27// config files based on build configuration to embed into /system and /apex on a device.
28//
29// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
30// on the device.
31
32type classpathType int
33
34const (
35 // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
36 BOOTCLASSPATH classpathType = iota
37 DEX2OATBOOTCLASSPATH
38 SYSTEMSERVERCLASSPATH
39)
40
41func (c classpathType) String() string {
42 return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
43}
44
45type classpathFragmentProperties struct {
46}
47
48// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
49// variables at runtime.
50type classpathFragment interface {
51 android.Module
52
Artur Satayev97259dc2021-04-07 15:17:14 +010053 classpathFragmentBase() *ClasspathFragmentBase
satayev013485b2021-05-06 23:38:10 +010054
55 // ClasspathFragmentToConfiguredJarList returns android.ConfiguredJarList representation of all
56 // the jars in this classpath fragment.
57 ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList
Artur Satayeveabf2c12021-04-07 15:45:02 +010058}
59
Artur Satayev97259dc2021-04-07 15:17:14 +010060// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
Artur Satayeveabf2c12021-04-07 15:45:02 +010061// such modules are expected to call initClasspathFragment().
Artur Satayev97259dc2021-04-07 15:17:14 +010062type ClasspathFragmentBase struct {
Artur Satayeveabf2c12021-04-07 15:45:02 +010063 properties classpathFragmentProperties
64
satayev95e9c5b2021-04-29 11:50:26 +010065 classpathType classpathType
66
Artur Satayeveabf2c12021-04-07 15:45:02 +010067 outputFilepath android.OutputPath
Artur Satayev97259dc2021-04-07 15:17:14 +010068 installDirPath android.InstallPath
Artur Satayeveabf2c12021-04-07 15:45:02 +010069}
70
Artur Satayev97259dc2021-04-07 15:17:14 +010071func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
72 return c
73}
74
75// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
satayev95e9c5b2021-04-29 11:50:26 +010076func initClasspathFragment(c classpathFragment, classpathType classpathType) {
Artur Satayeveabf2c12021-04-07 15:45:02 +010077 base := c.classpathFragmentBase()
satayev95e9c5b2021-04-29 11:50:26 +010078 base.classpathType = classpathType
Artur Satayeveabf2c12021-04-07 15:45:02 +010079 c.AddProperties(&base.properties)
80}
Artur Satayev97259dc2021-04-07 15:17:14 +010081
82// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
83type classpathJar struct {
84 path string
85 classpath classpathType
86 // TODO(satayev): propagate min/max sdk versions for the jars
87 minSdkVersion int32
88 maxSdkVersion int32
89}
90
satayev013485b2021-05-06 23:38:10 +010091// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
92func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
93 paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
94 jars := make([]classpathJar, 0, len(paths)*len(classpaths))
95 for i := 0; i < len(paths); i++ {
96 for _, classpathType := range classpaths {
97 jars = append(jars, classpathJar{
98 classpath: classpathType,
99 path: paths[i],
100 })
101 }
102 }
103 return jars
104}
105
106func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
Artur Satayev97259dc2021-04-07 15:17:14 +0100107 outputFilename := ctx.ModuleName() + ".pb"
108 c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
109 c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
110
Artur Satayev97259dc2021-04-07 15:17:14 +0100111 generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
112 writeClasspathsJson(ctx, generatedJson, jars)
113
114 rule := android.NewRuleBuilder(pctx, ctx)
115 rule.Command().
116 BuiltTool("conv_classpaths_proto").
117 Flag("encode").
118 Flag("--format=json").
119 FlagWithInput("--input=", generatedJson).
120 FlagWithOutput("--output=", c.outputFilepath)
121
122 rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
123}
124
125func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
126 var content strings.Builder
127 fmt.Fprintf(&content, "{\n")
128 fmt.Fprintf(&content, "\"jars\": [\n")
129 for idx, jar := range jars {
130 fmt.Fprintf(&content, "{\n")
131
132 fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
133 fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
134
135 if idx < len(jars)-1 {
136 fmt.Fprintf(&content, "},\n")
137 } else {
138 fmt.Fprintf(&content, "}\n")
139 }
140 }
141 fmt.Fprintf(&content, "]\n")
142 fmt.Fprintf(&content, "}\n")
143 android.WriteFileRule(ctx, output, content.String())
144}
145
satayev3db35472021-05-06 23:59:58 +0100146// Returns AndroidMkEntries objects to install generated classpath.proto.
147// 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 +0100148func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
satayev013485b2021-05-06 23:38:10 +0100149 return []android.AndroidMkEntries{{
Artur Satayev97259dc2021-04-07 15:17:14 +0100150 Class: "ETC",
151 OutputFile: android.OptionalPathForPath(c.outputFilepath),
152 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
153 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
154 entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
155 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
156 },
157 },
158 }}
159}