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

Commit 2069c3f7 authored by Spandan Das's avatar Spandan Das
Browse files

Move dexpreopt processing from java_*_import to prebuilt_apex

dexpreopt of apex system server from prebuilts involves three soong
modules
1. prebuilt_apex / apex_set
2. an internal deapexer module created by the prebuilt apex
3. java_import/java_sdk_library

(3) acts as a shim for the deapexer to set the dexjar extracted from the
prebuilt apex. This methodolody requires a 1:1 correspondence across the
three modules

This breaks down when we have multiple versions of the same prebuilt
apex in the tree. In preparation for this, move the dexpreopt
processing from (3) to (1). Each prebuilt_apex will create the necessary
rules for dexpreopting the jars deapexed from itself. In the future,
apex_contributions will be used to pick which service-foo.{odex|.vdex} to
install depending on which prebuilt apex is selected.

Implementation details
- Embed dexpreopter in prebuiltApex structs so that this module type can
  register the dexpreopt rules. Since a single apex can have multiple
  system server jars, this also requires creating an additional scope in
  dexpreopt.go to prevent name collisions
- Add the dexpreopt modules as required in initApexFilesForAndroidMk
- Add the depreopt modules to androidMk in AndroidMkEntries. Drop the
  equivalent from java_import and java_sdk_library_import

Bug: 308790457
Test: existing soong unit tests
Test: lunch cf_x86_64_phone-next-userdebug && m out/target/product/vsoc_x86_64/system/apex/com.google.android.adservices.apex
Test: Verified that the above command installs
/out/target/product/vsoc_x86_64/system/framework/oat/x86_64/apex@com.android.adservices@javalib@service-adservices.jar@classes.{odex|vdex} and the equivalent files of service-sdksandbox

Test: presubmits

Change-Id: I01cea8956d2857fb864b415e73d3d2686d069b5e
parent 51428c45
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3725,7 +3725,7 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var
}

func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
	deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer")
	deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
	outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
	if deapexer.Output != nil {
		outputs = append(outputs, deapexer.Output.String())
+2 −0
Original line number Diff line number Diff line
@@ -530,6 +530,8 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {

		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
			`com.android.art.apex.selector`,
			`com.android.art.deapexer`,
			`dex2oatd`,
			`prebuilt_art-bootclasspath-fragment`,
		})

+51 −41
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import (
	"strings"

	"android/soong/android"
	"android/soong/dexpreopt"
	"android/soong/java"
	"android/soong/provenance"

@@ -50,6 +51,7 @@ type prebuilt interface {

type prebuiltCommon struct {
	android.ModuleBase
	java.Dexpreopter
	prebuilt android.Prebuilt

	// Properties common to both prebuilt_apex and apex_set.
@@ -170,50 +172,39 @@ func (p *prebuiltCommon) installable() bool {
	return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
}

// initApexFilesForAndroidMk initializes the prebuiltCommon.apexFilesForAndroidMk field from the
// modules that this depends upon.
func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
	// Walk the dependencies of this module looking for the java modules that it exports.
	ctx.WalkDeps(func(child, parent android.Module) bool {
		tag := ctx.OtherModuleDependencyTag(child)
// To satisfy java.DexpreopterInterface
func (p *prebuiltCommon) IsInstallable() bool {
	return p.installable()
}

		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
		if java.IsBootclasspathFragmentContentDepTag(tag) ||
			java.IsSystemServerClasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
			// If the exported java module provides a dex jar path then add it to the list of apexFiles.
			path := child.(interface {
				DexJarBuildPath() java.OptionalDexJarPath
			}).DexJarBuildPath()
			if path.IsSet() {
				af := apexFile{
					module:              child,
					moduleDir:           ctx.OtherModuleDir(child),
					androidMkModuleName: name,
					builtFile:           path.Path(),
					class:               javaSharedLib,
				}
				if module, ok := child.(java.DexpreopterInterface); ok {
					for _, install := range module.DexpreoptBuiltInstalledForApex() {
						af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
					}
				}
				p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af)
			}
		} else if tag == exportedBootclasspathFragmentTag {
			_, ok := child.(*java.PrebuiltBootclasspathFragmentModule)
			if !ok {
				ctx.PropertyErrorf("exported_bootclasspath_fragments", "%q is not a prebuilt_bootclasspath_fragment module", name)
				return false
// initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex
func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
	// If this apex contains a system server jar, then the dexpreopt artifacts should be added as required
	for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
		p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName())
	}
			// Visit the children of the bootclasspath_fragment.
			return true
		} else if tag == exportedSystemserverclasspathFragmentTag {
			// Visit the children of the systemserver_fragment.
			return true
}

		return false
	})
// If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex
func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
	// If this apex does not export anything, return
	if !p.hasExportedDeps() {
		return
	}
	// Use apex_name to determine the api domain of this prebuilt apex
	apexName := p.ApexVariationName()
	di := android.FindDeapexerProviderForModule(ctx)
	dc := dexpreopt.GetGlobalConfig(ctx)
	systemServerJarList := dc.AllApexSystemServerJars(ctx)

	for i := 0; i < systemServerJarList.Len(); i++ {
		sscpApex := systemServerJarList.Apex(i)
		sscpJar := systemServerJarList.Jar(i)
		if apexName != sscpApex {
			continue
		}
		p.Dexpreopter.DexpreoptPrebuiltApexSystemServerJars(ctx, sscpJar, di)
	}
}

func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
@@ -248,6 +239,11 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
		},
	}

	// Add the dexpreopt artifacts to androidmk
	for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
		entriesList = append(entriesList, install.ToMakeEntries())
	}

	// Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each
	// file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the
	// apex specific variants of the exported java modules available for use from within make.
@@ -756,6 +752,14 @@ func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
	p.prebuiltApexContentsDeps(ctx)
}

func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
	if p.hasExportedDeps() {
		// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
		// The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
		ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.BaseModuleName()))
	}
}

var _ ApexInfoMutator = (*Prebuilt)(nil)

func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
@@ -783,6 +787,9 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		return
	}

	// dexpreopt any system server jars if present
	p.dexpreoptSystemServerJars(ctx)

	// Save the files that need to be made available to Make.
	p.initApexFilesForAndroidMk(ctx)

@@ -999,6 +1006,9 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		return
	}

	// dexpreopt any system server jars if present
	a.dexpreoptSystemServerJars(ctx)

	// Save the files that need to be made available to Make.
	a.initApexFilesForAndroidMk(ctx)

+2 −0
Original line number Diff line number Diff line
@@ -272,7 +272,9 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
	ctx := result.TestContext

	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
		`dex2oatd`,
		`myapex.apex.selector`,
		`myapex.deapexer`,
		`prebuilt_mysystemserverclasspathfragment`,
	})

+1 −5
Original line number Diff line number Diff line
@@ -207,11 +207,7 @@ func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries {

func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
	if prebuilt.hideApexVariantFromMake {
		// For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
		// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
		// is preopted.
		dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
		return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
		return []android.AndroidMkEntries{}
	}
	return []android.AndroidMkEntries{android.AndroidMkEntries{
		Class:      "JAVA_LIBRARIES",
Loading