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

Commit 0727ba76 authored by Spandan Das's avatar Spandan Das
Browse files

Disable dexpreopt if optional_uses_libs does not have an impl

At ToT, an optional_uses_libs is not added to the build time CLC if it
does not exist in the tree. One edge case here is
java_sdk_library_import, which might exist in the tree, but without an
implementation. This cause issues during analysis when we try to verify
the correctness of the build time CLC.

This CL disables dexpreopt if a dependency does not have an
implementation. To limit inadvertent side effects, this is restricted to
java_sdk_library(_import) module types. (more precisely, it is restricted
to java_sdk_library_import, since the source module type will always
have an impl)

Bug: 315802285
Test: Added a unit test
Test: m nothing
Test: printf debugging in internal main, verified that this CL does not
disable dexpreopt on any android app inadvertently

Change-Id: I173fc2f3ff654fe4091e9a43322164afd3222ee7
parent 1c9213d8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -808,6 +808,9 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	a.aapt.isLibrary = true
	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
	if a.usesLibrary.shouldDisableDexpreopt {
		a.dexpreopter.disableDexpreopt()
	}
	a.aapt.buildActions(ctx,
		aaptBuildActionOptions{
			sdkContext:                     android.SdkContext(a),
+15 −0
Original line number Diff line number Diff line
@@ -777,6 +777,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
	a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir)

	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
	if a.usesLibrary.shouldDisableDexpreopt {
		a.dexpreopter.disableDexpreopt()
	}

	var noticeAssetPath android.WritablePath
	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
@@ -1547,6 +1550,9 @@ type usesLibrary struct {

	// Whether to enforce verify_uses_library check.
	enforce bool

	// Whether dexpreopt should be disabled
	shouldDisableDexpreopt bool
}

func (u *usesLibrary) addLib(lib string, optional bool) {
@@ -1628,6 +1634,15 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext
			}
		}

		// Skip java_sdk_library dependencies that provide stubs, but not an implementation.
		// This will be restricted to optional_uses_libs
		if sdklib, ok := m.(SdkLibraryDependency); ok {
			if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil {
				u.shouldDisableDexpreopt = true
				return
			}
		}

		if lib, ok := m.(UsesLibraryDependency); ok {
			libName := dep
			if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
+3 −0
Original line number Diff line number Diff line
@@ -319,6 +319,9 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext

	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
	if a.usesLibrary.shouldDisableDexpreopt {
		a.dexpreopter.disableDexpreopt()
	}

	if a.usesLibrary.enforceUsesLibraries() {
		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+23 −0
Original line number Diff line number Diff line
@@ -4378,3 +4378,26 @@ func TestAppFlagsPackages(t *testing.T) {
		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
	)
}

// Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation.
func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) {
	bp := `
		java_sdk_library_import {
			name: "sdklib_noimpl",
			public: {
				jars: ["stub.jar"],
			},
		}
		android_app {
			name: "app",
			srcs: ["a.java"],
			sdk_version: "current",
			optional_uses_libs: [
				"sdklib_noimpl",
			],
		}
	`
	result := prepareForJavaTest.RunTestWithBp(t, bp)
	dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule
	android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil)
}
+13 −0
Original line number Diff line number Diff line
@@ -102,6 +102,11 @@ type dexpreopter struct {
	dexpreoptProperties       DexpreoptProperties
	importDexpreoptProperties ImportDexpreoptProperties

	// If true, the dexpreopt rules will not be generated
	// Unlike Dex_preopt.Enabled which is user-facing,
	// shouldDisableDexpreopt is a mutated propery.
	shouldDisableDexpreopt bool

	installPath         android.InstallPath
	uncompressedDex     bool
	isSDKLibrary        bool
@@ -197,6 +202,10 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName s
		return true
	}

	if d.shouldDisableDexpreopt {
		return true
	}

	// If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
	// dexpreopted.
	if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
@@ -528,3 +537,7 @@ func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
	return d.outputProfilePathOnHost
}

func (d *dexpreopter) disableDexpreopt() {
	d.shouldDisableDexpreopt = true
}
Loading