From 14e49130bbeba7d222c8851e2f59710ac0f6eb71 Mon Sep 17 00:00:00 2001 From: satayev Date: Mon, 17 May 2021 21:03:07 +0100 Subject: [PATCH 1/3] Move classpaths.proto related info into a separate provider. The new info struct can be easily shared with systemserverclasspath fragments. Bug: 180105615 Test: m nothing Change-Id: I9986e64fdf19f4168da63c156de3dc9bcafac8d8 --- apex/apex.go | 12 +++++++++--- java/bootclasspath_fragment.go | 32 +++++--------------------------- java/classpath_fragment.go | 27 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index a8fbf2274..543c43264 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -2106,13 +2106,19 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint. } // Add classpaths.proto config. - classpathProtoOutput := bootclasspathFragmentInfo.ClasspathFragmentProtoOutput - classpathProto := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), bootclasspathFragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil) - filesToAdd = append(filesToAdd, classpathProto) + filesToAdd = append(filesToAdd, apexClasspathFragmentProtoFile(ctx, module)) return filesToAdd } +// apexClasspathFragmentProtoFile returns apexFile structure defining the classpath.proto config that +// the module contributes to the apex. +func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) apexFile { + fragmentInfo := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo) + classpathProtoOutput := fragmentInfo.ClasspathFragmentProtoOutput + return newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), fragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil) +} + // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment // content module, i.e. a library that is part of the bootclasspath. func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile { diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index b6b877b6f..5d8a8e525 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -268,22 +268,6 @@ var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(Bootcla // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the // apex contents. type BootclasspathFragmentApexContentInfo struct { - // 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/, - // 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 - // The image config, internal to this module (and the dex_bootjars singleton). // // Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur @@ -396,25 +380,19 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Perform hidden API processing. b.generateHiddenAPIBuildActions(ctx, contents) - // Construct the boot image info from the config. - info := BootclasspathFragmentApexContentInfo{ - ClasspathFragmentProtoInstallDir: b.classpathFragmentBase().installDirPath, - ClasspathFragmentProtoOutput: b.classpathFragmentBase().outputFilepath, - imageConfig: nil, - } - if !SkipDexpreoptBootJars(ctx) { // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars // GenerateSingletonBuildActions method as it cannot create it for itself. dexpreopt.GetGlobalSoongConfig(ctx) - info.imageConfig = b.getImageConfig(ctx) // Only generate the boot image if the configuration does not skip it. b.generateBootImageBuildActions(ctx, contents) - } - // Make it available for other modules. - ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info) + // Make the boot image info available for other modules + ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, BootclasspathFragmentApexContentInfo{ + imageConfig: b.getImageConfig(ctx), + }) + } } // generateClasspathProtoBuildActions generates all required build actions for classpath.proto config diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index 7422fa2d5..740809093 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -18,6 +18,7 @@ package java import ( "fmt" + "github.com/google/blueprint" "strings" "android/soong/android" @@ -120,6 +121,12 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M FlagWithOutput("--output=", c.outputFilepath) rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String()) + + classpathProtoInfo := ClasspathFragmentProtoContentInfo{ + ClasspathFragmentProtoInstallDir: c.installDirPath, + ClasspathFragmentProtoOutput: c.outputFilepath, + } + ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo) } func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { @@ -157,3 +164,23 @@ func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries { }, }} } + +var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{}) + +type ClasspathFragmentProtoContentInfo struct { + // 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/, + // 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 +} From 9366a053da11ba44c9d70671dfac7c294c5427d0 Mon Sep 17 00:00:00 2001 From: satayev Date: Mon, 17 May 2021 21:13:44 +0100 Subject: [PATCH 2/3] Add "contents" property to systemserverclasspath_fragment. Similar to bcp_fragment's contents, this property lists all java library contributions made by this fragment. Bug: 180105615 Test: m nothing Change-Id: Ifb1f54d5db290fffaa31933d15207014bb72d2fb --- java/systemserver_classpath_fragment.go | 34 ++++++++++++++++++++ java/systemserver_classpath_fragment_test.go | 25 ++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index cc5ff96ca..4e65c056b 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -17,6 +17,7 @@ package java import ( "android/soong/android" "android/soong/dexpreopt" + "github.com/google/blueprint" ) func init() { @@ -70,16 +71,30 @@ type systemServerClasspathModule struct { android.ModuleBase ClasspathFragmentBase + + properties systemServerClasspathFragmentProperties +} + +type systemServerClasspathFragmentProperties struct { + // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library. + // + // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH. + Contents []string } func systemServerClasspathFactory() android.Module { m := &systemServerClasspathModule{} + m.AddProperties(&m.properties) initClasspathFragment(m, SYSTEMSERVERCLASSPATH) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m } func (s *systemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if len(s.properties.Contents) == 0 { + ctx.PropertyErrorf("contents", "empty contents are not allowed") + } + s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJarListToClasspathJars(ctx, s.ClasspathFragmentToConfiguredJarList(ctx))) } @@ -87,3 +102,22 @@ func (s *systemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx a // TODO(satayev): populate with actual content return android.EmptyConfiguredJarList() } + +type systemServerClasspathFragmentContentDependencyTag struct { + blueprint.BaseDependencyTag +} + +// The tag used for the dependency between the systemserverclasspath_fragment module and its contents. +var systemServerClasspathFragmentContentDepTag = systemServerClasspathFragmentContentDependencyTag{} + +func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool { + return tag == systemServerClasspathFragmentContentDepTag +} + +func (s *systemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { + module := ctx.Module() + + for _, name := range s.properties.Contents { + ctx.AddDependency(module, systemServerClasspathFragmentContentDepTag, name) + } +} diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go index 6126d5eb1..5272f271d 100644 --- a/java/systemserver_classpath_fragment_test.go +++ b/java/systemserver_classpath_fragment_test.go @@ -20,13 +20,13 @@ import ( "android/soong/android" ) -var prepareForTestWithSystemserverClasspath = android.GroupFixturePreparers( +var prepareForTestWithSystemServerClasspath = android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ) -func TestSystemserverClasspathVariant(t *testing.T) { +func TestPlatformSystemserverClasspathVariant(t *testing.T) { result := android.GroupFixturePreparers( - prepareForTestWithSystemserverClasspath, + prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` platform_systemserverclasspath { name: "platform-systemserverclasspath", @@ -38,9 +38,9 @@ func TestSystemserverClasspathVariant(t *testing.T) { android.AssertIntEquals(t, "expect 1 variant", 1, len(variants)) } -func TestSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) { +func TestPlatformSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) { result := android.GroupFixturePreparers( - prepareForTestWithSystemserverClasspath, + prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` platform_systemserverclasspath { name: "platform-systemserverclasspath", @@ -53,9 +53,9 @@ func TestSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) { android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) } -func TestSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { +func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { preparer := android.GroupFixturePreparers( - prepareForTestWithSystemserverClasspath, + prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` platform_systemserverclasspath { name: "platform-systemserverclasspath", @@ -95,3 +95,14 @@ func TestSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { } }) } + +func TestSystemserverclasspathFragmentWithoutContents(t *testing.T) { + prepareForTestWithSystemServerClasspath. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\Qempty contents are not allowed\E`)). + RunTestWithBp(t, ` + systemserverclasspath_fragment { + name: "systemserverclasspath-fragment", + } + `) +} From 333a1732b17887260f2290ffacffffeff760eee5 Mon Sep 17 00:00:00 2001 From: satayev Date: Mon, 17 May 2021 21:35:26 +0100 Subject: [PATCH 3/3] Add systemserverclasspath_fragments property to apex. - All contents of the fragment are added as java_lib dependencies. - Generated classpaths.proto is added into etc as required. Bug: 180105615 Test: m nothing Change-Id: I8e8e8b019c4ca2909182f205a47deffa946de6da --- apex/Android.bp | 1 + apex/apex.go | 25 ++++++- apex/systemserver_classpath_fragment_test.go | 78 ++++++++++++++++++++ java/systemserver_classpath_fragment.go | 16 ++-- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 apex/systemserver_classpath_fragment_test.go diff --git a/apex/Android.bp b/apex/Android.bp index e234181d3..14c877100 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "apex_test.go", "bootclasspath_fragment_test.go", "platform_bootclasspath_test.go", + "systemserver_classpath_fragment_test.go", "vndk_test.go", ], pluginFor: ["soong_build"], diff --git a/apex/apex.go b/apex/apex.go index 543c43264..7b2e19d03 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -102,6 +102,9 @@ type apexBundleProperties struct { // List of bootclasspath fragments that are embedded inside this APEX bundle. Bootclasspath_fragments []string + // List of systemserverclasspath fragments that are embedded inside this APEX bundle. + Systemserverclasspath_fragments []string + // List of java libraries that are embedded inside this APEX bundle. Java_libs []string @@ -575,6 +578,7 @@ var ( executableTag = dependencyTag{name: "executable", payload: true} fsTag = dependencyTag{name: "filesystem", payload: true} bcpfTag = dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true} + sscpfTag = dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true} compatConfigTag = dependencyTag{name: "compatConfig", payload: true, sourceOnly: true} javaLibTag = dependencyTag{name: "javaLib", payload: true} jniLibTag = dependencyTag{name: "jniLib", payload: true} @@ -755,6 +759,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { // Common-arch dependencies come next commonVariation := ctx.Config().AndroidCommonTarget.Variations() ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...) + ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...) ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...) ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...) ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...) @@ -1715,6 +1720,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, filesToAdd...) return true } + case sscpfTag: + { + if _, ok := child.(*java.SystemServerClasspathModule); !ok { + ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName) + return false + } + filesInfo = append(filesInfo, apexClasspathFragmentProtoFile(ctx, child)) + return true + } case javaLibTag: switch child.(type) { case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import: @@ -1941,7 +1955,16 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { default: ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child)) } - + } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) { + // Add the contents of the systemserverclasspath fragment to the apex. + switch child.(type) { + case *java.Library, *java.SdkLibrary: + af := apexFileForJavaModule(ctx, child.(javaModule)) + filesInfo = append(filesInfo, af) + return true // track transitive dependencies + default: + ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child)) + } } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok { // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go new file mode 100644 index 000000000..e1a101ad9 --- /dev/null +++ b/apex/systemserver_classpath_fragment_test.go @@ -0,0 +1,78 @@ +// 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 apex + +import ( + "testing" + + "android/soong/android" + "android/soong/java" +) + +var prepareForTestWithSystemserverclasspathFragment = android.GroupFixturePreparers( + java.PrepareForTestWithDexpreopt, + PrepareForTestWithApexBuildComponents, +) + +func TestSystemserverclasspathFragmentContents(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", + contents: [ + "foo", + ], + apex_available: [ + "myapex", + ], + } + `) + + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + "etc/classpaths/mysystemserverclasspathfragment.pb", + "javalib/foo.jar", + }) + + java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + `myapex.key`, + `mysystemserverclasspathfragment`, + }) +} diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index 4e65c056b..a505c6d01 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -67,14 +67,19 @@ func (p *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarLi }).(android.ConfiguredJarList) } -type systemServerClasspathModule struct { +type SystemServerClasspathModule struct { android.ModuleBase + android.ApexModuleBase ClasspathFragmentBase properties systemServerClasspathFragmentProperties } +func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { + return nil +} + type systemServerClasspathFragmentProperties struct { // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library. // @@ -83,14 +88,15 @@ type systemServerClasspathFragmentProperties struct { } func systemServerClasspathFactory() android.Module { - m := &systemServerClasspathModule{} + m := &SystemServerClasspathModule{} m.AddProperties(&m.properties) + android.InitApexModule(m) initClasspathFragment(m, SYSTEMSERVERCLASSPATH) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m } -func (s *systemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(s.properties.Contents) == 0 { ctx.PropertyErrorf("contents", "empty contents are not allowed") } @@ -98,7 +104,7 @@ func (s *systemServerClasspathModule) GenerateAndroidBuildActions(ctx android.Mo s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJarListToClasspathJars(ctx, s.ClasspathFragmentToConfiguredJarList(ctx))) } -func (s *systemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { +func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { // TODO(satayev): populate with actual content return android.EmptyConfiguredJarList() } @@ -114,7 +120,7 @@ func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) b return tag == systemServerClasspathFragmentContentDepTag } -func (s *systemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { +func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { module := ctx.Module() for _, name := range s.properties.Contents {