Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d32118c5 authored by Paul Duffin's avatar Paul Duffin Committed by Gerrit Code Review
Browse files

Merge "Add dependencies from platform_bootclasspath to contents"

parents d137306c b432df9c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ bootstrap_go_package {
    testSrcs: [
        "apex_test.go",
        "boot_image_test.go",
        "platform_bootclasspath_test.go",
        "vndk_test.go",
    ],
    pluginFor: ["soong_build"],
+158 −0
Original line number Diff line number Diff line
// 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/dexpreopt"
	"android/soong/java"
	"github.com/google/blueprint"
)

// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
// apexes.

var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
	java.PrepareForTestWithDexpreopt,
	PrepareForTestWithApexBuildComponents,
)

func TestPlatformBootclasspathDependencies(t *testing.T) {
	result := android.GroupFixturePreparers(
		prepareForTestWithPlatformBootclasspath,
		prepareForTestWithArtApex,
		prepareForTestWithMyapex,
		// Configure some libraries in the art and framework boot images.
		dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
		dexpreopt.FixtureSetBootJars("platform:foo"),
		dexpreopt.FixtureSetUpdatableBootJars("myapex:bar"),
		java.PrepareForTestWithJavaSdkLibraryFiles,
		java.FixtureWithLastReleaseApis("foo"),
	).RunTestWithBp(t, `
		apex {
			name: "com.android.art",
			key: "com.android.art.key",
 			bootclasspath_fragments: [
				"art-bootclasspath-fragment",
			],
			updatable: false,
		}

		apex_key {
			name: "com.android.art.key",
			public_key: "com.android.art.avbpubkey",
			private_key: "com.android.art.pem",
		}

		bootclasspath_fragment {
			name: "art-bootclasspath-fragment",
			apex_available: [
				"com.android.art",
			],
			contents: [
				"baz",
				"quuz",
			],
		}

		java_library {
			name: "baz",
			apex_available: [
				"com.android.art",
			],
			srcs: ["b.java"],
			installable: true,
		}

		// Add a java_import that is not preferred and so won't have an appropriate apex variant created
		// for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
		java_import {
			name: "baz",
			apex_available: [
				"com.android.art",
			],
			jars: ["b.jar"],
		}

		java_library {
			name: "quuz",
			apex_available: [
				"com.android.art",
			],
			srcs: ["b.java"],
			installable: true,
		}

		apex {
			name: "myapex",
			key: "myapex.key",
			java_libs: [
				"bar",
			],
			updatable: false,
		}

		apex_key {
			name: "myapex.key",
			public_key: "testkey.avbpubkey",
			private_key: "testkey.pem",
		}

		java_sdk_library {
			name: "foo",
			srcs: ["b.java"],
		}

		java_library {
			name: "bar",
			srcs: ["b.java"],
			installable: true,
			apex_available: ["myapex"],
			permitted_packages: ["bar"],
		}

		platform_bootclasspath {
			name: "myplatform-bootclasspath",
		}
`,
	)

	// Make sure that the myplatform-bootclasspath has the correct dependencies.
	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
		`platform:dex2oatd`,
		`com.android.art:baz`,
		`com.android.art:quuz`,
		`platform:foo`,
		`myapex:bar`,
	})
}

// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
//
// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
// name of the apex, or platform is it is not part of an apex and <module> is the module name.
func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
	t.Helper()
	module := ctx.ModuleForTests(name, variant).Module()
	modules := []android.Module{}
	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
		modules = append(modules, m.(android.Module))
	})

	pairs := java.ApexNamePairsFromModules(ctx, modules)
	android.AssertDeepEquals(t, "module dependencies", expected, pairs)
}
+93 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package java
import (
	"android/soong/android"
	"android/soong/dexpreopt"
	"github.com/google/blueprint"
)

func init() {
@@ -25,10 +26,38 @@ func init() {

func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
	ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)

	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
		ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
	})
}

type platformBootclasspathDependencyTag struct {
	blueprint.BaseDependencyTag

	name string
}

// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
//
// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
// dependencies.
// TODO(b/177892522): Remove this and add needed visibility.
func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
}

// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}

var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}

type platformBootclasspathModule struct {
	android.ModuleBase

	// The apex:module pairs obtained from the configured modules.
	//
	// Currently only for testing.
	configuredModules []android.Module
}

func platformBootclasspathFactory() android.Module {
@@ -47,7 +76,71 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon
	dexpreopt.RegisterToolDeps(ctx)
}

func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
	m := ctx.Module()
	if p, ok := m.(*platformBootclasspathModule); ok {
		// Add dependencies on all the modules configured in the "art" boot image.
		artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
		addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)

		// Add dependencies on all the modules configured in the "boot" boot image. That does not
		// include modules configured in the "art" boot image.
		bootImageConfig := p.getImageConfig(ctx)
		addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)

		// Add dependencies on all the updatable modules.
		updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
		addDependenciesOntoBootImageModules(ctx, updatableModules)
	}
}

