blob: 00e95913b10f111c48554568c8b6b9dbb6d5dbca [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
Artur Satayeveabf2c12021-04-07 15:45:02 +010054}
55
Artur Satayev97259dc2021-04-07 15:17:14 +010056// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
Artur Satayeveabf2c12021-04-07 15:45:02 +010057// such modules are expected to call initClasspathFragment().
Artur Satayev97259dc2021-04-07 15:17:14 +010058type ClasspathFragmentBase struct {
Artur Satayeveabf2c12021-04-07 15:45:02 +010059 properties classpathFragmentProperties
60
satayev95e9c5b2021-04-29 11:50:26 +010061 classpathType classpathType
62
Artur Satayeveabf2c12021-04-07 15:45:02 +010063 outputFilepath android.OutputPath
Artur Satayev97259dc2021-04-07 15:17:14 +010064 installDirPath android.InstallPath
Artur Satayeveabf2c12021-04-07 15:45:02 +010065}
66
Artur Satayev97259dc2021-04-07 15:17:14 +010067func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
68 return c
69}
70
71// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
satayev95e9c5b2021-04-29 11:50:26 +010072func initClasspathFragment(c classpathFragment, classpathType classpathType) {
Artur Satayeveabf2c12021-04-07 15:45:02 +010073 base := c.classpathFragmentBase()
satayev95e9c5b2021-04-29 11:50:26 +010074 base.classpathType = classpathType
Artur Satayeveabf2c12021-04-07 15:45:02 +010075 c.AddProperties(&base.properties)
76}
Artur Satayev97259dc2021-04-07 15:17:14 +010077
78// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
79type classpathJar struct {
80 path string
81 classpath classpathType
82 // TODO(satayev): propagate min/max sdk versions for the jars
83 minSdkVersion int32
84 maxSdkVersion int32
85}
86
satayev128ce2f2021-05-06 13:21:15 +010087func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
Artur Satayev97259dc2021-04-07 15:17:14 +010088 outputFilename := ctx.ModuleName() + ".pb"
89 c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
90 c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
91
92 var jars []classpathJar
satayev95e9c5b2021-04-29 11:50:26 +010093 switch c.classpathType {
94 case BOOTCLASSPATH:
95 jars = appendClasspathJar(jars, BOOTCLASSPATH, defaultBootclasspath(ctx)...)
96 jars = appendClasspathJar(jars, DEX2OATBOOTCLASSPATH, defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps...)
97 case SYSTEMSERVERCLASSPATH:
98 jars = appendClasspathJar(jars, SYSTEMSERVERCLASSPATH, systemServerClasspath(ctx)...)
99 default:
100 // Only supported classpath fragments are BOOTCLASSPATH and SYSTEMSERVERCLASSPATH.
101 // DEX2OATBOOTCLASSPATH is a special case of BOOTCLASSPATH and is auto-generated.
102 panic(fmt.Errorf("found %v, expected either BOOTCLASSPATH or SYSTEMSERVERCLASSPATH", c.classpathType))
103 }
Artur Satayev97259dc2021-04-07 15:17:14 +0100104
105 generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
106 writeClasspathsJson(ctx, generatedJson, jars)
107
108 rule := android.NewRuleBuilder(pctx, ctx)
109 rule.Command().
110 BuiltTool("conv_classpaths_proto").
111 Flag("encode").
112 Flag("--format=json").
113 FlagWithInput("--input=", generatedJson).
114 FlagWithOutput("--output=", c.outputFilepath)
115
116 rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
117}
118
119func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
120 var content strings.Builder
121 fmt.Fprintf(&content, "{\n")
122 fmt.Fprintf(&content, "\"jars\": [\n")
123 for idx, jar := range jars {
124 fmt.Fprintf(&content, "{\n")
125
126 fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
127 fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
128
129 if idx < len(jars)-1 {
130 fmt.Fprintf(&content, "},\n")
131 } else {
132 fmt.Fprintf(&content, "}\n")
133 }
134 }
135 fmt.Fprintf(&content, "]\n")
136 fmt.Fprintf(&content, "}\n")
137 android.WriteFileRule(ctx, output, content.String())
138}
139
140func appendClasspathJar(slice []classpathJar, classpathType classpathType, paths ...string) (result []classpathJar) {
141 result = append(result, slice...)
142 for _, path := range paths {
143 result = append(result, classpathJar{
144 path: path,
145 classpath: classpathType,
146 })
147 }
148 return
149}
150
satayev128ce2f2021-05-06 13:21:15 +0100151func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
Artur Satayev97259dc2021-04-07 15:17:14 +0100152 return []android.AndroidMkEntries{android.AndroidMkEntries{
153 Class: "ETC",
154 OutputFile: android.OptionalPathForPath(c.outputFilepath),
155 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
156 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
157 entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
158 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
159 },
160 },
161 }}
162}