2021-04-07 16:45:02 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package java
|
|
|
|
|
|
|
|
import (
|
2021-04-07 16:17:14 +02:00
|
|
|
"fmt"
|
2021-05-17 22:03:07 +02:00
|
|
|
"github.com/google/blueprint"
|
2021-06-15 17:49:50 +02:00
|
|
|
"github.com/google/blueprint/proptools"
|
2021-04-07 16:17:14 +02:00
|
|
|
"strings"
|
|
|
|
|
2021-04-07 16:45:02 +02:00
|
|
|
"android/soong/android"
|
|
|
|
)
|
|
|
|
|
2021-10-29 21:46:45 +02:00
|
|
|
// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
|
2021-04-07 16:45:02 +02:00
|
|
|
// config files based on build configuration to embed into /system and /apex on a device.
|
|
|
|
//
|
|
|
|
// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
|
|
|
|
// on the device.
|
|
|
|
|
|
|
|
type classpathType int
|
|
|
|
|
|
|
|
const (
|
2021-10-29 21:46:45 +02:00
|
|
|
// Matches definition in packages/modules/common/proto/classpaths.proto
|
2021-04-07 16:45:02 +02:00
|
|
|
BOOTCLASSPATH classpathType = iota
|
|
|
|
DEX2OATBOOTCLASSPATH
|
|
|
|
SYSTEMSERVERCLASSPATH
|
2021-10-29 21:46:45 +02:00
|
|
|
STANDALONE_SYSTEMSERVER_JARS
|
2021-04-07 16:45:02 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func (c classpathType) String() string {
|
2021-10-29 21:46:45 +02:00
|
|
|
return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
|
2021-04-07 16:45:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type classpathFragmentProperties struct {
|
2021-06-15 17:49:50 +02:00
|
|
|
// Whether to generated classpaths.proto config instance for the fragment. If the config is not
|
|
|
|
// generated, then relevant boot jars are added to platform classpath, i.e. platform_bootclasspath
|
|
|
|
// or platform_systemserverclasspath. This is useful for non-updatable APEX boot jars, to keep
|
|
|
|
// them as part of dexopt on device. Defaults to true.
|
|
|
|
Generate_classpaths_proto *bool
|
2021-04-07 16:45:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
|
|
|
|
// variables at runtime.
|
|
|
|
type classpathFragment interface {
|
|
|
|
android.Module
|
|
|
|
|
2021-04-07 16:17:14 +02:00
|
|
|
classpathFragmentBase() *ClasspathFragmentBase
|
2021-04-07 16:45:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-07 16:17:14 +02:00
|
|
|
// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
|
2021-04-07 16:45:02 +02:00
|
|
|
// such modules are expected to call initClasspathFragment().
|
2021-04-07 16:17:14 +02:00
|
|
|
type ClasspathFragmentBase struct {
|
2021-04-07 16:45:02 +02:00
|
|
|
properties classpathFragmentProperties
|
|
|
|
|
2021-04-29 12:50:26 +02:00
|
|
|
classpathType classpathType
|
|
|
|
|
2021-04-07 16:45:02 +02:00
|
|
|
outputFilepath android.OutputPath
|
2021-04-07 16:17:14 +02:00
|
|
|
installDirPath android.InstallPath
|
2021-04-07 16:45:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-07 16:17:14 +02:00
|
|
|
func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
|
2021-04-29 12:50:26 +02:00
|
|
|
func initClasspathFragment(c classpathFragment, classpathType classpathType) {
|
2021-04-07 16:45:02 +02:00
|
|
|
base := c.classpathFragmentBase()
|
2021-04-29 12:50:26 +02:00
|
|
|
base.classpathType = classpathType
|
2021-04-07 16:45:02 +02:00
|
|
|
c.AddProperties(&base.properties)
|
|
|
|
}
|
2021-04-07 16:17:14 +02:00
|
|
|
|
|
|
|
// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
|
|
|
|
type classpathJar struct {
|
2021-11-30 13:33:55 +01:00
|
|
|
path string
|
|
|
|
classpath classpathType
|
|
|
|
minSdkVersion string
|
|
|
|
maxSdkVersion string
|
2021-04-07 16:17:14 +02:00
|
|
|
}
|
|
|
|
|
2021-07-21 15:23:52 +02:00
|
|
|
// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
|
|
|
|
// supplied contents that may be in the apex boot jars.
|
2021-06-29 21:04:45 +02:00
|
|
|
//
|
|
|
|
// The module names are included because sometimes the stem is set to just change the name of
|
|
|
|
// the installed file and it expects the configuration to still use the actual module name.
|
|
|
|
//
|
|
|
|
// The stem names are included because sometimes the stem is set to change the effective name of the
|
|
|
|
// module that is used in the configuration as well,e .g. when a test library is overriding an
|
|
|
|
// actual boot jar
|
2021-07-21 15:23:52 +02:00
|
|
|
func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
|
2021-06-29 21:04:45 +02:00
|
|
|
set := map[string]struct{}{}
|
|
|
|
for _, name := range contents {
|
|
|
|
dep := ctx.GetDirectDepWithTag(name, tag)
|
|
|
|
set[name] = struct{}{}
|
|
|
|
if m, ok := dep.(ModuleWithStem); ok {
|
|
|
|
set[m.Stem()] = struct{}{}
|
|
|
|
} else {
|
|
|
|
ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return android.SortedStringKeys(set)
|
|
|
|
}
|
|
|
|
|
2021-05-07 00:38:10 +02:00
|
|
|
// Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
|
|
|
|
func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, classpaths ...classpathType) []classpathJar {
|
|
|
|
paths := configuredJars.DevicePaths(ctx.Config(), android.Android)
|
|
|
|
jars := make([]classpathJar, 0, len(paths)*len(classpaths))
|
|
|
|
for i := 0; i < len(paths); i++ {
|
|
|
|
for _, classpathType := range classpaths {
|
2021-11-30 13:33:55 +01:00
|
|
|
jar := classpathJar{
|
2021-05-07 00:38:10 +02:00
|
|
|
classpath: classpathType,
|
|
|
|
path: paths[i],
|
2021-11-30 13:33:55 +01:00
|
|
|
}
|
|
|
|
ctx.VisitDirectDepsIf(func(m android.Module) bool {
|
|
|
|
return m.Name() == configuredJars.Jar(i)
|
|
|
|
}, func(m android.Module) {
|
|
|
|
if s, ok := m.(*SdkLibrary); ok {
|
|
|
|
// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
|
|
|
|
if s.minSdkVersion.Specified() {
|
|
|
|
if s.minSdkVersion.ApiLevel.IsCurrent() {
|
|
|
|
jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
|
|
|
|
} else {
|
|
|
|
jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if s.maxSdkVersion.Specified() {
|
|
|
|
if s.maxSdkVersion.ApiLevel.IsCurrent() {
|
|
|
|
jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
|
|
|
|
} else {
|
|
|
|
jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-07 00:38:10 +02:00
|
|
|
})
|
2021-11-30 13:33:55 +01:00
|
|
|
jars = append(jars, jar)
|
2021-05-07 00:38:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return jars
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:49:10 +02:00
|
|
|
func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) {
|
2021-06-15 17:49:50 +02:00
|
|
|
generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
|
|
|
|
if generateProto {
|
|
|
|
outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
|
|
|
|
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
|
|
|
|
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
|
|
|
|
|
2021-12-01 19:24:09 +01:00
|
|
|
generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
|
|
|
|
writeClasspathsTextproto(ctx, generatedTextproto, jars)
|
2021-06-15 17:49:50 +02:00
|
|
|
|
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
|
|
rule.Command().
|
|
|
|
BuiltTool("conv_classpaths_proto").
|
|
|
|
Flag("encode").
|
2021-12-01 19:24:09 +01:00
|
|
|
Flag("--format=textproto").
|
|
|
|
FlagWithInput("--input=", generatedTextproto).
|
2021-06-15 17:49:50 +02:00
|
|
|
FlagWithOutput("--output=", c.outputFilepath)
|
|
|
|
|
|
|
|
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
|
|
|
|
}
|
2021-05-17 22:03:07 +02:00
|
|
|
|
|
|
|
classpathProtoInfo := ClasspathFragmentProtoContentInfo{
|
2021-06-15 17:49:50 +02:00
|
|
|
ClasspathFragmentProtoGenerated: generateProto,
|
2021-06-15 18:49:10 +02:00
|
|
|
ClasspathFragmentProtoContents: configuredJars,
|
2021-05-17 22:03:07 +02:00
|
|
|
ClasspathFragmentProtoInstallDir: c.installDirPath,
|
|
|
|
ClasspathFragmentProtoOutput: c.outputFilepath,
|
|
|
|
}
|
|
|
|
ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
|
2021-04-07 16:17:14 +02:00
|
|
|
}
|
|
|
|
|
2021-12-01 19:24:09 +01:00
|
|
|
func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
|
2021-04-07 16:17:14 +02:00
|
|
|
var content strings.Builder
|
2021-11-30 13:33:55 +01:00
|
|
|
|
2021-12-01 19:24:09 +01:00
|
|
|
for _, jar := range jars {
|
|
|
|
fmt.Fprintf(&content, "jars {\n")
|
|
|
|
fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
|
|
|
|
fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
|
|
|
|
fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
|
|
|
|
fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
|
|
|
|
fmt.Fprintf(&content, "}\n")
|
2021-04-07 16:17:14 +02:00
|
|
|
}
|
2021-11-30 13:33:55 +01:00
|
|
|
|
2021-04-07 16:17:14 +02:00
|
|
|
android.WriteFileRule(ctx, output, content.String())
|
|
|
|
}
|
|
|
|
|
2021-05-07 00:59:58 +02:00
|
|
|
// Returns AndroidMkEntries objects to install generated classpath.proto.
|
|
|
|
// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
|
2021-05-06 14:21:15 +02:00
|
|
|
func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
|
2021-05-07 00:38:10 +02:00
|
|
|
return []android.AndroidMkEntries{{
|
2021-04-07 16:17:14 +02:00
|
|
|
Class: "ETC",
|
|
|
|
OutputFile: android.OptionalPathForPath(c.outputFilepath),
|
|
|
|
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
|
|
|
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
|
|
|
entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
|
|
|
|
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
}
|
2021-05-17 22:03:07 +02:00
|
|
|
|
|
|
|
var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
|
|
|
|
|
|
|
|
type ClasspathFragmentProtoContentInfo struct {
|
2021-06-15 17:49:50 +02:00
|
|
|
// Whether the classpaths.proto config is generated for the fragment.
|
|
|
|
ClasspathFragmentProtoGenerated bool
|
|
|
|
|
2021-06-15 18:49:10 +02:00
|
|
|
// ClasspathFragmentProtoContents contains a list of jars that are part of this classpath fragment.
|
|
|
|
ClasspathFragmentProtoContents android.ConfiguredJarList
|
|
|
|
|
2021-05-17 22:03:07 +02:00
|
|
|
// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
|
|
|
|
//
|
|
|
|
// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
|
|
|
|
// for more details.
|
|
|
|
ClasspathFragmentProtoOutput android.OutputPath
|
|
|
|
|
|
|
|
// ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
|
|
|
|
//
|
|
|
|
// The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
|
|
|
|
// for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
|
|
|
|
// use android.InstallPath#Rel().
|
|
|
|
//
|
|
|
|
// This is only relevant for APEX modules as they perform their own installation; while regular
|
|
|
|
// system files are installed via ClasspathFragmentBase#androidMkEntries().
|
|
|
|
ClasspathFragmentProtoInstallDir android.InstallPath
|
|
|
|
}
|