Add classpath fragment property to skip proto generation.
This must always be true for updatable apexes, but is not necessary for non-updatable apexes like com.android.i18n. In a follow up this will be used to figure out whether apex boot jars should be bundled into platform_bootclasspath. Bug: 191127295 Test: atest CtsClasspathsTestCases derive_classpath_test Change-Id: Ib7dc5b057cb24955222fb97f3ff9da079f30ed77
This commit is contained in:
42
apex/apex.go
42
apex/apex.go
@@ -1756,7 +1756,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
|
ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
filesInfo = append(filesInfo, apexClasspathFragmentProtoFile(ctx, child))
|
if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
|
||||||
|
filesInfo = append(filesInfo, *af)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case javaLibTag:
|
case javaLibTag:
|
||||||
@@ -2159,17 +2161,23 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add classpaths.proto config.
|
// Add classpaths.proto config.
|
||||||
filesToAdd = append(filesToAdd, apexClasspathFragmentProtoFile(ctx, module))
|
if af := apexClasspathFragmentProtoFile(ctx, module); af != nil {
|
||||||
|
filesToAdd = append(filesToAdd, *af)
|
||||||
|
}
|
||||||
|
|
||||||
return filesToAdd
|
return filesToAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
// apexClasspathFragmentProtoFile returns apexFile structure defining the classpath.proto config that
|
// apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that
|
||||||
// the module contributes to the apex.
|
// the module contributes to the apex; or nil if the proto config was not generated.
|
||||||
func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) apexFile {
|
func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) *apexFile {
|
||||||
fragmentInfo := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
|
info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
|
||||||
classpathProtoOutput := fragmentInfo.ClasspathFragmentProtoOutput
|
if !info.ClasspathFragmentProtoGenerated {
|
||||||
return newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), fragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
|
return nil
|
||||||
|
}
|
||||||
|
classpathProtoOutput := info.ClasspathFragmentProtoOutput
|
||||||
|
af := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), info.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
|
||||||
|
return &af
|
||||||
}
|
}
|
||||||
|
|
||||||
// apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
|
// apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
|
||||||
@@ -2355,16 +2363,30 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce that Java deps of the apex are using stable SDKs to compile
|
// checkUpdatable enforces APEX and its transitive dep properties to have desired values for updatable APEXes.
|
||||||
func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
|
func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) {
|
||||||
if a.Updatable() {
|
if a.Updatable() {
|
||||||
if String(a.properties.Min_sdk_version) == "" {
|
if String(a.properties.Min_sdk_version) == "" {
|
||||||
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
|
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
|
||||||
}
|
}
|
||||||
a.checkJavaStableSdkVersion(ctx)
|
a.checkJavaStableSdkVersion(ctx)
|
||||||
|
a.checkClasspathFragments(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkClasspathFragments enforces that all classpath fragments in deps generate classpaths.proto config.
|
||||||
|
func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) {
|
||||||
|
ctx.VisitDirectDeps(func(module android.Module) {
|
||||||
|
if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag {
|
||||||
|
info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
|
||||||
|
if !info.ClasspathFragmentProtoGenerated {
|
||||||
|
ctx.OtherModuleErrorf(module, "is included in updatable apex %v, it must not set generate_classpaths_proto to false", ctx.ModuleName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkJavaStableSdkVersion enforces that all Java deps are using stable SDKs to compile.
|
||||||
func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
|
func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
|
||||||
// Visit direct deps only. As long as we guarantee top-level deps are using stable SDKs,
|
// Visit direct deps only. As long as we guarantee top-level deps are using stable SDKs,
|
||||||
// java's checkLinkType guarantees correct usage for transitive deps
|
// java's checkLinkType guarantees correct usage for transitive deps
|
||||||
@@ -2383,7 +2405,7 @@ func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures that the all the dependencies are marked as available for this APEX
|
// checkApexAvailability ensures that the all the dependencies are marked as available for this APEX.
|
||||||
func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
|
||||||
// Let's be practical. Availability for test, host, and the VNDK apex isn't important
|
// Let's be practical. Availability for test, host, and the VNDK apex isn't important
|
||||||
if ctx.Host() || a.testApex || a.vndkApex {
|
if ctx.Host() || a.testApex || a.vndkApex {
|
||||||
|
@@ -6699,6 +6699,47 @@ func TestUpdatableDefault_should_set_min_sdk_version(t *testing.T) {
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) {
|
||||||
|
testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
systemserverclasspath_fragments: [
|
||||||
|
"mysystemserverclasspathfragment",
|
||||||
|
],
|
||||||
|
min_sdk_version: "29",
|
||||||
|
updatable: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "foo",
|
||||||
|
srcs: ["b.java"],
|
||||||
|
min_sdk_version: "29",
|
||||||
|
installable: true,
|
||||||
|
apex_available: [
|
||||||
|
"myapex",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
systemserverclasspath_fragment {
|
||||||
|
name: "mysystemserverclasspathfragment",
|
||||||
|
generate_classpaths_proto: false,
|
||||||
|
contents: [
|
||||||
|
"foo",
|
||||||
|
],
|
||||||
|
apex_available: [
|
||||||
|
"myapex",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNoUpdatableJarsInBootImage(t *testing.T) {
|
func TestNoUpdatableJarsInBootImage(t *testing.T) {
|
||||||
// Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
|
// Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
|
||||||
// result in an invalid configuration as it does not set the ArtApexJars and allows art apex
|
// result in an invalid configuration as it does not set the ArtApexJars and allows art apex
|
||||||
|
@@ -76,3 +76,54 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) {
|
|||||||
`mysystemserverclasspathfragment`,
|
`mysystemserverclasspathfragment`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) {
|
||||||
|
result := android.GroupFixturePreparers(
|
||||||
|
prepareForTestWithSystemserverclasspathFragment,
|
||||||
|
prepareForTestWithMyapex,
|
||||||
|
).RunTestWithBp(t, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
systemserverclasspath_fragments: [
|
||||||
|
"mysystemserverclasspathfragment",
|
||||||
|
],
|
||||||
|
updatable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "foo",
|
||||||
|
srcs: ["b.java"],
|
||||||
|
installable: true,
|
||||||
|
apex_available: [
|
||||||
|
"myapex",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
systemserverclasspath_fragment {
|
||||||
|
name: "mysystemserverclasspathfragment",
|
||||||
|
generate_classpaths_proto: false,
|
||||||
|
contents: [
|
||||||
|
"foo",
|
||||||
|
],
|
||||||
|
apex_available: [
|
||||||
|
"myapex",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
|
||||||
|
"javalib/foo.jar",
|
||||||
|
})
|
||||||
|
|
||||||
|
java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
|
||||||
|
`myapex.key`,
|
||||||
|
`mysystemserverclasspathfragment`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -19,6 +19,7 @@ package java
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
@@ -44,6 +45,11 @@ func (c classpathType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type classpathFragmentProperties struct {
|
type classpathFragmentProperties struct {
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
|
// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
|
||||||
@@ -101,24 +107,28 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
|
func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
|
||||||
outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
|
generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true)
|
||||||
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
|
if generateProto {
|
||||||
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
|
outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
|
||||||
|
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
|
||||||
|
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
|
||||||
|
|
||||||
generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
|
generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
|
||||||
writeClasspathsJson(ctx, generatedJson, jars)
|
writeClasspathsJson(ctx, generatedJson, jars)
|
||||||
|
|
||||||
rule := android.NewRuleBuilder(pctx, ctx)
|
rule := android.NewRuleBuilder(pctx, ctx)
|
||||||
rule.Command().
|
rule.Command().
|
||||||
BuiltTool("conv_classpaths_proto").
|
BuiltTool("conv_classpaths_proto").
|
||||||
Flag("encode").
|
Flag("encode").
|
||||||
Flag("--format=json").
|
Flag("--format=json").
|
||||||
FlagWithInput("--input=", generatedJson).
|
FlagWithInput("--input=", generatedJson).
|
||||||
FlagWithOutput("--output=", c.outputFilepath)
|
FlagWithOutput("--output=", c.outputFilepath)
|
||||||
|
|
||||||
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
|
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
|
||||||
|
}
|
||||||
|
|
||||||
classpathProtoInfo := ClasspathFragmentProtoContentInfo{
|
classpathProtoInfo := ClasspathFragmentProtoContentInfo{
|
||||||
|
ClasspathFragmentProtoGenerated: generateProto,
|
||||||
ClasspathFragmentProtoInstallDir: c.installDirPath,
|
ClasspathFragmentProtoInstallDir: c.installDirPath,
|
||||||
ClasspathFragmentProtoOutput: c.outputFilepath,
|
ClasspathFragmentProtoOutput: c.outputFilepath,
|
||||||
}
|
}
|
||||||
@@ -164,6 +174,9 @@ func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
|
|||||||
var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
|
var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
|
||||||
|
|
||||||
type ClasspathFragmentProtoContentInfo struct {
|
type ClasspathFragmentProtoContentInfo struct {
|
||||||
|
// Whether the classpaths.proto config is generated for the fragment.
|
||||||
|
ClasspathFragmentProtoGenerated bool
|
||||||
|
|
||||||
// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
|
// 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
|
// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
|
||||||
|
Reference in New Issue
Block a user