func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
	var variations []blueprint.Variation
	if apex != "platform" {
		// Pick the correct apex variant.
		variations = []blueprint.Variation{
			{Mutator: "apex", Variation: apex},
		}
	}

	addedDep := false
	if ctx.OtherModuleDependencyVariantExists(variations, name) {
		ctx.AddFarVariationDependencies(variations, tag, name)
		addedDep = true
	}

	// Add a dependency on the prebuilt module if it exists.
	prebuiltName := android.PrebuiltNameFromSource(name)
	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
		ctx.AddVariationDependencies(variations, tag, prebuiltName)
		addedDep = true
	}

	// If no appropriate variant existing for this, so no dependency could be added, then it is an
	// error, unless missing dependencies are allowed. The simplest way to handle that is to add a
	// dependency that will not be satisfied and the default behavior will handle it.
	if !addedDep {
		ctx.AddFarVariationDependencies(variations, tag, name)
	}
}

func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
	for i := 0; i < modules.Len(); i++ {
		apex := modules.Apex(i)
		name := modules.Jar(i)

		addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
	}
}

func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
		tag := ctx.OtherModuleDependencyTag(module)
		if tag == platformBootclasspathModuleDepTag {
			b.configuredModules = append(b.configuredModules, module)
		}
	})

	// Nothing to do if skipping the dexpreopt of boot image jars.
	if SkipDexpreoptBootJars(ctx) {
		return
+98 −3
Original line number Diff line number Diff line
@@ -29,10 +29,105 @@ var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
)

func TestPlatformBootclasspath(t *testing.T) {
	prepareForTestWithPlatformBootclasspath.
		RunTestWithBp(t, `
	preparer := android.GroupFixturePreparers(
		prepareForTestWithPlatformBootclasspath,
		dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
		android.FixtureWithRootAndroidBp(`
			platform_bootclasspath {
				name: "platform-bootclasspath",
			}

			java_library {
				name: "bar",
				srcs: ["a.java"],
				system_modules: "none",
				sdk_version: "none",
				compile_dex: true,
			}
		`),
	)

	var addSourceBootclassPathModule = android.FixtureAddTextFile("source/Android.bp", `
		java_library {
			name: "foo",
			srcs: ["a.java"],
			system_modules: "none",
			sdk_version: "none",
			compile_dex: true,
		}
	`)

	var addPrebuiltBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
		java_import {
			name: "foo",
			jars: ["a.jar"],
			compile_dex: true,
			prefer: false,
		}
	`)

	var addPrebuiltPreferredBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
		java_import {
			name: "foo",
			jars: ["a.jar"],
			compile_dex: true,
			prefer: true,
		}
	`)

	t.Run("missing", func(t *testing.T) {
		preparer.
			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
			RunTest(t)
	})

	t.Run("source", func(t *testing.T) {
		result := android.GroupFixturePreparers(
			preparer,
			addSourceBootclassPathModule,
		).RunTest(t)

		CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
			"platform:foo",
			"platform:bar",
		})
	})

	t.Run("prebuilt", func(t *testing.T) {
		result := android.GroupFixturePreparers(
			preparer,
			addPrebuiltBootclassPathModule,
		).RunTest(t)

		CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
			"platform:prebuilt_foo",
			"platform:bar",
		})
	})

	t.Run("source+prebuilt - source preferred", func(t *testing.T) {
		result := android.GroupFixturePreparers(
			preparer,
			addSourceBootclassPathModule,
			addPrebuiltBootclassPathModule,
		).RunTest(t)

		CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
			"platform:foo",
			"platform:bar",
		})
	})

	t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
		result := android.GroupFixturePreparers(
			preparer,
			addSourceBootclassPathModule,
			addPrebuiltPreferredBootclassPathModule,
		).RunTest(t)

		CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
			"platform:prebuilt_foo",
			"platform:bar",
		})
	})
}
+31 −0
Original line number Diff line number Diff line
@@ -300,6 +300,37 @@ func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, varia
	}
}

// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
// the platform-bootclasspath module.
func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
	t.Helper()
	platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
	pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
	android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
}

// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
	pairs := []string{}
	for _, module := range modules {
		pairs = append(pairs, apexNamePairFromModule(ctx, module))
	}
	return pairs
}

func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
	name := module.Name()
	var apex string
	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
	if apexInfo.IsForPlatform() {
		apex = "platform"
	} else {
		apex = apexInfo.InApexes[0]
	}

	return fmt.Sprintf("%s:%s", apex, name)
}

func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
	t.Helper()
	actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))