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

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

Merge "Workaround to make AlwaysUsePrebuiltSdks() work with platform_bootclasspath"

parents 6333b0e4 7487a7ab
Loading
Loading
Loading
Loading
+136 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import (
	"android/soong/android"
	"android/soong/java"
	"github.com/google/blueprint"
	"github.com/google/blueprint/proptools"
)

// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
@@ -174,6 +175,141 @@ func TestPlatformBootclasspathDependencies(t *testing.T) {
	})
}

// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
// currently exists in some places in the Android build but it is not the intended structure. It is
// in fact an invalid structure that should cause build failures. However, fixing that structure
// will take too long so in the meantime this tests the workarounds to avoid build breakages.
//
// The main issues with this structure are:
// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
//    prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
//
// Together these cause the following symptoms:
// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
// 2. The "foo" java_sdk_library_import does not have a myapex variant.
//
// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
	result := android.GroupFixturePreparers(
		prepareForTestWithPlatformBootclasspath,
		prepareForTestWithMyapex,
		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
		// of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
		// a boot dex jar. The second is a normal library that is unaffected. The order matters because
		// if the dependency on myapex:foo is filtered out because of either of those conditions then
		// the dependencies resolved by the platform_bootclasspath will not match the configured list
		// and so will fail the test.
		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
		java.PrepareForTestWithJavaSdkLibraryFiles,
		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
		}),
		java.FixtureWithPrebuiltApis(map[string][]string{
			"current": {},
			"30":      {"foo"},
		}),
	).RunTestWithBp(t, `
		apex {
			name: "myapex",
			key: "myapex.key",
			bootclasspath_fragments: [
				"mybootclasspath-fragment",
			],
			updatable: false,
		}

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

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

		java_sdk_library {
			name: "foo",
			srcs: ["b.java"],
			shared_library: false,
			public: {
				enabled: true,
			},
			apex_available: ["myapex"],
			permitted_packages: ["foo"],
		}

		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
		// because AlwaysUsePrebuiltSdks() is true.
		java_sdk_library_import {
			name: "foo",
			prefer: false,
			shared_library: false,
			public: {
				jars: ["sdk_library/public/foo-stubs.jar"],
				stub_srcs: ["sdk_library/public/foo_stub_sources"],
				current_api: "sdk_library/public/foo.txt",
				removed_api: "sdk_library/public/foo-removed.txt",
				sdk_version: "current",
			},
			apex_available: ["myapex"],
		}

		// This always depends on the source foo module, its dependencies are not affected by the
		// AlwaysUsePrebuiltSdks().
		bootclasspath_fragment {
			name: "mybootclasspath-fragment",
			apex_available: [
				"myapex",
			],
			contents: [
				"foo", "bar",
			],
		}

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

	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
		// The configured contents of BootJars.
		"platform:prebuilt_foo", // Note: This is the platform not myapex variant.
		"myapex:bar",
	})

	// Make sure that the myplatform-bootclasspath has the correct dependencies.
	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
		// The following are stubs.
		"platform:prebuilt_sdk_public_current_android",
		"platform:prebuilt_sdk_system_current_android",
		"platform:prebuilt_sdk_test_current_android",

		// Not a prebuilt as no prebuilt existed when it was added.
		"platform:legacy.core.platform.api.stubs",

		// Needed for generating the boot image.
		`platform:dex2oatd`,

		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
		// modules when available as it does not know which one will be preferred.
		//
		// The source module has an APEX variant but the prebuilt does not.
		"myapex:foo",
		"platform:prebuilt_foo",

		// Only a source module exists.
		"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
+10 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ func init() {

func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
	})
}

@@ -95,6 +95,15 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st
	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
		ctx.AddVariationDependencies(variations, tag, prebuiltName)
		addedDep = true
	} else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
		// TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
		//  use bootclasspath_fragment properly.
		// Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
		// dependency on the non-APEX variant.
		if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
			ctx.AddVariationDependencies(nil, tag, prebuiltName)
			addedDep = true
		}
	}

	// If no appropriate variant existing for this, so no dependency could be added, then it is an
+1 −1
Original line number Diff line number Diff line
@@ -766,7 +766,7 @@ func generateUpdatableBcpPackagesRule(ctx android.ModuleContext, image *bootImag
			if len(pp) > 0 {
				updatablePackages = append(updatablePackages, pp...)
			} else {
				ctx.ModuleErrorf("Missing permitted_packages")
				ctx.OtherModuleErrorf(module, "Missing permitted_packages")
			}
		}
	}
+20 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package java

import (
	"fmt"
	"strings"

	"android/soong/android"
@@ -560,7 +561,25 @@ func extractBootDexJarsFromHiddenAPIModules(ctx android.ModuleContext, contents
	for _, module := range contents {
		bootDexJar := module.bootDexJar()
		if bootDexJar == nil {
			if ctx.Config().AlwaysUsePrebuiltSdks() {
				// TODO(b/179354495): Remove this work around when it is unnecessary.
				// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
				// create a fake one that will cause a build error only if it is used.
				fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())

				// Create an error rule that pretends to create the output file but will actually fail if it
				// is run.
				ctx.Build(pctx, android.BuildParams{
					Rule:   android.ErrorRule,
					Output: fake,
					Args: map[string]string{
						"error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
					},
				})
				bootDexJars = append(bootDexJars, fake)
			} else {
				ctx.ModuleErrorf("module %s does not provide a dex jar", module)
			}
		} else {
			bootDexJars = append(bootDexJars, bootDexJar)
		}
+9 −2
Original line number Diff line number Diff line
@@ -242,8 +242,15 @@ func (b *platformBootclasspathModule) checkUpdatableModules(ctx android.ModuleCo
		} else {
			name := ctx.OtherModuleName(m)
			if apexInfo.IsForPlatform() {
				// If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will
				// include platform variants of a prebuilt module due to workarounds elsewhere. In that case
				// do not treat this as an error.
				// TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment
				//  modules is complete.
				if !ctx.Config().AlwaysUsePrebuiltSdks() {
					// error: this jar is part of the platform
					ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
				}
			} else {
				// TODO(b/177892522): Treat this as an error.
				// Cannot do that at the moment because framework-wifi and framework-tethering are in the