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

Commit 5be63336 authored by Spandan Das's avatar Spandan Das
Browse files

Use the correct bootjars when multiple prebuilt apexes exist

hiddenapi and dexpreopt require boot and system server jars from apexes.
When building with prebuilts, this comes via
java_import/java_sdk_library_import, which acts as a hook for
prebuilt_apex/apex_set. If we have multiple apexes in the tree, this
hook becomes 1:many. This CL prepares dex_bootjars to select the right
deapexerd .jar files when mutliple prebuilts exist.

Implementation details
- Update prebuilt module types (prebuilt_apex/apex_set) and source
  apexes to set a map of
  library name to dex jar path on host.
- dex_bootjars will access the path of the .dex jar on host via the
  provider. These then
  copied/installed to the right locations.

This CL does not drop the old mechanism to get the dex file (i.e. by
creating a dep on java_library). Once all mainline
modules have been flagged using apex_contributions, the old mechanism
will be dropped

Bug: 308790457
Test: git_master-art-host:art-gtest https://android-build.corp.google.com/builds/abtd/run/L21500030000926533
Test: git_main:art_standalone_dexpreopt_tests https://android-build.corp.google.com/builds/abtd/run/L99000030000891212
Test: Added a unit test that checks that the right .jar is selected
when multiple prebuilts exists

Change-Id: I6ef94135b9303a35135810930af4b641df13a583
parent a4cca85e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -965,4 +965,7 @@ type ApexExportsInfo struct {

	// Path to the image profile file on host (or empty, if profile is not generated).
	ProfilePathOnHost Path

	// Map from the apex library name (without prebuilt_ prefix) to the dex file path on host
	LibraryNameToDexJarPathOnHost map[string]Path
}
+12 −3
Original line number Diff line number Diff line
@@ -79,6 +79,10 @@ type DeapexerInfo struct {
	//
	// See Prebuilt.ApexInfoMutator for more information.
	exports map[string]WritablePath

	// name of the java libraries exported from the apex
	// e.g. core-libart
	exportedModuleNames []string
}

// ApexModuleName returns the name of the APEX module that provided the info.
@@ -97,6 +101,10 @@ func (i DeapexerInfo) PrebuiltExportPath(apexRelativePath string) WritablePath {
	return path
}

func (i DeapexerInfo) GetExportedModuleNames() []string {
	return i.exportedModuleNames
}

// Provider that can be used from within the `GenerateAndroidBuildActions` of a module that depends
// on a `deapexer` module to retrieve its `DeapexerInfo`.
var DeapexerProvider = blueprint.NewProvider[DeapexerInfo]()
@@ -105,10 +113,11 @@ var DeapexerProvider = blueprint.NewProvider[DeapexerInfo]()
// for use with a prebuilt_apex module.
//
// See apex/deapexer.go for more information.
func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath) DeapexerInfo {
func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath, moduleNames []string) DeapexerInfo {
	return DeapexerInfo{
		apexModuleName:      apexModuleName,
		exports:             exports,
		exportedModuleNames: moduleNames,
	}
}

+3 −2
Original line number Diff line number Diff line
@@ -2384,6 +2384,7 @@ func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) {
			exports := android.ApexExportsInfo{
				ApexName:                      a.ApexVariationName(),
				ProfilePathOnHost:             info.ProfilePathOnHost(),
				LibraryNameToDexJarPathOnHost: info.DexBootJarPathMap(),
			}
			ctx.SetProvider(android.ApexExportsInfoProvider, exports)
		}
+175 −11
Original line number Diff line number Diff line
@@ -8408,30 +8408,32 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F
func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
	preparers := android.GroupFixturePreparers(
		java.PrepareForTestWithJavaDefaultModules,
		prepareForTestWithBootclasspathFragment,
		dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"),
		PrepareForTestWithApexBuildComponents,
	).
		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
			"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex"))
			"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art"))

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

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

		prebuilt_bootclasspath_fragment {
			name: "my-bootclasspath-fragment",
			apex_available: ["com.android.myapex"],
			name: "art-bootclasspath-fragment",
			apex_available: ["com.android.art"],
			hidden_api: {
				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
				metadata: "my-bootclasspath-fragment/metadata.csv",
@@ -8448,7 +8450,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
			java_import {
				name: "libfoo",
				jars: ["libfoo.jar"],
				apex_available: ["com.android.myapex"],
				apex_available: ["com.android.art"],
			}
		`)
	})
@@ -8461,7 +8463,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
					jars: ["libbar.jar"],
				},
				shared_library: false,
				apex_available: ["com.android.myapex"],
				apex_available: ["com.android.art"],
			}
		`)
	})
