diff options
Diffstat (limited to 'java')
-rw-r--r-- | java/aar.go | 43 | ||||
-rw-r--r-- | java/aar_test.go | 11 | ||||
-rw-r--r--[-rwxr-xr-x] | java/app.go | 18 | ||||
-rw-r--r-- | java/app_test.go | 38 | ||||
-rw-r--r-- | java/base.go | 18 | ||||
-rw-r--r-- | java/device_host_converter_test.go | 10 | ||||
-rw-r--r-- | java/droiddoc.go | 15 | ||||
-rw-r--r-- | java/fuzz.go | 2 | ||||
-rw-r--r-- | java/generated_java_library.go | 6 | ||||
-rw-r--r-- | java/generated_java_library_test.go | 4 | ||||
-rw-r--r-- | java/java.go | 23 | ||||
-rw-r--r-- | java/java_test.go | 169 | ||||
-rw-r--r-- | java/sdk_library.go | 52 | ||||
-rw-r--r-- | java/sdk_library_test.go | 35 |
14 files changed, 370 insertions, 74 deletions
diff --git a/java/aar.go b/java/aar.go index fef0d8c58..a36626732 100644 --- a/java/aar.go +++ b/java/aar.go @@ -922,7 +922,8 @@ func AndroidLibraryFactory() android.Module { module.Module.addHostAndDeviceProperties() module.AddProperties( &module.aaptProperties, - &module.androidLibraryProperties) + &module.androidLibraryProperties, + &module.sourceProperties) module.androidLibraryProperties.BuildAAR = true module.Module.linter.library = true @@ -978,6 +979,7 @@ type AARImport struct { headerJarFile android.WritablePath implementationJarFile android.WritablePath + implementationAndResourcesJarFile android.WritablePath proguardFlags android.WritablePath exportPackage android.WritablePath transitiveAaptResourcePackagesFile android.Path @@ -1013,7 +1015,7 @@ func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { case ".aar": return []android.Path{a.aarPath}, nil case "": - return []android.Path{a.implementationJarFile}, nil + return []android.Path{a.implementationAndResourcesJarFile}, nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -1155,8 +1157,9 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile) } + jarName := ctx.ModuleName() + ".jar" extractedAARDir := android.PathForModuleOut(ctx, "aar") - classpathFile := extractedAARDir.Join(ctx, ctx.ModuleName()+".jar") + classpathFile := extractedAARDir.Join(ctx, jarName) a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") a.rTxt = extractedAARDir.Join(ctx, "R.txt") a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip") @@ -1272,6 +1275,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { var staticJars android.Paths var staticHeaderJars android.Paths + var staticResourceJars android.Paths ctx.VisitDirectDeps(func(module android.Module) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { tag := ctx.OtherModuleDependencyTag(module) @@ -1279,6 +1283,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { case staticLibTag: staticJars = append(staticJars, dep.ImplementationJars...) staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...) + staticResourceJars = append(staticResourceJars, dep.ResourceJars...) } } addCLCFromDep(ctx, module, a.classLoaderContexts) @@ -1287,18 +1292,39 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { var implementationJarFile android.OutputPath if len(staticJars) > 0 { combineJars := append(android.Paths{classpathFile}, staticJars...) - implementationJarFile = android.PathForModuleOut(ctx, "combined", ctx.ModuleName()+".jar").OutputPath + implementationJarFile = android.PathForModuleOut(ctx, "combined", jarName).OutputPath TransformJarsToJar(ctx, implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil) } else { implementationJarFile = classpathFile } + var resourceJarFile android.Path + if len(staticResourceJars) > 1 { + combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) + TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{}, + false, nil, nil) + resourceJarFile = combinedJar + } else if len(staticResourceJars) == 1 { + resourceJarFile = staticResourceJars[0] + } + + // merge implementation jar with resources if necessary + implementationAndResourcesJar := implementationJarFile + if resourceJarFile != nil { + jars := android.Paths{resourceJarFile, implementationAndResourcesJar} + combinedJar := android.PathForModuleOut(ctx, "withres", jarName).OutputPath + TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{}, + false, nil, nil) + implementationAndResourcesJar = combinedJar + } + + a.implementationJarFile = implementationJarFile // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource - a.implementationJarFile = implementationJarFile.WithoutRel() + a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel() if len(staticHeaderJars) > 0 { combineJars := append(android.Paths{classpathFile}, staticHeaderJars...) - a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", ctx.ModuleName()+".jar") + a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", jarName) TransformJarsToJar(ctx, a.headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil) } else { a.headerJarFile = classpathFile @@ -1306,9 +1332,10 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, JavaInfoProvider, JavaInfo{ HeaderJars: android.PathsIfNonNil(a.headerJarFile), + ResourceJars: android.PathsIfNonNil(resourceJarFile), TransitiveLibsHeaderJars: a.transitiveLibsHeaderJars, TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars, - ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationJarFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile), ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), StubsLinkType: Implementation, // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts @@ -1346,7 +1373,7 @@ func (a *AARImport) HeaderJars() android.Paths { } func (a *AARImport) ImplementationAndResourcesJars() android.Paths { - return android.Paths{a.implementationJarFile} + return android.Paths{a.implementationAndResourcesJarFile} } func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { diff --git a/java/aar_test.go b/java/aar_test.go index 3361bf929..d6dbe3c25 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -136,18 +136,19 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { android_library { name: "foo", srcs: ["a.java"], + java_resources: ["foo.txt"], } android_library_import { name: "bar", - aars: ["bar.aar"], + aars: ["bar_prebuilt.aar"], } android_library_import { name: "baz", - aars: ["baz.aar"], - static_libs: ["bar"], + aars: ["baz_prebuilt.aar"], + static_libs: ["foo", "bar"], } `) @@ -160,11 +161,11 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "") android.AssertPathRelativeToTopEquals(t, "foo output path", - "out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath) + "out/soong/.intermediates/foo/android_common/withres/foo.jar", fooOutputPath) android.AssertPathRelativeToTopEquals(t, "bar output path", "out/soong/.intermediates/bar/android_common/aar/bar.jar", barOutputPath) android.AssertPathRelativeToTopEquals(t, "baz output path", - "out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath) + "out/soong/.intermediates/baz/android_common/withres/baz.jar", bazOutputPath) android.AssertStringEquals(t, "foo relative output path", "foo.jar", fooOutputPath.Rel()) diff --git a/java/app.go b/java/app.go index 7b2577538..1aa3afe8e 100755..100644 --- a/java/app.go +++ b/java/app.go @@ -329,6 +329,10 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon a.aapt.manifestValues.applicationId = *applicationId } a.generateAndroidBuildActions(ctx) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + }) + } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1191,7 +1195,8 @@ func AndroidAppFactory() android.Module { module.AddProperties( &module.aaptProperties, &module.appProperties, - &module.overridableAppProperties) + &module.overridableAppProperties, + &module.Library.sourceProperties) module.usesLibrary.enforce = true @@ -1340,6 +1345,11 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { TestSuites: a.testProperties.Test_suites, IsHost: false, }) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) + } func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path { @@ -1532,9 +1542,13 @@ type OverrideAndroidTest struct { android.OverrideModuleBase } -func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) { +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) } // override_android_test is used to create an android_app module based on another android_test by overriding diff --git a/java/app_test.go b/java/app_test.go index 8262777b2..0c2800041 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -4432,6 +4432,44 @@ func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) { android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil) } +func TestTestOnlyApp(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + // These should be test-only + android_test { + name: "android-test", + } + android_test_helper_app { + name: "helper-app", + } + override_android_test { + name: "override-test", + base: "android-app", + } + // And these should not be + android_app { + name: "android-app", + srcs: ["b.java"], + sdk_version: "current", + } + `) + + expectedTestOnly := []string{ + "android-test", + "helper-app", + "override-test", + } + + expectedTopLevel := []string{ + "android-test", + "override-test", + } + + assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel) +} + func TestAppStem(t *testing.T) { ctx := testApp(t, ` android_app { diff --git a/java/base.go b/java/base.go index e2f20cee5..ef61f1cc2 100644 --- a/java/base.go +++ b/java/base.go @@ -197,6 +197,9 @@ type CommonProperties struct { // Additional srcJars tacked in by GeneratedJavaLibraryModule Generated_srcjars []android.Path `android:"mutated"` + // intermediate aconfig cache file tacked in by GeneratedJavaLibraryModule + Aconfig_Cache_files []android.Path `android:"mutated"` + // If true, then only the headers are built and not the implementation jar. Headers_only *bool @@ -432,6 +435,7 @@ type Module struct { deviceProperties DeviceProperties overridableProperties OverridableProperties + sourceProperties android.SourceProperties // jar file containing header classes including static library dependencies, suitable for // inserting into the bootclasspath/classpath of another compile @@ -541,6 +545,11 @@ type Module struct { jarjarRenameRules map[string]string stubsLinkType StubsLinkType + + // Paths to the aconfig intermediate cache files that are provided by the + // java_aconfig_library or java_library modules that are statically linked + // to this module. Does not contain cache files from all transitive dependencies. + aconfigCacheFiles android.Paths } func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { @@ -1197,6 +1206,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // final R classes from the app. flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...) + j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...) + // If compiling headers then compile them and skip the rest if proptools.Bool(j.properties.Headers_only) { if srcFiles.HasExt(".kt") { @@ -1736,7 +1747,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ExportedPluginDisableTurbine: j.exportedDisableTurbine, JacocoReportClassesFile: j.jacocoReportClassesFile, StubsLinkType: j.stubsLinkType, - AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles, + AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles, }) // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource @@ -2350,7 +2361,10 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) } } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok { - deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) + switch tag { + case staticLibTag: + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) + } } else { switch tag { case bootClasspathTag: diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go index 3413da03d..6ccc5c1b1 100644 --- a/java/device_host_converter_test.go +++ b/java/device_host_converter_test.go @@ -16,7 +16,7 @@ package java import ( "android/soong/android" - "reflect" + "slices" "strings" "testing" ) @@ -84,7 +84,7 @@ func TestDeviceForHost(t *testing.T) { deviceImportCombined.Output, } - if !reflect.DeepEqual(combined.Inputs, expectedInputs) { + if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected host_module combined inputs:\n%q\ngot:\n%q", expectedInputs, combined.Inputs) } @@ -95,7 +95,7 @@ func TestDeviceForHost(t *testing.T) { deviceRes.Output, } - if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) { + if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected host_module res combined inputs:\n%q\ngot:\n%q", expectedInputs, resCombined.Inputs) } @@ -165,7 +165,7 @@ func TestHostForDevice(t *testing.T) { hostImportCombined.Output, } - if !reflect.DeepEqual(combined.Inputs, expectedInputs) { + if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected device_module combined inputs:\n%q\ngot:\n%q", expectedInputs, combined.Inputs) } @@ -176,7 +176,7 @@ func TestHostForDevice(t *testing.T) { hostRes.Output, } - if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) { + if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected device_module res combined inputs:\n%q\ngot:\n%q", expectedInputs, resCombined.Inputs) } diff --git a/java/droiddoc.go b/java/droiddoc.go index aec40b312..176779eb4 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -391,12 +391,14 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { deps.classpath = append(deps.classpath, dep.HeaderJars...) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) } else if dep, ok := module.(android.SourceFileProducer); ok { checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } + case java9LibTag: if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) @@ -429,6 +431,19 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) j.implicits = append(j.implicits, srcFiles...) + // Module can depend on a java_aconfig_library module using the ":module_name{.tag}" syntax. + // Find the corresponding aconfig_declarations module name for such case. + for _, src := range j.properties.Srcs { + if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" { + otherModule := android.GetModuleFromPathDep(ctx, moduleName, tag) + if otherModule != nil { + if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok { + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) + } + } + } + } + filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path { if filterPackages == nil { return srcs diff --git a/java/fuzz.go b/java/fuzz.go index dc4c6bec5..fb31ce794 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -64,6 +64,8 @@ func JavaFuzzFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) + module.Module.sourceProperties.Top_level_test_target = true android.AddLoadHook(module, func(ctx android.LoadHookContext) { disableLinuxBionic := struct { diff --git a/java/generated_java_library.go b/java/generated_java_library.go index e8316ccc4..d5e6d8fec 100644 --- a/java/generated_java_library.go +++ b/java/generated_java_library.go @@ -34,7 +34,7 @@ type GeneratedJavaLibraryCallbacks interface { // Called from inside GenerateAndroidBuildActions. Add the build rules to // make the srcjar, and return the path to it. - GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path + GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) } // GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated @@ -103,8 +103,10 @@ func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx androi checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins) checkPropertyEmpty(ctx, module, "exported_plugins", module.Library.properties.Exported_plugins) - srcJarPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx) + srcJarPath, cacheOutputPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx) + module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath) + module.Library.properties.Aconfig_Cache_files = append(module.Library.properties.Aconfig_Cache_files, cacheOutputPath) module.Library.GenerateAndroidBuildActions(ctx) } diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go index be816cda9..a5c4be111 100644 --- a/java/generated_java_library_test.go +++ b/java/generated_java_library_test.go @@ -36,8 +36,8 @@ type JavaGenLibTestCallbacks struct { func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) { } -func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path { - return android.PathForOutput(ctx, "blah.srcjar") +func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) { + return android.PathForOutput(ctx, "blah.srcjar"), android.PathForOutput(ctx, "blah.pb") } func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult { diff --git a/java/java.go b/java/java.go index fb5bb1cae..ca99e6991 100644 --- a/java/java.go +++ b/java/java.go @@ -958,6 +958,11 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) } + + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: Bool(j.sourceProperties.Test_only), + TopLevelTarget: j.sourceProperties.Top_level_test_target, + }) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -1123,6 +1128,7 @@ func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() + module.AddProperties(&module.sourceProperties) module.initModuleAndImport(module) @@ -1604,6 +1610,8 @@ func TestFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) + module.Module.sourceProperties.Top_level_test_target = true InitJavaModule(module, android.HostAndDeviceSupported) return module @@ -1619,6 +1627,7 @@ func TestHelperLibraryFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) InitJavaModule(module, android.HostAndDeviceSupported) return module @@ -1674,6 +1683,8 @@ func InitTestHost(th *TestHost, installable *bool, testSuites []string, autoGenC th.properties.Installable = installable th.testProperties.Auto_gen_config = autoGenConfig th.testProperties.Test_suites = testSuites + th.sourceProperties.Test_only = proptools.BoolPtr(true) + th.sourceProperties.Top_level_test_target = true } // @@ -1799,7 +1810,7 @@ func BinaryFactory() android.Module { module := &Binary{} module.addHostAndDeviceProperties() - module.AddProperties(&module.binaryProperties) + module.AddProperties(&module.binaryProperties, &module.sourceProperties) module.Module.properties.Installable = proptools.BoolPtr(true) @@ -2564,7 +2575,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // header jar for this module. reuseImplementationJarAsHeaderJar := slices.Equal(staticJars, staticHeaderJars) - var headerOutputFile android.WritablePath + var headerOutputFile android.ModuleOutPath if reuseImplementationJarAsHeaderJar { headerOutputFile = outputFile } else { @@ -2587,8 +2598,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { headerOutputFile = outputFile } } - j.combinedHeaderFile = headerOutputFile - j.combinedImplementationFile = outputFile + + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource. + // Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check + // in a module that depends on this module considers them equal. + j.combinedHeaderFile = headerOutputFile.WithoutRel() + j.combinedImplementationFile = outputFile.WithoutRel() j.maybeInstall(ctx, jarName, outputFile) diff --git a/java/java_test.go b/java/java_test.go index 2676aa558..a1192bb5f 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2838,6 +2838,99 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt") } +func TestTestOnly(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + // These should be test-only + java_library { + name: "lib1-test-only", + srcs: ["a.java"], + test_only: true, + } + java_test { + name: "java-test", + } + java_test_host { + name: "java-test-host", + } + java_test_helper_library { + name: "helper-library", + } + java_binary { + name: "java-data-binary", + srcs: ["foo.java"], + main_class: "foo.bar.jb", + test_only: true, + } + + // These are NOT + java_library { + name: "lib2-app", + srcs: ["b.java"], + } + java_import { + name: "bar", + jars: ["bar.jar"], + } + java_binary { + name: "java-binary", + srcs: ["foo.java"], + main_class: "foo.bar.jb", + } + `) + + expectedTestOnlyModules := []string{ + "lib1-test-only", + "java-test", + "java-test-host", + "helper-library", + "java-data-binary", + } + expectedTopLevelTests := []string{ + "java-test", + "java-test-host", + } + assertTestOnlyAndTopLevel(t, ctx, expectedTestOnlyModules, expectedTopLevelTests) +} + +// Don't allow setting test-only on things that are always tests or never tests. +func TestInvalidTestOnlyTargets(t *testing.T) { + testCases := []string{ + ` java_test { name: "java-test", test_only: true, srcs: ["foo.java"], } `, + ` java_test_host { name: "java-test-host", test_only: true, srcs: ["foo.java"], } `, + ` java_test_import { name: "java-test-import", test_only: true, } `, + ` java_api_library { name: "java-api-library", test_only: true, } `, + ` java_test_helper_library { name: "test-help-lib", test_only: true, } `, + ` java_defaults { name: "java-defaults", test_only: true, } `, + } + + for i, bp := range testCases { + android.GroupFixturePreparers(prepareForJavaTest). + ExtendWithErrorHandler( + expectOneError("unrecognized property \"test_only\"", + fmt.Sprintf("testcase: %d", i))). + RunTestWithBp(t, bp) + } +} + +// Expect exactly one that matches 'expected'. +// Append 'msg' to the Errorf that printed. +func expectOneError(expected string, msg string) android.FixtureErrorHandler { + return android.FixtureCustomErrorHandler(func(t *testing.T, result *android.TestResult) { + t.Helper() + if len(result.Errs) != 1 { + t.Errorf("Expected exactly one error, but found: %d when setting test_only on: %s", len(result.Errs), msg) + return + } + actualErrMsg := result.Errs[0].Error() + if !strings.Contains(actualErrMsg, expected) { + t.Errorf("Different error than expected. Received: [%v] on %s expected: %s", actualErrMsg, msg, expected) + } + }) +} + func TestJavaLibHostWithStem(t *testing.T) { ctx, _ := testJava(t, ` java_library_host { @@ -2872,3 +2965,79 @@ func TestJavaLibWithStem(t *testing.T) { t.Errorf("Module output does not contain expected jar %s", "foo-new.jar") } } + +func TestJavaLibraryOutputFilesRel(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + } + + java_import { + name: "bar", + jars: ["bar.aar"], + + } + + java_import { + name: "baz", + jars: ["baz.aar"], + static_libs: ["bar"], + } + `) + + foo := result.ModuleForTests("foo", "android_common") + bar := result.ModuleForTests("bar", "android_common") + baz := result.ModuleForTests("baz", "android_common") + + fooOutputPath := android.OutputFileForModule(android.PathContext(nil), foo.Module(), "") + barOutputPath := android.OutputFileForModule(android.PathContext(nil), bar.Module(), "") + bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "") + + android.AssertPathRelativeToTopEquals(t, "foo output path", + "out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath) + android.AssertPathRelativeToTopEquals(t, "bar output path", + "out/soong/.intermediates/bar/android_common/combined/bar.jar", barOutputPath) + android.AssertPathRelativeToTopEquals(t, "baz output path", + "out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath) + + android.AssertStringEquals(t, "foo relative output path", + "foo.jar", fooOutputPath.Rel()) + android.AssertStringEquals(t, "bar relative output path", + "bar.jar", barOutputPath.Rel()) + android.AssertStringEquals(t, "baz relative output path", + "baz.jar", bazOutputPath.Rel()) +} + +func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) { + t.Helper() + actualTrueModules := []string{} + actualTopLevelTests := []string{} + addActuals := func(m blueprint.Module, key blueprint.ProviderKey[android.TestModuleInformation]) { + if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, key); ok { + if provider.TestOnly { + actualTrueModules = append(actualTrueModules, m.Name()) + } + if provider.TopLevelTarget { + actualTopLevelTests = append(actualTopLevelTests, m.Name()) + } + } + } + + ctx.VisitAllModules(func(m blueprint.Module) { + addActuals(m, android.TestOnlyProviderKey) + + }) + + notEqual, left, right := android.ListSetDifference(expectedTestOnly, actualTrueModules) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } + + notEqual, left, right = android.ListSetDifference(expectedTopLevel, actualTopLevelTests) + if notEqual { + t.Errorf("top-level: Expected but not found: %v, Found but not expected: %v", left, right) + } +} diff --git a/java/sdk_library.go b/java/sdk_library.go index 355654fb2..e7e53a2a8 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -3238,14 +3238,14 @@ func formattedOptionalAttribute(attrName string, value *string) string { if value == nil { return "" } - return fmt.Sprintf(` %s=\"%s\"\n`, attrName, *value) + return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value) } func formattedDependenciesAttribute(dependencies []string) string { if dependencies == nil { return "" } - return fmt.Sprintf(` dependency=\"%s\"\n`, strings.Join(dependencies, ":")) + return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":")) } func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { @@ -3262,28 +3262,28 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T var libraryTag string if module.properties.Min_device_sdk != nil { - libraryTag = ` <apex-library\n` + libraryTag = " <apex-library\n" } else { - libraryTag = ` <library\n` + libraryTag = " <library\n" } return strings.Join([]string{ - `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`, - `<!-- Copyright (C) 2018 The Android Open Source Project\n`, - `\n`, - ` Licensed under the Apache License, Version 2.0 (the \"License\");\n`, - ` you may not use this file except in compliance with the License.\n`, - ` You may obtain a copy of the License at\n`, - `\n`, - ` http://www.apache.org/licenses/LICENSE-2.0\n`, - `\n`, - ` Unless required by applicable law or agreed to in writing, software\n`, - ` distributed under the License is distributed on an \"AS IS\" BASIS,\n`, - ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`, - ` See the License for the specific language governing permissions and\n`, - ` limitations under the License.\n`, - `-->\n`, - `<permissions>\n`, + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", + "<!-- Copyright (C) 2018 The Android Open Source Project\n", + "\n", + " Licensed under the Apache License, Version 2.0 (the \"License\");\n", + " you may not use this file except in compliance with the License.\n", + " You may obtain a copy of the License at\n", + "\n", + " http://www.apache.org/licenses/LICENSE-2.0\n", + "\n", + " Unless required by applicable law or agreed to in writing, software\n", + " distributed under the License is distributed on an \"AS IS\" BASIS,\n", + " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + " See the License for the specific language governing permissions and\n", + " limitations under the License.\n", + "-->\n", + "<permissions>\n", libraryTag, libNameAttr, filePathAttr, @@ -3292,8 +3292,9 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri minSdkAttr, maxSdkAttr, dependenciesAttr, - ` />\n`, - `</permissions>\n`}, "") + " />\n", + "</permissions>\n", + }, "") } func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -3305,12 +3306,7 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte xmlContent := module.permissionsContents(ctx) module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath - rule := android.NewRuleBuilder(pctx, ctx) - rule.Command(). - Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > "). - Output(module.outputFilePath) - - rule.Build("java_sdk_xml", "Permission XML") + android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) } diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index a19d3829f..5fac2556d 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -227,19 +227,21 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { `) // test that updatability attributes are passed on correctly - fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml") - android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"U\"`) - android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"V\"`) - android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"W\"`) - android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"X\"`) + fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Output("fooUpdatable.xml") + fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable) + android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-since="U"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-before="V"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `min-device-sdk="W"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `max-device-sdk="X"`) // double check that updatability attributes are not written if they don't exist in the bp file // the permissions file for the foo library defined above - fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") - android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`) - android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`) - android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`) - android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`) + fooPermissions := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml") + fooPermissionsContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooPermissions) + android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-since`) + android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-before`) + android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `min-device-sdk`) + android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `max-device-sdk`) } func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) { @@ -370,9 +372,10 @@ func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) { } `) // test that updatability attributes are passed on correctly - fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") - android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<apex-library`) - android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`) + fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml") + fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable) + android.AssertStringDoesContain(t, "foo.xml contents", fooUpdatableContents, `<apex-library`) + android.AssertStringDoesNotContain(t, "foo.xml contents", fooUpdatableContents, `<library`) } func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { @@ -1707,9 +1710,9 @@ func TestSdkLibraryDependency(t *testing.T) { } `) - barPermissions := result.ModuleForTests("bar.xml", "android_common").Rule("java_sdk_xml") - - android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barPermissions.RuleParams.Command, `dependency=\"foo\"`) + barPermissions := result.ModuleForTests("bar.xml", "android_common").Output("bar.xml") + barContents := android.ContentFromFileRuleForTests(t, result.TestContext, barPermissions) + android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barContents, `dependency="foo"`) } func TestSdkLibraryExportableStubsLibrary(t *testing.T) { |