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

Commit 60c0b9ec authored by Paul Duffin's avatar Paul Duffin Committed by Android (Google) Code Review
Browse files

Merge "Treat <x> and <x>_compressed prebuilt APEXes as being equivalent" into tm-dev

parents d23c863f 1aa50564
Loading
Loading
Loading
Loading
+41 −2
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
package android

import (
	"strings"

	"github.com/google/blueprint"
)

@@ -148,12 +150,19 @@ type RequiresFilesFromPrebuiltApexTag interface {
func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
	var di *DeapexerInfo
	ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
		p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
		c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
		p := &c
		if di != nil {
			// If two DeapexerInfo providers have been found then check if they are
			// equivalent. If they are then use the selected one, otherwise fail.
			if selected := equivalentDeapexerInfoProviders(di, p); selected != nil {
				di = selected
				return
			}
			ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
				di.ApexModuleName(), p.ApexModuleName())
		}
		di = &p
		di = p
	})
	if di != nil {
		return di
@@ -162,3 +171,33 @@ func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
	ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
	return nil
}

// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
func removeCompressedApexSuffix(name string) string {
	return strings.TrimSuffix(name, "_compressed")
}

// equivalentDeapexerInfoProviders checks to make sure that the two DeapexerInfo structures are
// equivalent.
//
// At the moment <x> and <x>_compressed APEXes are treated as being equivalent.
//
// If they are not equivalent then this returns nil, otherwise, this returns the DeapexerInfo that
// should be used by the build, which is always the uncompressed one. That ensures that the behavior
// of the build is not dependent on which prebuilt APEX is visited first.
func equivalentDeapexerInfoProviders(p1 *DeapexerInfo, p2 *DeapexerInfo) *DeapexerInfo {
	n1 := removeCompressedApexSuffix(p1.ApexModuleName())
	n2 := removeCompressedApexSuffix(p2.ApexModuleName())

	// If the names don't match then they are not equivalent.
	if n1 != n2 {
		return nil
	}

	// Select the uncompressed APEX.
	if n1 == removeCompressedApexSuffix(n1) {
		return p1
	} else {
		return p2
	}
}
+102 −1
Original line number Diff line number Diff line
@@ -7428,7 +7428,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F
	return result.TestContext
}

func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) {
func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
	preparers := android.GroupFixturePreparers(
		java.PrepareForTestWithJavaDefaultModules,
		PrepareForTestWithApexBuildComponents,
@@ -7497,6 +7497,107 @@ func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) {
	})
}

func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
	preparers := android.GroupFixturePreparers(
		java.PrepareForTestWithJavaDefaultModules,
		PrepareForTestWithApexBuildComponents,
	)

	bpBase := `
		apex_set {
			name: "com.android.myapex",
			installable: true,
			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
			set: "myapex.apks",
		}

		apex_set {
			name: "com.android.myapex_compressed",
			apex_name: "com.android.myapex",
			installable: true,
			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
			set: "myapex_compressed.apks",
		}

		prebuilt_bootclasspath_fragment {
			name: "my-bootclasspath-fragment",
			apex_available: [
				"com.android.myapex",
				"com.android.myapex_compressed",
			],
			hidden_api: {
				annotation_flags: "annotation-flags.csv",
				metadata: "metadata.csv",
				index: "index.csv",
				signature_patterns: "signature_patterns.csv",
			},
			%s
		}
	`

	t.Run("java_import", func(t *testing.T) {
		result := preparers.RunTestWithBp(t,
			fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
			java_import {
				name: "libfoo",
				jars: ["libfoo.jar"],
				apex_available: [
					"com.android.myapex",
					"com.android.myapex_compressed",
				],
			}
		`)

		module := result.Module("libfoo", "android_common_com.android.myapex")
		usesLibraryDep := module.(java.UsesLibraryDependency)
		android.AssertPathRelativeToTopEquals(t, "dex jar path",
			"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
			usesLibraryDep.DexJarBuildPath().Path())
	})

	t.Run("java_sdk_library_import", func(t *testing.T) {
		result := preparers.RunTestWithBp(t,
			fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
			java_sdk_library_import {
				name: "libfoo",
				public: {
					jars: ["libbar.jar"],
				},
				apex_available: [
					"com.android.myapex",
					"com.android.myapex_compressed",
				],
				compile_dex: true,
			}
		`)

		module := result.Module("libfoo", "android_common_com.android.myapex")
		usesLibraryDep := module.(java.UsesLibraryDependency)
		android.AssertPathRelativeToTopEquals(t, "dex jar path",
			"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
			usesLibraryDep.DexJarBuildPath().Path())
	})

	t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
		_ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
			image_name: "art",
			contents: ["libfoo"],
		`)+`
			java_sdk_library_import {
				name: "libfoo",
				public: {
					jars: ["libbar.jar"],
				},
				apex_available: [
					"com.android.myapex",
					"com.android.myapex_compressed",
				],
				compile_dex: true,
			}
		`)
	})
}

func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
	testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
		apex {