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

Commit 8fe1982e authored by Jihoon Kang's avatar Jihoon Kang
Browse files

Sort api files by api surface in java_api_library

metalava requires api files to be sorted in the narrower api scope to
the wider api scope when passed as inputs. Previously, the api files
were sorted based on the naming convention, but some api files in
prebuilts do not necessarily follow the naming convention (i.e.
*-current.txt). Therefore, utilize the api surface information provided
by the java_api_contribution provider instead of the naming convention
to sort the api files.

Test: m nothing
Bug: 300175323
Change-Id: I8466db712bff8fef906186bd272d85682877533d
parent fdf32369
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -1625,6 +1625,7 @@ func ApiContributionFactory() android.Module {

type JavaApiImportInfo struct {
	ApiFile    android.Path
	ApiSurface string
}

var JavaApiImportProvider = blueprint.NewProvider(JavaApiImportInfo{})
@@ -1637,6 +1638,7 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon

	ctx.SetProvider(JavaApiImportProvider, JavaApiImportInfo{
		ApiFile:    apiFile,
		ApiSurface: proptools.String(ap.properties.Api_surface),
	})
}

@@ -1821,18 +1823,29 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
var scopeOrderedSourceFileNames = allApiScopes.Strings(
	func(s *apiScope) string { return s.apiFilePrefix + "current.txt" })

func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths {
	sortedSrcFiles := android.Paths{}
func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo, apiFiles android.Paths) android.Paths {
	var sortedSrcFiles android.Paths

	for _, scopeSourceFileName := range scopeOrderedSourceFileNames {
		for _, sourceFileName := range srcFiles {
			if sourceFileName.Base() == scopeSourceFileName {
				sortedSrcFiles = append(sortedSrcFiles, sourceFileName)
	for i, apiScope := range allApiScopes {
		for _, srcFileInfo := range srcFilesInfo {
			if srcFileInfo.ApiFile.Base() == scopeOrderedSourceFileNames[i] || srcFileInfo.ApiSurface == apiScope.name {
				sortedSrcFiles = append(sortedSrcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
			}
		}
		// TODO: b/300964421 - Remove when api_files property is removed
		for _, apiFileName := range apiFiles {
			if apiFileName.Base() == scopeOrderedSourceFileNames[i] {
				sortedSrcFiles = append(sortedSrcFiles, apiFileName)
			}
	if len(srcFiles) != len(sortedSrcFiles) {
		ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles)
		}
	}

	if len(srcFilesInfo)+len(apiFiles) != len(sortedSrcFiles) {
		var srcFiles android.Paths
		for _, srcFileInfo := range srcFilesInfo {
			srcFiles = append(srcFiles, srcFileInfo.ApiFile)
		}
		ctx.ModuleErrorf("Unrecognizable source file found within %s", append(srcFiles, apiFiles...))
	}

	return sortedSrcFiles
@@ -1853,7 +1866,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {

	homeDir := android.PathForModuleOut(ctx, "metalava", "home")

	var srcFiles android.Paths
	var srcFilesInfo []JavaApiImportInfo
	var classPaths android.Paths
	var staticLibs android.Paths
	var depApiSrcsStubsJar android.Path
@@ -1862,11 +1875,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		switch tag {
		case javaApiContributionTag:
			provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
			providerApiFile := provider.ApiFile
			if providerApiFile == nil && !ctx.Config().AllowMissingDependencies() {
			if provider.ApiFile == nil && !ctx.Config().AllowMissingDependencies() {
				ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name())
			}
			srcFiles = append(srcFiles, android.PathForSource(ctx, providerApiFile.String()))
			srcFilesInfo = append(srcFilesInfo, provider)
		case libTag:
			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
			classPaths = append(classPaths, provider.HeaderJars...)
@@ -1880,16 +1892,19 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	})

	// Add the api_files inputs
	// These are api files in the module subdirectory, which are not provided by
	// java_api_contribution but provided directly as module property.
	var apiFiles android.Paths
	for _, api := range al.properties.Api_files {
		srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, api))
		apiFiles = append(apiFiles, android.PathForModuleSrc(ctx, api))
	}

	srcFiles := al.sortApiFilesByApiScope(ctx, srcFilesInfo, apiFiles)

	if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
	}

	srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles)

	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)

	al.stubsFlags(ctx, cmd, stubsDir)
+20 −4
Original line number Diff line number Diff line
@@ -1865,11 +1865,13 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	ctx, _ := testJavaWithFS(t, `
@@ -1919,24 +1921,28 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `
	java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_c := `
	java_api_contribution {
		name: "foo3",
		api_file: "current.txt",
		api_file: "system-current.txt",
		api_surface: "system",
	}
	`
	provider_bp_d := `
	java_api_contribution {
		name: "foo4",
		api_file: "current.txt",
		api_file: "system-current.txt",
		api_surface: "system",
	}
	`
	ctx, _ := testJavaWithFS(t, `
@@ -1993,7 +1999,8 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
		},
		{
			moduleName: "bar3",
			sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"},
			// API text files need to be sorted from the narrower api scope to the wider api scope
			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt", "c/system-current.txt", "d/system-current.txt"},
		},
	}
	for _, c := range testcases {
@@ -2011,12 +2018,14 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `
	java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	ctx, _ := testJavaWithFS(t, `
@@ -2064,12 +2073,14 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `
	java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	lib_bp_a := `
@@ -2139,12 +2150,14 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `
	java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	lib_bp_a := `
@@ -2213,12 +2226,14 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
	java_api_contribution {
		name: "foo1",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	provider_bp_b := `
	java_api_contribution {
		name: "foo2",
		api_file: "current.txt",
		api_surface: "public",
	}
	`
	lib_bp_a := `
@@ -2398,6 +2413,7 @@ func TestJavaApiContributionImport(t *testing.T) {
		java_api_contribution_import {
			name: "bar",
			api_file: "current.txt",
			api_surface: "public",
		}
	`)
	m := ctx.ModuleForTests("foo", "android_common")