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

Commit 1267d875 authored by Paul Duffin's avatar Paul Duffin
Browse files

java_sdk_library: Make dex stub jars available for hiddenapi

The hidden API processing needs access to dex jars for the API stubs in
order to determine which dex members are part of an API surface. The
dex stubs used for the monolithic file are provided by normal
java_library modules for legacy reasons. However, the APEXes that
contribute to the bootclasspath, and so need to perform hidden API
processing, typically provide stubs created by a java_sdk_library.

This change adds support to java_sdk_library/_import to make the dex
stub jars available when requested, that involves:
1. Adding compile_dex property to java_sdk_library_import and
   propagating it down the the java_import modules for the stubs. That
   is already handled for java_sdk_library.
2. Propagating the java_sdk_library compile_dex property to the
   java_sdk_library_import in the generated snapshot.
3. Refactoring and wiring to make the dex stubs jar available to other
   parts of Soong.

Bug: 179354495
Test: m nothing
Change-Id: I5895d4f2ba0b684870862b9429b2364865e4afc6
parent e1381887
Loading
Loading
Loading
Loading
+52 −2
Original line number Diff line number Diff line
@@ -534,6 +534,11 @@ type scopePaths struct {
	// This is not the implementation jar, it still only contains stubs.
	stubsImplPath android.Paths

	// The dex jar for the stubs.
	//
	// This is not the implementation jar, it still only contains stubs.
	stubsDexJarPath android.Path

	// The API specification file, e.g. system_current.txt.
	currentApiFilePath android.OptionalPath

@@ -549,6 +554,9 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.Modul
		lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
		paths.stubsHeaderPath = lib.HeaderJars
		paths.stubsImplPath = lib.ImplementationJars

		libDep := dep.(UsesLibraryDependency)
		paths.stubsDexJarPath = libDep.DexJarBuildPath()
		return nil
	} else {
		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
@@ -825,8 +833,22 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.
		return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
	}

	paths := c.selectScopePaths(ctx, sdkVersion.Kind)
	if paths == nil {
		return nil
	}

	return paths.stubsHeaderPath
}

// selectScopePaths returns the *scopePaths appropriate for the specific kind.
//
// If the module does not support the specific kind then it will return the *scopePaths for the
// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
	var apiScope *apiScope
	switch sdkVersion.Kind {
	switch kind {
	case android.SdkSystem:
		apiScope = apiScopeSystem
	case android.SdkModule:
@@ -851,7 +873,17 @@ func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.
		return nil
	}

	return paths.stubsHeaderPath
	return paths
}

// to satisfy SdkLibraryDependency interface
func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path {
	paths := c.selectScopePaths(ctx, kind)
	if paths == nil {
		return nil
	}

	return paths.stubsDexJarPath
}

func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
@@ -944,6 +976,10 @@ type SdkLibraryDependency interface {
	// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
	// they are identical to the corresponding header jars.
	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths

	// SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
	// tool which processes dex files.
	SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path
}

type SdkLibrary struct {
@@ -1781,6 +1817,9 @@ type sdkLibraryImportProperties struct {
	// List of shared java libs, common to all scopes, that this module has
	// dependencies to
	Libs []string

	// If set to true, compile dex files for the stubs. Defaults to false.
	Compile_dex *bool
}

type SdkLibraryImport struct {
@@ -1916,6 +1955,7 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl
		Libs        []string
		Jars        []string
		Prefer      *bool
		Compile_dex *bool
	}{}
	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
	props.Sdk_version = scopeProperties.Sdk_version
@@ -1927,6 +1967,9 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl
	// The imports are preferred if the java_sdk_library_import is preferred.
	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())

	// The imports need to be compiled to dex if the java_sdk_library_import requests it.
	props.Compile_dex = module.properties.Compile_dex

	mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}

@@ -2348,6 +2391,9 @@ type sdkLibrarySdkMemberProperties struct {
	// otherwise.
	Shared_library *bool

	// True if the stub imports should produce dex jars.
	Compile_dex *bool

	// The paths to the doctag files to add to the prebuilt.
	Doctag_paths android.Paths
}
@@ -2389,6 +2435,7 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe
	s.Libs = sdk.properties.Libs
	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
	s.Compile_dex = sdk.dexProperties.Compile_dex
	s.Doctag_paths = sdk.doctagPaths
}

@@ -2399,6 +2446,9 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo
	if s.Shared_library != nil {
		propertySet.AddProperty("shared_library", *s.Shared_library)
	}
	if s.Compile_dex != nil {
		propertySet.AddProperty("compile_dex", *s.Compile_dex)
	}

	for _, apiScope := range allApiScopes {
		if properties, ok := s.Scopes[apiScope]; ok {
+74 −0
Original line number Diff line number Diff line
@@ -1089,6 +1089,80 @@ sdk_snapshot {
	)
}

func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) {
	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
		sdk {
			name: "mysdk",
			java_sdk_libs: ["myjavalib"],
		}

		java_sdk_library {
			name: "myjavalib",
			srcs: ["Test.java"],
			sdk_version: "current",
			shared_library: false,
			compile_dex: true,
			public: {
				enabled: true,
			},
			system: {
				enabled: true,
			},
		}
	`)

	CheckSnapshot(t, result, "mysdk", "",
		checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.

java_sdk_library_import {
    name: "myjavalib",
    prefer: false,
    visibility: ["//visibility:public"],
    apex_available: ["//apex_available:platform"],
    shared_library: false,
    compile_dex: true,
    public: {
        jars: ["sdk_library/public/myjavalib-stubs.jar"],
        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
        current_api: "sdk_library/public/myjavalib.txt",
        removed_api: "sdk_library/public/myjavalib-removed.txt",
        sdk_version: "current",
    },
    system: {
        jars: ["sdk_library/system/myjavalib-stubs.jar"],
        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
        current_api: "sdk_library/system/myjavalib.txt",
        removed_api: "sdk_library/system/myjavalib-removed.txt",
        sdk_version: "system_current",
    },
}
`),
		snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
			ctx := android.ModuleInstallPathContextForTesting(result.Config)
			dexJarBuildPath := func(name string, kind android.SdkKind) string {
				dep := result.Module(name, "android_common").(java.SdkLibraryDependency)
				path := dep.SdkApiStubDexJar(ctx, kind)
				return path.RelativeToTop().String()
			}

			dexJarPath := dexJarBuildPath("myjavalib", android.SdkPublic)
			android.AssertStringEquals(t, "source dex public stubs jar build path", "out/soong/.intermediates/myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)

			dexJarPath = dexJarBuildPath("myjavalib", android.SdkSystem)
			systemDexJar := "out/soong/.intermediates/myjavalib.stubs.system/android_common/dex/myjavalib.stubs.system.jar"
			android.AssertStringEquals(t, "source dex system stubs jar build path", systemDexJar, dexJarPath)

			// This should fall back to system as module is not available.
			dexJarPath = dexJarBuildPath("myjavalib", android.SdkModule)
			android.AssertStringEquals(t, "source dex module stubs jar build path", systemDexJar, dexJarPath)

			dexJarPath = dexJarBuildPath(android.PrebuiltNameFromSource("myjavalib"), android.SdkPublic)
			android.AssertStringEquals(t, "prebuilt dex public stubs jar build path", "out/soong/.intermediates/snapshot/prebuilt_myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)
		}),
	)
}

func TestSnapshotWithJavaSdkLibrary_SdkVersion_None(t *testing.T) {
	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
		sdk {