diff --git a/java/java.go b/java/java.go index 82c5535ec..97d55146c 100644 --- a/java/java.go +++ b/java/java.go @@ -388,6 +388,8 @@ var ( jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} + javaApiContributionTag = dependencyTag{name: "java-api-contribution"} + depApiSrcsTag = dependencyTag{name: "dep-api-srcs"} jniInstallTag = installDependencyTag{name: "jni install"} binaryInstallTag = installDependencyTag{name: "binary install"} usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) @@ -1609,6 +1611,13 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon }) } +type JavaApiLibraryDepsInfo struct { + StubsJar android.Path + StubsSrcJar android.Path +} + +var JavaApiLibraryDepsProvider = blueprint.NewProvider(JavaApiLibraryDepsInfo{}) + type ApiLibrary struct { android.ModuleBase android.DefaultableModuleBase @@ -1618,8 +1627,10 @@ type ApiLibrary struct { properties JavaApiLibraryProperties - stubsSrcJar android.WritablePath - stubsJar android.WritablePath + stubsSrcJar android.WritablePath + stubsJar android.WritablePath + stubsJarWithoutStaticLibs android.WritablePath + extractedSrcJar android.WritablePath // .dex of stubs, used for hiddenapi processing dexJarFile OptionalDexJarPath } @@ -1645,8 +1656,13 @@ type JavaApiLibraryProperties struct { Libs []string // List of java libs that this module has static dependencies to and will be - // passed in metalava invocation + // merge zipped after metalava invocation Static_libs []string + + // Java Api library to provide the full API surface text files and jar file. + // If this property is set, the provided full API surface text files and + // jar file are passed to metalava invocation. + Dep_api_srcs *string } func ApiLibraryFactory() android.Module { @@ -1725,7 +1741,36 @@ func (al *ApiLibrary) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBui } } -var javaApiContributionTag = dependencyTag{name: "java-api-contribution"} +// This method extracts the stub java files from the srcjar file provided from dep_api_srcs module +// and replaces the java stubs generated by invoking metalava in this module. +// This method is used because metalava can generate compilable from-text stubs only when +// the codebase encompasses all classes listed in the input API text file, but a class can extend +// a class that is not within the same API domain. +func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, depApiSrcsSrcJar android.Path) { + generatedStubsList := android.PathForModuleOut(ctx, "metalava", "sources.txt") + unzippedSrcJarDir := android.PathForModuleOut(ctx, "metalava", "unzipDir") + + rule.Command(). + BuiltTool("list_files"). + Text(stubsDir.String()). + FlagWithOutput("--out ", generatedStubsList). + FlagWithArg("--extensions ", ".java"). + FlagWithArg("--root ", unzippedSrcJarDir.String()) + + rule.Command(). + Text("unzip"). + Flag("-q"). + Input(depApiSrcsSrcJar). + FlagWithArg("-d ", unzippedSrcJarDir.String()) + + rule.Command(). + BuiltTool("soong_zip"). + Flag("-srcjar"). + Flag("-write_if_changed"). + FlagWithArg("-C ", unzippedSrcJarDir.String()). + FlagWithInput("-l ", generatedStubsList). + FlagWithOutput("-o ", al.stubsSrcJar) +} func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { apiContributions := al.properties.Api_contributions @@ -1734,6 +1779,9 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...) ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...) + if al.properties.Dep_api_srcs != nil { + ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Dep_api_srcs)) + } } func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1754,6 +1802,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { var srcFiles android.Paths var classPaths android.Paths var staticLibs android.Paths + var depApiSrcsStubsSrcJar android.Path ctx.VisitDirectDeps(func(dep android.Module) { tag := ctx.OtherModuleDependencyTag(dep) switch tag { @@ -1770,6 +1819,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { case staticLibTag: provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) staticLibs = append(staticLibs, provider.HeaderJars...) + case depApiSrcsTag: + provider := ctx.OtherModuleProvider(dep, JavaApiLibraryDepsProvider).(JavaApiLibraryDepsInfo) + classPaths = append(classPaths, provider.StubsJar) + depApiSrcsStubsSrcJar = provider.StubsSrcJar } }) @@ -1780,21 +1833,31 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { srcFiles = append(srcFiles, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), api)) } + if srcFiles == nil { + ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName()) + } + cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir) al.stubsFlags(ctx, cmd, stubsDir) al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar") - rule.Command(). - BuiltTool("soong_zip"). - Flag("-write_if_changed"). - Flag("-jar"). - FlagWithOutput("-o ", al.stubsSrcJar). - FlagWithArg("-C ", stubsDir.String()). - FlagWithArg("-D ", stubsDir.String()) + + if depApiSrcsStubsSrcJar != nil { + al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsSrcJar) + } else { + rule.Command(). + BuiltTool("soong_zip"). + Flag("-write_if_changed"). + Flag("-jar"). + FlagWithOutput("-o ", al.stubsSrcJar). + FlagWithArg("-C ", stubsDir.String()). + FlagWithArg("-D ", stubsDir.String()) + } rule.Build("metalava", "metalava merged") - compiledStubs := android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar") + + al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar") al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName())) var flags javaBuilderFlags @@ -1802,14 +1865,14 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { flags.javacFlags = strings.Join(al.properties.Javacflags, " ") flags.classpath = classpath(classPaths) - TransformJavaToClasses(ctx, compiledStubs, 0, android.Paths{}, + TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{}, android.Paths{al.stubsSrcJar}, flags, android.Paths{}) builder := android.NewRuleBuilder(pctx, ctx) builder.Command(). BuiltTool("merge_zips"). Output(al.stubsJar). - Inputs(android.Paths{compiledStubs}). + Inputs(android.Paths{al.stubsJarWithoutStaticLibs}). Inputs(staticLibs) builder.Build("merge_zips", "merge jar files") @@ -1835,6 +1898,11 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ImplementationJars: android.PathsIfNonNil(al.stubsJar), AidlIncludeDirs: android.Paths{}, }) + + ctx.SetProvider(JavaApiLibraryDepsProvider, JavaApiLibraryDepsInfo{ + StubsJar: al.stubsJar, + StubsSrcJar: al.stubsSrcJar, + }) } func (al *ApiLibrary) DexJarBuildPath() OptionalDexJarPath { diff --git a/java/java_test.go b/java/java_test.go index 68b749b6d..553b762ee 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2209,6 +2209,50 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { } } +func TestJavaApiLibraryDepApiSrcs(t *testing.T) { + provider_bp_a := ` + java_api_contribution { + name: "foo1", + api_file: "foo1.txt", + } + ` + provider_bp_b := ` + java_api_contribution { + name: "foo2", + api_file: "foo2.txt", + } + ` + lib_bp_a := ` + java_api_library { + name: "lib1", + api_surface: "public", + api_contributions: ["foo1", "foo2"], + } + ` + + ctx, _ := testJavaWithFS(t, ` + java_api_library { + name: "bar1", + api_surface: "public", + api_contributions: ["foo1"], + dep_api_srcs: "lib1", + } + `, + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + "c/Android.bp": []byte(lib_bp_a), + }) + + m := ctx.ModuleForTests("bar1", "android_common") + manifest := m.Output("metalava.sbox.textproto") + sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest) + manifestCommand := sboxProto.Commands[0].GetCommand() + + android.AssertStringDoesContain(t, "Command expected to contain module srcjar file", manifestCommand, "bar1-stubs.srcjar") + android.AssertStringDoesContain(t, "Command expected to contain output files list text file flag", manifestCommand, "--out __SBOX_SANDBOX_DIR__/out/sources.txt") +} + func TestTradefedOptions(t *testing.T) { result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, ` java_test_host {