From fdf323697eeb6f10577120afb7af69e166b33642 Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Tue, 12 Sep 2023 00:36:43 +0000 Subject: [PATCH 1/2] Add java_api_contribution_import module type java_api_contribution_import is a prebuilt module type of java_api_contribution. It's build actions are identical to those of java_api_contribution. Test: m nothing Bug: 300174357 Change-Id: I831806990b37b340af21858eb2bab5de62fdf7a9 --- java/java.go | 28 ++++++++++++++++++++++++++++ java/java_test.go | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/java/java.go b/java/java.go index 99bb1b3ee..1ee2f5df4 100644 --- a/java/java.go +++ b/java/java.go @@ -64,6 +64,7 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("dex_import", DexImportFactory) ctx.RegisterModuleType("java_api_library", ApiLibraryFactory) ctx.RegisterModuleType("java_api_contribution", ApiContributionFactory) + ctx.RegisterModuleType("java_api_contribution_import", ApiContributionImportFactory) // This mutator registers dependencies on dex2oat for modules that should be // dexpreopted. This is done late when the final variants have been @@ -3421,3 +3422,30 @@ func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) { func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { return true } + +type JavaApiContributionImport struct { + JavaApiContribution + + prebuilt android.Prebuilt +} + +func ApiContributionImportFactory() android.Module { + module := &JavaApiContributionImport{} + android.InitAndroidModule(module) + android.InitDefaultableModule(module) + android.InitPrebuiltModule(module, &[]string{""}) + module.AddProperties(&module.properties) + return module +} + +func (module *JavaApiContributionImport) Prebuilt() *android.Prebuilt { + return &module.prebuilt +} + +func (module *JavaApiContributionImport) Name() string { + return module.prebuilt.Name(module.ModuleBase.Name()) +} + +func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { + ap.JavaApiContribution.GenerateAndroidBuildActions(ctx) +} diff --git a/java/java_test.go b/java/java_test.go index 27933c3bf..8d602b70a 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2388,3 +2388,22 @@ func TestHeadersOnly(t *testing.T) { javac := ctx.ModuleForTests("foo", "android_common").MaybeRule("javac") android.AssertDeepEquals(t, "javac rule", nil, javac.Rule) } + +func TestJavaApiContributionImport(t *testing.T) { + ctx, _ := testJava(t, ` + java_api_library { + name: "foo", + api_contributions: ["bar"], + } + java_api_contribution_import { + name: "bar", + api_file: "current.txt", + } + `) + m := ctx.ModuleForTests("foo", "android_common") + manifest := m.Output("metalava.sbox.textproto") + sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest) + manifestCommand := sboxProto.Commands[0].GetCommand() + sourceFilesFlag := "--source-files current.txt" + android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag) +} From 8fe1982e8bf6728b2f7d1de7380d9a2f86556fbe Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Thu, 14 Sep 2023 06:27:36 +0000 Subject: [PATCH 2/2] 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 --- java/java.go | 49 +++++++++++++++++++++++++++++++---------------- java/java_test.go | 24 +++++++++++++++++++---- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/java/java.go b/java/java.go index 1ee2f5df4..ee0442697 100644 --- a/java/java.go +++ b/java/java.go @@ -1624,7 +1624,8 @@ func ApiContributionFactory() android.Module { } type JavaApiImportInfo struct { - ApiFile android.Path + ApiFile android.Path + ApiSurface string } var JavaApiImportProvider = blueprint.NewProvider(JavaApiImportInfo{}) @@ -1636,7 +1637,8 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon } ctx.SetProvider(JavaApiImportProvider, JavaApiImportInfo{ - ApiFile: apiFile, + 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) diff --git a/java/java_test.go b/java/java_test.go index 8d602b70a..2ee05ec73 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -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, ` @@ -1992,8 +1998,9 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"}, }, { - moduleName: "bar3", - sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"}, + moduleName: "bar3", + // 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")