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

Commit 1aa50564 authored by Paul Duffin's avatar Paul Duffin
Browse files

Treat <x> and <x>_compressed prebuilt APEXes as being equivalent

When extracting dex files from prebuilt APEXes the build fails if it
finds two or more prebuilt APEXes that could provide the dex files.
This change treats <x> and <x>_compressed APEXes as being the same
and always selects the uncompressed APEX.

Bug: 235284603
Test: m nothing
      # Added TestDuplicateButEquivalentDeapexersFromPrebuiltApexes
      # Failed without this change, works with it.
Change-Id: I805cb9dfa9f590c91585d75c4f4586b212b73d41
parent b706b4ef
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 {