@@ -8477,7 +8479,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
					jars: ["libbar.jar"],
				},
				shared_library: false,
				apex_available: ["com.android.myapex"],
				apex_available: ["com.android.art"],
			}
		`)
	})
@@ -11413,3 +11415,165 @@ func TestAconfigFilesRemoveDuplicates(t *testing.T) {
	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
}

// Test that the boot jars come from the _selected_ apex prebuilt
// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
		t.Helper()
		s := ctx.ModuleForTests("dex_bootjars", "android_common")
		foundLibfooJar := false
		base := stem + ".jar"
		for _, output := range s.AllOutputs() {
			if filepath.Base(output) == base {
				foundLibfooJar = true
				buildRule := s.Output(output)
				android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String())
			}
		}
		if !foundLibfooJar {
			t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
		}
	}

	bp := `
		// Source APEX.

		java_library {
			name: "framework-foo",
			srcs: ["foo.java"],
			installable: true,
			apex_available: [
				"com.android.foo",
			],
		}

		bootclasspath_fragment {
			name: "foo-bootclasspath-fragment",
			contents: ["framework-foo"],
			apex_available: [
				"com.android.foo",
			],
			hidden_api: {
				split_packages: ["*"],
			},
		}

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

		apex {
			name: "com.android.foo",
			key: "com.android.foo.key",
			bootclasspath_fragments: ["foo-bootclasspath-fragment"],
			updatable: false,
		}

		// Prebuilt APEX.

		java_sdk_library_import {
			name: "framework-foo",
			public: {
				jars: ["foo.jar"],
			},
			apex_available: ["com.android.foo"],
			shared_library: false,
		}

		prebuilt_bootclasspath_fragment {
			name: "foo-bootclasspath-fragment",
			contents: ["framework-foo"],
			hidden_api: {
				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
				metadata: "my-bootclasspath-fragment/metadata.csv",
				index: "my-bootclasspath-fragment/index.csv",
				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
				all_flags: "my-bootclasspath-fragment/all-flags.csv",
			},
			apex_available: [
				"com.android.foo",
			],
		}

		prebuilt_apex {
			name: "com.android.foo",
			apex_name: "com.android.foo",
			src: "com.android.foo-arm.apex",
			exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
		}

		// Another Prebuilt ART APEX
		prebuilt_apex {
			name: "com.android.foo.v2",
			apex_name: "com.android.foo", // Used to determine the API domain
			src: "com.android.foo-arm.apex",
			exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
		}

		// APEX contribution modules

		apex_contributions {
			name: "foo.source.contributions",
			api_domain: "com.android.foo",
			contents: ["com.android.foo"],
		}

		apex_contributions {
			name: "foo.prebuilt.contributions",
			api_domain: "com.android.foo",
			contents: ["prebuilt_com.android.foo"],
		}

		apex_contributions {
			name: "foo.prebuilt.v2.contributions",
			api_domain: "com.android.foo",
			contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
		}
	`

	testCases := []struct {
		desc                      string
		selectedApexContributions string
		expectedBootJar           string
	}{
		{
			desc:                      "Source apex com.android.foo is selected, bootjar should come from source java library",
			selectedApexContributions: "foo.source.contributions",
			expectedBootJar:           "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar",
		},
		{
			desc:                      "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
			selectedApexContributions: "foo.prebuilt.contributions",
			expectedBootJar:           "out/soong/.intermediates/com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
		},
		{
			desc:                      "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
			selectedApexContributions: "foo.prebuilt.v2.contributions",
			expectedBootJar:           "out/soong/.intermediates/com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
		},
	}

	fragment := java.ApexVariantReference{
		Apex:   proptools.StringPtr("com.android.foo"),
		Module: proptools.StringPtr("foo-bootclasspath-fragment"),
	}

	for _, tc := range testCases {
		preparer := android.GroupFixturePreparers(
			java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"),
			android.FixtureMergeMockFs(map[string][]byte{
				"system/sepolicy/apex/com.android.foo-file_contexts": nil,
			}),
			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
				variables.BuildFlags = map[string]string{
					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
				}
			}),
		)
		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
		checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar)
	}
}
+2 −1
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ func privateDeapexerFactory() android.Module {
func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
	// this module so that they can access the `DeapexerInfo` object that this provides.
	// TODO: b/308174306 - Once all the mainline modules have been flagged, drop this dependency edge
	for _, lib := range p.properties.CommonModules {
		dep := prebuiltApexExportedModuleName(ctx, lib)
		ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
@@ -126,7 +127,7 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	// apex relative path to extracted file path available for other modules.
	if len(exports) > 0 {
		// Make the information available for other modules.
		di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports)
		di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports, p.properties.CommonModules)
		android.SetProvider(ctx, android.DeapexerProvider, di)

		// Create a sorted list of the files that this exports.
Loading