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

Commit 9f9c0a22 authored by Sam Delmerico's avatar Sam Delmerico
Browse files

transitive Java deps for r8

The -libraryjars argument to r8 was missing transitive dependencies, and
so complained when there were classes used in the program JAR which were
not provided via libraries. This CL propagates transitive dependencies
to the r8 command to reduce the warnings that are generated for missing classes.

Bug: 242088131
Change-Id: Ifad7bc7c5d406e3de8d98ea963c97e88c84b45a1
parent 57b1e406
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -651,6 +651,8 @@ type AARImport struct {
	// Functionality common to Module and Import.
	embeddableInModuleAndImport

	providesTransitiveHeaderJars

	properties AARImportProperties

	classpathFile         android.WritablePath
@@ -897,8 +899,11 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		a.assetsPackage = mergedAssets
	}

	a.collectTransitiveHeaderJars(ctx)
	ctx.SetProvider(JavaInfoProvider, JavaInfo{
		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
	})
+3 −0
Original line number Diff line number Diff line
@@ -1310,6 +1310,9 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps boo
			ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
			ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
		}
	} else {
		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...)
		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...)
	}
}

+49 −0
Original line number Diff line number Diff line
@@ -1583,6 +1583,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {

	ctx.SetProvider(JavaInfoProvider, JavaInfo{
		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
		ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
		ImplementationJars:             android.PathsIfNonNil(j.implementationJarFile),
		ResourceJars:                   android.PathsIfNonNil(j.resourceJar),
@@ -1719,6 +1721,52 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
	return instrumentedJar
}

type providesTransitiveHeaderJars struct {
	// set of header jars for all transitive libs deps
	transitiveLibsHeaderJars *android.DepSet
	// set of header jars for all transitive static libs deps
	transitiveStaticLibsHeaderJars *android.DepSet
}

func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet {
	return j.transitiveLibsHeaderJars
}

func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet {
	return j.transitiveStaticLibsHeaderJars
}

func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
	directLibs := android.Paths{}
	directStaticLibs := android.Paths{}
	transitiveLibs := []*android.DepSet{}
	transitiveStaticLibs := []*android.DepSet{}
	ctx.VisitDirectDeps(func(module android.Module) {
		// don't add deps of the prebuilt version of the same library
		if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) {
			return
		}

		dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
		if dep.TransitiveLibsHeaderJars != nil {
			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
		}
		if dep.TransitiveStaticLibsHeaderJars != nil {
			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
		}

		tag := ctx.OtherModuleDependencyTag(module)
		_, isUsesLibDep := tag.(usesLibraryDependencyTag)
		if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep {
			directLibs = append(directLibs, dep.HeaderJars...)
		} else if tag == staticLibTag {
			directStaticLibs = append(directStaticLibs, dep.HeaderJars...)
		}
	})
	j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
	j.transitiveStaticLibsHeaderJars = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
}

func (j *Module) HeaderJars() android.Paths {
	if j.headerJarFile == nil {
		return nil
@@ -1947,6 +1995,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {

	sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())

	j.collectTransitiveHeaderJars(ctx)
	ctx.VisitDirectDeps(func(module android.Module) {
		otherName := ctx.OtherModuleName(module)
		tag := ctx.OtherModuleDependencyTag(module)
+31 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import (
	"github.com/google/blueprint/proptools"

	"android/soong/android"
	"android/soong/java/config"
	"android/soong/remoteexec"
)

@@ -90,6 +91,8 @@ type dexer struct {
	extraProguardFlagFiles android.Paths
	proguardDictionary     android.OptionalPath
	proguardUsageZip       android.OptionalPath

	providesTransitiveHeaderJars
}

func (d *dexer) effectiveOptimizeEnabled() bool {
@@ -249,12 +252,37 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
	})

	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
	r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
	r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars"))

	r8Deps = append(r8Deps, proguardRaiseDeps...)
	r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
	r8Deps = append(r8Deps, flags.bootClasspath...)
	r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars"))
	r8Deps = append(r8Deps, flags.dexClasspath...)
	r8Flags = append(r8Flags, flags.processorPath.FormJavaClassPath("-libraryjars"))
	r8Deps = append(r8Deps, flags.processorPath...)

	errorProneClasspath := classpath(android.PathsForSource(ctx, config.ErrorProneClasspath))
	r8Flags = append(r8Flags, errorProneClasspath.FormJavaClassPath("-libraryjars"))
	r8Deps = append(r8Deps, errorProneClasspath...)

	transitiveStaticLibsLookupMap := map[android.Path]bool{}
	if d.transitiveStaticLibsHeaderJars != nil {
		for _, jar := range d.transitiveStaticLibsHeaderJars.ToList() {
			transitiveStaticLibsLookupMap[jar] = true
		}
	}
	transitiveHeaderJars := android.Paths{}
	if d.transitiveLibsHeaderJars != nil {
		for _, jar := range d.transitiveLibsHeaderJars.ToList() {
			if _, ok := transitiveStaticLibsLookupMap[jar]; ok {
				// don't include a lib if it is already packaged in the current JAR as a static lib
				continue
			}
			transitiveHeaderJars = append(transitiveHeaderJars, jar)
		}
	}
	transitiveClasspath := classpath(transitiveHeaderJars)
	r8Flags = append(r8Flags, transitiveClasspath.FormJavaClassPath("-libraryjars"))
	r8Deps = append(r8Deps, transitiveClasspath...)

	flagFiles := android.Paths{
		android.PathForSource(ctx, "build/make/core/proguard.flags"),
+171 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ import (
	"testing"

	"android/soong/android"

	"github.com/google/blueprint/proptools"
)

func TestR8(t *testing.T) {
@@ -74,7 +76,7 @@ func TestR8(t *testing.T) {

	android.AssertStringDoesContain(t, "expected lib header jar in app r8 classpath",
		appR8.Args["r8Flags"], libHeader.String())
	android.AssertStringDoesNotContain(t, "expected no  static_lib header jar in app javac classpath",
	android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app r8 classpath",
		appR8.Args["r8Flags"], staticLibHeader.String())
	android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
		appR8.Args["r8Flags"], "-ignorewarnings")
@@ -86,6 +88,174 @@ func TestR8(t *testing.T) {
		corePlatformAppR8.Args["r8Flags"], "--android-platform-build")
}

func TestR8TransitiveDeps(t *testing.T) {
	bp := `
		override_android_app {
			name: "override_app",
			base: "app",
		}

		android_app {
			name: "app",
			srcs: ["foo.java"],
			libs: [
				"lib",
				"uses_libs_dep_import",
			],
			static_libs: [
				"static_lib",
				"repeated_dep",
			],
			platform_apis: true,
		}

		java_library {
			name: "static_lib",
			srcs: ["foo.java"],
		}

		java_library {
			name: "lib",
			libs: [
				"transitive_lib",
				"repeated_dep",
				"prebuilt_lib",
			],
			static_libs: ["transitive_static_lib"],
			srcs: ["foo.java"],
		}

		java_library {
			name: "repeated_dep",
			srcs: ["foo.java"],
		}

		java_library {
			name: "transitive_static_lib",
			srcs: ["foo.java"],
		}

		java_library {
			name: "transitive_lib",
			srcs: ["foo.java"],
			libs: ["transitive_lib_2"],
		}

		java_library {
			name: "transitive_lib_2",
			srcs: ["foo.java"],
		}

		java_import {
			name: "lib",
			jars: ["lib.jar"],
		}

		java_library {
			name: "uses_lib",
			srcs: ["foo.java"],
		}

		java_library {
			name: "optional_uses_lib",
			srcs: ["foo.java"],
		}

		android_library {
			name: "uses_libs_dep",
			uses_libs: ["uses_lib"],
			optional_uses_libs: ["optional_uses_lib"],
		}

		android_library_import {
			name: "uses_libs_dep_import",
			aars: ["aar.aar"],
			static_libs: ["uses_libs_dep"],
		}
	`

	testcases := []struct {
		name      string
		unbundled bool
	}{
		{
			name:      "non-unbundled build",
			unbundled: false,
		},
		{
			name:      "unbundled build",
			unbundled: true,
		},
	}

	for _, tc := range testcases {
		t.Run(tc.name, func(t *testing.T) {
			fixturePreparer := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd
			if tc.unbundled {
				fixturePreparer = android.GroupFixturePreparers(
					fixturePreparer,
					android.FixtureModifyProductVariables(
						func(variables android.FixtureProductVariables) {
							variables.Unbundled_build = proptools.BoolPtr(true)
						},
					),
				)
			}
			result := fixturePreparer.RunTestWithBp(t, bp)

			getHeaderJar := func(name string) android.Path {
				mod := result.ModuleForTests(name, "android_common")
				return mod.Output("turbine-combined/" + name + ".jar").Output
			}

			appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
			overrideAppR8 := result.ModuleForTests("app", "android_common_override_app").Rule("r8")
			appHeader := getHeaderJar("app")
			overrideAppHeader := result.ModuleForTests("app", "android_common_override_app").Output("turbine-combined/app.jar").Output
			libHeader := getHeaderJar("lib")
			transitiveLibHeader := getHeaderJar("transitive_lib")
			transitiveLib2Header := getHeaderJar("transitive_lib_2")
			staticLibHeader := getHeaderJar("static_lib")
			transitiveStaticLibHeader := getHeaderJar("transitive_static_lib")
			repeatedDepHeader := getHeaderJar("repeated_dep")
			usesLibHeader := getHeaderJar("uses_lib")
			optionalUsesLibHeader := getHeaderJar("optional_uses_lib")
			prebuiltLibHeader := result.ModuleForTests("prebuilt_lib", "android_common").Output("combined/lib.jar").Output

			for _, rule := range []android.TestingBuildParams{appR8, overrideAppR8} {
				android.AssertStringDoesNotContain(t, "expected no app header jar in app r8 classpath",
					rule.Args["r8Flags"], appHeader.String())
				android.AssertStringDoesNotContain(t, "expected no override_app header jar in app r8 classpath",
					rule.Args["r8Flags"], overrideAppHeader.String())
				android.AssertStringDoesContain(t, "expected transitive lib header jar in app r8 classpath",
					rule.Args["r8Flags"], transitiveLibHeader.String())
				android.AssertStringDoesContain(t, "expected transitive lib ^2 header jar in app r8 classpath",
					rule.Args["r8Flags"], transitiveLib2Header.String())
				android.AssertStringDoesContain(t, "expected lib header jar in app r8 classpath",
					rule.Args["r8Flags"], libHeader.String())
				android.AssertStringDoesContain(t, "expected uses_lib header jar in app r8 classpath",
					rule.Args["r8Flags"], usesLibHeader.String())
				android.AssertStringDoesContain(t, "expected optional_uses_lib header jar in app r8 classpath",
					rule.Args["r8Flags"], optionalUsesLibHeader.String())
				android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app r8 classpath",
					rule.Args["r8Flags"], staticLibHeader.String())
				android.AssertStringDoesNotContain(t, "expected no transitive static_lib header jar in app r8 classpath",
					rule.Args["r8Flags"], transitiveStaticLibHeader.String())
				// we shouldn't list this dep because it is already included as static_libs in the app
				android.AssertStringDoesNotContain(t, "expected no repeated_dep header jar in app r8 classpath",
					rule.Args["r8Flags"], repeatedDepHeader.String())
				// skip a prebuilt transitive dep if the source is also a transitive dep
				android.AssertStringDoesNotContain(t, "expected no prebuilt header jar in app r8 classpath",
					rule.Args["r8Flags"], prebuiltLibHeader.String())
				android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
					rule.Args["r8Flags"], "-ignorewarnings")
				android.AssertStringDoesContain(t, "expected --android-platform-build in app r8 flags",
					rule.Args["r8Flags"], "--android-platform-build")
			}
		})
	}
}

func TestR8Flags(t *testing.T) {
	result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
		android_app {
Loading